2011-12-17 15:23:51 -08:00
/*
This file is part of Warzone 2100.
Copyright ( C ) 1999 - 2004 Eidos Interactive
2013-01-16 12:34:57 -08:00
Copyright ( C ) 2005 - 2013 Warzone 2100 Project
2011-12-17 15:23:51 -08:00
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"
2011-12-18 03:20:48 -08:00
# include "lib/framework/wzconfig.h"
2011-12-17 15:23:51 -08:00
# 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"
2012-03-04 13:23:29 -08:00
# include "main.h"
2011-12-17 15:23:51 -08:00
// Template storage
DROID_TEMPLATE * apsDroidTemplates [ MAX_PLAYERS ] ;
2013-05-21 11:48:17 -07:00
2012-01-18 13:24:27 -08:00
bool allowDesign = true ;
2013-05-21 11:48:17 -07:00
bool includeRedundantDesigns = false ;
2012-01-18 13:24:27 -08:00
2012-06-29 00:44:21 -07:00
static bool researchedItem ( DROID_TEMPLATE * psCurr , int player , COMPONENT_TYPE partIndex , int part , bool allowZero , bool allowRedundant )
{
if ( allowZero & & part < = 0 )
{
return true ;
}
int availability = apCompLists [ player ] [ partIndex ] [ part ] ;
return availability = = AVAILABLE | | ( allowRedundant & & availability = = REDUNDANT ) ;
}
static bool researchedPart ( DROID_TEMPLATE * psCurr , int player , COMPONENT_TYPE partIndex , bool allowZero , bool allowRedundant )
{
return researchedItem ( psCurr , player , partIndex , psCurr - > asParts [ partIndex ] , allowZero , allowRedundant ) ;
}
static bool researchedWeap ( DROID_TEMPLATE * psCurr , int player , int weapIndex , bool allowRedundant )
{
2013-05-19 12:06:24 -07:00
int availability = apCompLists [ player ] [ COMP_WEAPON ] [ psCurr - > asWeaps [ weapIndex ] ] ;
return availability = = AVAILABLE | | ( allowRedundant & & availability = = REDUNDANT ) ;
2012-06-29 00:44:21 -07:00
}
2012-08-04 09:12:44 -07:00
bool researchedTemplate ( DROID_TEMPLATE * psCurr , int player , bool allowRedundant , bool verbose )
2011-12-18 03:20:48 -08:00
{
2012-11-24 08:36:45 -08:00
ASSERT_OR_RETURN ( false , psCurr , " Given a null template " ) ;
2012-08-04 09:12:44 -07:00
bool resBody = researchedPart ( psCurr , player , COMP_BODY , false , allowRedundant ) ;
bool resBrain = researchedPart ( psCurr , player , COMP_BRAIN , true , allowRedundant ) ;
bool resProp = researchedPart ( psCurr , player , COMP_PROPULSION , false , allowRedundant ) ;
bool resSensor = researchedPart ( psCurr , player , COMP_SENSOR , true , allowRedundant ) ;
bool resEcm = researchedPart ( psCurr , player , COMP_ECM , true , allowRedundant ) ;
bool resRepair = researchedPart ( psCurr , player , COMP_REPAIRUNIT , true , allowRedundant ) ;
bool resConstruct = researchedPart ( psCurr , player , COMP_CONSTRUCT , true , allowRedundant ) ;
bool researchedEverything = resBody & & resBrain & & resProp & & resSensor & & resEcm & & resRepair & & resConstruct ;
if ( verbose & & ! researchedEverything )
{
2013-05-12 14:50:57 -07:00
debug ( LOG_ERROR , " %s : not researched : body=%d brai=%d prop=%d sensor=%d ecm=%d rep=%d con=%d " , getName ( psCurr ) ,
2012-08-04 09:12:44 -07:00
( int ) resBody , ( int ) resBrain , ( int ) resProp , ( int ) resSensor , ( int ) resEcm , ( int ) resRepair , ( int ) resConstruct ) ;
}
2013-05-19 12:06:24 -07:00
for ( unsigned weapIndex = 0 ; weapIndex < psCurr - > numWeaps & & researchedEverything ; + + weapIndex )
2011-12-18 03:20:48 -08:00
{
2012-06-29 00:44:21 -07:00
researchedEverything = researchedWeap ( psCurr , player , weapIndex , allowRedundant ) ;
2012-08-04 09:12:44 -07:00
if ( ! researchedEverything & & verbose )
{
2013-05-12 14:50:57 -07:00
debug ( LOG_ERROR , " %s : not researched weapon %u " , getName ( psCurr ) , weapIndex ) ;
2012-08-04 09:12:44 -07:00
}
2011-12-18 03:20:48 -08:00
}
2012-06-29 00:44:21 -07:00
return researchedEverything ;
2011-12-18 03:20:48 -08:00
}
bool initTemplates ( )
{
2012-10-26 15:19:18 -07:00
WzConfig ini ( " userdata/ " + QString ( rulesettag ) + " /templates.ini " ) ;
2011-12-18 03:20:48 -08:00
if ( ini . status ( ) ! = QSettings : : NoError )
{
2012-10-26 15:19:18 -07:00
debug ( LOG_FATAL , " Could not open templates.ini " ) ;
2011-12-18 03:20:48 -08:00
return false ;
}
QStringList list = ini . childGroups ( ) ;
for ( int i = 0 ; i < list . size ( ) ; + + i )
{
ini . beginGroup ( list [ i ] ) ;
DROID_TEMPLATE design ;
design . droidType = ( DROID_TYPE ) ini . value ( " droidType " ) . toInt ( ) ;
design . multiPlayerID = generateNewObjectId ( ) ;
2013-05-12 14:50:57 -07:00
design . asParts [ COMP_BODY ] = getCompFromName ( COMP_BODY , ini . value ( " body " , QString ( " ZNULLBODY " ) ) . toString ( ) ) ;
design . asParts [ COMP_BRAIN ] = getCompFromName ( COMP_BRAIN , ini . value ( " brain " , QString ( " ZNULLBRAIN " ) ) . toString ( ) ) ;
design . asParts [ COMP_PROPULSION ] = getCompFromName ( COMP_PROPULSION , ini . value ( " propulsion " , QString ( " ZNULLPROP " ) ) . toString ( ) ) ;
design . asParts [ COMP_REPAIRUNIT ] = getCompFromName ( COMP_REPAIRUNIT , ini . value ( " repair " , QString ( " ZNULLREPAIR " ) ) . toString ( ) ) ;
design . asParts [ COMP_ECM ] = getCompFromName ( COMP_ECM , ini . value ( " ecm " , QString ( " ZNULLECM " ) ) . toString ( ) ) ;
design . asParts [ COMP_SENSOR ] = getCompFromName ( COMP_SENSOR , ini . value ( " sensor " , QString ( " ZNULLSENSOR " ) ) . toString ( ) ) ;
design . asParts [ COMP_CONSTRUCT ] = getCompFromName ( COMP_CONSTRUCT , ini . value ( " construct " , QString ( " ZNULLCONSTRUCT " ) ) . toString ( ) ) ;
design . asWeaps [ 0 ] = getCompFromName ( COMP_WEAPON , ini . value ( " weapon/1 " , QString ( " ZNULLWEAPON " ) ) . toString ( ) ) ;
design . asWeaps [ 1 ] = getCompFromName ( COMP_WEAPON , ini . value ( " weapon/2 " , QString ( " ZNULLWEAPON " ) ) . toString ( ) ) ;
design . asWeaps [ 2 ] = getCompFromName ( COMP_WEAPON , ini . value ( " weapon/3 " , QString ( " ZNULLWEAPON " ) ) . toString ( ) ) ;
2011-12-18 03:20:48 -08:00
design . numWeaps = ini . value ( " weapons " ) . toInt ( ) ;
design . prefab = false ; // not AI template
design . stored = true ;
2013-03-03 13:57:16 -08:00
if ( ! ( asBodyStats + design . asParts [ COMP_BODY ] ) - > designable
| | ! ( asPropulsionStats + design . asParts [ COMP_PROPULSION ] ) - > designable
| | ( design . asParts [ COMP_BRAIN ] > 0 & & ! ( asBrainStats + design . asParts [ COMP_BRAIN ] ) - > designable )
| | ( design . asParts [ COMP_REPAIRUNIT ] > 0 & & ! ( asRepairStats + design . asParts [ COMP_REPAIRUNIT ] ) - > designable )
| | ( design . asParts [ COMP_ECM ] > 0 & & ! ( asECMStats + design . asParts [ COMP_ECM ] ) - > designable )
| | ( design . asParts [ COMP_SENSOR ] > 0 & & ! ( asSensorStats + design . asParts [ COMP_SENSOR ] ) - > designable )
| | ( design . asParts [ COMP_CONSTRUCT ] > 0 & & ! ( asConstructStats + design . asParts [ COMP_CONSTRUCT ] ) - > designable )
| | ( design . numWeaps > 0 & & ! ( asWeaponStats + design . asWeaps [ 0 ] ) - > designable )
| | ( design . numWeaps > 1 & & ! ( asWeaponStats + design . asWeaps [ 1 ] ) - > designable )
| | ( design . numWeaps > 2 & & ! ( asWeaponStats + design . asWeaps [ 2 ] ) - > designable ) )
{
debug ( LOG_ERROR , " Template %d / %s from stored templates cannot be designed " , i , list [ i ] . toUtf8 ( ) . constData ( ) ) ;
continue ;
}
2013-01-21 13:17:58 -08:00
bool valid = intValidTemplate ( & design , ini . value ( " name " ) . toString ( ) . toUtf8 ( ) . constData ( ) , false , selectedPlayer ) ;
2011-12-18 12:56:06 -08:00
if ( ! valid )
{
debug ( LOG_ERROR , " Invalid template %d / %s from stored templates " , i , list [ i ] . toUtf8 ( ) . constData ( ) ) ;
continue ;
}
2011-12-19 04:01:45 -08:00
DROID_TEMPLATE * psDestTemplate = apsDroidTemplates [ selectedPlayer ] ;
while ( psDestTemplate ! = NULL )
{
// Check if template is identical to a loaded template
if ( psDestTemplate - > droidType = = design . droidType
2013-05-12 14:50:57 -07:00
& & psDestTemplate - > name . compare ( design . name ) = = 0
2011-12-19 04:01:45 -08:00
& & psDestTemplate - > numWeaps = = design . numWeaps
& & psDestTemplate - > asWeaps [ 0 ] = = design . asWeaps [ 0 ]
& & psDestTemplate - > asWeaps [ 1 ] = = design . asWeaps [ 1 ]
& & psDestTemplate - > asWeaps [ 2 ] = = design . asWeaps [ 2 ]
& & psDestTemplate - > asParts [ COMP_BODY ] = = design . asParts [ COMP_BODY ]
& & psDestTemplate - > asParts [ COMP_PROPULSION ] = = design . asParts [ COMP_PROPULSION ]
& & psDestTemplate - > asParts [ COMP_REPAIRUNIT ] = = design . asParts [ COMP_REPAIRUNIT ]
& & psDestTemplate - > asParts [ COMP_ECM ] = = design . asParts [ COMP_ECM ]
& & psDestTemplate - > asParts [ COMP_SENSOR ] = = design . asParts [ COMP_SENSOR ]
& & psDestTemplate - > asParts [ COMP_CONSTRUCT ] = = design . asParts [ COMP_CONSTRUCT ]
& & psDestTemplate - > asParts [ COMP_BRAIN ] = = design . asParts [ COMP_BRAIN ] )
{
break ;
}
psDestTemplate = psDestTemplate - > psNext ;
}
if ( psDestTemplate )
{
psDestTemplate - > stored = true ; // assimilate it
ini . endGroup ( ) ;
continue ; // next!
}
2012-01-18 13:24:27 -08:00
design . enabled = allowDesign ;
2011-12-18 03:20:48 -08:00
addTemplateToList ( & design , & apsDroidTemplates [ selectedPlayer ] ) ;
2011-12-25 08:29:29 -08:00
sendTemplate ( selectedPlayer , & design ) ;
2011-12-18 03:20:48 -08:00
localTemplates . push_back ( design ) ;
ini . endGroup ( ) ;
}
return true ;
}
2011-12-18 11:12:57 -08:00
bool storeTemplates ( )
2011-12-18 03:20:48 -08:00
{
// Write stored templates (back) to file
2012-10-26 15:19:18 -07:00
WzConfig ini ( " userdata/ " + QString ( rulesettag ) + " /templates.ini " ) ;
2011-12-18 11:12:57 -08:00
if ( ini . status ( ) ! = QSettings : : NoError | | ! ini . isWritable ( ) )
2011-12-18 03:20:48 -08:00
{
2012-10-26 15:19:18 -07:00
debug ( LOG_FATAL , " Could not open templates.ini " ) ;
2011-12-18 03:20:48 -08:00
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 ) ) ;
2013-05-12 14:50:57 -07:00
ini . setValue ( " name " , psCurr - > name ) ;
2011-12-18 03:20:48 -08:00
ini . setValue ( " droidType " , psCurr - > droidType ) ;
2013-05-12 14:50:57 -07:00
ini . setValue ( " body " , ( asBodyStats + psCurr - > asParts [ COMP_BODY ] ) - > id ) ;
ini . setValue ( " propulsion " , ( asPropulsionStats + psCurr - > asParts [ COMP_PROPULSION ] ) - > id ) ;
2011-12-18 12:56:06 -08:00
if ( psCurr - > asParts [ COMP_BRAIN ] ! = 0 )
{
2013-05-12 14:50:57 -07:00
ini . setValue ( " brain " , ( asBrainStats + psCurr - > asParts [ COMP_BRAIN ] ) - > id ) ;
2011-12-18 12:56:06 -08:00
}
if ( ( asRepairStats + psCurr - > asParts [ COMP_REPAIRUNIT ] ) - > location = = LOC_TURRET ) // avoid auto-repair...
{
2013-05-12 14:50:57 -07:00
ini . setValue ( " repair " , ( asRepairStats + psCurr - > asParts [ COMP_REPAIRUNIT ] ) - > id ) ;
2011-12-18 12:56:06 -08:00
}
if ( ( asECMStats + psCurr - > asParts [ COMP_ECM ] ) - > location = = LOC_TURRET )
{
2013-05-12 14:50:57 -07:00
ini . setValue ( " ecm " , ( asECMStats + psCurr - > asParts [ COMP_ECM ] ) - > id ) ;
2011-12-18 12:56:06 -08:00
}
if ( ( asSensorStats + psCurr - > asParts [ COMP_SENSOR ] ) - > location = = LOC_TURRET )
{
2013-05-12 14:50:57 -07:00
ini . setValue ( " sensor " , ( asSensorStats + psCurr - > asParts [ COMP_SENSOR ] ) - > id ) ;
2011-12-18 12:56:06 -08:00
}
if ( psCurr - > asParts [ COMP_CONSTRUCT ] ! = 0 )
{
2013-05-12 14:50:57 -07:00
ini . setValue ( " construct " , ( asConstructStats + psCurr - > asParts [ COMP_CONSTRUCT ] ) - > id ) ;
2011-12-18 12:56:06 -08:00
}
2011-12-18 03:20:48 -08:00
ini . setValue ( " weapons " , psCurr - > numWeaps ) ;
for ( int j = 0 ; j < psCurr - > numWeaps ; j + + )
{
2013-05-12 14:50:57 -07:00
ini . setValue ( " weapon/ " + QString : : number ( j + 1 ) , ( asWeaponStats + psCurr - > asWeaps [ j ] ) - > id ) ;
2011-12-18 03:20:48 -08:00
}
ini . endGroup ( ) ;
}
return true ;
}
2011-12-18 11:12:57 -08:00
bool shutdownTemplates ( )
{
return storeTemplates ( ) ;
}
2011-12-17 15:23:51 -08:00
DROID_TEMPLATE : : DROID_TEMPLATE ( ) // This constructor replaces a memset in scrAssembleWeaponTemplate(), not needed elsewhere.
2013-05-09 14:17:05 -07:00
: BASE_STATS ( REF_TEMPLATE_START )
2011-12-17 15:23:51 -08:00
//, asParts
, numWeaps ( 0 )
//, asWeaps
, droidType ( DROID_WEAPON )
, multiPlayerID ( 0 )
, psNext ( NULL )
, prefab ( false )
2011-12-18 03:20:48 -08:00
, stored ( false )
2013-02-03 14:23:02 -08:00
, enabled ( false )
2011-12-17 15:23:51 -08:00
{
std : : fill_n ( asParts , DROID_MAXCOMP , 0 ) ;
std : : fill_n ( asWeaps , DROID_MAXWEAPS , 0 ) ;
}
/* load the Droid stats for the components from the Access database */
2013-05-09 14:17:05 -07:00
bool loadDroidTemplates ( const char * filename )
2011-12-17 15:23:51 -08:00
{
2013-05-09 14:17:05 -07:00
WzConfig ini ( filename , WzConfig : : ReadOnlyAndRequired ) ;
QStringList list = ini . childGroups ( ) ;
for ( int i = 0 ; i < list . size ( ) ; + + i )
2011-12-17 15:23:51 -08:00
{
2013-05-09 14:17:05 -07:00
ini . beginGroup ( list [ i ] ) ;
DROID_TEMPLATE design ;
QString droidType = ini . value ( " type " ) . toString ( ) ;
2013-05-12 14:50:57 -07:00
design . id = list [ i ] ;
design . name = ini . value ( " name " ) . toString ( ) ;
2013-05-09 14:17:05 -07:00
if ( droidType = = " PERSON " ) design . droidType = DROID_PERSON ;
else if ( droidType = = " CYBORG " ) design . droidType = DROID_CYBORG ;
else if ( droidType = = " CYBORG_SUPER " ) design . droidType = DROID_CYBORG_SUPER ;
else if ( droidType = = " CYBORG_CONSTRUCT " ) design . droidType = DROID_CYBORG_CONSTRUCT ;
else if ( droidType = = " CYBORG_REPAIR " ) design . droidType = DROID_CYBORG_REPAIR ;
else if ( droidType = = " TRANSPORTER " ) design . droidType = DROID_TRANSPORTER ;
else if ( droidType = = " SUPERTRANSPORTER " ) design . droidType = DROID_SUPERTRANSPORTER ;
else if ( droidType = = " DROID " ) design . droidType = DROID_DEFAULT ;
2013-05-12 14:50:57 -07:00
else ASSERT ( false , " No such droid type \" %s \" for %s " , droidType . toUtf8 ( ) . constData ( ) , getID ( & design ) ) ;
2013-05-09 14:17:05 -07:00
design . multiPlayerID = generateNewObjectId ( ) ;
2013-05-12 14:50:57 -07:00
design . asParts [ COMP_BODY ] = getCompFromName ( COMP_BODY , ini . value ( " compBody " , " ZNULLBODY " ) . toString ( ) ) ;
design . asParts [ COMP_BRAIN ] = getCompFromName ( COMP_BRAIN , ini . value ( " compBrain " , " ZNULLBRAIN " ) . toString ( ) ) ;
design . asParts [ COMP_REPAIRUNIT ] = getCompFromName ( COMP_REPAIRUNIT , ini . value ( " compRepair " , " ZNULLREPAIR " ) . toString ( ) ) ;
design . asParts [ COMP_CONSTRUCT ] = getCompFromName ( COMP_CONSTRUCT , ini . value ( " compConstruct " , " ZNULLCONSTRUCT " ) . toString ( ) ) ;
design . asParts [ COMP_ECM ] = getCompFromName ( COMP_ECM , ini . value ( " compECM " , " ZNULLECM " ) . toString ( ) ) ;
design . asParts [ COMP_SENSOR ] = getCompFromName ( COMP_SENSOR , ini . value ( " compSensor " , " ZNULLSENSOR " ) . toString ( ) ) ;
design . asParts [ COMP_PROPULSION ] = getCompFromName ( COMP_PROPULSION , ini . value ( " compPropulsion " , " ZNULLPROP " ) . toString ( ) ) ;
2013-05-09 14:17:05 -07:00
QStringList weapons = ini . value ( " weapons " ) . toStringList ( ) ;
for ( int j = 0 ; j < weapons . size ( ) ; j + + )
2011-12-17 15:23:51 -08:00
{
2013-05-12 14:50:57 -07:00
design . asWeaps [ j ] = getCompFromName ( COMP_WEAPON , weapons [ j ] ) ;
2011-12-17 15:23:51 -08:00
}
2013-05-09 14:17:05 -07:00
design . numWeaps = weapons . size ( ) ;
design . prefab = true ;
design . stored = false ;
design . enabled = true ;
bool available = ini . value ( " available " , false ) . toBool ( ) ;
char const * droidResourceName = getDroidResourceName ( list [ i ] . toUtf8 ( ) . constData ( ) ) ;
2013-05-12 14:50:57 -07:00
design . name = droidResourceName ! = NULL ? droidResourceName : GetDefaultTemplateName ( & design ) ;
2013-05-09 14:17:05 -07:00
ini . endGroup ( ) ;
2011-12-17 15:23:51 -08:00
2013-05-09 14:17:05 -07:00
for ( int i = 0 ; i < MAX_PLAYERS ; + + i )
2011-12-17 15:23:51 -08:00
{
2013-05-09 14:17:05 -07:00
// Give those meant for humans to all human players.
if ( NetPlay . players [ i ] . allocated & & available )
2011-12-17 15:23:51 -08:00
{
2013-05-09 14:17:05 -07:00
design . prefab = false ;
addTemplateToList ( & design , & apsDroidTemplates [ i ] ) ;
// This sets up the UI templates for display purposes ONLY--we still only use apsDroidTemplates for making them.
// FIXME: Why are we doing this here, and not on demand ?
// Only add unique designs to the UI list (Note, perhaps better to use std::map instead?)
std : : list < DROID_TEMPLATE > : : iterator it ;
for ( it = localTemplates . begin ( ) ; it ! = localTemplates . end ( ) ; + + it )
2012-04-02 14:50:57 -07:00
{
2013-05-09 14:17:05 -07:00
DROID_TEMPLATE * psCurr = & * it ;
if ( psCurr - > multiPlayerID = = design . multiPlayerID )
2012-04-25 17:51:57 -07:00
{
2013-05-12 14:50:57 -07:00
debug ( LOG_ERROR , " Design id:%d (%s) *NOT* added to UI list (duplicate), player= %d " , design . multiPlayerID , getName ( & design ) , i ) ;
2013-05-09 14:17:05 -07:00
break ;
2012-04-25 17:51:57 -07:00
}
2012-04-02 14:50:57 -07:00
}
2013-05-09 14:17:05 -07:00
if ( it = = localTemplates . end ( ) )
2011-12-17 15:23:51 -08:00
{
2013-05-12 14:50:57 -07:00
debug ( LOG_NEVER , " Design id:%d (%s) added to UI list, player =%d " , design . multiPlayerID , getName ( & design ) , i ) ;
2013-05-09 14:17:05 -07:00
localTemplates . push_front ( design ) ;
2011-12-17 15:23:51 -08:00
}
}
2013-05-09 14:17:05 -07:00
else if ( ! NetPlay . players [ i ] . allocated ) // AI template
{
design . prefab = true ; // prefabricated templates referenced from VLOs
addTemplateToList ( & design , & apsDroidTemplates [ i ] ) ;
}
2011-12-17 15:23:51 -08:00
}
2013-05-12 14:50:57 -07:00
debug ( LOG_NEVER , " Droid template found, Name: %s, MP ID: %d, ref: %u, ID: %s, prefab: %s, type:%d (loading) " ,
getName ( & design ) , design . multiPlayerID , design . ref , getID ( & design ) , design . prefab ? " yes " : " no " , design . droidType ) ;
2011-12-17 15:23:51 -08:00
}
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 ;
delete pTemplate ;
}
apsDroidTemplates [ player ] = NULL ;
}
2012-04-02 14:50:57 -07:00
2011-12-17 15:23:51 -08:00
localTemplates . clear ( ) ;
return true ;
}
/*!
* 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 )
{
2012-04-02 14:50:57 -07:00
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
2011-12-17 15:23:51 -08:00
{
2012-04-02 14:50:57 -07:00
for ( DROID_TEMPLATE * psCurr = apsDroidTemplates [ i ] ; psCurr ! = NULL ; psCurr = psCurr - > psNext )
2011-12-17 15:23:51 -08:00
{
2013-05-12 14:50:57 -07:00
if ( psCurr - > id . compare ( pName ) = = 0 )
2012-04-02 14:50:57 -07:00
{
return psCurr ;
}
2011-12-17 15:23:51 -08:00
}
}
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 ;
}
/*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 " ) ;
2012-03-10 07:00:42 -08:00
// Clear the factory's subject, and returns power.
cancelProduction ( psStruct , ModeImmediate , false ) ;
// Check to see if anything left to produce. (Also calls cancelProduction again, if nothing left to produce, which is a no-op. But if other things are left to produce, doesn't call cancelProduction, so wouldn't return power without the explicit cancelProduction call above.)
doNextProduction ( psStruct , NULL , ModeImmediate ) ;
2011-12-17 15:23:51 -08:00
//tell the interface
intManufactureFinished ( psStruct ) ;
syncDebugStructure ( psStruct , ' > ' ) ;
}
}
}
}
}
// 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 ;
}
/*
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 )
{
2011-12-18 03:20:48 -08:00
const int player = psFactory - > player ;
2011-12-17 15:23:51 -08:00
pList . clear ( ) ;
DROID_TEMPLATE * psCurr ;
2013-11-14 19:26:19 -08:00
BODY_SIZE iCapacity = ( BODY_SIZE ) psFactory - > capacity ;
2011-12-17 15:23:51 -08:00
/* Add the templates to the list*/
for ( std : : list < DROID_TEMPLATE > : : iterator i = localTemplates . begin ( ) ; i ! = localTemplates . end ( ) ; + + i )
{
psCurr = & * i ;
2012-02-06 05:37:22 -08:00
// Must add droids if currently in production.
2011-12-17 15:23:51 -08:00
if ( ! getProduction ( psFactory , psCurr ) . quantity )
{
//can only have (MAX_CMDDROIDS) in the world at any one time
if ( psCurr - > droidType = = DROID_COMMAND )
{
2011-12-18 03:20:48 -08:00
if ( checkProductionForCommand ( player ) + checkCommandExist ( player ) > = ( MAX_CMDDROIDS ) )
2011-12-17 15:23:51 -08:00
{
continue ;
}
}
2012-02-07 13:05:36 -08:00
if ( ! psCurr - > enabled | | ! validTemplateForFactory ( psCurr , psFactory , false )
2013-05-21 11:48:17 -07:00
| | ! researchedTemplate ( psCurr , player , includeRedundantDesigns ) )
2012-02-06 05:37:22 -08:00
{
continue ;
}
2011-12-17 15:23:51 -08:00
}
//check the factory can cope with this sized body
2013-11-14 19:14:27 -08:00
if ( ( ( asBodyStats + psCurr - > asParts [ COMP_BODY ] ) - > size < = iCapacity ) )
2011-12-17 15:23:51 -08:00
{
pList . push_back ( psCurr ) ;
}
2013-11-14 19:14:27 -08:00
else if ( bMultiPlayer & & ( iCapacity = = SIZE_HEAVY ) )
{
// Special case for Super heavy bodyies (Super Transporter)
if ( ( asBodyStats + psCurr - > asParts [ COMP_BODY ] ) - > size = = SIZE_SUPER_HEAVY )
{
pList . push_back ( psCurr ) ;
}
}
2011-12-17 15:23:51 -08:00
}
}