Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: Warzone2100/warzone2100
base: 281dfd0
...
head fork: Warzone2100/warzone2100
compare: 7b87b26
  • 12 commits
  • 38 files changed
  • 0 commit comments
  • 1 contributor
Showing with 889 additions and 615 deletions.
  1. +1 −1  data/Makefile.am
  2. +1 −1  data/base/stats/templates.txt
  3. +1 −0  data/mp/stats/research/multiplayer/redcomponents.txt
  4. +1 −0  data/mp/stats/research/multiplayer/redstructure.txt
  5. +1 −1  data/mp/stats/research/multiplayer/research.txt
  6. +1 −0  data/mp/stats/research/multiplayer/researchfunctions.txt
  7. +1 −0  data/mp/stats/research/multiplayer/researchstruct.txt
  8. +1 −0  data/mp/stats/research/multiplayer/resultcomponent.txt
  9. +1 −0  data/mp/stats/research/multiplayer/resultstructure.txt
  10. +1 −1  data/mp/stats/templates.txt
  11. +2 −0  src/Makefile.am
  12. +1 −0  src/ai.cpp
  13. +1 −0  src/data.cpp
  14. +64 −2 src/design.cpp
  15. +2 −0  src/design.h
  16. +5 −540 src/droid.cpp
  17. +0 −30 src/droid.h
  18. +1 −0  src/droiddef.h
  19. +1 −0  src/game.cpp
  20. +1 −0  src/hci.cpp
  21. +6 −0 src/init.cpp
  22. +1 −0  src/keybind.cpp
  23. +1 −0  src/map.cpp
  24. +4 −3 src/multimenu.cpp
  25. +1 −1  src/multiopt.cpp
  26. +8 −3 src/multiplay.cpp
  27. +9 −10 src/projectile.cpp
  28. +1 −0  src/qtscriptfuncs.cpp
  29. +29 −4 src/research.cpp
  30. +1 −0  src/scriptfuncs.cpp
  31. +1 −1  src/scriptobj.cpp
  32. +1 −0  src/scriptvals_parser.ypp
  33. +21 −16 src/stats.cpp
  34. +1 −0  src/stats.h
  35. +1 −0  src/statsdef.h
  36. +1 −1  src/structure.cpp
  37. +672 −0 src/template.cpp
  38. +42 −0 src/template.h
