Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 12 commits
  • 38 files changed
  • 0 comments
  • 1 contributor

Showing 38 changed files with 889 additions and 615 deletions. Show diff stats Hide diff stats

  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
@@ -4,7 +4,7 @@ stamp:
4 4 touch stamp
5 5
6 6 %.wz: $(abs_srcdir)/% stamp
7   - (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"
  7 + (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"
8 8 $(ZIP) -T $@
9 9 rm -f stamp
10 10
2  data/base/stats/templates.txt
... ... @@ -1,5 +1,5 @@
1 1 BarbarianTrike,139,B4body-sml-trike01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,7,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
2   -ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,0,wheeled01,ZNULLREPAIR,DROID,DefaultSensor1Mk1,0
  2 +ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,0,wheeled01,ZNULLREPAIR,DROID,ZNULLSENSOR,0
3 3 BarbarianBuggy,150,B3body-sml-buggy01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,7,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
4 4 BaBaPeople,158,B1BaBaPerson01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,7,BaBaLegs,ZNULLREPAIR,PERSON,DefaultSensor1Mk1,1
5 5 ViperLtCannonWheels,177,Body1REC,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,4,wheeled01,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
1  data/mp/stats/research/multiplayer/redcomponents.txt
... ... @@ -1,3 +1,4 @@
  1 +Research ID,Component ID,unused
1 2 R-Comp-CommandTurret02,CommandTurret1,WEAPON,10
2 3 R-Comp-CommandTurret03,CommandTurret2,WEAPON,10
3 4 R-Comp-CommandTurret04,CommandTurret3,WEAPON,10
1  data/mp/stats/research/multiplayer/redstructure.txt
... ... @@ -1,3 +1,4 @@
  1 +Research ID,Structure ID,unused
1 2 R-Defense-AASite-QuadRotMg,AASite-QuadMg1,189
2 3 R-Defense-Emplacement-HPVcannon,PillBox4,130
3 4 R-Defense-GuardTower-ATMiss,GuardTower5,123
2  data/mp/stats/research/multiplayer/research.txt
... ... @@ -1,4 +1,4 @@
1   -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
  1 +Research ID,unused,Subgroup icon,Major tech,Main icon,IMD,IMD2,MsgName,StructName,CompName,CompType,ResearchPoints,keyTopic,unused,unused,unused,unused,unused,unused,unused
2 2 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
3 3 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
4 4 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
... ... @@ -1,3 +1,4 @@
  1 +Research ID,Function ID,unused
1 2 R-Struc-PowerModuleMk1,Struc-PowerModuleMk1,225
2 3 R-Vehicle-Engine01,Vehicle-Engine01,381
3 4 R-Vehicle-Engine02,Vehicle-Engine02,382
1  data/mp/stats/research/multiplayer/researchstruct.txt
... ... @@ -1,3 +1,4 @@
  1 +Research ID,Structure ID,unused
1 2 R-Defense-Tower01,A0CommandCentre,0
2 3 R-Defense-Tower06,A0CommandCentre,0
3 4 R-Defense-Pillbox01,A0CommandCentre,0
1  data/mp/stats/research/multiplayer/resultcomponent.txt
... ... @@ -1,3 +1,4 @@
  1 +Research ID,Component ID,Type,Replaced Component,Replaced Type,unused
1 2 R-Wpn-AAGun02,AAGun2Mk1,WEAPON,0,0,10
2 3 R-Wpn-AALaser,AAGunLaser,WEAPON,0,0,10
3 4 R-Sys-Autorepair-General,AutoRepair,REPAIR,ZNULLREPAIR,REPAIR,6
1  data/mp/stats/research/multiplayer/resultstructure.txt
... ... @@ -1,3 +1,4 @@
  1 +Research ID,Structure ID,unused,unused
1 2 R-Defense-AA-Laser,P0-AASite-Laser,0,340
2 3 R-Defense-AASite-QuadBof,AASite-QuadBof,0,188
3 4 R-Defense-AASite-QuadMg1,AASite-QuadMg1,0,189
2  data/mp/stats/templates.txt
... ... @@ -1,4 +1,4 @@
1   -ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,YES,wheeled01,ZNULLREPAIR,DROID,DefaultSensor1Mk1,0
  1 +ConstructionDroid,140,Body1REC,ZNULLBRAIN,Spade1Mk1,ZNULLECM,YES,wheeled01,ZNULLREPAIR,DROID,ZNULLSENSOR,0
2 2 BarbarianTrike,139,B4body-sml-trike01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,NO,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
3 3 BarbarianBuggy,150,B3body-sml-buggy01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,NO,BaBaProp,ZNULLREPAIR,DROID,DefaultSensor1Mk1,1
4 4 BaBaPeople,158,B1BaBaPerson01,ZNULLBRAIN,ZNULLCONSTRUCT,ZNULLECM,NO,BaBaLegs,ZNULLREPAIR,PERSON,DefaultSensor1Mk1,1
2  src/Makefile.am
@@ -140,6 +140,7 @@ noinst_HEADERS = \
140 140 stringdef.h \
141 141 structuredef.h \
142 142 structure.h \
  143 + template.h \
143 144 terrain.h \
144 145 text.h \
145 146 texture.h \
@@ -254,6 +255,7 @@ warzone2100_SOURCES = \
254 255 seqdisp.cpp \
255 256 stats.cpp \
256 257 structure.cpp \
  258 + template.cpp \
257 259 terrain.cpp \
258 260 text.cpp \
259 261 texture.cpp \
1  src/ai.cpp
@@ -377,6 +377,7 @@ static SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker,
377 377
378 378 /* Now calculate the overall weight */
379 379 attackWeight = asWeaponModifier[weaponEffect][(asPropulsionStats + targetDroid->asBits[COMP_PROPULSION].nStat)->propulsionType] // Our weapon's effect against target
  380 + + asWeaponModifierBody[weaponEffect][(asBodyStats + targetDroid->asBits[COMP_BODY].nStat)->size]
380 381 + WEIGHT_DIST_TILE_DROID * psAttacker->sensorRange/TILE_UNITS
381 382 - WEIGHT_DIST_TILE_DROID * map_coord(iHypot(psAttacker->pos.x - targetDroid->pos.x, psAttacker->pos.y - targetDroid->pos.y)) // farer droids are less attractive
382 383 + WEIGHT_HEALTH_DROID * damageRatio // we prefer damaged droids
1  src/data.cpp
@@ -48,6 +48,7 @@
48 48 #include "research.h"
49 49 #include "scriptvals.h"
50 50 #include "stats.h"
  51 +#include "template.h"
51 52 #include "text.h"
52 53 #include "texture.h"
53 54
66 src/design.cpp
@@ -77,7 +77,7 @@
77 77 #include "cmddroid.h"
78 78 #include "scriptextern.h"
79 79 #include "mission.h"
80   -
  80 +#include "template.h"
81 81 #include "multiplay.h"
82 82 #include "multistat.h"
83 83
@@ -362,6 +362,13 @@ static bool saveTemplate();
362 362
363 363 static void desCreateDefaultTemplate( void );
364 364
  365 +/**
  366 + * Updates the status of the stored template toggle button.
  367 + *
  368 + * @param isStored If the template is stored or not.
  369 + */
  370 +static void updateStoreButton(bool isStored);
  371 +
365 372 /* The current name of the design */
366 373 static char aCurrName[WIDG_MAXSTR];
367 374
@@ -452,6 +459,7 @@ static bool _intAddDesign( bool bShowCentreScreen )
452 459 /* Initialise the current design */
453 460 sCurrDesign = sDefaultDesignTemplate;
454 461 sCurrDesign.pName = NULL;
  462 + sCurrDesign.stored = false;
455 463 sstrcpy(aCurrName, _("New Vehicle"));
456 464 sstrcpy(sCurrDesign.aName, aCurrName);
457 465
@@ -612,6 +620,24 @@ static bool _intAddDesign( bool bShowCentreScreen )
612 620 return false;
613 621 }
614 622
  623 + // Add the store template button
  624 + sButInit.formID = IDDES_PARTFORM;
  625 + sButInit.id = IDDES_STOREBUTTON;
  626 + sButInit.style = WBUT_PLAIN;
  627 + sButInit.width = iV_GetImageWidth(IntImages, IMAGE_DES_BIN);
  628 + sButInit.height = iV_GetImageHeight(IntImages, IMAGE_DES_BIN);
  629 + sButInit.x = DES_PARTSEPARATIONX;
  630 + sButInit.y = DES_PARTFORMHEIGHT - 2*sButInit.height - 2*DES_PARTSEPARATIONY;
  631 + sButInit.pTip = _("Store Design");
  632 + sButInit.FontID = font_regular;
  633 + sButInit.pDisplay = intDisplayButtonHilight;
  634 + sButInit.UserData = PACKDWORD_TRI(0, IMAGE_DES_BINH, IMAGE_DES_BIN);
  635 +
  636 + if (!widgAddButton(psWScreen, &sButInit))
  637 + {
  638 + return false;
  639 + }
  640 +
615 641 /* add central stats form */
616 642 sFormInit.formID = 0;
617 643 sFormInit.id = IDDES_STATSFORM;
@@ -866,7 +892,8 @@ void desSetupDesignTemplates(void)
866 892 psTempl->droidType != DROID_CYBORG_SUPER &&
867 893 psTempl->droidType != DROID_CYBORG_CONSTRUCT &&
868 894 psTempl->droidType != DROID_CYBORG_REPAIR &&
869   - psTempl->droidType != DROID_PERSON)
  895 + psTempl->droidType != DROID_PERSON &&
  896 + researchedTemplate(psTempl, selectedPlayer))
