CnC_Remastered_Collection/TIBERIANDAWN/TEAMTYPE.CPP
PG-SteveT 03416d24e1 Initial Source Code commit
Initial commit of original Tiberian Dawn and Red Alert source code converted to build as DLLs, and compatible with the release version of Command & Conquer Remastered.
2020-05-27 12:16:20 -07:00

978 lines
39 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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 3 of the License, or (at your option) any later version.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: F:\projects\c&c\vcs\code\teamtype.cpv 2.17 16 Oct 1995 16:48:52 JOE_BOSTIC $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : TEAMTYPE.CPP *
* *
* Programmer : Bill Randolph *
* *
* Start Date : December 7, 1994 *
* *
* Last Update : July 21, 1995 [JLB] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* TeamTypeClass::TeamTypeClass -- class constructor *
* TeamTypeClass::~TeamTypeClass -- class destructor *
* TeamTypeClass::Init -- pre-scenario initialization *
* TeamTypeClass::Read_INI -- reads INI data *
* TeamTypeClass::Write_INI -- writes INI data *
* TeamTypeClass::Read_Old_INI -- reads old INI format *
* TeamTypeClass::As_Pointer -- gets ptr for team type with given name *
* TeamTypeClass::Remove -- removes this team from the system *
* TeamTypeClass::Mission_From_Name -- returns mission for given name *
* TeamTypeClass::Name_From_Mission -- returns name for given mission *
* TeamTypeClass::operator new -- 'new' operator *
* TeamTypeClass::operator delete -- 'delete' operator *
* TeamTypeClass::Suggested_New_Team -- Suggests a new team to create. *
* TeamTypeClass::Validate -- validates teamtype pointer *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
/*
********************************** Globals **********************************
*/
char const * TeamTypeClass::TMissions[TMISSION_COUNT] = {
"Attack Base",
"Attack Units",
"Attack Civil.",
"Rampage",
"Defend Base",
// "Harvest",
"Move",
"Move to Cell",
"Retreat",
"Guard",
"Loop",
"Attack Tarcom",
"Unload",
};
/*
** This contains the value of the Virtual Function Table Pointer
*/
void * TeamTypeClass::VTable;
/***********************************************************************************************
* TeamTypeClass::Validate -- validates teamtype pointer *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 1 = ok, 0 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 08/09/1995 BRR : Created. *
*=============================================================================================*/
#ifdef CHEAT_KEYS
int TeamTypeClass::Validate(void) const
{
int num;
num = TeamTypes.ID(this);
if (num < 0 || num >= TEAMTYPE_MAX) {
Validate_Error("TEAMTYPE");
return (0);
}
else
return (1);
}
#else
#define Validate()
#endif
/***************************************************************************
* TeamTypeClass::TeamTypeClass -- class constructor *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/07/1994 BR : Created. *
*=========================================================================*/
TeamTypeClass::TeamTypeClass(void)
{
IsPrebuilt = true;
IsReinforcable = true;
IsRoundAbout = false;
IsLearning = false;
IsSuicide = false;
IsAutocreate = false;
IsTransient = false;
IsMercenary = false;
RecruitPriority = 7;
MaxAllowed = 0;
Fear = 0;
InitNum = 0;
House = HOUSE_NONE;
MissionCount = 0;
IniName[0] = '\0';
ClassCount = 0;
for (int i = 0; i < MAX_TEAM_CLASSCOUNT; i++) {
Class[i] = NULL;
DesiredNum[i] = 0;
}
}
/***************************************************************************
* TeamTypeClass::Init -- pre-scenario initialization *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/07/1994 BR : Created. *
*=========================================================================*/
void TeamTypeClass::Init(void)
{
TeamTypeClass *ptr;
TeamTypes.Free_All();
ptr = new TeamTypeClass();
VTable = ((void **)(((char *)ptr) + sizeof(AbstractTypeClass) - 4))[0];
delete ptr;
}
/***************************************************************************
* TeamTypeClass::Read_INI -- reads INI data *
* *
* INI entry format: *
* TeamName = Housename,Roundabout,Learning,Suicide,Spy,Mercenary, *
* RecruitPriority,MaxAllowed,InitNum,Fear, *
* ClassCount,Class:Num,Class:Num,..., *
* MissionCount,Mission:Arg,Mission:Arg,Mission:Arg,... *
* *
* INPUT: *
* buffer buffer to hold the INI data *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/07/1994 BR : Created. *
* 02/01/1995 BR : No del team if no classes (editor needs empty teams!) *
*=========================================================================*/
void TeamTypeClass::Read_INI(char *buffer)
{
TeamTypeClass * team; // Working team pointer.
char *tbuffer; // Accumulation buffer of team names.
int len; // Length of data in buffer.
char buf[500]; // INI entry buffer
/*------------------------------------------------------------------------
Set 'tbuffer' to point just past the INI buffer
------------------------------------------------------------------------*/
len = strlen(buffer) + 2;
tbuffer = buffer + len;
/*------------------------------------------------------------------------
Read all TeamType entry names into 'tbuffer'
------------------------------------------------------------------------*/
WWGetPrivateProfileString(INI_Name(), NULL, NULL, tbuffer, ShapeBufferSize-len, buffer);
/*
----------------------- Loop for all team entries ------------------------
*/
while (*tbuffer != '\0') {
/*
....................... Create a new team type ........................
*/
team = new TeamTypeClass();
/*
......................... Get the team entry ..........................
*/
WWGetPrivateProfileString(INI_Name(), tbuffer, NULL, buf, sizeof(buf)-1, buffer);
/*
.......................... Fill the team in ...........................
*/
team->Fill_In(tbuffer, buf);
/*
...................... Go to the next INI entry .......................
*/
tbuffer += strlen(tbuffer)+1;
}
/*
** If no teams were read in, try reading the old INI format.
*/
if (TeamTypes.Count()==0) {
Read_Old_INI(buffer);
}
}
/***********************************************************************************************
* TeamTypeClass::Fill_In -- fills in trigger from the given INI entry *
* *
* This routine fills in the given teamtype with the given name, and values from *
* the given INI entry. *
* *
* (This routine is used by the scenario editor, to import teams from the MASTER.INI file.) *
* *
* INI entry format: *
* TeamName = Housename,Roundabout,Learning,Suicide,Spy,Mercenary, *
* RecruitPriority,MaxAllowed,InitNum,Fear, *
* ClassCount,Class:Num,Class:Num,..., *
* MissionCount,Mission:Arg,Mission:Arg,Mission:Arg,... *
* *
* INPUT: *
* name mnemonic for the desired trigger *
* entry INI entry to parse *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/28/1994 BR : Created. *
*=============================================================================================*/
void TeamTypeClass::Fill_In(char * name, char *entry)
{
Validate();
int num_classes;
char *p1; // parsing pointer
char *p2; // parsing pointer
int i; // loop counter
TechnoTypeClass const *otype; // ptr to type of object
InfantryType i_id; // infantry ID
UnitType u_id; // unit ID
AircraftType a_id; // aircraft ID
TeamMissionStruct mission;
/*
------------------------------ Set its name ------------------------------
*/
Set_Name(name);
/*
---------------------------- 1st token: House ----------------------------
*/
House = HouseTypeClass::From_Name(strtok(entry,","));
/*
-------------------------- 2nd token: RoundAbout -------------------------
*/
IsRoundAbout = atoi(strtok(NULL,","));
/*
--------------------------- 3rd token: Learning --------------------------
*/
IsLearning = atoi(strtok(NULL,","));
/*
--------------------------- 4th token: Suicide ---------------------------
*/
IsSuicide = atoi(strtok(NULL,","));
/*
----------------------------- 5th token: Spy -----------------------------
*/
IsAutocreate = atoi(strtok(NULL,","));
/*
-------------------------- 6th token: Mercenary --------------------------
*/
IsMercenary = atoi(strtok(NULL,","));
/*
----------------------- 7th token: RecruitPriority -----------------------
*/
RecruitPriority = atoi(strtok(NULL,","));
/*
-------------------------- 8th token: MaxAllowed -------------------------
*/
MaxAllowed = atoi(strtok(NULL,","));
/*
--------------------------- 9th token: InitNum ---------------------------
*/
InitNum = atoi(strtok(NULL,","));
/*
------------------------- 10th token: Fear level -------------------------
*/
Fear = atoi(strtok(NULL,","));
/*
------------------------ 11th token: Class count -------------------------
*/
num_classes = atoi(strtok(NULL,","));
/*
-------------- Loop through entries, setting class ptr & num -------------
*/
ClassCount = 0;
for (i = 0; i < num_classes; i++) {
p1 = strtok(NULL,",:");
p2 = strtok(NULL,",:");
otype = NULL;
/*
------------------- See if this is an infantry name -------------------
*/
i_id = InfantryTypeClass::From_Name(p1);
if (i_id != INFANTRY_NONE) {
otype = &InfantryTypeClass::As_Reference(i_id);
}
/*
---------------------- See if this is a unit name ---------------------
*/
u_id = UnitTypeClass::From_Name(p1);
if (u_id != UNIT_NONE) {
otype = &UnitTypeClass::As_Reference(u_id);
}
/*
------------------- See if this is an aircraft name -------------------
*/
a_id = AircraftTypeClass::From_Name(p1);
if (a_id != AIRCRAFT_NONE) {
otype = &AircraftTypeClass::As_Reference(a_id);
}
/*
--------------- If the name was resolved, add this class --------------
*/
if (otype) {
if (ClassCount < MAX_TEAM_CLASSCOUNT) {
Class[ClassCount] = otype;
DesiredNum[ClassCount] = atoi(p2);
ClassCount++;
}
}
}
/*
----------------------- next token: Mission count ------------------------
*/
MissionCount = atoi(strtok(NULL,","));
for (i = 0; i < MissionCount; i++) {
p1 = strtok(NULL,",:");
p2 = strtok(NULL,",:");
mission.Mission = Mission_From_Name(p1);
mission.Argument = atoi(p2);
MissionList[i] = mission;
}
char * ptr = strtok(NULL, ",");
if (ptr) {
IsReinforcable = atoi(ptr);
}
ptr = strtok(NULL, ",");
if (ptr) {
IsPrebuilt = atoi(ptr);
}
}
/***************************************************************************
* TeamTypeClass::Write_INI -- writes INI data *
* *
* INI entry format: *
* TeamName = Housename,Roundabout,Learning,Suicide,Spy,Mercenary, *
* RecruitPriority,MaxAllowed,InitNum,Fear, *
* ClassCount,Class:Num,Class:Num,..., *
* MissionCount,Mission,Arg,Mission,Arg,Mission,Arg,... *
* *
* INPUT: *
* buffer buffer to store INI data in *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/07/1994 BR : Created. *
*=========================================================================*/
void TeamTypeClass::Write_INI(char *buffer, bool refresh)
{
int index;
int i;
char buf[500];
TeamTypeClass * team;
char const *hname;
/*------------------------------------------------------------------------
First, clear out all existing teamtypes in the old-style format.
------------------------------------------------------------------------*/
WWWritePrivateProfileString("Teams", NULL, NULL, buffer);
/*------------------------------------------------------------------------
Clear out all existing teamtype data from the INI file.
------------------------------------------------------------------------*/
if (refresh) {
WWWritePrivateProfileString(INI_Name(), NULL, NULL, buffer);
}
/*------------------------------------------------------------------------
Now write all the team data out
------------------------------------------------------------------------*/
buf[0] = 0;
for (index = 0; index < TeamTypes.Count(); index++) {
/*
.................. Get ptr to next active teamtype ....................
*/
team = TeamTypes.Ptr(index);
/*
.......................... Find house's name ..........................
*/
if (team->House==HOUSE_NONE) {
hname = "None";
} else {
hname = HouseClass::As_Pointer(team->House)->Class->IniName;
}
/*
......................... Generate INI entry ..........................
*/
sprintf(buf,"%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
hname,
team->IsRoundAbout,
team->IsLearning,
team->IsSuicide,
team->IsAutocreate,
team->IsMercenary,
team->RecruitPriority,
team->MaxAllowed,
team->InitNum,
team->Fear,
team->ClassCount);
/*.....................................................................
For every class in the team, record the class's name & desired count
.....................................................................*/
for (i = 0; i < team->ClassCount; i++) {
sprintf (buf + strlen(buf), ",%s:%d",
team->Class[i]->IniName,
team->DesiredNum[i]);
}
/*.....................................................................
Record the # of missions, and each mission name & argument value.
.....................................................................*/
sprintf(buf + strlen(buf),",%d",team->MissionCount);
for (i = 0; i < team->MissionCount; i++) {
sprintf (buf + strlen(buf), ",%s:%d",
Name_From_Mission(team->MissionList[i].Mission),
team->MissionList[i].Argument);
}
if (team->IsReinforcable) {
strcat(buf, ",1");
} else {
strcat(buf, ",0");
}
if (team->IsPrebuilt) {
strcat(buf, ",1");
} else {
strcat(buf, ",0");
}
WWWritePrivateProfileString(INI_Name(), team->IniName, buf, buffer);
}
}
/***************************************************************************
* TeamTypeClass::Read_Old_INI -- reads old INI format *
* *
* INI entry format: *
* TeamName = Housename,Roundabout,Learning,Suicide,Spy,Mercenary, *
* RecruitPriority,MaxAllowed,InitNum,Class:Num,Class:Num,...,Fear *
* *
* INPUT: *
* buffer buffer to hold the INI data *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/07/1994 BR : Created. *
* 02/01/1995 BR : No del team if no classes (editor needs empty teams!) *
*=========================================================================*/
void TeamTypeClass::Read_Old_INI(char *buffer)
{
TeamTypeClass * team; // Working team pointer.
char *tbuffer; // Accumulation buffer of team names.
int len; // Length of data in buffer.
char buf[256]; // INI entry buffer
char *p1; // parsing pointer
char *p2; // parsing pointer
int index;
TechnoTypeClass const *otype; // ptr to type of object
InfantryType i_id; // infantry ID
UnitType u_id; // unit ID
AircraftType a_id; // infantry ID
/*------------------------------------------------------------------------
Set 'tbuffer' to point just past the INI buffer
------------------------------------------------------------------------*/
len = strlen(buffer) + 2;
tbuffer = buffer + len;
/*------------------------------------------------------------------------
Read all TeamType entry names into 'tbuffer'
------------------------------------------------------------------------*/
WWGetPrivateProfileString("Teams", NULL, NULL, tbuffer, ShapeBufferSize-len, buffer);
/*
----------------------- Loop for all team entries ------------------------
*/
while (*tbuffer != '\0') {
/*
........................ Create a new trigger .........................
*/
team = new TeamTypeClass();
/*
............................ Set its name .............................
*/
team->Set_Name(tbuffer);
/*
......................... Get the team entry ..........................
*/
WWGetPrivateProfileString("Teams", tbuffer, NULL, buf, sizeof(buf)-1, buffer);
/*
.......................... 1st token: House ...........................
*/
team->House = HouseTypeClass::From_Name(strtok(buf,","));
/*
........................ 2nd token: RoundAbout ........................
*/
team->IsRoundAbout = atoi(strtok(NULL,","));
/*
......................... 3rd token: Learning .........................
*/
team->IsLearning = atoi(strtok(NULL,","));
/*
......................... 4th token: Suicide ..........................
*/
team->IsSuicide = atoi(strtok(NULL,","));
/*
........................... 5th token: Spy ............................
*/
team->IsAutocreate = atoi(strtok(NULL,","));
/*
........................ 6th token: Mercenary .........................
*/
team->IsMercenary = atoi(strtok(NULL,","));
/*
..................... 7th token: RecruitPriority ......................
*/
team->RecruitPriority = atoi(strtok(NULL,","));
/*
........................ 8th token: MaxAllowed ........................
*/
team->MaxAllowed = atoi(strtok(NULL,","));
/*
......................... 9th token: InitNum ..........................
*/
team->InitNum = atoi(strtok(NULL,","));
/*
....................... 10th token: Mission name ......................
*/
strtok(NULL,","); // just throw it away
/*
............ Loop through entries, setting class ptr & num ............
*/
index = 0;
p1 = strtok(NULL,",:");
p2 = strtok(NULL,",:");
while (p1 && p2) {
otype = NULL;
/*
................. See if this is an infantry name ..................
*/
i_id = InfantryTypeClass::From_Name(p1);
if (i_id!=INFANTRY_NONE) {
otype = &InfantryTypeClass::As_Reference(i_id);
}
/*
.................... See if this is a unit name ....................
*/
u_id = UnitTypeClass::From_Name(p1);
if (u_id != UNIT_NONE) {
otype = &UnitTypeClass::As_Reference(u_id);
}
/*
................. See if this is an aircraft name ..................
*/
a_id = AircraftTypeClass::From_Name(p1);
if (a_id != AIRCRAFT_NONE) {
otype = &AircraftTypeClass::As_Reference(a_id);
}
/*
............. If the name was resolved, add this class .............
*/
if (otype) {
team->Class[index] = otype;
team->DesiredNum[index] = atoi(p2);
index++;
team->ClassCount = index;
}
/*
................. Go to the next entry on the line .................
*/
p1 = strtok(NULL,",:");
p2 = strtok(NULL,",:");
}
team->Fear = 0;
/*
...................... Go to the next INI entry .......................
*/
tbuffer += strlen(tbuffer)+1;
}
}
/***************************************************************************
* TeamTypeClass::As_Pointer -- gets ptr for team type with given name *
* *
* INPUT: *
* name name of teamtype *
* *
* OUTPUT: *
* ptr to TeamType with that name *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/07/1994 BR : Created. *
*=========================================================================*/
TeamTypeClass * TeamTypeClass::As_Pointer(char *name)
{
int i;
if (name == NULL) {
return(NULL);
}
for (i = 0; i < TeamTypes.Count(); i++) {
if (!stricmp(name, TeamTypes.Ptr(i)->IniName)) {
return(TeamTypes.Ptr(i));
}
}
return(NULL);
}
/***************************************************************************
* TeamTypeClass::Remove -- removes this team from the system *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/09/1994 BR : Created. *
*=========================================================================*/
void TeamTypeClass::Remove(void)
{
Validate();
int i;
TriggerClass * trigger;
/*
** Remove all trigger references to this team.
*/
for (i = 0; i < Triggers.Count(); i++) {
trigger = Triggers.Ptr(i);
if (trigger->Team == this) {
trigger->Team = NULL;
}
}
/*
** Delete myself.
*/
delete this;
}
/***************************************************************************
* TeamTypeClass::Mission_From_Name -- returns team mission for given name *
* *
* INPUT: *
* name name to compare *
* *
* OUTPUT: *
* mission for that name *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/13/1994 BR : Created. *
*=========================================================================*/
TeamMissionType TeamTypeClass::Mission_From_Name(char const *name)
{
int order;
if (name) {
for (order = TMISSION_FIRST; order < TMISSION_COUNT; order++) {
if (stricmp(TMissions[order], name) == 0) {
return((TeamMissionType) order);
}
}
}
return(TMISSION_NONE);
}
/***************************************************************************
* TeamTypeClass::Name_From_Mission -- returns name for given mission *
* *
* INPUT: *
* order mission to get name for *
* *
* OUTPUT: *
* name of mission *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/13/1994 BR : Created. *
*=========================================================================*/
char const * TeamTypeClass::Name_From_Mission(TeamMissionType order)
{
if (order <= TMISSION_NONE || order >= TMISSION_COUNT) {
return("None");
} else {
return(TMissions[order]);
}
}
/***************************************************************************
* TeamTypeClass::operator new -- 'new' operator *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* pointer to new TeamType *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/28/1994 BR : Created. *
*=========================================================================*/
void * TeamTypeClass::operator new(size_t )
{
void * ptr = TeamTypes.Allocate();
if (ptr) {
((TeamTypeClass *)ptr)->IsActive = true;
}
return(ptr);
}
/***************************************************************************
* TeamTypeClass::operator delete -- 'delete' operator *
* *
* INPUT: *
* ptr pointer to delete *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 11/28/1994 BR : Created. *
*=========================================================================*/
void TeamTypeClass::operator delete(void *ptr)
{
if (ptr) {
((TeamTypeClass *)ptr)->IsActive = false;
}
TeamTypes.Free((TeamTypeClass *)ptr);
}
TeamClass * TeamTypeClass::Create_One_Of(void) const
{
if (ScenarioInit || TeamClass::Number[TeamTypes.ID(this)] < MaxAllowed) {
return(new TeamClass(this, HouseClass::As_Pointer(House)));
}
return(NULL);
}
TARGET TeamTypeClass::As_Target(void) const
{
Validate();
return(Build_Target(KIND_TEAMTYPE, TeamTypes.ID(this)));
}
void TeamTypeClass::Destroy_All_Of(void) const
{
for (int index = 0; index < Teams.Count(); index++) {
TeamClass * team = Teams.Ptr(index);
if (team->Class == this) {
delete team;
index--;
}
}
}
/***********************************************************************************************
* TeamTypeClass::Suggested_New_Team -- Suggests a new team to create. *
* *
* This routine will scan through the team types available and create teams of the *
* type that can best utilize the existing unit mix. *
* *
* INPUT: house -- Pointer to the house that this team is to be created for. *
* *
* utype -- A bit mask of the unit types available for this house. *
* *
* itypes -- A bit mask of the infantry types available for this house. *
* *
* alerted -- Is this house alerted? If true, then the Autocreate teams will be *
* considered in the selection process. *
* *
* OUTPUT: Returns with a pointer to the team type that should be created. If no team should *
* be created, then it returns NULL. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/13/1995 JLB : Created. *
* 07/21/1995 JLB : Will autocreate team even if no members in field. *
*=============================================================================================*/
TeamTypeClass const * TeamTypeClass::Suggested_New_Team(HouseClass * house, long utypes, long itypes, bool alerted)
{
TeamTypeClass const * best = NULL;
int bestvalue = 0;
for (int index = 0; index < TeamTypes.Count(); index++) {
TeamTypeClass const * ttype = TeamTypes.Ptr(index);
if (ttype &&
ttype->House == house->Class->House &&
TeamClass::Number[index] < ((alerted || !ttype->IsAutocreate) ? ttype->MaxAllowed : 0)) {
/*
** Determine what kind of units this team requires.
*/
long uneeded = 0;
long ineeded = 0;
for (int ctype = 0; ctype < ttype->ClassCount; ctype++) {
switch (ttype->Class[ctype]->What_Am_I()) {
case RTTI_INFANTRYTYPE:
ineeded |= (1 << ((InfantryTypeClass *)ttype->Class[ctype])->Type);
break;
case RTTI_UNITTYPE:
uneeded |= (1 << ((UnitTypeClass *)ttype->Class[ctype])->Type);
break;
}
}
/*
** If this team can use the types required, then consider it a possible
** team type to create.
*/
int value = 0;
if ((ineeded & itypes) || (uneeded & utypes)) {
value = ttype->RecruitPriority;
} else {
value = ttype->RecruitPriority/2;
}
if (!best || bestvalue < value) {
bestvalue = value;
best = ttype;
}
}
}
return(best);
}