2  data/Makefile.am
View
@@ -4,7 +4,7 @@ stamp:
touch stamp
%.wz: $(abs_srcdir)/% stamp
- (cd $(srcdir)/$(notdir $<) && $(ZIP) -r0 $(ZIP_UPDATE) $(abs_builddir)/$@ $(filter-out stamp,$(filter-out $<,$(^:$</%=%))) -x '*svn*' -x '*Makefile*' || [ $$? -eq 12 ] && true) # zip returns 12 on "nothing to do"
+ (cd $(srcdir)/$(notdir $<) && $(ZIP) -r0 $(ZIP_UPDATE) $(abs_builddir)/$@ $(filter-out stamp,$(filter-out $<,$(^:$</%=%))) -x '*svn*' -x '*Makefile*' -x '*.svg' || [ $$? -eq 12 ] && true) # zip returns 12 on "nothing to do"
$(ZIP) -T $@
rm -f stamp
2  data/base/stats/templates.txt
View
@@ -1,5 +1,5 @@
BarbarianTrike,139,B4body-sml-trike01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,7,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
-ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,0,wheeled01,ZNULLREPAIR,DROID,DefaultSensor1Mk1,0
+ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,0,wheeled01,ZNULLREPAIR,DROID,ZNULLSENSOR,0
BarbarianBuggy,150,B3body-sml-buggy01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,7,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
BaBaPeople,158,B1BaBaPerson01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,7,BaBaLegs,ZNULLREPAIR,PERSON,DefaultSensor1Mk1,1
ViperLtCannonWheels,177,Body1REC,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,4,wheeled01,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
1  data/mp/stats/research/multiplayer/redcomponents.txt
View
@@ -1,3 +1,4 @@
+Research ID,Component ID,unused
R-Comp-CommandTurret02,CommandTurret1,WEAPON,10
R-Comp-CommandTurret03,CommandTurret2,WEAPON,10
R-Comp-CommandTurret04,CommandTurret3,WEAPON,10
1  data/mp/stats/research/multiplayer/redstructure.txt
View
@@ -1,3 +1,4 @@
+Research ID,Structure ID,unused
R-Defense-AASite-QuadRotMg,AASite-QuadMg1,189
R-Defense-Emplacement-HPVcannon,PillBox4,130
R-Defense-GuardTower-ATMiss,GuardTower5,123
2  data/mp/stats/research/multiplayer/research.txt
View
@@ -1,4 +1,4 @@
-Research ID,-,Left icon,Major tech,Right icon,IMD,-,MsgName,StructName,CompName,CompType,ResearchPoints,keyTopic,Prereqs,Function results,Structure prereqs,Redundant structures,Structure results,Redundant components,Component results
+Research ID,unused,Subgroup icon,Major tech,Main icon,IMD,IMD2,MsgName,StructName,CompName,CompType,ResearchPoints,keyTopic,unused,unused,unused,unused,unused,unused,unused
R-Cyborg-Wpn-Thermite,Level Two,0,0,IMAGE_RES_CYBORGTECH,0,0,RES_CYW_TFL,0,Flame2,WEAPON,900,0,0,0,0,0,0,0,0
R-Cyborg-Wpn-Grenade,Level Two,0,0,IMAGE_RES_CYBORGTECH,0,0,RES_CYW_GRN,0,Mortar1Mk1,WEAPON,900,0,0,0,0,0,0,0,0
R-Cyborg-Sys-ComEng,Level One,0,0,IMAGE_RES_CYBORGTECH,0,0,RES_CYS_CEN,0,Spade1Mk1,CONSTRUCT,600,0,0,0,0,0,0,0,0
1  data/mp/stats/research/multiplayer/researchfunctions.txt
View
@@ -1,3 +1,4 @@
+Research ID,Function ID,unused
R-Struc-PowerModuleMk1,Struc-PowerModuleMk1,225
R-Vehicle-Engine01,Vehicle-Engine01,381
R-Vehicle-Engine02,Vehicle-Engine02,382
1  data/mp/stats/research/multiplayer/researchstruct.txt
View
@@ -1,3 +1,4 @@
+Research ID,Structure ID,unused
R-Defense-Tower01,A0CommandCentre,0
R-Defense-Tower06,A0CommandCentre,0
R-Defense-Pillbox01,A0CommandCentre,0
1  data/mp/stats/research/multiplayer/resultcomponent.txt
View
@@ -1,3 +1,4 @@
+Research ID,Component ID,Type,Replaced Component,Replaced Type,unused
R-Wpn-AAGun02,AAGun2Mk1,WEAPON,0,0,10
R-Wpn-AALaser,AAGunLaser,WEAPON,0,0,10
R-Sys-Autorepair-General,AutoRepair,REPAIR,ZNULLREPAIR,REPAIR,6
1  data/mp/stats/research/multiplayer/resultstructure.txt
View
@@ -1,3 +1,4 @@
+Research ID,Structure ID,unused,unused
R-Defense-AA-Laser,P0-AASite-Laser,0,340
R-Defense-AASite-QuadBof,AASite-QuadBof,0,188
R-Defense-AASite-QuadMg1,AASite-QuadMg1,0,189
2  data/mp/stats/templates.txt
View
@@ -1,4 +1,4 @@
-ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,YES,wheeled01,ZNULLREPAIR,DROID,DefaultSensor1Mk1,0
+ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,YES,wheeled01,ZNULLREPAIR,DROID,ZNULLSENSOR,0
BarbarianTrike,139,B4body-sml-trike01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,NO,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
BarbarianBuggy,150,B3body-sml-buggy01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,NO,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
BaBaPeople,158,B1BaBaPerson01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,NO,BaBaLegs,ZNULLREPAIR,PERSON,DefaultSensor1Mk1,1
2  src/Makefile.am
View
@@ -140,6 +140,7 @@ noinst_HEADERS = \
stringdef.h \
structuredef.h \
structure.h \
+ template.h \
terrain.h \
text.h \
texture.h \
@@ -254,6 +255,7 @@ warzone2100_SOURCES = \
seqdisp.cpp \
stats.cpp \
structure.cpp \
+ template.cpp \
terrain.cpp \
text.cpp \
texture.cpp \
1  src/ai.cpp
View
@@ -377,6 +377,7 @@ static SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker,
/* Now calculate the overall weight */
attackWeight = asWeaponModifier[weaponEffect][(asPropulsionStats + targetDroid->asBits[COMP_PROPULSION].nStat)->propulsionType] // Our weapon's effect against target
+ + asWeaponModifierBody[weaponEffect][(asBodyStats + targetDroid->asBits[COMP_BODY].nStat)->size]
+ WEIGHT_DIST_TILE_DROID * psAttacker->sensorRange/TILE_UNITS
- WEIGHT_DIST_TILE_DROID * map_coord(iHypot(psAttacker->pos.x - targetDroid->pos.x, psAttacker->pos.y - targetDroid->pos.y)) // farer droids are less attractive
+ WEIGHT_HEALTH_DROID * damageRatio // we prefer damaged droids
1  src/data.cpp
View
@@ -48,6 +48,7 @@
#include "research.h"
#include "scriptvals.h"
#include "stats.h"
+#include "template.h"
#include "text.h"
#include "texture.h"
66 src/design.cpp
View
@@ -77,7 +77,7 @@
#include "cmddroid.h"
#include "scriptextern.h"
#include "mission.h"
-
+#include "template.h"
#include "multiplay.h"
#include "multistat.h"
@@ -362,6 +362,13 @@ static bool saveTemplate();
static void desCreateDefaultTemplate( void );
+/**
+ * Updates the status of the stored template toggle button.
+ *
+ * @param isStored If the template is stored or not.
+ */
+static void updateStoreButton(bool isStored);
+
/* The current name of the design */
static char aCurrName[WIDG_MAXSTR];
@@ -452,6 +459,7 @@ static bool _intAddDesign( bool bShowCentreScreen )
/* Initialise the current design */
sCurrDesign = sDefaultDesignTemplate;
sCurrDesign.pName = NULL;
+ sCurrDesign.stored = false;
sstrcpy(aCurrName, _("New Vehicle"));
sstrcpy(sCurrDesign.aName, aCurrName);
@@ -612,6 +620,24 @@ static bool _intAddDesign( bool bShowCentreScreen )
return false;
}
+ // Add the store template button
+ sButInit.formID = IDDES_PARTFORM;
+ sButInit.id = IDDES_STOREBUTTON;
+ sButInit.style = WBUT_PLAIN;
+ sButInit.width = iV_GetImageWidth(IntImages, IMAGE_DES_BIN);
+ sButInit.height = iV_GetImageHeight(IntImages, IMAGE_DES_BIN);
+ sButInit.x = DES_PARTSEPARATIONX;
+ sButInit.y = DES_PARTFORMHEIGHT - 2*sButInit.height - 2*DES_PARTSEPARATIONY;
+ sButInit.pTip = _("Store Design");
+ sButInit.FontID = font_regular;
+ sButInit.pDisplay = intDisplayButtonHilight;
+ sButInit.UserData = PACKDWORD_TRI(0, IMAGE_DES_BINH, IMAGE_DES_BIN);
+
+ if (!widgAddButton(psWScreen, &sButInit))
+ {
+ return false;
+ }
+
/* add central stats form */
sFormInit.formID = 0;
sFormInit.id = IDDES_STATSFORM;
@@ -866,7 +892,8 @@ void desSetupDesignTemplates(void)
psTempl->droidType != DROID_CYBORG_SUPER &&
psTempl->droidType != DROID_CYBORG_CONSTRUCT &&
psTempl->droidType != DROID_CYBORG_REPAIR &&
- psTempl->droidType != DROID_PERSON)
+ psTempl->droidType != DROID_PERSON &&
+ researchedTemplate(psTempl, selectedPlayer))
{
apsTemplateList.push_back(psTempl);
}
@@ -3276,6 +3303,12 @@ bool intValidTemplate(DROID_TEMPLATE *psTempl, const char *newName)
}
}
+ // Check number of weapon slots
+ if (psTempl->numWeaps > (asBodyStats + psTempl->asParts[COMP_BODY])->weaponSlots)
+ {
+ return false;
+ }
+
// Check no mixing of systems and weapons
if (psTempl->numWeaps != 0 &&
(psTempl->asParts[COMP_SENSOR] ||
@@ -3338,6 +3371,7 @@ static void desCreateDefaultTemplate( void )
/* set current design to default */
sCurrDesign = sDefaultDesignTemplate;
sCurrDesign.pName = NULL;
+ sCurrDesign.stored = false;
/* reset stats */
intSetDesignStats(&sCurrDesign);
@@ -3450,6 +3484,8 @@ void intProcessDesign(UDWORD id)
intSetButtonFlash( IDDES_PROPBUTTON, true );
intSetButtonFlash( IDDES_WPABUTTON, true );
intSetButtonFlash( IDDES_WPBBUTTON, true );
+
+ widgHide(psWScreen, IDDES_STOREBUTTON);
}
else
{
@@ -3496,6 +3532,9 @@ void intProcessDesign(UDWORD id)
{
intSetButtonFlash( IDDES_WPBBUTTON, true );
}
+
+ widgReveal(psWScreen, IDDES_STOREBUTTON);
+ updateStoreButton(sCurrDesign.stored);
}
}
@@ -4008,6 +4047,10 @@ void intProcessDesign(UDWORD id)
}
break;
}
+ case IDDES_STOREBUTTON:
+ sCurrDesign.stored = !sCurrDesign.stored; // Invert the current status
+ saveTemplate();
+ break;
case IDDES_SYSTEMBUTTON:
// Add the correct component form
switch (droidTemplateType(&sCurrDesign))
@@ -4409,8 +4452,11 @@ static bool saveTemplate(void)
{
if (!intValidTemplate(&sCurrDesign, aCurrName))
{
+ widgHide(psWScreen, IDDES_STOREBUTTON);
return false;
}
+ widgReveal(psWScreen, IDDES_STOREBUTTON);
+ updateStoreButton(sCurrDesign.stored); // Change the buttons icon
/* if first (New Design) button selected find empty template
* else find current button template
@@ -4436,6 +4482,7 @@ static bool saveTemplate(void)
psTempl = templateFromButtonId(droidTemplID);
if (psTempl == NULL)
{
+ debug(LOG_ERROR, "Template not found for button");
return false;
}
@@ -4636,3 +4683,18 @@ void reverseTemplateList(DROID_TEMPLATE **ppsList)
*ppsList = psPrev;
}
+void updateStoreButton(bool isStored)
+{
+ UDWORD imageset;
+
+ if (isStored)
+ {
+ imageset = PACKDWORD_TRI(0, IMAGE_DES_TURRETH, IMAGE_DES_TURRET);
+ }
+ else
+ {
+ imageset = PACKDWORD_TRI(0, IMAGE_DES_BINH, IMAGE_DES_BIN);
+ }
+
+ widgSetUserData2(psWScreen, IDDES_STOREBUTTON, imageset);
+}
2  src/design.h
View
@@ -59,6 +59,8 @@
#define IDDES_WEAPONS_A 5028 // The weapon TURRET_A button for the Component form (right)
#define IDDES_WEAPONS_B 5029 // The weapon TURRET_B button for the Component form (right)
+#define IDDES_STOREBUTTON 5905 // Stored template button
+
/* Design screen bar graph IDs */
#define IDDES_BODYARMOUR_K 5100 // The body armour bar graph for kinetic weapons
#define IDDES_BODYPOWER 5101 // The body power plant graph
545 src/droid.cpp
View
@@ -82,32 +82,23 @@
#include "research.h"
#include "combat.h"
#include "scriptfuncs.h" //for ThreatInRange()
-#include "design.h" //for GetDefaultTemplateName
+#include "template.h"
#define DEFAULT_RECOIL_TIME (GAME_TICKS_PER_SEC/4)
#define DROID_DAMAGE_SPREAD (16 - rand()%32)
#define DROID_REPAIR_SPREAD (20 - rand()%40)
-
-/* default droid design template */
-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];
UDWORD selectedGroup = UBYTE_MAX;
UDWORD selectedCommander = UBYTE_MAX;
+/* default droid design template */
+extern DROID_TEMPLATE sDefaultDesignTemplate;
+
/** Height the transporter hovers at above the terrain. */
#define TRANSPORTER_HOVER_HEIGHT 10
-/* Sorry, Keith, your abreviation [sic] is gone.
- * NAYBOR = neighbour - thanks to Keith for a great abreviation
- */
-
// the structure that was last hit
DROID *psLastDroidHit;
@@ -1495,175 +1486,6 @@ bool droidUpdateDroidRepair(DROID *psRepairDroid)
return psDroidToRepair->body < psDroidToRepair->originalBody;
}
-static const StringToEnum<DROID_TYPE> map_DROID_TYPE[] =
-{
- {"PERSON", DROID_PERSON },
- {"CYBORG", DROID_CYBORG },
- {"CYBORG_SUPER", DROID_CYBORG_SUPER },
- {"CYBORG_CONSTRUCT", DROID_CYBORG_CONSTRUCT },
- {"CYBORG_REPAIR", DROID_CYBORG_REPAIR },
- {"TRANSPORTER", DROID_TRANSPORTER },
- {"ZNULLDROID", DROID_ANY },
- {"DROID", DROID_DEFAULT },
-};
-
-DROID_TEMPLATE::DROID_TEMPLATE() // This constructor replaces a memset in scrAssembleWeaponTemplate(), not needed elsewhere.
- : BASE_STATS()
- //, aName
- //, asParts
- , buildPoints(0)
- , powerPoints(0)
- , storeCount(0)
- , numWeaps(0)
- //, asWeaps
- , droidType(DROID_WEAPON)
- , multiPlayerID(0)
- , psNext(NULL)
- , prefab(false)
-{
- aName[0] = '\0';
- std::fill_n(asParts, DROID_MAXCOMP, 0);
- std::fill_n(asWeaps, DROID_MAXWEAPS, 0);
-}
-
-DROID_TEMPLATE::DROID_TEMPLATE(LineView line)
- : BASE_STATS(REF_TEMPLATE_START + line.line())
- //, aName
- //, asParts
- , buildPoints(0)
- , powerPoints(0)
- , storeCount(0)
- , numWeaps(line.i(11, 0, DROID_MAXWEAPS))
- //, asWeaps
- , droidType(line.e(9, map_DROID_TYPE))
- , multiPlayerID(line.u32(1))
- , psNext(NULL)
- , prefab(false)
- // Ignored columns: 6 - but used later to decide whether the template is for human players.
-{
- std::string name = line.s(0);
- sstrcpy(aName, name.c_str());
-
- asParts[COMP_UNKNOWN] = 0; // Is this one useful for anything at all?
- asParts[COMP_BODY] = line.stats( 2, asBodyStats, numBodyStats) - asBodyStats;
- asParts[COMP_BRAIN] = line.stats( 3, asBrainStats, numBrainStats) - asBrainStats;
- asParts[COMP_CONSTRUCT] = line.stats( 4, asConstructStats, numConstructStats) - asConstructStats;
- asParts[COMP_ECM] = line.stats( 5, asECMStats, numECMStats) - asECMStats;
- asParts[COMP_PROPULSION] = line.stats( 7, asPropulsionStats, numPropulsionStats) - asPropulsionStats;
- asParts[COMP_REPAIRUNIT] = line.stats( 8, asRepairStats, numRepairStats) - asRepairStats;
- asParts[COMP_SENSOR] = line.stats(10, asSensorStats, numSensorStats) - asSensorStats;
-
- std::fill_n(asWeaps, DROID_MAXWEAPS, 0);
-}
-
-/* load the Droid stats for the components from the Access database */
-bool loadDroidTemplates(const char *pDroidData, UDWORD bufferSize)
-{
- bool bDefaultTemplateFound = false;
-
- TableView table(pDroidData, bufferSize);
-
- for (unsigned i = 0; i < table.size(); ++i)
- {
- LineView line(table, i);
-
- DROID_TEMPLATE design(line);
- if (table.isError())
- {
- debug(LOG_ERROR, "%s", table.getError().toUtf8().constData());
- return false;
- }
-
- std::string const pNameCache = design.aName;
- design.pName = const_cast<char *>(pNameCache.c_str());
-
- if (getTemplateFromUniqueName(design.pName, 0))
- {
- debug(LOG_ERROR, "Duplicate template %s", design.pName);
- continue;
- }
-
- // Store translated name in aName
- char const *droidResourceName = getDroidResourceName(design.aName);
- sstrcpy(design.aName, droidResourceName != NULL? droidResourceName : GetDefaultTemplateName(&design));
-
- // Store global default design if found else store in the appropriate array
- if (design.droidType == DROID_ANY)
- {
- design.droidType = DROID_DEFAULT;
- // NOTE: sDefaultDesignTemplate.pName takes ownership
- // of the memory allocated to pDroidDesign->pName
- // here. Which is good because pDroidDesign leaves
- // scope here anyway.
- sDefaultDesignTemplate = design;
- sDefaultDesignTemplate.pName = strdup(design.pName);
- bDefaultTemplateFound = true;
- }
- else
- {
- std::string playerType = line.s(6);
- // Give those meant for humans to all human players.
- // Also support the old template format, in which those meant
- // for humans were player 0 (in campaign) or 5 (in multiplayer).
- if ((!bMultiPlayer && playerType == "0") ||
- ( bMultiPlayer && playerType == "5") ||
- playerType == "YES"
- )
- {
- for (int i = 0; i < MAX_PLAYERS; ++i)
- {
- if (NetPlay.players[i].allocated) // human prototype template
- {
- design.prefab = false;
- addTemplateToList(&design, &apsDroidTemplates[i]);
- }
- }
- localTemplates.push_front(design);
- localTemplates.front().pName = strdup(localTemplates.front().pName);
- }
- // Add all templates to static template list
- design.prefab = true; // prefabricated templates referenced from VLOs
- addTemplateToList(&design, &apsStaticTemplates);
- }
-
- debug(LOG_NEVER, "(default) Droid template found, aName: %s, MP ID: %d, ref: %u, pname: %s, prefab: %s, type:%d (loading)",
- design.aName, design.multiPlayerID, design.ref, design.pName, design.prefab ? "yes":"no", design.droidType);
- }
-
- ASSERT_OR_RETURN(false, bDefaultTemplateFound, "Default template not found");
-
- return true;
-}
-
-static void initTemplatePoints(DROID_TEMPLATE *pDroidDesign)
-{
- //calculate the total build points
- pDroidDesign->buildPoints = calcTemplateBuild(pDroidDesign);
- //calc the total power points
- pDroidDesign->powerPoints = calcTemplatePower(pDroidDesign);
-}
-
-/*initialise the template build and power points */
-void initTemplatePoints(void)
-{
- for (int player = 0; player < MAX_PLAYERS; ++player)
- {
- for (DROID_TEMPLATE *pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
- {
- initTemplatePoints(pDroidDesign);
- }
- }
- for (DROID_TEMPLATE *pDroidDesign = apsStaticTemplates; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
- {
- initTemplatePoints(pDroidDesign);
- }
- for (std::list<DROID_TEMPLATE>::iterator pDroidDesign = localTemplates.begin(); pDroidDesign != localTemplates.end(); ++pDroidDesign)
- {
- initTemplatePoints(&*pDroidDesign);
- }
-}
-
-
// return whether a droid is IDF
bool idfDroid(DROID *psDroid)
{
@@ -1683,31 +1505,12 @@ bool idfDroid(DROID *psDroid)
return true;
}
-// return whether a template is for an IDF droid
-bool templateIsIDF(DROID_TEMPLATE *psTemplate)
-{
- //add Cyborgs
- if (!(psTemplate->droidType == DROID_WEAPON || psTemplate->droidType == DROID_CYBORG ||
- psTemplate->droidType == DROID_CYBORG_SUPER))
- {
- return false;
- }
-
- if (proj_Direct(psTemplate->asWeaps[0] + asWeaponStats))
- {
- return false;
- }
-
- return true;
-}
-
/* Return the type of a droid */
DROID_TYPE droidType(DROID *psDroid)
{
return psDroid->droidType;
}
-
/* Return the type of a droid from it's template */
DROID_TYPE droidTemplateType(DROID_TEMPLATE *psTemplate)
{
@@ -1830,49 +1633,6 @@ bool loadDroidWeapons(const char *pWeaponData, UDWORD bufferSize)
return true;
}
-//free the storage for the droid templates
-bool droidTemplateShutDown(void)
-{
- unsigned int player;
- DROID_TEMPLATE *pTemplate, *pNext;
-
- for (player = 0; player < MAX_PLAYERS; player++)
- {
- for (pTemplate = apsDroidTemplates[player]; pTemplate != NULL; pTemplate = pNext)
- {
- pNext = pTemplate->psNext;
- 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);
- delete 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);
- delete pTemplate;
- }
- apsStaticTemplates = NULL;
- free(sDefaultDesignTemplate.pName);
- sDefaultDesignTemplate.pName = NULL;
-
- for (std::list<DROID_TEMPLATE>::iterator i = localTemplates.begin(); i != localTemplates.end(); ++i)
- {
- free(i->pName);
- }
- localTemplates.clear();
-
- return true;
-}
-
/* Calculate the weight of a droid from it's template */
UDWORD calcDroidWeight(DROID_TEMPLATE *psTemplate)
{
@@ -2401,13 +2161,9 @@ void droidSetBits(DROID_TEMPLATE *pTemplate,DROID *psDroid)
// Sets the parts array in a template given a droid.
void templateSetParts(const DROID *psDroid, DROID_TEMPLATE *psTemplate)
{
- UDWORD inc;
psTemplate->numWeaps = 0;
-
psTemplate->droidType = psDroid->droidType;
-
- //can only have DROID_MAXWEAPS weapon now
- for (inc = 0; inc < DROID_MAXWEAPS; inc++)
+ for (int inc = 0; inc < DROID_MAXWEAPS; inc++)
{
//this should fix the NULL weapon stats for empty weaponslots
psTemplate->asWeaps[inc] = 0;
@@ -2417,81 +2173,15 @@ void templateSetParts(const DROID *psDroid, DROID_TEMPLATE *psTemplate)
psTemplate->asWeaps[inc] = psDroid->asWeaps[inc].nStat;
}
}
-
psTemplate->asParts[COMP_BODY] = psDroid->asBits[COMP_BODY].nStat;
-
psTemplate->asParts[COMP_BRAIN] = psDroid->asBits[COMP_BRAIN].nStat;
-
psTemplate->asParts[COMP_PROPULSION] = psDroid->asBits[COMP_PROPULSION].nStat;
-
psTemplate->asParts[COMP_SENSOR] = psDroid->asBits[COMP_SENSOR].nStat;
-
psTemplate->asParts[COMP_ECM] = psDroid->asBits[COMP_ECM].nStat;
-
psTemplate->asParts[COMP_REPAIRUNIT] = psDroid->asBits[COMP_REPAIRUNIT].nStat;
-
psTemplate->asParts[COMP_CONSTRUCT] = psDroid->asBits[COMP_CONSTRUCT].nStat;
}
-
-/*
-fills the list with Templates that can be manufactured
-in the Factory - based on size. There is a limit on how many can be manufactured
-at any one time. Pass back the number available.
-*/
-void fillTemplateList(std::vector<DROID_TEMPLATE *> &pList, STRUCTURE *psFactory)
-{
- pList.clear();
-
- DROID_TEMPLATE *psCurr;
- UDWORD iCapacity = psFactory->pFunctionality->factory.capacity;
-
- /* Add the templates to the list*/
- for (std::list<DROID_TEMPLATE>::iterator i = localTemplates.begin(); i != localTemplates.end(); ++i)
- {
- psCurr = &*i;
- //must add Command Droid if currently in production
- if (!getProduction(psFactory, psCurr).quantity)
- {
- //can only have (MAX_CMDDROIDS) in the world at any one time
- if (psCurr->droidType == DROID_COMMAND)
- {
- if (checkProductionForCommand(psFactory->player) +
- checkCommandExist(psFactory->player) >= (MAX_CMDDROIDS))
- {
- continue;
- }
- }
- }
-
- if (!validTemplateForFactory(psCurr, psFactory))
- {
- continue;
- }
-
- //check the factory can cope with this sized body
- if (!((asBodyStats + psCurr->asParts[COMP_BODY])->size > iCapacity) )
- {
- //cyborg templates are available when the body has been research
- //-same for Transporter in multiPlayer
- if ( psCurr->droidType == DROID_CYBORG ||
- psCurr->droidType == DROID_CYBORG_SUPER ||
- psCurr->droidType == DROID_CYBORG_CONSTRUCT ||
- psCurr->droidType == DROID_CYBORG_REPAIR ||
- psCurr->droidType == DROID_TRANSPORTER)
- {
- if ( apCompLists[psFactory->player][COMP_BODY]
- [psCurr->asParts[COMP_BODY]] != AVAILABLE )
- {
- //ignore if not research yet
- continue;
- }
- }
- pList.push_back(psCurr);
- }
- }
-}
-
/* Make all the droids for a certain player a member of a specific group */
void assignDroidsToGroup(UDWORD playerNumber, UDWORD groupNumber)
{
@@ -2823,152 +2513,7 @@ bool calcDroidMuzzleLocation(DROID *psDroid, Vector3i *muzzle, int weapon_slot)
return true;
}
-/*!
- * Get a static template from its aName.
- * This checks the all the Human's apsDroidTemplates list.
- * This function is similar to getTemplateFromUniqueName() but we use aName,
- * and not pName, since we don't have that information, and we are checking all player's list.
- * \param aName Template aName
- *
- */
-DROID_TEMPLATE *GetHumanDroidTemplate(const char *aName)
-{
- DROID_TEMPLATE *templatelist, *found = NULL, *foundOtherPlayer = NULL;
- int i, playerFound = 0;
- for (i=0; i < MAX_PLAYERS; i++)
- {
- templatelist = apsDroidTemplates[i];
- while (templatelist)
- {
- if (!strcmp(templatelist->aName, aName))
- {
- debug(LOG_NEVER, "Droid template found, aName: %s, MP ID: %d, ref: %u, pname: %s (for player %d)",
- templatelist->aName, templatelist->multiPlayerID, templatelist->ref, templatelist->pName, i);
- if (i == selectedPlayer)
- {
- found = templatelist;
- }
- else
- {
- foundOtherPlayer = templatelist;
- playerFound = i;
- }
- }
-
- templatelist = templatelist->psNext;
- }
- }
-
- if (foundOtherPlayer && !found)
- {
- debug(LOG_ERROR, "The template was not in our list, but was in another players list.");
- debug(LOG_ERROR, "Droid template's aName: %s, MP ID: %d, ref: %u, pname: %s (for player %d)",
- foundOtherPlayer->aName, foundOtherPlayer->multiPlayerID, foundOtherPlayer->ref, foundOtherPlayer->pName, playerFound);
- return foundOtherPlayer;
- }
-
- return found;
-}
-
-/*!
- * Get a static template from its aName.
- * This checks the AI apsStaticTemplates.
- * This function is similar to getTemplateFromTranslatedNameNoPlayer() but we use aName,
- * and not pName, since we don't have that information.
- * \param aName Template aName
- *
- */
-DROID_TEMPLATE *GetAIDroidTemplate(const char *aName)
-{
- DROID_TEMPLATE *templatelist, *found = NULL;
-
- templatelist = apsStaticTemplates;
- while (templatelist)
- {
- if (!strcmp(templatelist->aName, aName))
- {
- debug(LOG_INFO, "Droid template found, name: %s, MP ID: %d, ref: %u, pname: %s ",
- templatelist->aName, templatelist->multiPlayerID, templatelist->ref, templatelist->pName);
-
- found = templatelist;
- }
- templatelist = templatelist->psNext;
- }
-
- return found;
-}
-
-/*!
- * Gets a template from its name
- * relies on the name being unique (or it will return the first one it finds!)
- * \param pName Template name
- * \param player Player number
- * \pre pName has to be the unique, untranslated name!
- * \pre player \< MAX_PLAYERS
- */
-DROID_TEMPLATE * getTemplateFromUniqueName(const char *pName, unsigned int player)
-{
- DROID_TEMPLATE *psCurr;
- DROID_TEMPLATE *list = apsStaticTemplates; // assume AI
-
- if (isHumanPlayer(player))
- {
- list = apsDroidTemplates[player]; // was human
- }
-
- for (psCurr = list; psCurr != NULL; psCurr = psCurr->psNext)
- {
- if (strcmp(psCurr->pName, pName) == 0)
- {
- return psCurr;
- }
- }
-
- return NULL;
-}
-
-/*!
- * 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!
- */
-DROID_TEMPLATE *getTemplateFromTranslatedNameNoPlayer(char const *pName)
-{
- const char *rName;
- DROID_TEMPLATE *psCurr;
-
- for (psCurr = apsStaticTemplates; psCurr != NULL; psCurr = psCurr->psNext)
- {
- rName = psCurr->pName ? psCurr->pName : psCurr->aName;
- if (strcmp(rName, pName) == 0)
- {
- return psCurr;
- }
- }
-
- 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(pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
- {
- if (pDroidDesign->multiPlayerID == multiPlayerID)
- {
- return pDroidDesign;
- }
- }
- }
- return NULL;
-}
// finds a droid for the player and sets it to be the current selected droid
bool selectDroidByID(UDWORD id, UDWORD player)
@@ -3103,8 +2648,6 @@ void droidSetName(DROID *psDroid,const char *pName)
sstrcpy(psDroid->aName, pName);
}
-
-
// ////////////////////////////////////////////////////////////////////////////
// returns true when no droid on x,y square.
bool noDroid(UDWORD x, UDWORD y)
@@ -3416,11 +2959,6 @@ void setUpBuildModule(DROID *psDroid)
}
}
-const char* getTemplateName(const DROID_TEMPLATE *psTemplate)
-{
- return psTemplate->aName;
-}
-
/* Just returns true if the droid's present body points aren't as high as the original*/
bool droidIsDamaged(DROID *psDroid)
{
@@ -4225,79 +3763,7 @@ bool checkValidWeaponForProp(DROID_TEMPLATE *psTemplate)
return true;
}
-/*called when a Template is deleted in the Design screen*/
-void deleteTemplateFromProduction(DROID_TEMPLATE *psTemplate, unsigned player, QUEUE_MODE mode)
-{
- STRUCTURE *psStruct;
- STRUCTURE *psList;
-
- //see if any factory is currently using the template
- for (unsigned i = 0; i < 2; ++i)
- {
- psList = NULL;
- switch (i)
- {
- case 0:
- psList = apsStructLists[player];
- break;
- case 1:
- psList = mission.apsStructLists[player];
- break;
- }
- for (psStruct = psList; psStruct != NULL; psStruct = psStruct->psNext)
- {
- if (StructIsFactory(psStruct))
- {
- FACTORY *psFactory = &psStruct->pFunctionality->factory;
- if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size())
- {
- ProductionRun &productionRun = asProductionRun[psFactory->psAssemblyPoint->factoryType][psFactory->psAssemblyPoint->factoryInc];
- for (unsigned inc = 0; inc < productionRun.size(); ++inc)
- {
- if (productionRun[inc].psTemplate->multiPlayerID == psTemplate->multiPlayerID && mode == ModeQueue)
- {
- //just need to erase this production run entry
- productionRun.erase(productionRun.begin() + inc);
- --inc;
- }
- }
- }
-
- if (psFactory->psSubject == NULL)
- {
- continue;
- }
-
- // check not being built in the factory for the template player
- if (psTemplate->multiPlayerID == psFactory->psSubject->multiPlayerID && mode == ModeImmediate)
- {
- syncDebugStructure(psStruct, '<');
- syncDebug("Clearing production");
-
- // Clear the factory's subject.
- psFactory->psSubject = NULL;
-
- if (player == productionPlayer)
- {
- //check to see if anything left to produce
- DROID_TEMPLATE *psNextTemplate = factoryProdUpdate(psStruct, NULL);
- //power is returned by factoryProdAdjust()
- if (psNextTemplate)
- {
- structSetManufacture(psStruct, psNextTemplate, ModeQueue); // ModeQueue because production lists aren't synchronised.
- }
- }
-
- //tell the interface
- intManufactureFinished(psStruct);
-
- syncDebugStructure(psStruct, '>');
- }
- }
- }
- }
-}
// Select a droid and do any necessary housekeeping.
@@ -4345,7 +3811,6 @@ bool droidAudioTrackStopped( void *psObj )
return true;
}
-
/*returns true if droid type is one of the Cyborg types*/
bool cyborgDroid(const DROID* psDroid)
{
30 src/droid.h
View
@@ -44,10 +44,6 @@
// Changing this breaks campaign saves!
#define MAX_RECYCLED_DROIDS 450
-//storage
-extern DROID_TEMPLATE *apsDroidTemplates[MAX_PLAYERS];
-extern DROID_TEMPLATE *apsStaticTemplates; // for AIs and scripts
-
//used to stop structures being built too near the edge and droids being placed down
#define TOO_NEAR_EDGE 3
@@ -83,12 +79,8 @@ extern bool droidInit(void);
extern void removeDroidBase(DROID *psDel);
-extern bool loadDroidTemplates(const char *pDroidData, UDWORD bufferSize);
extern bool loadDroidWeapons(const char *pWeaponData, UDWORD bufferSize);
-/*initialise the template build and power points */
-extern void initTemplatePoints(void);
-
struct INITIAL_DROID_ORDERS
{
uint32_t secondaryOrder;
@@ -132,9 +124,6 @@ extern UDWORD calcTemplateBuild(DROID_TEMPLATE *psTemplate);
/* Calculate the power points required to build/maintain the droid */
extern UDWORD calcTemplatePower(DROID_TEMPLATE *psTemplate);
-// return whether a template is for an IDF droid
-bool templateIsIDF(DROID_TEMPLATE *psTemplate);
-
// return whether a droid is IDF
bool idfDroid(DROID *psDroid);
@@ -205,9 +194,6 @@ extern DROID_TYPE droidType(DROID *psDroid);
/* Return the type of a droid from it's template */
extern DROID_TYPE droidTemplateType(DROID_TEMPLATE *psTemplate);
-//fills the list with Templates that can be manufactured in the Factory - based on size
-void fillTemplateList(std::vector<DROID_TEMPLATE *> &pList, STRUCTURE *psFactory);
-
extern void assignDroidsToGroup(UDWORD playerNumber, UDWORD groupNumber);
extern bool activateGroup(UDWORD playerNumber, UDWORD groupNumber);
@@ -220,16 +206,6 @@ bool calcDroidMuzzleLocation(DROID *psDroid, Vector3i *muzzle, int weapon_slot);
/* calculate muzzle base location in 3d world added int weapon_slot to fix the always slot 0 hack*/
bool calcDroidMuzzleBaseLocation(DROID *psDroid, Vector3i *muzzle, int weapon_slot);
-/* gets a template from its aName (when pName is unknown) */
-extern DROID_TEMPLATE *GetHumanDroidTemplate(const char *aName);
-extern DROID_TEMPLATE *GetAIDroidTemplate(const char *aName);
-/* gets a template from its name - relies on the name being unique */
-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 const *pName);
-/*getTemplateFromMultiPlayerID gets template for unique ID searching all lists */
-extern DROID_TEMPLATE* getTemplateFromMultiPlayerID(UDWORD multiPlayerID);
-
// finds a droid for the player and sets it to be the current selected droid
extern bool selectDroidByID(UDWORD id, UDWORD player);
@@ -275,10 +251,6 @@ extern bool buildModule(STRUCTURE *psStruct);
- if so, helping to build the current one*/
extern void setUpBuildModule(DROID *psDroid);
-/*return the name to display for the interface - we don't know if this is
-a string ID or something the user types in*/
-extern const char* getTemplateName(const DROID_TEMPLATE *psTemplate);
-
/* Just returns true if the droid's present body points aren't as high as the original*/
extern bool droidIsDamaged(DROID *psDroid);
@@ -288,10 +260,8 @@ extern void setSelectedGroup(UDWORD groupNumber);
extern UDWORD getSelectedCommander( void );
extern void setSelectedCommander(UDWORD commander);
-
extern char const *getDroidResourceName(char const *pName);
-
/*checks to see if an electronic warfare weapon is attached to the droid*/
extern bool electronicDroid(DROID *psDroid);
1  src/droiddef.h
View
@@ -125,6 +125,7 @@ struct DROID_TEMPLATE : public BASE_STATS
UDWORD multiPlayerID; ///< multiplayer unique descriptor(cant use id's for templates). Used for save games as well now - AB 29/10/98
DROID_TEMPLATE* psNext; ///< Pointer to next template
bool prefab; ///< Not player designed, not saved, never delete or change
+ bool stored; ///< Stored template
};
struct PACKAGED_CHECK;
1  src/game.cpp
View
@@ -85,6 +85,7 @@
#include "scriptfuncs.h"
#include "challenge.h"
#include "combat.h"
+#include "template.h"
#define MAX_SAVE_NAME_SIZE_V19 40
#define MAX_SAVE_NAME_SIZE 60
1  src/hci.cpp
View
@@ -75,6 +75,7 @@
#include "transporter.h"
#include "warcam.h"
#include "main.h"
+#include "template.h"
#include "wrappers.h"
#include "keybind.h"
6 src/init.cpp
View
@@ -95,6 +95,7 @@
#include "terrain.h"
#include "ingameop.h"
#include "qtscript.h"
+#include "template.h"
static void initMiscVars(void);
@@ -1097,6 +1098,9 @@ bool stageThreeInitialise(void)
preProcessVisibility();
closeLoadingScreen(); // reset the loading screen.
+ // Load any stored templates; these need to be available ASAP
+ initTemplates();
+
if (!fpathInitialise())
{
return false;
@@ -1183,6 +1187,8 @@ bool stageThreeShutDown(void)
challengeActive = false;
isInGamePopupUp = false;
+ shutdownTemplates();
+
// make sure any button tips are gone.
widgReset();
1  src/keybind.cpp
View
@@ -91,6 +91,7 @@
#include "scriptfuncs.h"
#include "clparse.h"
#include "research.h"
+#include "template.h"
/*
KeyBind.c
1  src/map.cpp
View
@@ -1923,6 +1923,7 @@ void mapInit()
}
// Start thread
+ ASSERT(dangerSemaphore == NULL && dangerThread == NULL, "Map data not cleaned up before starting!");
if (game.type == SKIRMISH)
{
lastDangerPlayer = 0;
7 src/multimenu.cpp
View
@@ -145,7 +145,6 @@ UDWORD current_numplayers = 4;
#define M_REQUEST_15P (MULTIMENU+84)
#define M_REQUEST_16P (MULTIMENU+85)
static const unsigned M_REQUEST_NP[] = {M_REQUEST_2P, M_REQUEST_3P, M_REQUEST_4P, M_REQUEST_5P, M_REQUEST_6P, M_REQUEST_7P, M_REQUEST_8P, M_REQUEST_9P, M_REQUEST_10P, M_REQUEST_11P, M_REQUEST_12P, M_REQUEST_13P, M_REQUEST_14P, M_REQUEST_15P, M_REQUEST_16P};
-static char const * M_REQUEST_NP_TIPS[] = { N_("2 players"), N_("3 players"), N_("4 players"), N_("5 players"), N_("6 players"), N_("7 players"), N_("8 players"), N_("9 players"), N_("10 players"), N_("11 players"), N_("12 players"), N_("13 players"), N_("14 players"), N_("15 players"), N_("16 players")};
#define M_REQUEST_BUT (MULTIMENU+100) // allow loads of buttons.
#define M_REQUEST_BUTM (MULTIMENU+1100)
@@ -646,13 +645,15 @@ void addMultiRequest(const char* searchDir, const char* fileExtension, UDWORD mo
sButInit.pDisplay = displayNumPlayersBut;
widgAddButton(psRScreen, &sButInit);
- STATIC_ASSERT(MAX_PLAYERS_IN_GUI <= ARRAY_SIZE(M_REQUEST_NP) + 1 && MAX_PLAYERS <= ARRAY_SIZE(M_REQUEST_NP_TIPS) + 1);
+ STATIC_ASSERT(MAX_PLAYERS_IN_GUI <= ARRAY_SIZE(M_REQUEST_NP) + 1);
for (unsigned numPlayers = 2; numPlayers <= MAX_PLAYERS_IN_GUI; ++numPlayers)
{
+ static char ttip[MAX_PLAYERS_IN_GUI][20];
sButInit.id = M_REQUEST_NP[numPlayers - 2];
sButInit.y += 22;
sButInit.UserData = numPlayers;
- sButInit.pTip = gettext(M_REQUEST_NP_TIPS[numPlayers - 2]);
+ ssprintf(ttip[numPlayers], ngettext("%d player", "%d players", numPlayers), numPlayers);
+ sButInit.pTip = (const char *)&ttip[numPlayers];
widgAddButton(psRScreen, &sButInit);
}
}
2  src/multiopt.cpp
View
@@ -53,7 +53,7 @@
#include "multiint.h"
#include "multirecv.h"
#include "scriptfuncs.h"
-
+#include "template.h"
#include "lib/framework/wzapp.h"
11 src/multiplay.cpp
View
@@ -60,7 +60,7 @@
#include "scripttabs.h" //because of CALL_AI_MSG
#include "scriptcb.h" //for console callback
#include "scriptfuncs.h"
-
+#include "template.h"
#include "lib/netplay/netplay.h" // the netplay library.
#include "multiplay.h" // warzone net stuff.
#include "multijoin.h" // player management stuff.
@@ -1349,6 +1349,7 @@ static void NETtemplate(DROID_TEMPLATE *pTempl)
NETuint32_t(&pTempl->powerPoints);
NETuint32_t(&pTempl->storeCount);
NETuint32_t(&pTempl->numWeaps);
+ NETbool(&pTempl->stored); // other players don't need to know, but we need to keep the knowledge in the loop somehow...
for (int i = 0; i < DROID_MAXWEAPS; ++i)
{
@@ -1394,12 +1395,16 @@ bool recvTemplate(NETQUEUE queue)
{
t.psNext = psTempl->psNext;
*psTempl = t;
- debug(LOG_SYNC, "Updating MP template %d", (int)t.multiPlayerID);
+ debug(LOG_SYNC, "Updating MP template %d (stored=%s)", (int)t.multiPlayerID, t.stored ? "yes" : "no");
}
else
{
addTemplateBack(player, &t); // Add to back of list, to avoid game state templates being in wrong order, which matters when saving games.
- debug(LOG_SYNC, "Creating MP template %d", (int)t.multiPlayerID);
+ debug(LOG_SYNC, "Creating MP template %d (stored=%s)", (int)t.multiPlayerID, t.stored ? "yes" : "no");
+ }
+ if (!t.prefab && player == selectedPlayer)
+ {
+ storeTemplates();
}
return true;
19 src/projectile.cpp
View
@@ -1570,14 +1570,13 @@ UDWORD calcDamage(UDWORD baseDamage, WEAPON_EFFECT weaponEffect, BASE_OBJECT *ps
if (psTarget->type == OBJ_STRUCTURE)
{
- damage = baseDamage * asStructStrengthModifier[weaponEffect][((
- STRUCTURE *)psTarget)->pStructureType->strength] / 100;
+ damage = baseDamage * asStructStrengthModifier[weaponEffect][((STRUCTURE *)psTarget)->pStructureType->strength] / 100;
}
else if (psTarget->type == OBJ_DROID)
{
- damage = baseDamage * asWeaponModifier[weaponEffect][(
- asPropulsionStats + ((DROID *)psTarget)->asBits[COMP_PROPULSION].
- nStat)->propulsionType] / 100;
+ const int propulsion = (asPropulsionStats + ((DROID *)psTarget)->asBits[COMP_PROPULSION].nStat)->propulsionType;
+ const int body = (asBodyStats + ((DROID *)psTarget)->asBits[COMP_BODY].nStat)->size;
+ damage = baseDamage * (asWeaponModifier[weaponEffect][propulsion] + asWeaponModifierBody[weaponEffect][body]) / 100;
}
// Default value
else
@@ -1585,11 +1584,11 @@ UDWORD calcDamage(UDWORD baseDamage, WEAPON_EFFECT weaponEffect, BASE_OBJECT *ps
damage = baseDamage;
}
- // A little fail safe!
- if (damage == 0 && baseDamage != 0)
- {
- damage = 1;
- }
+ // A little fail safe!
+ if (damage == 0 && baseDamage != 0)
+ {
+ damage = 1;
+ }
return damage;
}
1  src/qtscriptfuncs.cpp
View
@@ -44,6 +44,7 @@
#include "challenge.h"
#include "research.h"
#include "multilimit.h"
+#include "template.h"
// hack, this is used from scriptfuncs.cpp -- and we don't want to include any stinkin' wzscript headers here!
// TODO, move this stuff into a script common subsystem
33 src/research.cpp
View
@@ -44,6 +44,7 @@
#include "frend.h" // frontend ids.
#include "intimage.h"
#include "multiplay.h"
+#include "template.h"
//used to calc the research power
#define RESEARCH_FACTOR 32
@@ -99,6 +100,9 @@ bool researchInitVars(void)
for (int i = 0; i < MAX_PLAYERS; i++)
{
bSelfRepair[i] = false;
+ aDefaultSensor[i] = 0;
+ aDefaultECM[i] = 0;
+ aDefaultRepair[i] = 0;
}
return true;
@@ -302,7 +306,7 @@ bool loadResearch(const char *pResearchData, UDWORD bufferSize)
//Load the pre-requisites for a research list
bool loadResearchPR(const char *pPRData, UDWORD bufferSize)
{
- const unsigned int NumToAlloc = numCR(pPRData, bufferSize);
+ unsigned NumToAlloc = numCR(pPRData, bufferSize);
char ResearchName[MAX_STR_LENGTH], PRName[MAX_STR_LENGTH];
for (int i = 0; i < NumToAlloc; i++)
@@ -344,11 +348,18 @@ bool loadResearchPR(const char *pPRData, UDWORD bufferSize)
//Load the artefacts for a research list
bool loadResearchArtefacts(const char *pArteData, UDWORD bufferSize, UDWORD listNumber)
{
- const unsigned int NumToAlloc = numCR(pArteData, bufferSize);
+ unsigned NumToAlloc = numCR(pArteData, bufferSize);
char ResearchName[MAX_STR_LENGTH], ArteName[MAX_STR_LENGTH], TypeName[MAX_STR_LENGTH];
COMPONENT_STATS *pArtefact;
UDWORD newType;
+ // Skip descriptive header
+ if (strncmp(pArteData, "Research ", 9) == 0)
+ {
+ pArteData = strchr(pArteData, '\n') + 1;
+ NumToAlloc--;
+ }
+
for (int i = 0; i < NumToAlloc; i++)
{
//read the data into the storage - the data is delimited using commas
@@ -436,13 +447,20 @@ bool loadResearchArtefacts(const char *pArteData, UDWORD bufferSize, UDWORD list
//Load the Structures for a research list
bool loadResearchStructures(const char *pStructData, UDWORD bufferSize,UDWORD listNumber)
{
- const unsigned int NumToAlloc = numCR(pStructData, bufferSize);
+ unsigned NumToAlloc = numCR(pStructData, bufferSize);
unsigned int i = 0;
char ResearchName[MAX_STR_LENGTH], StructureName[MAX_STR_LENGTH];
UWORD incR, incS;
STRUCTURE_STATS *pStructure = asStructureStats;
bool recFound;
+ // Skip descriptive header
+ if (strncmp(pStructData, "Research ", 9) == 0)
+ {
+ pStructData = strchr(pStructData, '\n') + 1;
+ NumToAlloc--;
+ }
+
for (i = 0; i < NumToAlloc; i++)
{
recFound = false;
@@ -512,13 +530,20 @@ bool loadResearchStructures(const char *pStructData, UDWORD bufferSize,UDWORD li
//Load the pre-requisites for a research list
bool loadResearchFunctions(const char *pFunctionData, UDWORD bufferSize)
{
- const unsigned int NumToAlloc = numCR(pFunctionData, bufferSize);
+ unsigned NumToAlloc = numCR(pFunctionData, bufferSize);
unsigned int i = 0;
char ResearchName[MAX_STR_LENGTH], FunctionName[MAX_STR_LENGTH];
UDWORD incR, incF;
FUNCTION **pFunction = asFunctions;
bool recFound;
+ // Skip descriptive header
+ if (strncmp(pFunctionData, "Research ", 9) == 0)
+ {
+ pFunctionData = strchr(pFunctionData, '\n') + 1;
+ NumToAlloc--;
+ }
+
for (i=0; i < NumToAlloc; i++)
{
recFound = false;
1  src/scriptfuncs.cpp
View
@@ -96,6 +96,7 @@
#include "visibility.h"
#include "design.h"
#include "random.h"
+#include "template.h"
static INTERP_VAL scrFunctionResult; //function return value to be pushed to stack
2  src/scriptobj.cpp
View
@@ -777,7 +777,7 @@ bool scrValDefSave(INTERP_VAL *psVal, WzConfig &ini)
break;
case ST_RESEARCH:
psResearch = (RESEARCH *)psVal->v.oval;
- if (psResearch && psResearch->pName[0] != '\0')
+ if (psResearch && psResearch->pName && psResearch->pName[0] != '\0')
{
ini.setValue("data", QString(psResearch->pName));
ASSERT(psResearch == getResearch(psResearch->pName), "Research %s not found!", psResearch->pName);
1  src/scriptvals_parser.ypp
View
@@ -49,6 +49,7 @@
#include "src/levels.h"
#include "src/research.h"
#include "src/text.h"
+#include "src/template.h"
// The current script code
static SCRIPT_CODE *psCurrScript;
37 src/stats.cpp
View
@@ -55,6 +55,7 @@ static SPECIAL_ABILITY *asSpecialAbility;
//used to hold the modifiers cross refd by weapon effect and propulsion type
WEAPON_MODIFIER asWeaponModifier[WE_NUMEFFECTS][PROPULSION_TYPE_NUM];
+WEAPON_MODIFIER asWeaponModifierBody[WE_NUMEFFECTS][SIZE_NUM];
//used to hold the current upgrade level per player per weapon subclass
WEAPON_UPGRADE asWeaponUpgrade[MAX_PLAYERS][WSC_NUM_WEAPON_SUBCLASSES];
@@ -622,7 +623,6 @@ bool loadWeaponStats(const char *pWeaponData, UDWORD bufferSize)
facePlayer[0] = '\0';
faceInFlight[0] = '\0';
-
//read the data into the storage - the data is delimeted using comma's
sscanf(pWeaponData,"%255[^,'\r\n],%255[^,'\r\n],%d,%d,%d,%d,%d,%d,%255[^,'\r\n],\
%255[^,'\r\n],%255[^,'\r\n],%255[^,'\r\n],%255[^,'\r\n],%255[^,'\r\n],%255[^,'\r\n],%255[^,'\r\n],%d,\
@@ -2209,38 +2209,43 @@ bool loadWeaponModifiers(const char *pWeapModData, UDWORD bufferSize)
for (j=0; j < PROPULSION_TYPE_NUM; j++)
{
asWeaponModifier[i][j] = 100;
+ asWeaponModifierBody[i][j] = 100;
}
}
for (i=0; i < NumRecords; i++)
{
//read the data into the storage - the data is delimeted using comma's
- sscanf(pWeapModData,"%255[^,'\r\n],%255[^,'\r\n],%d",
- weaponEffectName, propulsionName, &modifier);
+ sscanf(pWeapModData,"%255[^,'\r\n],%255[^,'\r\n],%d", weaponEffectName, propulsionName, &modifier);
//get the weapon effect inc
if (!getWeaponEffect(weaponEffectName, &effectInc))
{
- debug( LOG_FATAL, "loadWeaponModifiers: Invalid Weapon Effect - %s", weaponEffectName );
- abort();
- return false;
+ debug(LOG_FATAL, "Invalid Weapon Effect - %s", weaponEffectName);
+ continue;
+ }
+ if (modifier > UWORD_MAX)
+ {
+ debug(LOG_FATAL, "Modifier for effect %s, prop type %s is too large", weaponEffectName, propulsionName);
+ continue;
}
//get the propulsion inc
if (!getPropulsionType(propulsionName, &propInc))
{
- debug( LOG_FATAL, "loadWeaponModifiers: Invalid Propulsion type - %s", propulsionName );
- abort();
- return false;
+ UBYTE body = 0;
+ // If not propulsion, must be body
+ if (!getBodySize(propulsionName, &body))
+ {
+ debug(LOG_FATAL, "Invalid Propulsion or Body type - %s", propulsionName);
+ continue;
+ }
+ asWeaponModifierBody[effectInc][body] = modifier;
}
-
- if (modifier > UWORD_MAX)
+ else
{
- debug( LOG_FATAL, "loadWeaponModifiers: modifier for effect %s, prop type %s is too large", weaponEffectName, propulsionName );
- abort();
- return false;
+ //store in the appropriate index
+ asWeaponModifier[effectInc][propInc] = (UWORD)modifier;
}
- //store in the appropriate index
- asWeaponModifier[effectInc][propInc] = (UWORD)modifier;
//increment the pointer to the start of the next record
pWeapModData = strchr(pWeapModData,'\n') + 1;
1  src/stats.h
View
@@ -46,6 +46,7 @@ extern PROPULSION_TYPES *asPropulsionTypes;
//used to hold the modifiers cross refd by weapon effect and propulsion type
extern WEAPON_MODIFIER asWeaponModifier[WE_NUMEFFECTS][PROPULSION_TYPE_NUM];
+extern WEAPON_MODIFIER asWeaponModifierBody[WE_NUMEFFECTS][SIZE_NUM];
//used to hold the current upgrade level per player per weapon subclass
extern WEAPON_UPGRADE asWeaponUpgrade[MAX_PLAYERS][WSC_NUM_WEAPON_SUBCLASSES];
1  src/statsdef.h
View
@@ -225,6 +225,7 @@ enum BODY_SIZE
SIZE_MEDIUM,
SIZE_HEAVY,
SIZE_SUPER_HEAVY,
+ SIZE_NUM
};
/**
2  src/structure.cpp
View
@@ -86,7 +86,7 @@
#include "lib/netplay/netplay.h"
#include "multigifts.h"
#include "loop.h"
-
+#include "template.h"
#include "scores.h"
#include "gateway.h"
672 src/template.cpp
View
@@ -0,0 +1,672 @@
+/*
+ This file is part of Warzone 2100.
+ Copyright (C) 1999-2004 Eidos Interactive
+ Copyright (C) 2005-2011 Warzone 2100 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
+*/
+/**
+ * @file template.cpp
+ *
+ * Droid template functions.
+ *
+ */
+#include "template.h"
+
+#include "lib/framework/frame.h"
+#include "lib/framework/wzconfig.h"
+#include "lib/framework/math_ext.h"
+#include "lib/framework/strres.h"
+#include "lib/netplay/netplay.h"
+#include "cmddroiddef.h"
+#include "mission.h"
+#include "objects.h"
+#include "droid.h"
+#include "design.h"
+#include "hci.h"
+#include "multiplay.h"
+#include "projectile.h"
+
+/* default droid design template */
+extern DROID_TEMPLATE sDefaultDesignTemplate;
+
+// Template storage
+DROID_TEMPLATE *apsDroidTemplates[MAX_PLAYERS];
+DROID_TEMPLATE *apsStaticTemplates; // for AIs and scripts
+
+static const StringToEnum<DROID_TYPE> map_DROID_TYPE[] =
+{
+ {"PERSON", DROID_PERSON },
+ {"CYBORG", DROID_CYBORG },
+ {"CYBORG_SUPER", DROID_CYBORG_SUPER },
+ {"CYBORG_CONSTRUCT", DROID_CYBORG_CONSTRUCT },
+ {"CYBORG_REPAIR", DROID_CYBORG_REPAIR },
+ {"TRANSPORTER", DROID_TRANSPORTER },
+ {"ZNULLDROID", DROID_ANY },
+ {"DROID", DROID_DEFAULT },
+};
+
+bool researchedTemplate(DROID_TEMPLATE *psCurr, int player)
+{
+ // super hack -- cyborgs and transports are special, only check their body
+ switch (psCurr->droidType)
+ {
+ case DROID_PERSON:
+ case DROID_CYBORG:
+ case DROID_CYBORG_SUPER:
+ case DROID_CYBORG_CONSTRUCT:
+ case DROID_CYBORG_REPAIR:
+ case DROID_TRANSPORTER:
+ return (apCompLists[player][COMP_BODY][psCurr->asParts[COMP_BODY]] == AVAILABLE);
+ default:
+ break; // now proceed to normal droids...
+ }
+ // Note the ugly special case for commanders - their weapon is unavailable
+ if (apCompLists[player][COMP_BODY][psCurr->asParts[COMP_BODY]] != AVAILABLE
+ || (psCurr->asParts[COMP_BRAIN] > 0 && apCompLists[player][COMP_BRAIN][psCurr->asParts[COMP_BRAIN]] != AVAILABLE)
+ || apCompLists[player][COMP_PROPULSION][psCurr->asParts[COMP_PROPULSION]] != AVAILABLE
+ || (psCurr->asParts[COMP_SENSOR] > 0 && apCompLists[player][COMP_SENSOR][psCurr->asParts[COMP_SENSOR]] != AVAILABLE)
+ || (psCurr->asParts[COMP_ECM] > 0 && apCompLists[player][COMP_ECM][psCurr->asParts[COMP_ECM]] != AVAILABLE)
+ || (psCurr->asParts[COMP_REPAIRUNIT] > 0 && apCompLists[player][COMP_REPAIRUNIT][psCurr->asParts[COMP_REPAIRUNIT]] != AVAILABLE)
+ || (psCurr->asParts[COMP_CONSTRUCT] > 0 && apCompLists[player][COMP_CONSTRUCT][psCurr->asParts[COMP_CONSTRUCT]] != AVAILABLE)
+ || (psCurr->asParts[COMP_BRAIN] == 0 && psCurr->numWeaps > 0 && apCompLists[player][COMP_WEAPON][psCurr->asWeaps[0]] != AVAILABLE)
+ || (psCurr->numWeaps > 1 && apCompLists[player][COMP_WEAPON][psCurr->asWeaps[1]] != AVAILABLE))
+ {
+ return false;
+ }
+ return true;
+}
+
+bool initTemplates()
+{
+ WzConfig ini("templates.ini");
+ if (ini.status() != QSettings::NoError)
+ {
+ debug(LOG_FATAL, "Could not open templates.ini");
+ return false;
+ }
+ QStringList list = ini.childGroups();
+ for (int i = 0; i < list.size(); ++i)
+ {
+ ini.beginGroup(list[i]);
+ DROID_TEMPLATE design;
+ design.pName = NULL;
+ design.droidType = (DROID_TYPE)ini.value("droidType").toInt();
+ design.multiPlayerID = generateNewObjectId();
+ design.asParts[COMP_BODY] = getCompFromName(COMP_BODY, ini.value("body", QString("ZNULLBODY")).toString().toUtf8().constData());
+ design.asParts[COMP_BRAIN] = getCompFromName(COMP_BRAIN, ini.value("brain", QString("ZNULLBRAIN")).toString().toUtf8().constData());
+ design.asParts[COMP_PROPULSION] = getCompFromName(COMP_PROPULSION, ini.value("propulsion", QString("ZNULLPROP")).toString().toUtf8().constData());
+ design.asParts[COMP_REPAIRUNIT] = getCompFromName(COMP_REPAIRUNIT, ini.value("repair", QString("ZNULLREPAIR")).toString().toUtf8().constData());
+ design.asParts[COMP_ECM] = getCompFromName(COMP_ECM, ini.value("ecm", QString("ZNULLECM")).toString().toUtf8().constData());
+ design.asParts[COMP_SENSOR] = getCompFromName(COMP_SENSOR, ini.value("sensor", QString("ZNULLSENSOR")).toString().toUtf8().constData());
+ design.asParts[COMP_CONSTRUCT] = getCompFromName(COMP_CONSTRUCT, ini.value("construct", QString("ZNULLCONSTRUCT")).toString().toUtf8().constData());
+ design.asWeaps[0] = getCompFromName(COMP_WEAPON, ini.value("weapon/1", QString("ZNULLWEAPON")).toString().toUtf8().constData());
+ design.asWeaps[1] = getCompFromName(COMP_WEAPON, ini.value("weapon/2", QString("ZNULLWEAPON")).toString().toUtf8().constData());
+ design.asWeaps[2] = getCompFromName(COMP_WEAPON, ini.value("weapon/3", QString("ZNULLWEAPON")).toString().toUtf8().constData());
+ design.numWeaps = ini.value("weapons").toInt();
+ design.prefab = false; // not AI template
+ design.stored = true;
+ bool valid = intValidTemplate(&design, ini.value("name").toString().toUtf8().constData());
+ if (!valid)
+ {
+ debug(LOG_ERROR, "Invalid template %d / %s from stored templates", i, list[i].toUtf8().constData());
+ continue;
+ }
+ addTemplateToList(&design, &apsDroidTemplates[selectedPlayer]);
+ localTemplates.push_back(design);
+ ini.endGroup();
+ }
+ return true;
+}
+
+bool storeTemplates()
+{
+ // Write stored templates (back) to file
+ WzConfig ini("templates.ini");
+ if (ini.status() != QSettings::NoError || !ini.isWritable())
+ {
+ debug(LOG_FATAL, "Could not open templates.ini");
+ return false;
+ }
+ for (DROID_TEMPLATE *psCurr = apsDroidTemplates[selectedPlayer]; psCurr != NULL; psCurr = psCurr->psNext)
+ {
+ if (!psCurr->stored) continue; // not stored
+ ini.beginGroup("template_" + QString::number(psCurr->multiPlayerID));
+ ini.setValue("name", psCurr->aName);
+ ini.setValue("droidType", psCurr->droidType);
+ ini.setValue("body", (asBodyStats + psCurr->asParts[COMP_BODY])->pName);
+ ini.setValue("propulsion", (asPropulsionStats + psCurr->asParts[COMP_PROPULSION])->pName);
+ if (psCurr->asParts[COMP_BRAIN] != 0)
+ {
+ ini.setValue("brain", (asBrainStats + psCurr->asParts[COMP_BRAIN])->pName);
+ }
+ if ((asRepairStats + psCurr->asParts[COMP_REPAIRUNIT])->location == LOC_TURRET) // avoid auto-repair...
+ {
+ ini.setValue("repair", (asRepairStats + psCurr->asParts[COMP_REPAIRUNIT])->pName);
+ }
+ if ((asECMStats + psCurr->asParts[COMP_ECM])->location == LOC_TURRET)
+ {
+ ini.setValue("ecm", (asECMStats + psCurr->asParts[COMP_ECM])->pName);
+ }
+ if ((asSensorStats + psCurr->asParts[COMP_SENSOR])->location == LOC_TURRET)
+ {
+ ini.setValue("sensor", (asSensorStats + psCurr->asParts[COMP_SENSOR])->pName);
+ }
+ if (psCurr->asParts[COMP_CONSTRUCT] != 0)
+ {
+ ini.setValue("construct", (asConstructStats + psCurr->asParts[COMP_CONSTRUCT])->pName);
+ }
+ ini.setValue("weapons", psCurr->numWeaps);
+ for (int j = 0; j < psCurr->numWeaps; j++)
+ {
+ ini.setValue("weapon/" + QString::number(j + 1), (asWeaponStats + psCurr->asWeaps[j])->pName);
+ }
+ ini.endGroup();
+ }
+ return true;
+}
+
+bool shutdownTemplates()
+{
+ return storeTemplates();
+}
+
+static void initTemplatePoints(DROID_TEMPLATE *pDroidDesign)
+{
+ //calculate the total build points
+ pDroidDesign->buildPoints = calcTemplateBuild(pDroidDesign);
+ //calc the total power points
+ pDroidDesign->powerPoints = calcTemplatePower(pDroidDesign);
+}
+
+/*initialise the template build and power points */
+void initTemplatePoints(void)
+{
+ for (int player = 0; player < MAX_PLAYERS; ++player)
+ {
+ for (DROID_TEMPLATE *pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
+ {
+ initTemplatePoints(pDroidDesign);
+ }
+ }
+ for (DROID_TEMPLATE *pDroidDesign = apsStaticTemplates; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
+ {
+ initTemplatePoints(pDroidDesign);
+ }
+ for (std::list<DROID_TEMPLATE>::iterator pDroidDesign = localTemplates.begin(); pDroidDesign != localTemplates.end(); ++pDroidDesign)
+ {
+ initTemplatePoints(&*pDroidDesign);
+ }
+}
+
+DROID_TEMPLATE::DROID_TEMPLATE() // This constructor replaces a memset in scrAssembleWeaponTemplate(), not needed elsewhere.
+ : BASE_STATS()
+ //, aName
+ //, asParts
+ , buildPoints(0)
+ , powerPoints(0)
+ , storeCount(0)
+ , numWeaps(0)
+ //, asWeaps
+ , droidType(DROID_WEAPON)
+ , multiPlayerID(0)
+ , psNext(NULL)
+ , prefab(false)
+ , stored(false)
+{
+ aName[0] = '\0';
+ std::fill_n(asParts, DROID_MAXCOMP, 0);
+ std::fill_n(asWeaps, DROID_MAXWEAPS, 0);
+}
+
+DROID_TEMPLATE::DROID_TEMPLATE(LineView line)
+ : BASE_STATS(REF_TEMPLATE_START + line.line())
+ //, aName
+ //, asParts
+ , buildPoints(0)
+ , powerPoints(0)
+ , storeCount(0)
+ , numWeaps(line.i(11, 0, DROID_MAXWEAPS))
+ //, asWeaps
+ , droidType(line.e(9, map_DROID_TYPE))
+ , multiPlayerID(line.u32(1))
+ , psNext(NULL)
+ , prefab(false)
+ , stored(false)
+ // Ignored columns: 6 - but used later to decide whether the template is for human players.
+{
+ std::string name = line.s(0);
+ sstrcpy(aName, name.c_str());
+
+ asParts[COMP_UNKNOWN] = 0; // Is this one useful for anything at all?
+ asParts[COMP_BODY] = line.stats( 2, asBodyStats, numBodyStats) - asBodyStats;
+ asParts[COMP_BRAIN] = line.stats( 3, asBrainStats, numBrainStats) - asBrainStats;
+ asParts[COMP_CONSTRUCT] = line.stats( 4, asConstructStats, numConstructStats) - asConstructStats;
+ asParts[COMP_ECM] = line.stats( 5, asECMStats, numECMStats) - asECMStats;
+ asParts[COMP_PROPULSION] = line.stats( 7, asPropulsionStats, numPropulsionStats) - asPropulsionStats;
+ asParts[COMP_REPAIRUNIT] = line.stats( 8, asRepairStats, numRepairStats) - asRepairStats;
+ asParts[COMP_SENSOR] = line.stats(10, asSensorStats, numSensorStats) - asSensorStats;
+
+ std::fill_n(asWeaps, DROID_MAXWEAPS, 0);
+}
+
+/* load the Droid stats for the components from the Access database */
+bool loadDroidTemplates(const char *pDroidData, UDWORD bufferSize)
+{
+ bool bDefaultTemplateFound = false;
+
+ TableView table(pDroidData, bufferSize);
+
+ for (unsigned i = 0; i < table.size(); ++i)
+ {
+ LineView line(table, i);
+
+ DROID_TEMPLATE design(line);
+ if (table.isError())
+ {
+ debug(LOG_ERROR, "%s", table.getError().toUtf8().constData());
+ return false;
+ }
+
+ std::string const pNameCache = design.aName;
+ design.pName = const_cast<char *>(pNameCache.c_str());
+
+ if (getTemplateFromUniqueName(design.pName, 0))
+ {
+ debug(LOG_ERROR, "Duplicate template %s", design.pName);
+ continue;
+ }
+
+ // Store translated name in aName
+ char const *droidResourceName = getDroidResourceName(design.aName);
+ sstrcpy(design.aName, droidResourceName != NULL? droidResourceName : GetDefaultTemplateName(&design));
+
+ // Store global default design if found else store in the appropriate array
+ if (design.droidType == DROID_ANY)
+ {
+ design.droidType = DROID_DEFAULT;
+ // NOTE: sDefaultDesignTemplate.pName takes ownership
+ // of the memory allocated to pDroidDesign->pName
+ // here. Which is good because pDroidDesign leaves
+ // scope here anyway.
+ sDefaultDesignTemplate = design;
+ sDefaultDesignTemplate.pName = strdup(design.pName);
+ bDefaultTemplateFound = true;
+ }
+ else
+ {
+ std::string playerType = line.s(6);
+ // Give those meant for humans to all human players.
+ // Also support the old template format, in which those meant
+ // for humans were player 0 (in campaign) or 5 (in multiplayer).
+ if ((!bMultiPlayer && playerType == "0") ||
+ ( bMultiPlayer && playerType == "5") ||
+ playerType == "YES"
+ )
+ {
+ for (int i = 0; i < MAX_PLAYERS; ++i)
+ {
+ if (NetPlay.players[i].allocated) // human prototype template
+ {
+ design.prefab = false;
+ addTemplateToList(&design, &apsDroidTemplates[i]);
+ }
+ }
+ localTemplates.push_front(design);
+ localTemplates.front().pName = strdup(localTemplates.front().pName);
+ }
+ // Add all templates to static template list
+ design.prefab = true; // prefabricated templates referenced from VLOs
+ addTemplateToList(&design, &apsStaticTemplates);
+ }
+
+ debug(LOG_NEVER, "(default) Droid template found, aName: %s, MP ID: %d, ref: %u, pname: %s, prefab: %s, type:%d (loading)",
+ design.aName, design.multiPlayerID, design.ref, design.pName, design.prefab ? "yes":"no", design.droidType);
+ }
+
+ ASSERT_OR_RETURN(false, bDefaultTemplateFound, "Default template not found");
+
+ return true;
+}
+
+//free the storage for the droid templates
+bool droidTemplateShutDown(void)
+{
+ unsigned int player;
+ DROID_TEMPLATE *pTemplate, *pNext;
+
+ for (player = 0; player < MAX_PLAYERS; player++)
+ {
+ for (pTemplate = apsDroidTemplates[player]; pTemplate != NULL; pTemplate = pNext)
+ {
+ pNext = pTemplate->psNext;
+ 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);
+ delete 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);
+ delete pTemplate;
+ }
+ apsStaticTemplates = NULL;
+ free(sDefaultDesignTemplate.pName);
+ sDefaultDesignTemplate.pName = NULL;
+
+ for (std::list<DROID_TEMPLATE>::iterator i = localTemplates.begin(); i != localTemplates.end(); ++i)
+ {
+ free(i->pName);
+ }
+ localTemplates.clear();
+
+ return true;
+}
+
+/*!
+ * Get a static template from its aName.
+ * This checks the all the Human's apsDroidTemplates list.
+ * This function is similar to getTemplateFromUniqueName() but we use aName,
+ * and not pName, since we don't have that information, and we are checking all player's list.
+ * \param aName Template aName
+ *
+ */
+DROID_TEMPLATE *GetHumanDroidTemplate(const char *aName)
+{
+ DROID_TEMPLATE *templatelist, *found = NULL, *foundOtherPlayer = NULL;
+ int i, playerFound = 0;
+
+ for (i=0; i < MAX_PLAYERS; i++)
+ {
+ templatelist = apsDroidTemplates[i];
+ while (templatelist)
+ {
+ if (!strcmp(templatelist->aName, aName))
+ {
+ debug(LOG_NEVER, "Droid template found, aName: %s, MP ID: %d, ref: %u, pname: %s (for player %d)",
+ templatelist->aName, templatelist->multiPlayerID, templatelist->ref, templatelist->pName, i);
+ if (i == selectedPlayer)
+ {
+ found = templatelist;
+ }
+ else
+ {
+ foundOtherPlayer = templatelist;
+ playerFound = i;
+ }
+ }
+
+ templatelist = templatelist->psNext;
+ }
+ }
+
+ if (foundOtherPlayer && !found)
+ {
+ debug(LOG_ERROR, "The template was not in our list, but was in another players list.");
+ debug(LOG_ERROR, "Droid template's aName: %s, MP ID: %d, ref: %u, pname: %s (for player %d)",
+ foundOtherPlayer->aName, foundOtherPlayer->multiPlayerID, foundOtherPlayer->ref, foundOtherPlayer->pName, playerFound);
+ return foundOtherPlayer;
+ }
+
+ return found;
+}
+
+/*!
+ * Get a static template from its aName.
+ * This checks the AI apsStaticTemplates.
+ * This function is similar to getTemplateFromTranslatedNameNoPlayer() but we use aName,
+ * and not pName, since we don't have that information.
+ * \param aName Template aName
+ *
+ */
+DROID_TEMPLATE *GetAIDroidTemplate(const char *aName)
+{
+ DROID_TEMPLATE *templatelist, *found = NULL;
+
+ templatelist = apsStaticTemplates;
+ while (templatelist)
+ {
+ if (!strcmp(templatelist->aName, aName))
+ {
+ debug(LOG_INFO, "Droid template found, name: %s, MP ID: %d, ref: %u, pname: %s ",
+ templatelist->aName, templatelist->multiPlayerID, templatelist->ref, templatelist->pName);
+
+ found = templatelist;
+ }
+ templatelist = templatelist->psNext;
+ }
+
+ return found;
+}
+
+/*!
+ * Gets a template from its name
+ * relies on the name being unique (or it will return the first one it finds!)
+ * \param pName Template name
+ * \param player Player number
+ * \pre pName has to be the unique, untranslated name!
+ * \pre player \< MAX_PLAYERS
+ */
+DROID_TEMPLATE * getTemplateFromUniqueName(const char *pName, unsigned int player)
+{
+ DROID_TEMPLATE *psCurr;
+ DROID_TEMPLATE *list = apsStaticTemplates; // assume AI
+
+ if (isHumanPlayer(player))
+ {
+ list = apsDroidTemplates[player]; // was human
+ }
+
+ for (psCurr = list; psCurr != NULL; psCurr = psCurr->psNext)
+ {
+ if (strcmp(psCurr->pName, pName) == 0)
+ {
+ return psCurr;
+ }
+ }
+
+ return NULL;
+}
+
+/*!
+ * 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!
+ */
+DROID_TEMPLATE *getTemplateFromTranslatedNameNoPlayer(char const *pName)
+{
+ const char *rName;
+ DROID_TEMPLATE *psCurr;
+
+ for (psCurr = apsStaticTemplates; psCurr != NULL; psCurr = psCurr->psNext)
+ {
+ rName = psCurr->pName ? psCurr->pName : psCurr->aName;
+ if (strcmp(rName, pName) == 0)
+ {
+ return psCurr;
+ }
+ }
+
+ 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(pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
+ {
+ if (pDroidDesign->multiPlayerID == multiPlayerID)
+ {
+ return pDroidDesign;
+ }
+ }
+ }
+ return NULL;
+}
+
+const char* getTemplateName(const DROID_TEMPLATE *psTemplate)
+{
+ return psTemplate->aName;
+}
+
+/*called when a Template is deleted in the Design screen*/
+void deleteTemplateFromProduction(DROID_TEMPLATE *psTemplate, unsigned player, QUEUE_MODE mode)
+{
+ STRUCTURE *psStruct;
+ STRUCTURE *psList;
+
+ //see if any factory is currently using the template
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ psList = NULL;
+ switch (i)
+ {
+ case 0:
+ psList = apsStructLists[player];
+ break;
+ case 1:
+ psList = mission.apsStructLists[player];
+ break;
+ }
+ for (psStruct = psList; psStruct != NULL; psStruct = psStruct->psNext)
+ {
+ if (StructIsFactory(psStruct))
+ {
+ FACTORY *psFactory = &psStruct->pFunctionality->factory;
+
+ if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size())
+ {
+ ProductionRun &productionRun = asProductionRun[psFactory->psAssemblyPoint->factoryType][psFactory->psAssemblyPoint->factoryInc];
+ for (unsigned inc = 0; inc < productionRun.size(); ++inc)
+ {
+ if (productionRun[inc].psTemplate->multiPlayerID == psTemplate->multiPlayerID && mode == ModeQueue)
+ {
+ //just need to erase this production run entry
+ productionRun.erase(productionRun.begin() + inc);
+ --inc;
+ }
+ }
+ }
+
+ if (psFactory->psSubject == NULL)
+ {
+ continue;
+ }
+
+ // check not being built in the factory for the template player
+ if (psTemplate->multiPlayerID == psFactory->psSubject->multiPlayerID && mode == ModeImmediate)
+ {
+ syncDebugStructure(psStruct, '<');
+ syncDebug("Clearing production");
+
+ // Clear the factory's subject.
+ psFactory->psSubject = NULL;
+
+ if (player == productionPlayer)
+ {
+ //check to see if anything left to produce
+ DROID_TEMPLATE *psNextTemplate = factoryProdUpdate(psStruct, NULL);
+ //power is returned by factoryProdAdjust()
+ if (psNextTemplate)
+ {
+ structSetManufacture(psStruct, psNextTemplate, ModeQueue); // ModeQueue because production lists aren't synchronised.
+ }
+ }