870 897 {
871 898 apsTemplateList.push_back(psTempl);
872 899 }
@@ -3276,6 +3303,12 @@ bool intValidTemplate(DROID_TEMPLATE *psTempl, const char *newName)
3276 3303 }
3277 3304 }
3278 3305
  3306 + // Check number of weapon slots
  3307 + if (psTempl->numWeaps > (asBodyStats + psTempl->asParts[COMP_BODY])->weaponSlots)
  3308 + {
  3309 + return false;
  3310 + }
  3311 +
3279 3312 // Check no mixing of systems and weapons
3280 3313 if (psTempl->numWeaps != 0 &&
3281 3314 (psTempl->asParts[COMP_SENSOR] ||
@@ -3338,6 +3371,7 @@ static void desCreateDefaultTemplate( void )
3338 3371 /* set current design to default */
3339 3372 sCurrDesign = sDefaultDesignTemplate;
3340 3373 sCurrDesign.pName = NULL;
  3374 + sCurrDesign.stored = false;
3341 3375
3342 3376 /* reset stats */
3343 3377 intSetDesignStats(&sCurrDesign);
@@ -3450,6 +3484,8 @@ void intProcessDesign(UDWORD id)
3450 3484 intSetButtonFlash( IDDES_PROPBUTTON, true );
3451 3485 intSetButtonFlash( IDDES_WPABUTTON, true );
3452 3486 intSetButtonFlash( IDDES_WPBBUTTON, true );
  3487 +
  3488 + widgHide(psWScreen, IDDES_STOREBUTTON);
3453 3489 }
3454 3490 else
3455 3491 {
@@ -3496,6 +3532,9 @@ void intProcessDesign(UDWORD id)
3496 3532 {
3497 3533 intSetButtonFlash( IDDES_WPBBUTTON, true );
3498 3534 }
  3535 +
  3536 + widgReveal(psWScreen, IDDES_STOREBUTTON);
  3537 + updateStoreButton(sCurrDesign.stored);
3499 3538 }
3500 3539 }
3501 3540
@@ -4008,6 +4047,10 @@ void intProcessDesign(UDWORD id)
4008 4047 }
4009 4048 break;
4010 4049 }
  4050 + case IDDES_STOREBUTTON:
  4051 + sCurrDesign.stored = !sCurrDesign.stored; // Invert the current status
  4052 + saveTemplate();
  4053 + break;
4011 4054 case IDDES_SYSTEMBUTTON:
4012 4055 // Add the correct component form
4013 4056 switch (droidTemplateType(&sCurrDesign))
@@ -4409,8 +4452,11 @@ static bool saveTemplate(void)
4409 4452 {
4410 4453 if (!intValidTemplate(&sCurrDesign, aCurrName))
4411 4454 {
  4455 + widgHide(psWScreen, IDDES_STOREBUTTON);
4412 4456 return false;
4413 4457 }
  4458 + widgReveal(psWScreen, IDDES_STOREBUTTON);
  4459 + updateStoreButton(sCurrDesign.stored); // Change the buttons icon
4414 4460
4415 4461 /* if first (New Design) button selected find empty template
4416 4462 * else find current button template
@@ -4436,6 +4482,7 @@ static bool saveTemplate(void)
4436 4482 psTempl = templateFromButtonId(droidTemplID);
4437 4483 if (psTempl == NULL)
4438 4484 {
  4485 + debug(LOG_ERROR, "Template not found for button");
4439 4486 return false;
4440 4487 }
4441 4488
@@ -4636,3 +4683,18 @@ void reverseTemplateList(DROID_TEMPLATE **ppsList)
4636 4683 *ppsList = psPrev;
4637 4684 }
4638 4685
  4686 +void updateStoreButton(bool isStored)
  4687 +{
  4688 + UDWORD imageset;
  4689 +
  4690 + if (isStored)
  4691 + {
  4692 + imageset = PACKDWORD_TRI(0, IMAGE_DES_TURRETH, IMAGE_DES_TURRET);
  4693 + }
  4694 + else
  4695 + {
  4696 + imageset = PACKDWORD_TRI(0, IMAGE_DES_BINH, IMAGE_DES_BIN);
  4697 + }
  4698 +
  4699 + widgSetUserData2(psWScreen, IDDES_STOREBUTTON, imageset);
  4700 +}
2  src/design.h
@@ -59,6 +59,8 @@
59 59 #define IDDES_WEAPONS_A 5028 // The weapon TURRET_A button for the Component form (right)
60 60 #define IDDES_WEAPONS_B 5029 // The weapon TURRET_B button for the Component form (right)
61 61
  62 +#define IDDES_STOREBUTTON 5905 // Stored template button
  63 +
62 64 /* Design screen bar graph IDs */
63 65 #define IDDES_BODYARMOUR_K 5100 // The body armour bar graph for kinetic weapons
64 66 #define IDDES_BODYPOWER 5101 // The body power plant graph
545 src/droid.cpp
@@ -82,32 +82,23 @@
82 82 #include "research.h"
83 83 #include "combat.h"
84 84 #include "scriptfuncs.h" //for ThreatInRange()
85   -#include "design.h" //for GetDefaultTemplateName
  85 +#include "template.h"
86 86
87 87 #define DEFAULT_RECOIL_TIME (GAME_TICKS_PER_SEC/4)
88 88 #define DROID_DAMAGE_SPREAD (16 - rand()%32)
89 89 #define DROID_REPAIR_SPREAD (20 - rand()%40)
90 90
91   -
92   -/* default droid design template */
93   -extern DROID_TEMPLATE sDefaultDesignTemplate;
94   -
95   -// Template storage
96   -DROID_TEMPLATE *apsDroidTemplates[MAX_PLAYERS];
97   -DROID_TEMPLATE *apsStaticTemplates; // for AIs and scripts
98   -
99 91 // store the experience of recently recycled droids
100 92 UWORD aDroidExperience[MAX_PLAYERS][MAX_RECYCLED_DROIDS];
101 93 UDWORD selectedGroup = UBYTE_MAX;
102 94 UDWORD selectedCommander = UBYTE_MAX;
103 95
  96 +/* default droid design template */
  97 +extern DROID_TEMPLATE sDefaultDesignTemplate;
  98 +
104 99 /** Height the transporter hovers at above the terrain. */
105 100 #define TRANSPORTER_HOVER_HEIGHT 10
106 101
107   -/* Sorry, Keith, your abreviation [sic] is gone.
108   - * NAYBOR = neighbour - thanks to Keith for a great abreviation
109   - */
110   -
111 102 // the structure that was last hit
112 103 DROID *psLastDroidHit;
113 104
@@ -1495,175 +1486,6 @@ bool droidUpdateDroidRepair(DROID *psRepairDroid)
1495 1486 return psDroidToRepair->body < psDroidToRepair->originalBody;
1496 1487 }
1497 1488
1498   -static const StringToEnum<DROID_TYPE> map_DROID_TYPE[] =
1499   -{
1500   - {"PERSON", DROID_PERSON },
1501   - {"CYBORG", DROID_CYBORG },
1502   - {"CYBORG_SUPER", DROID_CYBORG_SUPER },
1503   - {"CYBORG_CONSTRUCT", DROID_CYBORG_CONSTRUCT },
1504   - {"CYBORG_REPAIR", DROID_CYBORG_REPAIR },
1505   - {"TRANSPORTER", DROID_TRANSPORTER },
1506   - {"ZNULLDROID", DROID_ANY },
1507   - {"DROID", DROID_DEFAULT },
1508   -};
1509   -
1510   -DROID_TEMPLATE::DROID_TEMPLATE() // This constructor replaces a memset in scrAssembleWeaponTemplate(), not needed elsewhere.
1511   - : BASE_STATS()
1512   - //, aName
1513   - //, asParts
1514   - , buildPoints(0)
1515   - , powerPoints(0)
1516   - , storeCount(0)
1517   - , numWeaps(0)
1518   - //, asWeaps
1519   - , droidType(DROID_WEAPON)
1520   - , multiPlayerID(0)
1521   - , psNext(NULL)
1522   - , prefab(false)
1523   -{
1524   - aName[0] = '\0';
1525   - std::fill_n(asParts, DROID_MAXCOMP, 0);
1526   - std::fill_n(asWeaps, DROID_MAXWEAPS, 0);
1527   -}
1528   -
1529   -DROID_TEMPLATE::DROID_TEMPLATE(LineView line)
1530   - : BASE_STATS(REF_TEMPLATE_START + line.line())
1531   - //, aName
1532   - //, asParts
1533   - , buildPoints(0)
1534   - , powerPoints(0)
1535   - , storeCount(0)
1536   - , numWeaps(line.i(11, 0, DROID_MAXWEAPS))
1537   - //, asWeaps
1538   - , droidType(line.e(9, map_DROID_TYPE))
1539   - , multiPlayerID(line.u32(1))
1540   - , psNext(NULL)
1541   - , prefab(false)
1542   - // Ignored columns: 6 - but used later to decide whether the template is for human players.
1543   -{
1544   - std::string name = line.s(0);
1545   - sstrcpy(aName, name.c_str());
1546   -
1547   - asParts[COMP_UNKNOWN] = 0; // Is this one useful for anything at all?
1548   - asParts[COMP_BODY] = line.stats( 2, asBodyStats, numBodyStats) - asBodyStats;
1549   - asParts[COMP_BRAIN] = line.stats( 3, asBrainStats, numBrainStats) - asBrainStats;
1550   - asParts[COMP_CONSTRUCT] = line.stats( 4, asConstructStats, numConstructStats) - asConstructStats;
1551   - asParts[COMP_ECM] = line.stats( 5, asECMStats, numECMStats) - asECMStats;
1552   - asParts[COMP_PROPULSION] = line.stats( 7, asPropulsionStats, numPropulsionStats) - asPropulsionStats;
1553   - asParts[COMP_REPAIRUNIT] = line.stats( 8, asRepairStats, numRepairStats) - asRepairStats;
1554   - asParts[COMP_SENSOR] = line.stats(10, asSensorStats, numSensorStats) - asSensorStats;
1555   -
1556   - std::fill_n(asWeaps, DROID_MAXWEAPS, 0);
1557   -}
1558   -
1559   -/* load the Droid stats for the components from the Access database */
1560   -bool loadDroidTemplates(const char *pDroidData, UDWORD bufferSize)
1561   -{
1562   - bool bDefaultTemplateFound = false;
1563   -
1564   - TableView table(pDroidData, bufferSize);
1565   -
1566   - for (unsigned i = 0; i < table.size(); ++i)
1567   - {
1568   - LineView line(table, i);
1569   -
1570   - DROID_TEMPLATE design(line);
1571   - if (table.isError())
1572   - {
1573   - debug(LOG_ERROR, "%s", table.getError().toUtf8().constData());
1574   - return false;
1575   - }
1576   -
1577   - std::string const pNameCache = design.aName;
1578   - design.pName = const_cast<char *>(pNameCache.c_str());
1579   -
1580   - if (getTemplateFromUniqueName(design.pName, 0))
1581   - {
1582   - debug(LOG_ERROR, "Duplicate template %s", design.pName);
1583   - continue;
1584   - }
1585   -
1586   - // Store translated name in aName
1587   - char const *droidResourceName = getDroidResourceName(design.aName);
1588   - sstrcpy(design.aName, droidResourceName != NULL? droidResourceName : GetDefaultTemplateName(&design));
1589   -
1590   - // Store global default design if found else store in the appropriate array
1591   - if (design.droidType == DROID_ANY)
1592   - {
1593   - design.droidType = DROID_DEFAULT;
1594   - // NOTE: sDefaultDesignTemplate.pName takes ownership
1595   - // of the memory allocated to pDroidDesign->pName
1596   - // here. Which is good because pDroidDesign leaves
1597   - // scope here anyway.
1598   - sDefaultDesignTemplate = design;
1599   - sDefaultDesignTemplate.pName = strdup(design.pName);
1600   - bDefaultTemplateFound = true;
1601   - }
1602   - else
1603   - {
1604   - std::string playerType = line.s(6);
1605   - // Give those meant for humans to all human players.
1606   - // Also support the old template format, in which those meant
1607   - // for humans were player 0 (in campaign) or 5 (in multiplayer).
1608   - if ((!bMultiPlayer && playerType == "0") ||
1609   - ( bMultiPlayer && playerType == "5") ||
1610   - playerType == "YES"
1611   - )
1612   - {
1613   - for (int i = 0; i < MAX_PLAYERS; ++i)
1614   - {
1615   - if (NetPlay.players[i].allocated) // human prototype template
1616   - {
1617   - design.prefab = false;
1618   - addTemplateToList(&design, &apsDroidTemplates[i]);
1619   - }
1620   - }
1621   - localTemplates.push_front(design);
1622   - localTemplates.front().pName = strdup(localTemplates.front().pName);
1623   - }
1624   - // Add all templates to static template list
1625   - design.prefab = true; // prefabricated templates referenced from VLOs
1626   - addTemplateToList(&design, &apsStaticTemplates);
1627   - }
1628   -
1629   - debug(LOG_NEVER, "(default) Droid template found, aName: %s, MP ID: %d, ref: %u, pname: %s, prefab: %s, type:%d (loading)",
1630   - design.aName, design.multiPlayerID, design.ref, design.pName, design.prefab ? "yes":"no", design.droidType);
1631   - }
1632   -
1633   - ASSERT_OR_RETURN(false, bDefaultTemplateFound, "Default template not found");
1634   -
1635   - return true;
1636   -}
1637   -
1638   -static void initTemplatePoints(DROID_TEMPLATE *pDroidDesign)
1639   -{
1640   - //calculate the total build points
1641   - pDroidDesign->buildPoints = calcTemplateBuild(pDroidDesign);
1642   - //calc the total power points
1643   - pDroidDesign->powerPoints = calcTemplatePower(pDroidDesign);
1644   -}
1645   -
1646   -/*initialise the template build and power points */
1647   -void initTemplatePoints(void)
1648   -{
1649   - for (int player = 0; player < MAX_PLAYERS; ++player)
1650   - {
1651   - for (DROID_TEMPLATE *pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
1652   - {
1653   - initTemplatePoints(pDroidDesign);
1654   - }
1655   - }
1656   - for (DROID_TEMPLATE *pDroidDesign = apsStaticTemplates; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
1657   - {
1658   - initTemplatePoints(pDroidDesign);
1659   - }
1660   - for (std::list<DROID_TEMPLATE>::iterator pDroidDesign = localTemplates.begin(); pDroidDesign != localTemplates.end(); ++pDroidDesign)
1661   - {
1662   - initTemplatePoints(&*pDroidDesign);
1663   - }
1664   -}
1665   -
1666   -
1667 1489 // return whether a droid is IDF
1668 1490 bool idfDroid(DROID *psDroid)
1669 1491 {
@@ -1683,31 +1505,12 @@ bool idfDroid(DROID *psDroid)
1683 1505 return true;
1684 1506 }
1685 1507
1686   -// return whether a template is for an IDF droid
1687   -bool templateIsIDF(DROID_TEMPLATE *psTemplate)
1688   -{
1689   - //add Cyborgs
1690   - if (!(psTemplate->droidType == DROID_WEAPON || psTemplate->droidType == DROID_CYBORG ||
1691   - psTemplate->droidType == DROID_CYBORG_SUPER))
1692   - {
1693   - return false;
1694   - }
1695   -
1696   - if (proj_Direct(psTemplate->asWeaps[0] + asWeaponStats))
1697   - {
1698   - return false;
1699   - }
1700   -
1701   - return true;
1702   -}
1703   -
1704 1508 /* Return the type of a droid */
1705 1509 DROID_TYPE droidType(DROID *psDroid)
1706 1510 {
1707 1511 return psDroid->droidType;
1708 1512 }
1709 1513
1710   -
1711 1514 /* Return the type of a droid from it's template */
1712 1515 DROID_TYPE droidTemplateType(DROID_TEMPLATE *psTemplate)
1713 1516 {
@@ -1830,49 +1633,6 @@ bool loadDroidWeapons(const char *pWeaponData, UDWORD bufferSize)
1830 1633 return true;
1831 1634 }
1832 1635
1833   -//free the storage for the droid templates
1834   -bool droidTemplateShutDown(void)
1835   -{
1836   - unsigned int player;
1837   - DROID_TEMPLATE *pTemplate, *pNext;
1838   -
1839   - for (player = 0; player < MAX_PLAYERS; player++)
1840   - {
1841   - for (pTemplate = apsDroidTemplates[player]; pTemplate != NULL; pTemplate = pNext)
1842   - {
1843   - pNext = pTemplate->psNext;
1844   - if (pTemplate->pName != sDefaultDesignTemplate.pName) // sanity check probably no longer necessary
1845   - {
1846   - free(pTemplate->pName);
1847   - }
1848   - ASSERT(!pTemplate->prefab, "Static template %s in player template list!", pTemplate->aName);
1849   - delete pTemplate;
1850   - }
1851   - apsDroidTemplates[player] = NULL;
1852   - }
1853   - for (pTemplate = apsStaticTemplates; pTemplate != NULL; pTemplate = pNext)
1854   - {
1855   - pNext = pTemplate->psNext;
1856   - if (pTemplate->pName != sDefaultDesignTemplate.pName) // sanity check probably no longer necessary
1857   - {
1858   - free(pTemplate->pName);
1859   - }
1860   - ASSERT(pTemplate->prefab, "Player template %s in static template list!", pTemplate->aName);
1861   - delete pTemplate;
1862   - }
1863   - apsStaticTemplates = NULL;
1864   - free(sDefaultDesignTemplate.pName);
1865   - sDefaultDesignTemplate.pName = NULL;
1866   -
1867   - for (std::list<DROID_TEMPLATE>::iterator i = localTemplates.begin(); i != localTemplates.end(); ++i)
1868   - {
1869   - free(i->pName);
1870   - }
1871   - localTemplates.clear();
1872   -
1873   - return true;
1874   -}
1875   -
1876 1636 /* Calculate the weight of a droid from it's template */
1877 1637 UDWORD calcDroidWeight(DROID_TEMPLATE *psTemplate)
1878 1638 {
@@ -2401,13 +2161,9 @@ void droidSetBits(DROID_TEMPLATE *pTemplate,DROID *psDroid)
2401 2161 // Sets the parts array in a template given a droid.
2402 2162 void templateSetParts(const DROID *psDroid, DROID_TEMPLATE *psTemplate)
2403 2163 {
2404   - UDWORD inc;
2405 2164 psTemplate->numWeaps = 0;
2406   -
2407 2165 psTemplate->droidType = psDroid->droidType;
2408   -
2409   - //can only have DROID_MAXWEAPS weapon now
2410   - for (inc = 0; inc < DROID_MAXWEAPS; inc++)
  2166 + for (int inc = 0; inc < DROID_MAXWEAPS; inc++)
2411 2167 {
2412 2168 //this should fix the NULL weapon stats for empty weaponslots
2413 2169 psTemplate->asWeaps[inc] = 0;
@@ -2417,81 +2173,15 @@ void templateSetParts(const DROID *psDroid, DROID_TEMPLATE *psTemplate)
2417 2173 psTemplate->asWeaps[inc] = psDroid->asWeaps[inc].nStat;
2418 2174 }
2419 2175 }
2420   -
2421 2176 psTemplate->asParts[COMP_BODY] = psDroid->asBits[COMP_BODY].nStat;
2422   -
2423 2177 psTemplate->asParts[COMP_BRAIN] = psDroid->asBits[COMP_BRAIN].nStat;
2424   -
2425 2178 psTemplate->asParts[COMP_PROPULSION] = psDroid->asBits[COMP_PROPULSION].nStat;
2426   -
2427 2179 psTemplate->asParts[COMP_SENSOR] = psDroid->asBits[COMP_SENSOR].nStat;
2428   -
2429 2180 psTemplate->asParts[COMP_ECM] = psDroid->asBits[COMP_ECM].nStat;
2430   -
2431 2181 psTemplate->asParts[COMP_REPAIRUNIT] = psDroid->asBits[COMP_REPAIRUNIT].nStat;
2432   -
2433 2182 psTemplate->asParts[COMP_CONSTRUCT] = psDroid->asBits[COMP_CONSTRUCT].nStat;
2434 2183 }
2435 2184
2436   -
2437   -/*
2438   -fills the list with Templates that can be manufactured
2439   -in the Factory - based on size. There is a limit on how many can be manufactured
2440   -at any one time. Pass back the number available.
2441   -*/
2442   -void fillTemplateList(std::vector<DROID_TEMPLATE *> &pList, STRUCTURE *psFactory)
2443   -{
2444   - pList.clear();
2445   -
2446   - DROID_TEMPLATE *psCurr;
2447   - UDWORD iCapacity = psFactory->pFunctionality->factory.capacity;
2448   -
2449   - /* Add the templates to the list*/
2450   - for (std::list<DROID_TEMPLATE>::iterator i = localTemplates.begin(); i != localTemplates.end(); ++i)
2451   - {
2452   - psCurr = &*i;
2453   - //must add Command Droid if currently in production
2454   - if (!getProduction(psFactory, psCurr).quantity)
2455   - {
2456   - //can only have (MAX_CMDDROIDS) in the world at any one time
2457   - if (psCurr->droidType == DROID_COMMAND)
2458   - {
2459   - if (checkProductionForCommand(psFactory->player) +
2460   - checkCommandExist(psFactory->player) >= (MAX_CMDDROIDS))
2461   - {
2462   - continue;
2463   - }
2464   - }
2465   - }
2466   -
2467   - if (!validTemplateForFactory(psCurr, psFactory))
2468   - {
2469   - continue;
2470   - }
2471   -
2472   - //check the factory can cope with this sized body
2473   - if (!((asBodyStats + psCurr->asParts[COMP_BODY])->size > iCapacity) )
2474   - {
2475   - //cyborg templates are available when the body has been research
2476   - //-same for Transporter in multiPlayer
2477   - if ( psCurr->droidType == DROID_CYBORG ||
2478   - psCurr->droidType == DROID_CYBORG_SUPER ||
2479   - psCurr->droidType == DROID_CYBORG_CONSTRUCT ||
2480   - psCurr->droidType == DROID_CYBORG_REPAIR ||
2481   - psCurr->droidType == DROID_TRANSPORTER)
2482   - {
2483   - if ( apCompLists[psFactory->player][COMP_BODY]
2484   - [psCurr->asParts[COMP_BODY]] != AVAILABLE )
2485   - {
2486   - //ignore if not research yet
2487   - continue;
2488   - }
2489   - }
2490   - pList.push_back(psCurr);
2491   - }
2492   - }
2493   -}
2494   -
2495 2185 /* Make all the droids for a certain player a member of a specific group */
2496 2186 void assignDroidsToGroup(UDWORD playerNumber, UDWORD groupNumber)
2497 2187 {
@@ -2823,152 +2513,7 @@ bool calcDroidMuzzleLocation(DROID *psDroid, Vector3i *muzzle, int weapon_slot)
2823 2513
2824 2514 return true;
2825 2515 }
2826   -/*!
2827   - * Get a static template from its aName.
2828   - * This checks the all the Human's apsDroidTemplates list.
2829   - * This function is similar to getTemplateFromUniqueName() but we use aName,
2830   - * and not pName, since we don't have that information, and we are checking all player's list.
2831   - * \param aName Template aName
2832   - *
2833   - */
2834   -DROID_TEMPLATE *GetHumanDroidTemplate(const char *aName)
2835   -{
2836   - DROID_TEMPLATE *templatelist, *found = NULL, *foundOtherPlayer = NULL;
2837   - int i, playerFound = 0;
2838 2516
2839   - for (i=0; i < MAX_PLAYERS; i++)
2840   - {
2841   - templatelist = apsDroidTemplates[i];
2842   - while (templatelist)
2843   - {
2844   - if (!strcmp(templatelist->aName, aName))
2845   - {
2846   - debug(LOG_NEVER, "Droid template found, aName: %s, MP ID: %d, ref: %u, pname: %s (for player %d)",
2847   - templatelist->aName, templatelist->multiPlayerID, templatelist->ref, templatelist->pName, i);
2848   - if (i == selectedPlayer)
2849   - {
2850   - found = templatelist;
2851   - }
2852   - else
2853   - {
2854   - foundOtherPlayer = templatelist;
2855   - playerFound = i;
2856   - }
2857   - }
2858   -
2859   - templatelist = templatelist->psNext;
2860   - }
2861   - }
2862   -
2863   - if (foundOtherPlayer && !found)
2864   - {
2865   - debug(LOG_ERROR, "The template was not in our list, but was in another players list.");
2866   - debug(LOG_ERROR, "Droid template's aName: %s, MP ID: %d, ref: %u, pname: %s (for player %d)",
2867   - foundOtherPlayer->aName, foundOtherPlayer->multiPlayerID, foundOtherPlayer->ref, foundOtherPlayer->pName, playerFound);
2868   - return foundOtherPlayer;
2869   - }
2870   -
2871   - return found;
2872   -}
2873   -
2874   -/*!
2875   - * Get a static template from its aName.
2876   - * This checks the AI apsStaticTemplates.
2877   - * This function is similar to getTemplateFromTranslatedNameNoPlayer() but we use aName,
2878   - * and not pName, since we don't have that information.
2879   - * \param aName Template aName
2880   - *
2881   - */
2882   -DROID_TEMPLATE *GetAIDroidTemplate(const char *aName)
2883   -{
2884   - DROID_TEMPLATE *templatelist, *found = NULL;
2885   -
2886   - templatelist = apsStaticTemplates;
2887   - while (templatelist)
2888   - {
2889   - if (!strcmp(templatelist->aName, aName))
2890   - {
2891   - debug(LOG_INFO, "Droid template found, name: %s, MP ID: %d, ref: %u, pname: %s ",
2892   - templatelist->aName, templatelist->multiPlayerID, templatelist->ref, templatelist->pName);
2893   -
2894   - found = templatelist;
2895   - }
2896   - templatelist = templatelist->psNext;
2897   - }
2898   -
2899   - return found;
2900   -}
2901   -
2902   -/*!
2903   - * Gets a template from its name
2904   - * relies on the name being unique (or it will return the first one it finds!)
2905   - * \param pName Template name
2906   - * \param player Player number
2907   - * \pre pName has to be the unique, untranslated name!
2908   - * \pre player \< MAX_PLAYERS
2909   - */
2910   -DROID_TEMPLATE * getTemplateFromUniqueName(const char *pName, unsigned int player)
2911   -{
2912   - DROID_TEMPLATE *psCurr;
2913   - DROID_TEMPLATE *list = apsStaticTemplates; // assume AI
2914   -
2915   - if (isHumanPlayer(player))
2916   - {
2917   - list = apsDroidTemplates[player]; // was human
2918   - }
2919   -
2920   - for (psCurr = list; psCurr != NULL; psCurr = psCurr->psNext)
2921   - {
2922   - if (strcmp(psCurr->pName, pName) == 0)
2923   - {
2924   - return psCurr;
2925   - }
2926   - }
2927   -
2928   - return NULL;
2929   -}
2930   -
2931   -/*!
2932   - * Get a static template from its name. This is used from scripts. These templates must
2933   - * never be changed or deleted.
2934   - * \param pName Template name
2935   - * \pre pName has to be the unique, untranslated name!
2936   - */
2937   -DROID_TEMPLATE *getTemplateFromTranslatedNameNoPlayer(char const *pName)
2938   -{
2939   - const char *rName;
2940   - DROID_TEMPLATE *psCurr;
2941   -
2942   - for (psCurr = apsStaticTemplates; psCurr != NULL; psCurr = psCurr->psNext)
2943   - {
2944   - rName = psCurr->pName ? psCurr->pName : psCurr->aName;
2945   - if (strcmp(rName, pName) == 0)
2946   - {
2947   - return psCurr;
2948   - }
2949   - }
2950   -
2951   - return NULL;
2952   -}
2953   -
2954   -/*getTemplatefFromMultiPlayerID gets template for unique ID searching all lists */
2955   -DROID_TEMPLATE* getTemplateFromMultiPlayerID(UDWORD multiPlayerID)
2956   -{
2957   - UDWORD player;
2958   - DROID_TEMPLATE *pDroidDesign;
2959   -
2960   - for (player = 0; player < MAX_PLAYERS; player++)
2961   - {
2962   - for(pDroidDesign = apsDroidTemplates[player]; pDroidDesign != NULL; pDroidDesign = pDroidDesign->psNext)
2963   - {
2964   - if (pDroidDesign->multiPlayerID == multiPlayerID)
2965   - {
2966   - return pDroidDesign;
2967   - }
2968   - }
2969   - }
2970   - return NULL;
2971   -}
2972 2517
2973 2518 // finds a droid for the player and sets it to be the current selected droid
2974 2519 bool selectDroidByID(UDWORD id, UDWORD player)
@@ -3103,8 +2648,6 @@ void droidSetName(DROID *psDroid,const char *pName)
3103 2648 sstrcpy(psDroid->aName, pName);
3104 2649 }
3105 2650
3106   -
3107   -
3108 2651 // ////////////////////////////////////////////////////////////////////////////
3109 2652 // returns true when no droid on x,y square.
3110 2653 bool noDroid(UDWORD x, UDWORD y)
@@ -3416,11 +2959,6 @@ void setUpBuildModule(DROID *psDroid)
3416 2959 }
3417 2960 }
3418 2961
3419   -const char* getTemplateName(const DROID_TEMPLATE *psTemplate)
3420   -{
3421   - return psTemplate->aName;
3422   -}
3423   -
3424 2962 /* Just returns true if the droid's present body points aren't as high as the original*/
3425 2963 bool droidIsDamaged(DROID *psDroid)
3426 2964 {
@@ -4225,79 +3763,7 @@ bool checkValidWeaponForProp(DROID_TEMPLATE *psTemplate)
4225 3763 return true;
4226 3764 }
4227 3765
4228   -/*called when a Template is deleted in the Design screen*/
4229   -void deleteTemplateFromProduction(DROID_TEMPLATE *psTemplate, unsigned player, QUEUE_MODE mode)
4230   -{
4231   - STRUCTURE *psStruct;
4232   - STRUCTURE *psList;
4233   -
4234   - //see if any factory is currently using the template
4235   - for (unsigned i = 0; i < 2; ++i)
4236   - {
4237   - psList = NULL;
4238   - switch (i)
4239   - {
4240   - case 0:
4241   - psList = apsStructLists[player];
4242   - break;
4243   - case 1:
4244   - psList = mission.apsStructLists[player];
4245   - break;
4246   - }
4247   - for (psStruct = psList; psStruct != NULL; psStruct = psStruct->psNext)
4248   - {
4249   - if (StructIsFactory(psStruct))
4250   - {
4251   - FACTORY *psFactory = &psStruct->pFunctionality->factory;
4252 3766
4253   - if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size())
4254   - {
4255   - ProductionRun &productionRun = asProductionRun[psFactory->psAssemblyPoint->factoryType][psFactory->psAssemblyPoint->factoryInc];
4256   - for (unsigned inc = 0; inc < productionRun.size(); ++inc)
4257   - {
4258   - if (productionRun[inc].psTemplate->multiPlayerID == psTemplate->multiPlayerID && mode == ModeQueue)
4259   - {
4260   - //just need to erase this production run entry
4261   - productionRun.erase(productionRun.begin() + inc);
4262   - --inc;
4263   - }
4264   - }
4265   - }
4266   -
4267   - if (psFactory->psSubject == NULL)
4268   - {
4269   - continue;
4270   - }
4271   -
4272   - // check not being built in the factory for the template player
4273   - if (psTemplate->multiPlayerID == psFactory->psSubject->multiPlayerID && mode == ModeImmediate)
4274   - {
4275   - syncDebugStructure(psStruct, '<');
4276   - syncDebug("Clearing production");
4277   -
4278   - // Clear the factory's subject.
4279   - psFactory->psSubject = NULL;
4280   -
4281   - if (player == productionPlayer)
4282   - {
4283   - //check to see if anything left to produce
4284   - DROID_TEMPLATE *psNextTemplate = factoryProdUpdate(psStruct, NULL);
4285   - //power is returned by factoryProdAdjust()
4286   - if (psNextTemplate)
4287   - {
4288   - structSetManufacture(psStruct, psNextTemplate, ModeQueue); // ModeQueue because production lists aren't synchronised.
4289   - }
4290   - }
4291   -
4292   - //tell the interface
4293   - intManufactureFinished(psStruct);
4294   -
4295   - syncDebugStructure(psStruct, '>');
4296   - }
4297   - }
4298   - }
4299   - }
4300   -}
4301 3767
4302 3768
4303 3769 // Select a droid and do any necessary housekeeping.
@@ -4345,7 +3811,6 @@ bool droidAudioTrackStopped( void *psObj )
4345 3811 return true;
4346 3812 }
4347 3813
4348   -
4349 3814 /*returns true if droid type is one of the Cyborg types*/
4350 3815 bool cyborgDroid(const DROID* psDroid)
4351 3816 {
30 src/droid.h
@@ -44,10 +44,6 @@
44 44 // Changing this breaks campaign saves!
45 45 #define MAX_RECYCLED_DROIDS 450
46 46
47   -//storage
48   -extern DROID_TEMPLATE *apsDroidTemplates[MAX_PLAYERS];
49   -extern DROID_TEMPLATE *apsStaticTemplates; // for AIs and scripts
50   -
51 47 //used to stop structures being built too near the edge and droids being placed down
52 48 #define TOO_NEAR_EDGE 3
53 49
@@ -83,12 +79,8 @@ extern bool droidInit(void);
83 79
84 80 extern void removeDroidBase(DROID *psDel);
85 81
86   -extern bool loadDroidTemplates(const char *pDroidData, UDWORD bufferSize);
87 82 extern bool loadDroidWeapons(const char *pWeaponData, UDWORD bufferSize);
88 83
89   -/*initialise the template build and power points */
90   -extern void initTemplatePoints(void);
91   -
92 84 struct INITIAL_DROID_ORDERS
93 85 {
94 86 uint32_t secondaryOrder;
@@ -132,9 +124,6 @@ extern UDWORD calcTemplateBuild(DROID_TEMPLATE *psTemplate);
132 124 /* Calculate the power points required to build/maintain the droid */
133 125 extern UDWORD calcTemplatePower(DROID_TEMPLATE *psTemplate);
134 126
135   -// return whether a template is for an IDF droid
136   -bool templateIsIDF(DROID_TEMPLATE *psTemplate);
137   -
138 127 // return whether a droid is IDF
139 128 bool idfDroid(DROID *psDroid);
140 129
@@ -205,9 +194,6 @@ extern DROID_TYPE droidType(DROID *psDroid);
205 194 /* Return the type of a droid from it's template */
206 195 extern DROID_TYPE droidTemplateType(DROID_TEMPLATE *psTemplate);
207 196
208   -//fills the list with Templates that can be manufactured in the Factory - based on size
209   -void fillTemplateList(std::vector<DROID_TEMPLATE *> &pList, STRUCTURE *psFactory);
210   -
211 197 extern void assignDroidsToGroup(UDWORD playerNumber, UDWORD groupNumber);
212 198
213 199 extern bool activateGroup(UDWORD playerNumber, UDWORD groupNumber);
@@ -220,16 +206,6 @@ bool calcDroidMuzzleLocation(DROID *psDroid, Vector3i *muzzle, int weapon_slot);
220 206 /* calculate muzzle base location in 3d world added int weapon_slot to fix the always slot 0 hack*/
221 207 bool calcDroidMuzzleBaseLocation(DROID *psDroid, Vector3i *muzzle, int weapon_slot);
222 208
223   -/* gets a template from its aName (when pName is unknown) */
224   -extern DROID_TEMPLATE *GetHumanDroidTemplate(const char *aName);
225   -extern DROID_TEMPLATE *GetAIDroidTemplate(const char *aName);
226   -/* gets a template from its name - relies on the name being unique */
227   -extern DROID_TEMPLATE * getTemplateFromUniqueName(const char *pName, unsigned int player);
228   -/* gets a template from its name - relies on the name being unique */
229   -extern DROID_TEMPLATE* getTemplateFromTranslatedNameNoPlayer(char const *pName);
230   -/*getTemplateFromMultiPlayerID gets template for unique ID searching all lists */
231   -extern DROID_TEMPLATE* getTemplateFromMultiPlayerID(UDWORD multiPlayerID);
232   -
233 209 // finds a droid for the player and sets it to be the current selected droid
234 210 extern bool selectDroidByID(UDWORD id, UDWORD player);
235 211
@@ -275,10 +251,6 @@ extern bool buildModule(STRUCTURE *psStruct);
275 251 - if so, helping to build the current one*/
276 252 extern void setUpBuildModule(DROID *psDroid);
277 253
278   -/*return the name to display for the interface - we don't know if this is
279   -a string ID or something the user types in*/
280   -extern const char* getTemplateName(const DROID_TEMPLATE *psTemplate);
281   -
282 254 /* Just returns true if the droid's present body points aren't as high as the original*/
283 255 extern bool droidIsDamaged(DROID *psDroid);
284 256
@@ -288,10 +260,8 @@ extern void setSelectedGroup(UDWORD groupNumber);
288 260 extern UDWORD getSelectedCommander( void );
289 261 extern void setSelectedCommander(UDWORD commander);
290 262
291   -
292 263 extern char const *getDroidResourceName(char const *pName);
293 264
294   -
295 265 /*checks to see if an electronic warfare weapon is attached to the droid*/
296 266 extern bool electronicDroid(DROID *psDroid);
297 267
1  src/droiddef.h
@@ -125,6 +125,7 @@ struct DROID_TEMPLATE : public BASE_STATS
125 125 UDWORD multiPlayerID; ///< multiplayer unique descriptor(cant use id's for templates). Used for save games as well now - AB 29/10/98
126 126 DROID_TEMPLATE* psNext; ///< Pointer to next template
127 127 bool prefab; ///< Not player designed, not saved, never delete or change
  128 + bool stored; ///< Stored template
128 129 };
129 130
130 131 struct PACKAGED_CHECK;
1  src/game.cpp
@@ -85,6 +85,7 @@
85 85 #include "scriptfuncs.h"
86 86 #include "challenge.h"
87 87 #include "combat.h"
  88 +#include "template.h"
88 89
89 90 #define MAX_SAVE_NAME_SIZE_V19 40
90 91 #define MAX_SAVE_NAME_SIZE 60
1  src/hci.cpp
@@ -75,6 +75,7 @@
75 75 #include "transporter.h"
76 76 #include "warcam.h"
77 77 #include "main.h"
  78 +#include "template.h"
78 79 #include "wrappers.h"
79 80 #include "keybind.h"
80 81
6 src/init.cpp
@@ -95,6 +95,7 @@
95 95 #include "terrain.h"
96 96 #include "ingameop.h"
97 97 #include "qtscript.h"
  98 +#include "template.h"
98 99
99 100 static void initMiscVars(void);
100 101
@@ -1097,6 +1098,9 @@ bool stageThreeInitialise(void)
1097 1098 preProcessVisibility();
1098 1099 closeLoadingScreen(); // reset the loading screen.
1099 1100
  1101 + // Load any stored templates; these need to be available ASAP
  1102 + initTemplates();
  1103 +
1100 1104 if (!fpathInitialise())
1101 1105 {
1102 1106 return false;
@@ -1183,6 +1187,8 @@ bool stageThreeShutDown(void)
1183 1187 challengeActive = false;
1184 1188 isInGamePopupUp = false;
1185 1189
  1190 + shutdownTemplates();
  1191 +
1186 1192 // make sure any button tips are gone.
1187 1193 widgReset();
1188 1194
1  src/keybind.cpp
@@ -91,6 +91,7 @@
91 91 #include "scriptfuncs.h"
92 92 #include "clparse.h"
93 93 #include "research.h"
  94 +#include "template.h"
94 95
95 96 /*
96 97 KeyBind.c
1  src/map.cpp
@@ -1923,6 +1923,7 @@ void mapInit()
1923 1923 }
1924 1924
1925 1925 // Start thread
  1926 + ASSERT(dangerSemaphore == NULL && dangerThread == NULL, "Map data not cleaned up before starting!");
1926 1927 if (game.type == SKIRMISH)
1927 1928 {
1928 1929 lastDangerPlayer = 0;
7 src/multimenu.cpp
@@ -145,7 +145,6 @@ UDWORD current_numplayers = 4;
145 145 #define M_REQUEST_15P (MULTIMENU+84)
146 146 #define M_REQUEST_16P (MULTIMENU+85)
147 147 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};
148   -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")};
149 148
150 149 #define M_REQUEST_BUT (MULTIMENU+100) // allow loads of buttons.
151 150 #define M_REQUEST_BUTM (MULTIMENU+1100)
@@ -646,13 +645,15 @@ void addMultiRequest(const char* searchDir, const char* fileExtension, UDWORD mo
646 645 sButInit.pDisplay = displayNumPlayersBut;
647 646 widgAddButton(psRScreen, &sButInit);
648 647
649   - STATIC_ASSERT(MAX_PLAYERS_IN_GUI <= ARRAY_SIZE(M_REQUEST_NP) + 1 && MAX_PLAYERS <= ARRAY_SIZE(M_REQUEST_NP_TIPS) + 1);
  648 + STATIC_ASSERT(MAX_PLAYERS_IN_GUI <= ARRAY_SIZE(M_REQUEST_NP) + 1);
650 649 for (unsigned numPlayers = 2; numPlayers <= MAX_PLAYERS_IN_GUI; ++numPlayers)
651 650 {
  651 + static char ttip[MAX_PLAYERS_IN_GUI][20];
652 652 sButInit.id = M_REQUEST_NP[numPlayers - 2];
653 653 sButInit.y += 22;
654 654 sButInit.UserData = numPlayers;
655   - sButInit.pTip = gettext(M_REQUEST_NP_TIPS[numPlayers - 2]);
  655 + ssprintf(ttip[numPlayers], ngettext("%d player", "%d players", numPlayers), numPlayers);
  656 + sButInit.pTip = (const char *)&ttip[numPlayers];
656 657 widgAddButton(psRScreen, &sButInit);
657 658 }
658 659 }
2  src/multiopt.cpp
@@ -53,7 +53,7 @@
53 53 #include "multiint.h"
54 54 #include "multirecv.h"
55 55 #include "scriptfuncs.h"
56   -
  56 +#include "template.h"
57 57 #include "lib/framework/wzapp.h"
58 58
59 59
11 src/multiplay.cpp
@@ -60,7 +60,7 @@
60 60 #include "scripttabs.h" //because of CALL_AI_MSG
61 61 #include "scriptcb.h" //for console callback
62 62 #include "scriptfuncs.h"
63   -
  63 +#include "template.h"
64 64 #include "lib/netplay/netplay.h" // the netplay library.
65 65 #include "multiplay.h" // warzone net stuff.
66 66 #include "multijoin.h" // player management stuff.
@@ -1349,6 +1349,7 @@ static void NETtemplate(DROID_TEMPLATE *pTempl)
1349 1349 NETuint32_t(&pTempl->powerPoints);
1350 1350 NETuint32_t(&pTempl->storeCount);
1351 1351 NETuint32_t(&pTempl->numWeaps);
  1352 + NETbool(&pTempl->stored); // other players don't need to know, but we need to keep the knowledge in the loop somehow...
1352 1353
1353 1354 for (int i = 0; i < DROID_MAXWEAPS; ++i)
1354 1355 {
@@ -1394,12 +1395,16 @@ bool recvTemplate(NETQUEUE queue)
1394 1395 {
1395 1396 t.psNext = psTempl->psNext;
1396 1397 *psTempl = t;
1397   - debug(LOG_SYNC, "Updating MP template %d", (int)t.multiPlayerID);
  1398 + debug(LOG_SYNC, "Updating MP template %d (stored=%s)", (int)t.multiPlayerID, t.stored ? "yes" : "no");
1398 1399 }
1399 1400 else
1400 1401 {
1401 1402 addTemplateBack(player, &t); // Add to back of list, to avoid game state templates being in wrong order, which matters when saving games.
1402   - debug(LOG_SYNC, "Creating MP template %d", (int)t.multiPlayerID);
  1403 + debug(LOG_SYNC, "Creating MP template %d (stored=%s)", (int)t.multiPlayerID, t.stored ? "yes" : "no");
  1404 + }
  1405 + if (!t.prefab && player == selectedPlayer)
  1406 + {
  1407 + storeTemplates();
1403 1408 }
1404 1409
1405 1410 return true;
19 src/projectile.cpp
@@ -1570,14 +1570,13 @@ UDWORD calcDamage(UDWORD baseDamage, WEAPON_EFFECT weaponEffect, BASE_OBJECT *ps
1570 1570
1571 1571 if (psTarget->type == OBJ_STRUCTURE)
1572 1572 {
1573   - damage = baseDamage * asStructStrengthModifier[weaponEffect][((
1574   - STRUCTURE *)psTarget)->pStructureType->strength] / 100;
  1573 + damage = baseDamage * asStructStrengthModifier[weaponEffect][((STRUCTURE *)psTarget)->pStructureType->strength] / 100;
1575 1574 }
1576 1575 else if (psTarget->type == OBJ_DROID)
1577 1576 {
1578   - damage = baseDamage * asWeaponModifier[weaponEffect][(
1579   - asPropulsionStats + ((DROID *)psTarget)->asBits[COMP_PROPULSION].
1580   - nStat)->propulsionType] / 100;
  1577 + const int propulsion = (asPropulsionStats + ((DROID *)psTarget)->asBits[COMP_PROPULSION].nStat)->propulsionType;
  1578 + const int body = (asBodyStats + ((DROID *)psTarget)->asBits[COMP_BODY].nStat)->size;
  1579 + damage = baseDamage * (asWeaponModifier[weaponEffect][propulsion] + asWeaponModifierBody[weaponEffect][body]) / 100;
1581 1580 }
1582 1581 // Default value
1583 1582 else
@@ -1585,11 +1584,11 @@ UDWORD calcDamage(UDWORD baseDamage, WEAPON_EFFECT weaponEffect, BASE_OBJECT *ps
1585 1584 damage = baseDamage;
1586 1585 }
1587 1586
1588   - // A little fail safe!
1589   - if (damage == 0 && baseDamage != 0)
1590   - {
1591   - damage = 1;
1592   - }
  1587 + // A little fail safe!
  1588 + if (damage == 0 && baseDamage != 0)
  1589 + {
  1590 + damage = 1;
  1591 + }
1593 1592
1594 1593 return damage;
1595 1594 }
1  src/qtscriptfuncs.cpp
@@ -44,6 +44,7 @@
44 44 #include "challenge.h"
45 45 #include "research.h"
46 46 #include "multilimit.h"
  47 +#include "template.h"
47 48
48 49 // hack, this is used from scriptfuncs.cpp -- and we don't want to include any stinkin' wzscript headers here!
49 50 // TODO, move this stuff into a script common subsystem
33 src/research.cpp
@@ -44,6 +44,7 @@
44 44 #include "frend.h" // frontend ids.
45 45 #include "intimage.h"
46 46 #include "multiplay.h"
  47 +#include "template.h"
47 48
48 49 //used to calc the research power
49 50 #define RESEARCH_FACTOR 32
@@ -99,6 +100,9 @@ bool researchInitVars(void)
99 100 for (int i = 0; i < MAX_PLAYERS; i++)
100 101 {
101 102 bSelfRepair[i] = false;
  103 + aDefaultSensor[i] = 0;
  104 + aDefaultECM[i] = 0;
  105 + aDefaultRepair[i] = 0;
102 106 }
103 107
104 108 return true;
@@ -302,7 +306,7 @@ bool loadResearch(const char *pResearchData, UDWORD bufferSize)
302 306 //Load the pre-requisites for a research list
303 307 bool loadResearchPR(const char *pPRData, UDWORD bufferSize)
304 308 {
305   - const unsigned int NumToAlloc = numCR(pPRData, bufferSize);
  309 + unsigned NumToAlloc = numCR(pPRData, bufferSize);
306 310 char ResearchName[MAX_STR_LENGTH], PRName[MAX_STR_LENGTH];
307 311
308 312 for (int i = 0; i < NumToAlloc; i++)
@@ -344,11 +348,18 @@ bool loadResearchPR(const char *pPRData, UDWORD bufferSize)
344 348 //Load the artefacts for a research list
345 349 bool loadResearchArtefacts(const char *pArteData, UDWORD bufferSize, UDWORD listNumber)
346 350 {
347   - const unsigned int NumToAlloc = numCR(pArteData, bufferSize);
  351 + unsigned NumToAlloc = numCR(pArteData, bufferSize);
348 352 char ResearchName[MAX_STR_LENGTH], ArteName[MAX_STR_LENGTH], TypeName[MAX_STR_LENGTH];
349 353 COMPONENT_STATS *pArtefact;
350 354 UDWORD newType;
351 355
  356 + // Skip descriptive header
  357 + if (strncmp(pArteData, "Research ", 9) == 0)
  358 + {
  359 + pArteData = strchr(pArteData, '\n') + 1;
  360 + NumToAlloc--;
  361 + }
  362 +
352 363 for (int i = 0; i < NumToAlloc; i++)
353 364 {
354 365 //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
436 447 //Load the Structures for a research list
437 448 bool loadResearchStructures(const char *pStructData, UDWORD bufferSize,UDWORD listNumber)
438 449 {
439   - const unsigned int NumToAlloc = numCR(pStructData, bufferSize);
  450 + unsigned NumToAlloc = numCR(pStructData, bufferSize);
440 451 unsigned int i = 0;
441 452 char ResearchName[MAX_STR_LENGTH], StructureName[MAX_STR_LENGTH];
442 453 UWORD incR, incS;
443 454 STRUCTURE_STATS *pStructure = asStructureStats;
444 455 bool recFound;
445 456
  457 + // Skip descriptive header
  458 + if (strncmp(pStructData, "Research ", 9) == 0)
  459 + {
  460 + pStructData = strchr(pStructData, '\n') + 1;
  461 + NumToAlloc--;
  462 + }
  463 +
446 464 for (i = 0; i < NumToAlloc; i++)
447 465 {
448 466 recFound = false;
@@ -512,13 +530,20 @@ bool loadResearchStructures(const char *pStructData, UDWORD bufferSize,UDWORD li
512 530 //Load the pre-requisites for a research list
513 531 bool loadResearchFunctions(const char *pFunctionData, UDWORD bufferSize)
514 532 {
515   - const unsigned int NumToAlloc = numCR(pFunctionData, bufferSize);
  533 + unsigned NumToAlloc = numCR(pFunctionData, bufferSize);
516 534 unsigned int i = 0;
517 535 char ResearchName[MAX_STR_LENGTH], FunctionName[MAX_STR_LENGTH];
518 536 UDWORD incR, incF;
519 537 FUNCTION **pFunction = asFunctions;
520 538 bool recFound;
521 539
  540 + // Skip descriptive header
  541 + if (strncmp(pFunctionData, "Research ", 9) == 0)
  542 + {
  543 + pFunctionData = strchr(pFunctionData, '\n') + 1;
  544 + NumToAlloc--;
  545 + }
  546 +
522 547 for (i=0; i < NumToAlloc; i++)
523 548 {
524 549 recFound = false;
1  src/scriptfuncs.cpp
@@ -96,6 +96,7 @@
96 96 #include "visibility.h"
97 97 #include "design.h"
98 98 #include "random.h"
  99 +#include "template.h"
99 100
100 101 static INTERP_VAL scrFunctionResult; //function return value to be pushed to stack
101 102
2  src/scriptobj.cpp
@@ -777,7 +777,7 @@ bool scrValDefSave(INTERP_VAL *psVal, WzConfig &ini)
777 777 break;
778 778 case ST_RESEARCH:
779 779 psResearch = (RESEARCH *)psVal->v.oval;
780   - if (psResearch && psResearch->pName[0] != '\0')
  780 + if (psResearch && psResearch->pName && psResearch->pName[0] != '\0')
781 781 {
782 782 ini.setValue("data", QString(psResearch->pName));
783 783 ASSERT(psResearch == getResearch(psResearch->pName), "Research %s not found!", psResearch->pName);
1  src/scriptvals_parser.ypp
@@ -49,6 +49,7 @@
49 49 #include "src/levels.h"
50 50 #include "src/research.h"
51 51 #include "src/text.h"
  52 +#include "src/template.h"
52 53
53 54 // The current script code
54 55 static SCRIPT_CODE *psCurrScript;
37 src/stats.cpp
@@ -55,6 +55,7 @@ static SPECIAL_ABILITY *asSpecialAbility;
55 55
56 56 //used to hold the modifiers cross refd by weapon effect and propulsion type
57 57 WEAPON_MODIFIER asWeaponModifier[WE_NUMEFFECTS][PROPULSION_TYPE_NUM];
  58 +WEAPON_MODIFIER asWeaponModifierBody[WE_NUMEFFECTS][SIZE_NUM];
58 59
59 60 //used to hold the current upgrade level per player per weapon subclass
60 61 WEAPON_UPGRADE asWeaponUpgrade[MAX_PLAYERS][WSC_NUM_WEAPON_SUBCLASSES];
@@ -622,7 +623,6 @@ bool loadWeaponStats(const char *pWeaponData, UDWORD bufferSize)
622 623 facePlayer[0] = '\0';
623 624 faceInFlight[0] = '\0';
624 625
625   -
626 626 //read the data into the storage - the data is delimeted using comma's
627 627 sscanf(pWeaponData,"%255[^,'\r\n],%255[^,'\r\n],%d,%d,%d,%d,%d,%d,%255[^,'\r\n],\
628 628 %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)
2209 2209 for (j=0; j < PROPULSION_TYPE_NUM; j++)
2210 2210 {
2211 2211 asWeaponModifier[i][j] = 100;
  2212 + asWeaponModifierBody[i][j] = 100;
2212 2213 }
2213 2214 }
2214 2215
2215 2216 for (i=0; i < NumRecords; i++)
2216 2217 {
2217 2218 //read the data into the storage - the data is delimeted using comma's
2218   - sscanf(pWeapModData,"%255[^,'\r\n],%255[^,'\r\n],%d",
2219   - weaponEffectName, propulsionName, &modifier);
  2219 + sscanf(pWeapModData,"%255[^,'\r\n],%255[^,'\r\n],%d", weaponEffectName, propulsionName, &modifier);
2220 2220
2221 2221 //get the weapon effect inc
2222 2222 if (!getWeaponEffect(weaponEffectName, &effectInc))
2223 2223 {
2224   - debug( LOG_FATAL, "loadWeaponModifiers: Invalid Weapon Effect - %s", weaponEffectName );
2225   - abort();
2226   - return false;