// // 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: /CounterStrike/TEAMTYPE.CPP 1 3/03/97 10:25a 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 : Joe L. Bostic * * * * Start Date : 06/28/96 * * * * Last Update : July 30, 1996 [JLB] * * * *---------------------------------------------------------------------------------------------* * Functions: * * TeamMissionClass::Description -- Compose a text description of team mi * * TeamMissionClass::Draw_It -- Draws a team mission list box entry. * * TeamMission_Needs -- Determines what extra data is needed by team miss * * TeamTypeClass::As_Pointer -- gets ptr for team type with given name * * TeamTypeClass::Build_INI_Entry -- Builds the INI entry for this team type. * * TeamTypeClass::Create_One_Of -- Creates a team of this type. * * TeamTypeClass::Description -- Builds a description of the team. * * TeamTypeClass::Destroy_All_Of -- Destroy all teams of this type. * * TeamTypeClass::Detach -- Detach the specified target from this team type. * * TeamTypeClass::Draw_It -- Display the team type in a list box. * * TeamTypeClass::Edit -- Edit the team type. * * TeamTypeClass::Fill_In -- fills in trigger from the given INI entry * * TeamTypeClass::From_Name -- Converts a name into a team type pointer. * * TeamTypeClass::Init -- pre-scenario initialization * * TeamTypeClass::Member_Description -- Builds a member description string * * TeamTypeClass::Mission_From_Name -- returns mission for given name * * TeamTypeClass::Name_From_Mission -- returns name for given mission * * TeamTypeClass::Read_INI -- reads INI data * * TeamTypeClass::Suggested_New_Team -- Suggests a new team to create. * * TeamTypeClass::TeamTypeClass -- class constructor * * TeamTypeClass::Write_INI -- Write out the team types to the INI database. * * TeamTypeClass::operator delete -- 'delete' operator * * TeamTypeClass::operator new -- 'new' operator * * TeamTypeClass::~TeamTypeClass -- class destructor * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" TeamMissionClass TeamMissions[TMISSION_COUNT] = { {TMISSION_ATTACK}, {TMISSION_ATT_WAYPT}, {TMISSION_FORMATION}, {TMISSION_MOVE}, {TMISSION_MOVECELL}, {TMISSION_GUARD}, {TMISSION_LOOP}, {TMISSION_ATTACKTARCOM}, {TMISSION_UNLOAD}, {TMISSION_DEPLOY}, {TMISSION_HOUND_DOG}, {TMISSION_DO}, {TMISSION_SET_GLOBAL}, {TMISSION_LOAD}, {TMISSION_SPY}, {TMISSION_PATROL}, }; int atoh(char * str); #if defined(CHEAT_KEYS) || defined(SCENARIO_EDITOR) /*********************************************************************************************** * TeamTypeClass::Draw_It -- Display the team type in a list box. * * * * This is a helper routine that is used when this team type is stored into a list box * * and must be displayed. It will display the team type as a single line of text. * * * * INPUT: see below... * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 07/30/1996 JLB : Created. * *=============================================================================================*/ void TeamTypeClass::Draw_It(int , int x, int y, int width, int height, bool selected, TextPrintType flags) const { RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); static int _tabs[] = {35, 60, 80, 100}; if ((flags & 0x0F) == TPF_6PT_GRAD || (flags & 0x0F) == TPF_EFNT) { if (selected) { flags = flags | TPF_BRIGHT_COLOR; LogicPage->Fill_Rect(x, y, x + width - 1, y + height - 1, scheme->Shadow); } else { if (!(flags & TPF_USE_GRAD_PAL)) { flags = flags | TPF_MEDIUM_COLOR; } } Conquer_Clip_Text_Print(Description(), x, y, scheme, TBLACK, flags, width, _tabs); } else { Conquer_Clip_Text_Print(Description(), x, y, (selected ? &ColorRemaps[PCOLOR_DIALOG_BLUE] : &ColorRemaps[PCOLOR_GREY]), TBLACK, flags, width, _tabs); } } #endif /* ********************************** Globals ********************************** */ char const * TeamTypeClass::TMissions[TMISSION_COUNT] = { "Attack...", "Attack Waypoint...", "Change Formation to...", "Move to waypoint...", "Move to Cell...", "Guard area (1/10th min)...", "Jump to line #...", "Attack Tarcom", "Unload", "Deploy", "Follow friendlies", "Do this...", "Set global...", "Invulnerable", "Load onto Transport", "Spy on bldg @ waypt...", "Patrol to waypoint..." }; /*************************************************************************** * TeamTypeClass::TeamTypeClass -- class constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/07/1994 BR : Created. * * 11/22/1995 JLB : Uses initializer constructor method. * *=========================================================================*/ TeamTypeClass::TeamTypeClass(void) : AbstractTypeClass(RTTI_TEAMTYPE, TeamTypes.ID(this), TXT_NONE, ""), IsRoundAbout(false), IsSuicide(false), IsAutocreate(false), IsPrebuilt(true), IsReinforcable(true), IsTransient(false), RecruitPriority(7), InitNum(0), MaxAllowed(0), Fear(0), House(HOUSE_NONE), Trigger(0), Origin(-1), Number(0), MissionCount(0), ClassCount(0) { for (int i = 0; i < MAX_TEAM_CLASSCOUNT; i++) { Members[i].Class = NULL; Members[i].Quantity = 0; } } /*************************************************************************** * TeamTypeClass::Init -- pre-scenario initialization * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 12/07/1994 BR : Created. * *=========================================================================*/ void TeamTypeClass::Init(void) { TeamTypes.Free_All(); } /*************************************************************************** * 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 const * name) { if (name) { for (int index = 0; index < TeamTypes.Count(); index++) { if (!stricmp(name, TeamTypes.Ptr(index)->IniName)) { return(TeamTypes.Ptr(index)); } } } return(NULL); } /*************************************************************************** * 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) { if (name) { for (TeamMissionType order = TMISSION_FIRST; order < TMISSION_COUNT; order++) { if (stricmp(TMissions[order], name) == 0) { return(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) { assert((unsigned)order < TMISSION_COUNT); 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); } /*********************************************************************************************** * TeamTypeClass::Create_One_Of -- Creates a team of this type. * * * * Use this routine to create a team object from this team type. * * * * INPUT: none * * * * OUTPUT: Returns with a pointer to the newly created team object. If one could not be * * created, then NULL is returned. * * * * WARNINGS: none * * * * HISTORY: * * 09/21/1995 JLB : Created. * *=============================================================================================*/ TeamClass * TeamTypeClass::Create_One_Of(void) const { if (ScenarioInit || Number < MaxAllowed) { // if (ScenarioInit || TeamClass::Number[ID] < MaxAllowed) { return(new TeamClass(this, HouseClass::As_Pointer(House))); } return(NULL); } /*********************************************************************************************** * TeamTypeClass::Destroy_All_Of -- Destroy all teams of this type. * * * * This routine will destroy all teams of this type. Typical use of this is from a trigger * * event. * * * * INPUT: none * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 09/21/1995 JLB : Created. * *=============================================================================================*/ 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. * * * * atypes -- A bit mask of the aircraft types available for this house. * * * * utypes -- A bit mask of the unit types available for this house. * * * * itypes -- A bit mask of the infantry types available for this house. * * * * vtypes -- A bit mask of the vessel 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 , long , long , long , bool alerted) //TeamTypeClass const * TeamTypeClass::Suggested_New_Team(HouseClass * house, long atypes, long utypes, long itypes, long vtypes, bool alerted) { // TeamTypeClass const * best = NULL; // int bestvalue = 0; TeamTypeClass const * choices[20]; int choicecount = 0; for (int index = 0; index < TeamTypes.Count(); index++) { TeamTypeClass const * ttype = TeamTypes.Ptr(index); assert(ttype != NULL); int maxnum = ttype->MaxAllowed; if ((alerted && !ttype->IsAutocreate) || (!alerted && ttype->IsAutocreate)) { maxnum = 0; } if (choicecount >= ARRAY_SIZE(choices)) break; if (ttype != NULL && ttype->House == house->Class->House && ttype->Number < maxnum) { choices[choicecount++] = ttype; #ifdef OBSOLETE /* ** Determine what kind of units this team requires. */ long uneeded = 0; long ineeded = 0; long vneeded = 0; long aneeded = 0; for (int ctype = 0; ctype < ttype->ClassCount; ctype++) { switch (ttype->Members[ctype].Class->What_Am_I()) { case RTTI_INFANTRYTYPE: ineeded |= (1 << ((InfantryTypeClass *)ttype->Members[ctype].Class)->Type); break; case RTTI_UNITTYPE: uneeded |= (1 << ((UnitTypeClass *)ttype->Members[ctype].Class)->Type); break; case RTTI_VESSELTYPE: vneeded |= (1 << ((VesselTypeClass *)ttype->Members[ctype].Class)->Type); break; case RTTI_AIRCRAFTTYPE: aneeded |= (1 << ((AircraftTypeClass *)ttype->Members[ctype].Class)->Type); break; } } /* ** If this team can use the types required, then consider it a possible ** team type to create. */ int value = 0; if ((aneeded & atypes) != 0 || (ineeded & itypes) != 0 || (uneeded & utypes) != 0 || (vneeded & vtypes) != 0) { value = ttype->RecruitPriority; } else { value = ttype->RecruitPriority/2; } if (best == NULL || bestvalue < value) { bestvalue = value; best = ttype; } #endif } } if (choicecount > 0) { return(choices[Random_Pick(0, choicecount-1)]); } return(NULL); // return(best); } /*********************************************************************************************** * TeamTypeClass::From_Name -- Converts a name into a team type pointer. * * * * This routine is used to convert an ASCII name of a team type into the corresponding * * team type pointer. * * * * INPUT: name -- Pointer to the ASCII name of the team type. * * * * OUTPUT: Returns with a pointer to the team type that this ASCII name represents. If there * * is no match, the NULL is returned. * * * * WARNINGS: none * * * * HISTORY: * * 01/26/1996 JLB : Created. * *=============================================================================================*/ TeamTypeClass * TeamTypeClass::From_Name(char const * name) { if (name) { for (int index = 0; index < TeamTypes.Count(); index++) { if (stricmp(name, TeamTypes.Ptr(index)->IniName) == 0) { return(TeamTypes.Ptr(index)); } } } return(0); } /*********************************************************************************************** * TeamMission_Needs -- Determines what extra data is needed by team mission. * * * * This routine will return the required extra data that the specified team mission will * * need. * * * * INPUT: tmtype -- The team mission type to check. * * * * OUTPUT: Returns with the data type needed for this team mission. * * * * WARNINGS: none * * * * HISTORY: * * 01/26/1996 JLB : Created. * *=============================================================================================*/ NeedType TeamMission_Needs(TeamMissionType tmtype) { switch (tmtype) { /* ** Requires a formation type. */ case TMISSION_FORMATION: return(NEED_FORMATION); /* ** Team mission requires a target quarry value. */ case TMISSION_ATTACK: return(NEED_QUARRY); /* ** Team mission requires a data value. */ case TMISSION_MOVECELL: return(NEED_HEX_NUMBER); case TMISSION_SET_GLOBAL: case TMISSION_GUARD: case TMISSION_LOOP: return(NEED_NUMBER); /* ** Team mission requires a waypoint. */ case TMISSION_PATROL: case TMISSION_MOVE: case TMISSION_ATT_WAYPT: case TMISSION_SPY: return(NEED_WAYPOINT); /* ** Team mission requires a general mission type. */ case TMISSION_DO: return(NEED_MISSION); default: break; } return(NEED_NONE); } #ifdef SCENARIO_EDITOR /*********************************************************************************************** * TeamMissionClass::Draw_It -- Draws a team mission list box entry. * * * * This routine will display a team mission list box entry. It converts the index number * * into the appropriate text string and then displays the text at the coordinates * * specified. * * * * INPUT: index -- The index number to use when rendering the team mission. * * * * x,y -- The X,Y coordinate to use when drawing the team mission entry. * * * * width, height -- The dimensions of the area that the description can be * * rendered into. * * * * selected -- Is this entry currently selected? If so, then it should be rendered * * differently. * * * * flags -- Text print control flags used for when the text is printed. * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 01/05/1996 JLB : Created. * *=============================================================================================*/ void TeamMissionClass::Draw_It(int index, int x, int y, int width, int height, bool selected, TextPrintType flags) { RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); static int _tabs[] = {13,40}; if ((flags & 0x0F) == TPF_6PT_GRAD || (flags & 0x0F) == TPF_EFNT) { if (selected) { flags = flags | TPF_BRIGHT_COLOR; LogicPage->Fill_Rect(x, y, x + width - 1, y + height - 1, scheme->Shadow); } else { if (!(flags & TPF_USE_GRAD_PAL)) { flags = flags | TPF_MEDIUM_COLOR; } } Conquer_Clip_Text_Print(Description(index), x, y, scheme, TBLACK, flags, width, _tabs); } else { Conquer_Clip_Text_Print(Description(index), x, y, (selected ? &ColorRemaps[PCOLOR_DIALOG_BLUE] : &ColorRemaps[PCOLOR_GREY]), TBLACK, flags, width, _tabs); } } /*********************************************************************************************** * TeamTypeClass::Edit -- Edit the team type. * * * * This routine handles the editing dialog box for the team type. * * * * INPUT: none * * * * OUTPUT: Was the team type edited? A FALSE indicates that the dialog was canceled. * * * * WARNINGS: none * * * * HISTORY: * * 01/05/1996 JLB : Created. * *=============================================================================================*/ bool TeamTypeClass::Edit(void) { /* ** Dialog & button dimensions */ enum { D_DIALOG_W = 400, D_DIALOG_H = 250, D_DIALOG_X = 0, D_DIALOG_Y = 0, D_NAME_X=D_DIALOG_X+35, D_NAME_Y=D_DIALOG_Y+27, ED_WIDTH=40, D_CHECK_X=D_DIALOG_X+35, // Start of check box attribute list. D_CHECK_Y=D_NAME_Y+25, CB_SPACING_Y=9, // Vertical spacing between check box lines. CB_SPACING_X=8, // Horizontal spacing for check box description text. D_SPACING_X=9, // Horizontal spacing between data entry fields. D_CANCEL_W = 50, D_CANCEL_H = 9, D_CANCEL_X = D_DIALOG_X + D_DIALOG_W - (D_CANCEL_W+35), D_CANCEL_Y = D_DIALOG_Y + D_DIALOG_H - (D_CANCEL_H+20), D_OK_W = 50, D_OK_H = 9, D_OK_X = D_DIALOG_X + D_DIALOG_W - (D_OK_W+18)*2, D_OK_Y = D_CANCEL_Y }; /* ** Button enumerations: */ enum { BUTTON_NAME=100, BUTTON_RECRUIT, BUTTON_MAXNUM, BUTTON_INITNUM, BUTTON_HOUSE, BUTTON_ROUNDABOUT, BUTTON_LEARNING, BUTTON_SUICIDE, BUTTON_AUTO, BUTTON_PREBUILT, BUTTON_REINFORCE, BUTTON_MISSION1, BUTTON_MISSION2, BUTTON_ADD, BUTTON_INSERT, BUTTON_DELETE, BUTTON_REPLACE, BUTTON_ARG, BUTTON_FORMATION, BUTTON_MEMBERS, BUTTON_MISSION, BUTTON_TRIGGER, BUTTON_ORIGIN, BUTTON_OK, BUTTON_CANCEL, BUTTON_QUARRY, }; /* ** Dialog variables: */ ControlClass * commands = 0; RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); /* ** Team name edit field. */ char name_buf[10]; EditClass name_edt(BUTTON_NAME, name_buf, sizeof(name_buf), TPF_EFNT | TPF_NOSHADOW, D_NAME_X, D_NAME_Y, ED_WIDTH, 9, EditClass::ALPHANUMERIC); strcpy(name_buf, IniName); commands = &name_edt; /* ** House ownership of this team. */ char housetext[25] = ""; DropListClass housebtn(BUTTON_HOUSE, housetext, sizeof(housetext), TPF_EFNT | TPF_NOSHADOW, name_edt.X+name_edt.Width+D_SPACING_X, name_edt.Y, 55, 8*5, MFCD::Retrieve("EBTN-UP.SHP"), MFCD::Retrieve("EBTN-DN.SHP")); for (HousesType house = HOUSE_FIRST; house < HOUSE_COUNT; house++) { housebtn.Add_Item(HouseTypeClass::As_Reference(house).IniName); } if (House == HOUSE_NONE) House = HOUSE_GOOD; housebtn.Set_Selected_Index(House); housebtn.Add(*commands); /* ** Recruit priority for this team. */ char recr_buf[4]; EditClass recr_edt(BUTTON_RECRUIT, recr_buf, sizeof(recr_buf), TPF_EFNT | TPF_NOSHADOW, housebtn.X+housebtn.Width+5+D_SPACING_X, housebtn.Y, ED_WIDTH, 9, EditClass::NUMERIC); sprintf(recr_buf, "%d", RecruitPriority); recr_edt.Add(*commands); /* ** Maximum allowed for this team type. */ char maxnum_buf[4]; EditClass maxnum_edt(BUTTON_MAXNUM, maxnum_buf, sizeof(maxnum_buf), TPF_EFNT | TPF_NOSHADOW, recr_edt.X+recr_edt.Width+D_SPACING_X, recr_edt.Y, ED_WIDTH, 9, EditClass::NUMERIC); sprintf(maxnum_buf, "%d", MaxAllowed); maxnum_edt.Add(*commands); /* ** Initial number for this team type. */ char initnum_buf[4]; EditClass initnum_edt(BUTTON_INITNUM, initnum_buf, sizeof(initnum_buf), TPF_EFNT | TPF_NOSHADOW, maxnum_edt.X+maxnum_edt.Width+D_SPACING_X, maxnum_edt.Y, ED_WIDTH, 9, EditClass::NUMERIC); sprintf(initnum_buf, "%d", InitNum); initnum_edt.Add(*commands); /* ** Waypoint preference to create/reinforce this team. */ char origin[4]; EditClass originbtn(BUTTON_ORIGIN, origin, sizeof(origin), TPF_EFNT | TPF_NOSHADOW, initnum_edt.X+initnum_edt.Width+D_SPACING_X, initnum_edt.Y, 20, 9, EditClass::ALPHA); *originbtn.Get_Text() = '\0'; if (Origin != -1) { if (Origin < 26) { sprintf(originbtn.Get_Text(), "%c", Origin + 'A'); } else { sprintf(originbtn.Get_Text(), "%c%c", (Origin/26) + 'A'-1, Origin % 26 + 'A'); } } originbtn.Add(*commands); /* ** Members of this team control button. */ TextButtonClass membersbtn(BUTTON_MEMBERS, "Members", TPF_EBUTTON, name_edt.X, name_edt.Y+12, 50); membersbtn.Add(*commands); /* ** Trigger to assign to each member of this team (when object joins team). */ char trigtext[25] = ""; DropListClass triggerbtn(BUTTON_TRIGGER, trigtext, sizeof(trigtext), TPF_EFNT | TPF_NOSHADOW, D_DIALOG_X+D_DIALOG_W-95, membersbtn.Y, 60, 8*5, MFCD::Retrieve("EBTN-UP.SHP"), MFCD::Retrieve("EBTN-DN.SHP")); triggerbtn.Add_Item(""); for (int index = 0; index < TriggerTypes.Count(); index++) { triggerbtn.Add_Item(TriggerTypes.Ptr(index)->IniName); } if (Trigger.Is_Valid()) { triggerbtn.Set_Selected_Index(Trigger->Name()); } else { triggerbtn.Set_Selected_Index(0); } triggerbtn.Add(*commands); /* ** Roundabout travel logic attribute for this team. */ CheckBoxClass roundbtn(BUTTON_ROUNDABOUT, D_CHECK_X, D_CHECK_Y); if (IsRoundAbout) { roundbtn.Turn_On(); } else { roundbtn.Turn_Off(); } roundbtn.Add(*commands); /* ** Suicide travel to target attribute. */ CheckBoxClass suicidebtn(BUTTON_SUICIDE, D_CHECK_X, roundbtn.Y+CB_SPACING_Y); if (IsSuicide) { suicidebtn.Turn_On(); } else { suicidebtn.Turn_Off(); } suicidebtn.Add(*commands); /* ** Autocreate attribute for this team. */ CheckBoxClass autocreatebtn(BUTTON_AUTO, D_CHECK_X, suicidebtn.Y+CB_SPACING_Y); if (IsAutocreate) { autocreatebtn.Turn_On(); } else { autocreatebtn.Turn_Off(); } autocreatebtn.Add(*commands); /* ** Prebuild team members attribute for this team. */ CheckBoxClass prebuildbtn(BUTTON_PREBUILT, D_CHECK_X, autocreatebtn.Y+CB_SPACING_Y); if (IsPrebuilt) { prebuildbtn.Turn_On(); } else { prebuildbtn.Turn_Off(); } prebuildbtn.Add(*commands); /* ** Reinforce this team in progress attribute. */ CheckBoxClass reinforcebtn(BUTTON_REINFORCE, D_CHECK_X, prebuildbtn.Y+CB_SPACING_Y); if (IsReinforcable) { reinforcebtn.Turn_On(); } else { reinforcebtn.Turn_Off(); } reinforcebtn.Add(*commands); /* ** Create drop box of possible team missions. This is used when building/editing the ** team mission list. */ char droptext[45]; DropListClass missionlist1(BUTTON_MISSION1, droptext, sizeof(droptext), TPF_EFNT | TPF_NOSHADOW, reinforcebtn.X, reinforcebtn.Y+15, 170, 8*8, MFCD::Retrieve("EBTN-UP.SHP"), MFCD::Retrieve("EBTN-DN.SHP")); for (TeamMissionType tm = TMISSION_FIRST; tm < TMISSION_COUNT; tm++) { missionlist1.Add_Item(TeamTypeClass::Name_From_Mission(tm)); } missionlist1.Set_Selected_Index(0); missionlist1.Add_Tail(*commands); /* ** Optional mission argument entry field. */ char arg_buf[6] = {0}; EditClass arg_edt(BUTTON_ARG, arg_buf, sizeof(arg_buf), TPF_EFNT | TPF_NOSHADOW, missionlist1.X + missionlist1.Width + 15, missionlist1.Y, 60, -1, EditClass::ALPHANUMERIC); // arg_edt.Add(*commands); char qtext[55]; DropListClass qlist(BUTTON_QUARRY, qtext, sizeof(qtext), TPF_EFNT | TPF_NOSHADOW, missionlist1.X + missionlist1.Width + 15, missionlist1.Y, 100, 5*8, MFCD::Retrieve("EBTN-UP.SHP"), MFCD::Retrieve("EBTN-DN.SHP")); for (QuarryType q = QUARRY_FIRST; q < QUARRY_COUNT; q++) { qlist.Add_Item(QuarryName[q]); } qlist.Set_Selected_Index(0); qlist.Add_Tail(*commands); char ftext[55]; DropListClass flist(BUTTON_FORMATION, ftext, sizeof(ftext), TPF_EFNT | TPF_NOSHADOW, missionlist1.X + missionlist1.Width + 15, missionlist1.Y, 100, 5*8, MFCD::Retrieve("EBTN-UP.SHP"), MFCD::Retrieve("EBTN-DN.SHP")); for (FormationType f = FORMATION_FIRST; f < FORMATION_COUNT; f++) { flist.Add_Item(FormationName[f]); } flist.Set_Selected_Index(0); flist.Add_Tail(*commands); char mtext[55]; DropListClass mlist(BUTTON_MISSION, mtext, sizeof(mtext), TPF_EFNT | TPF_NOSHADOW, missionlist1.X + missionlist1.Width + 15, missionlist1.Y, 100, 5*8, MFCD::Retrieve("EBTN-UP.SHP"), MFCD::Retrieve("EBTN-DN.SHP")); for (MissionType m = MISSION_FIRST; m < MISSION_COUNT; m++) { mlist.Add_Item(MissionClass::Mission_Name(m)); } mlist.Set_Selected_Index(0); mlist.Add_Tail(*commands); TListClass missionlist2(BUTTON_MISSION2, missionlist1.X+60, missionlist1.Y+22, 240, 8*7, TPF_EFNT | TPF_NOSHADOW, MFCD::Retrieve("EBTN-UP.SHP"), MFCD::Retrieve("EBTN-DN.SHP")); for (index = 0; index < MissionCount; index++) { missionlist2.Add_Item(new TeamMissionClass(MissionList[index])); // missionlist2.Add_Item(&TeamMissions[MissionList[index].Mission]); } static int tabs[] = {13, 40}; // list box tab stops missionlist2.Set_Tabs(tabs); missionlist2.Add_Tail(*commands); /* ** Mission editing command buttons. */ TextButtonClass addbtn(BUTTON_ADD, "Append", TPF_EBUTTON, D_NAME_X, missionlist1.Y+missionlist1.Height+1, 50); addbtn.Add(*commands); TextButtonClass insertbtn(BUTTON_INSERT, "Insert", TPF_EBUTTON, addbtn.X, addbtn.Y+10, 50); insertbtn.Add(*commands); TextButtonClass delbtn(BUTTON_DELETE, "Delete", TPF_EBUTTON, insertbtn.X, insertbtn.Y+10, 50); delbtn.Add(*commands); TextButtonClass repbtn(BUTTON_REPLACE, "Replace", TPF_EBUTTON, delbtn.X, delbtn.Y+10, 50); repbtn.Add(*commands); TextButtonClass okbtn(BUTTON_OK, TXT_OK, TPF_EBUTTON, D_OK_X, D_OK_Y, D_OK_W, D_OK_H); TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL, TPF_EBUTTON, D_CANCEL_X, D_CANCEL_Y, D_CANCEL_W, D_CANCEL_H); /* ** Initialize */ Set_Logic_Page(SeenBuff); /* ** Create the list */ okbtn.Add(*commands); cancelbtn.Add_Tail(*commands); /* ** Main Processing Loop */ int lastindex = -1; int lastcount = -1; int lastbutton = -1; bool cancel = false; bool display = true; bool process = true; while (process) { /* ** Invoke game callback */ Call_Back(); /* ** Refresh display if needed */ if (display) { /* ** Add the optional data entry field as necessary. */ arg_edt.Remove(); qlist.Remove(); flist.Remove(); mlist.Remove(); switch (TeamMission_Needs(TeamMissionType(missionlist1.Current_Index()))) { default: break; case NEED_MISSION: mlist.Add(*commands); break; case NEED_FORMATION: flist.Add(*commands); break; case NEED_WAYPOINT: case NEED_NUMBER: case NEED_HEX_NUMBER: arg_edt.Add(*commands); break; case NEED_QUARRY: qlist.Add(*commands); break; } /* ** Display the dialog box */ Hide_Mouse(); Dialog_Box(D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W, D_DIALOG_H); Draw_Caption(TXT_TEAM_EDIT, D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W); /* ** Draw the captions */ Fancy_Text_Print("Name:", name_edt.X, name_edt.Y-7, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("House:", housebtn.X, housebtn.Y-7, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Pri:", recr_edt.X, recr_edt.Y-7, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Max:", maxnum_edt.X, maxnum_edt.Y-7, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Num:", initnum_edt.X, initnum_edt.Y-7, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Loc:", originbtn.X, originbtn.Y-7, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("# Team Mission", missionlist2.X, missionlist2.Y-7, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Trigger:", triggerbtn.X-4, triggerbtn.Y+1, scheme, TBLACK, TPF_RIGHT | TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print(Member_Description(), membersbtn.X + membersbtn.Width + 3, membersbtn.Y+1, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Use safest, possibly longer, route to target?", roundbtn.X+CB_SPACING_X, roundbtn.Y, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Charge toward target ignoring distractions?", suicidebtn.X+CB_SPACING_X, suicidebtn.Y, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Only 'Autocreate A.I.' uses this team type?", autocreatebtn.X+CB_SPACING_X, autocreatebtn.Y, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Prebuild team members before team is created?", prebuildbtn.X+CB_SPACING_X, prebuildbtn.Y, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); Fancy_Text_Print("Automatically reinforce team whenever possible?", reinforcebtn.X+CB_SPACING_X, reinforcebtn.Y, scheme, TBLACK, TPF_EFNT | TPF_NOSHADOW); /* ** Redraw the buttons */ commands->Draw_All(); Show_Mouse(); display = false; } /* ** Get user input */ KeyNumType input = commands->Input(); /* ** Process input */ switch (input) { /* ** Select a Mission on the right-hand mission list; update the Argument ** field to reflect the current value. This only serves as an aide to editing ** the team mission list. */ case BUTTON_MISSION2 | KN_BUTTON: if (missionlist2.Count() && lastcount == missionlist2.Count() && lastbutton == BUTTON_MISSION2 && lastindex == missionlist2.Current_Index()) { missionlist1.Set_Selected_Index(missionlist2.Current_Item()->Mission); switch (TeamMission_Needs(missionlist2.Current_Item()->Mission)) { case NEED_MISSION: mlist.Set_Selected_Index(missionlist2.Current_Item()->Data.Mission); break; case NEED_FORMATION: flist.Set_Selected_Index(missionlist2.Current_Item()->Data.Formation); break; case NEED_NUMBER: sprintf(arg_edt.Get_Text(), "%d", missionlist2.Current_Item()->Data.Value); break; case NEED_HEX_NUMBER: sprintf(arg_edt.Get_Text(), "%x", missionlist2.Current_Item()->Data.Value); break; case NEED_QUARRY: strcpy(qlist.Get_Text(), QuarryName[missionlist2.Current_Item()->Data.Quarry]); break; case NEED_WAYPOINT: if (missionlist2.Current_Item()->Data.Value < 26) { sprintf(arg_edt.Get_Text(), "%c", missionlist2.Current_Item()->Data.Value + 'A'); } else { sprintf(arg_edt.Get_Text(), "%c%c", (missionlist2.Current_Item()->Data.Value)/26 + 'A'-1, (missionlist2.Current_Item()->Data.Value % 26) + 'A'); } break; } } lastindex = missionlist2.Current_Index(); lastcount = missionlist2.Count(); display = true; break; /* ** Add current mission data to current position of team mission list. Any ** subsequent missions get moved downward. */ case BUTTON_INSERT | KN_BUTTON: if (missionlist2.Count() < MAX_TEAM_MISSIONS) { TeamMissionClass * tm = new TeamMissionClass; tm->Mission = TeamMissionType(missionlist1.Current_Index()); tm->Data.Value = 0; switch (TeamMission_Needs(tm->Mission)) { case NEED_MISSION: tm->Data.Mission = MissionType(mlist.Current_Index()); break; case NEED_FORMATION: tm->Data.Formation = FormationType(flist.Current_Index()); break; case NEED_QUARRY: tm->Data.Quarry = QuarryType(qlist.Current_Index()); break; case NEED_NUMBER: tm->Data.Value = atoi(arg_edt.Get_Text()); break; case NEED_HEX_NUMBER: tm->Data.Value = atoh(arg_edt.Get_Text()); break; case NEED_WAYPOINT: tm->Data.Value = toupper(*arg_edt.Get_Text()) - 'A'; if ( *((arg_edt.Get_Text())+1)) { tm->Data.Value = (tm->Data.Value+1)*26; tm->Data.Value += toupper(*((arg_edt.Get_Text())+1)) - 'A';; } if ((unsigned)tm->Data.Value >= WAYPT_HOME) { tm->Data.Value = 0; } break; default: tm->Data.Value = 0; break; } missionlist2.Insert_Item(tm); } display = true; break; /* ** Add mission data to the end of the mission list. */ case BUTTON_ADD | KN_BUTTON: if (missionlist2.Count() < MAX_TEAM_MISSIONS) { TeamMissionClass * tm = new TeamMissionClass; tm->Mission = TeamMissionType(missionlist1.Current_Index()); tm->Data.Value = 0; switch (TeamMission_Needs(tm->Mission)) { case NEED_MISSION: tm->Data.Mission = MissionType(mlist.Current_Index()); break; case NEED_FORMATION: tm->Data.Formation = FormationType(flist.Current_Index()); break; case NEED_QUARRY: tm->Data.Quarry = QuarryType(qlist.Current_Index()); break; case NEED_NUMBER: tm->Data.Value = atoi(arg_edt.Get_Text()); break; case NEED_HEX_NUMBER: tm->Data.Value = atoh(arg_edt.Get_Text()); break; case NEED_WAYPOINT: tm->Data.Value = toupper(*arg_edt.Get_Text()) - 'A';; if ( *((arg_edt.Get_Text())+1)) { tm->Data.Value = (tm->Data.Value+1)*26; tm->Data.Value += toupper(*((arg_edt.Get_Text())+1)) - 'A';; } if ((unsigned)tm->Data.Value >= WAYPT_HOME) { tm->Data.Value = 0; } break; default: tm->Data.Value = 0; break; } missionlist2.Add_Item(tm); display = true; } break; /* ** Replace the currently selected mission with the work mission data. */ case BUTTON_REPLACE | KN_BUTTON: if (missionlist2.Count()) { TeamMissionClass * tm = missionlist2.Current_Item(); tm->Mission = TeamMissionType(missionlist1.Current_Index()); tm->Data.Value = 0; switch (TeamMission_Needs(tm->Mission)) { case NEED_MISSION: tm->Data.Mission = MissionType(mlist.Current_Index()); break; case NEED_FORMATION: tm->Data.Formation = FormationType(flist.Current_Index()); break; case NEED_QUARRY: tm->Data.Quarry = QuarryType(qlist.Current_Index()); break; case NEED_NUMBER: tm->Data.Value = atoi(arg_edt.Get_Text()); break; case NEED_HEX_NUMBER: tm->Data.Value = atoh(arg_edt.Get_Text()); break; case NEED_WAYPOINT: tm->Data.Value = toupper(*arg_edt.Get_Text()) - 'A'; if ( *((arg_edt.Get_Text())+1)) { tm->Data.Value = (tm->Data.Value+1)*26; tm->Data.Value += toupper(*((arg_edt.Get_Text())+1)) - 'A'; } if ((unsigned)tm->Data.Value >= WAYPT_HOME) { tm->Data.Value = 0; } break; default: tm->Data.Value = 0; break; } missionlist2[missionlist2.Current_Index()] = tm; } display = true; break; /* ** Delete the currently selected mission. */ case BUTTON_DELETE | KN_BUTTON: if (missionlist2.Count()) { TeamMissionClass * tm = missionlist2.Current_Item(); missionlist2.Remove_Index(missionlist2.Current_Index()); delete tm; } display = true; break; /* ** Invoke the members dialog */ case BUTTON_MEMBERS | KN_BUTTON: /* ** Take editor focus away */ membersbtn.Turn_Off(); /* ** Invoke the dialog */ Map.Team_Members(HousesType(housebtn.Current_Index())); /* ** Redraw */ display = true; break; /* ** When the OK button is selected, lift the values from the dialog box ** and place them into the team type object. */ case BUTTON_OK | KN_BUTTON: strtrim(name_edt.Get_Text()); if (strlen(name_edt.Get_Text()) != 0) { strcpy(IniName, name_edt.Get_Text()); } else { strcpy(IniName, "----"); } IsRoundAbout = roundbtn.IsOn; IsSuicide = suicidebtn.IsOn; IsAutocreate = autocreatebtn.IsOn; IsPrebuilt = prebuildbtn.IsOn; IsReinforcable = reinforcebtn.IsOn; RecruitPriority = atoi(recr_edt.Get_Text()); InitNum = atoi(initnum_edt.Get_Text()); MaxAllowed = atoi(maxnum_edt.Get_Text()); House = HousesType(housebtn.Current_Index()); Trigger = NULL; if (triggerbtn.Current_Index() > 0) { Trigger = TriggerTypes.Ptr(triggerbtn.Current_Index()-1); } MissionCount = missionlist2.Count(); for (index = 0; index < MissionCount; index++) { MissionList[index].Data.Value = 0; // Clears extra bits. MissionList[index] = *missionlist2[index]; } #ifdef TOFIX // the mission class objects pointed to in the list should be deleted? #endif if (strlen(originbtn.Get_Text())) { if (strlen(originbtn.Get_Text()) == 1) { Origin = toupper(*originbtn.Get_Text()) - 'A'; } else { Origin = (toupper(*originbtn.Get_Text())+1 - 'A' ) * 26; Origin += toupper(*(originbtn.Get_Text()+1)) - 'A'; } } else { Origin = -1; } cancel = false; process = false; break; /* ** Cancel: return */ case BUTTON_CANCEL | KN_BUTTON: cancel = true; process = false; break; /* ** Unrecognized events are ignored. If any button related event is ** detected, then collapse any drop down list boxes. This keeps the ** dialog box clean. */ default: if (input & KN_BUTTON) { housebtn.Collapse(); missionlist1.Collapse(); triggerbtn.Collapse(); display = true; } break; } /* ** Record the last dialog control touched so that a double click ** can be detected. */ if (input & KN_BUTTON) { lastbutton = (input & ~KN_BUTTON); } } return(!cancel); } int atoh(char * str) { int retval = 0; while (*str) { retval *= 16; if (*str >= '0' && *str <= '9') { retval += *str-'0'; } else { if (*str >= 'a' && *str <= 'f') { retval += 10 + (*str - 'a'); } else { if (*str >= 'A' && *str <= 'F') { retval += 10 + (*str - 'A'); } } } str++; } return(retval); } #endif #if defined(CHEAT_KEYS) || defined(SCENARIO_EDITOR) /*********************************************************************************************** * TeamTypeClass::Member_Description -- Builds a member description string. * * * * This routine will build a team member description string. The string will be composed * * of the team member type and quantity. As many team member types will be listed that * * can fit within a reasonable size. * * * * INPUT: none * * * * OUTPUT: Returns with a pointer to the text string that contains a description of the team * * type members. * * * * WARNINGS: The return string may be truncated if necessary to fit within reasonable size * * limits. * * * * HISTORY: * * 01/05/1996 JLB : Created. * *=============================================================================================*/ char const * TeamTypeClass::Member_Description(void) const { static char buffer[128]; buffer[0] = '\0'; /* ** Fill in class & count for all classes */ for (int index = 0; index < ClassCount; index++) { char txt[10]; strcat(buffer, Members[index].Class->IniName); strcat(buffer, ":"); sprintf(txt, "%d", Members[index].Quantity); strcat(buffer, txt); if (index < ClassCount-1) { strcat(buffer, ","); } } if (strlen(buffer) > 25) { strcpy(&buffer[25-3], "..."); } return(buffer); } /*********************************************************************************************** * TeamTypeClass::Description -- Builds a description of the team. * * * * This routine will build a brief description of the team type. This description is used * * in the team type list. * * * * INPUT: none * * * * OUTPUT: Returns with the composed text string that represents the team type. * * * * WARNINGS: none * * * * HISTORY: * * 01/05/1996 JLB : Created. * *=============================================================================================*/ char const * TeamTypeClass::Description(void) const { static char _buffer[128]; char extra = ' '; char loc[3]; loc[0] = loc[1] = loc[2] = 0; if (IsAutocreate) extra = '*'; if (Origin > -1) { // if (Origin != -1) { if (Origin < 26) { loc[0] = 'A' + Origin; } else { loc[0] = Origin / 26 + 'A'-1; loc[1] = Origin % 26 + 'A'; } } sprintf(_buffer, "%s\t%s\t%c%s\t%d\t%s", IniName, HouseTypeClass::As_Reference(House).Suffix, extra, loc, MissionCount, Member_Description()); return(_buffer); } /*********************************************************************************************** * TeamMissionClass::Description -- Compose a text description of team mission. * * * * This routine will create a text representation of a team mission. This description will * * be used in the list of team missions for display purposes. * * * * INPUT: index -- The index to assign to this team. The index is used since some team * * missions refer to the another team mission by index number. * * * * OUTPUT: Returns with a pointer to the team mission text. * * * * WARNINGS: none * * * * HISTORY: * * 01/05/1996 JLB : Created. * *=============================================================================================*/ char const * TeamMissionClass::Description(int index) const { static char buffer[64]; sprintf(buffer, "%d\t%s", index, TeamTypeClass::Name_From_Mission(Mission)); switch (TeamMission_Needs(Mission)) { case NEED_MISSION: strcat(buffer, MissionClass::Mission_Name(Data.Mission)); break; case NEED_FORMATION: strcat(buffer, FormationName[Data.Quarry]); break; case NEED_NUMBER: sprintf(&buffer[strlen(buffer)], "%d", Data.Value); break; case NEED_HEX_NUMBER: sprintf(&buffer[strlen(buffer)], "%x", Data.Value); break; case NEED_QUARRY: strcat(buffer, QuarryName[Data.Quarry]); break; case NEED_WAYPOINT: if (Data.Value < 26) { sprintf(&buffer[strlen(buffer)], "%c", Data.Value + 'A'); } else { sprintf(&buffer[strlen(buffer)], "%c%c", (Data.Value/26) + 'A'-1, (Data.Value % 26) + 'A'); } break; } return(buffer); } #endif /*********************************************************************************************** * TeamTypeClass::Detach -- Detach the specified target from this team type. * * * * This routine is called when some object is about to be removed from the game system and * * all references to it must be severed. This will check to see if the specified object * * is a trigger that this team refers to. If so, then the reference will be cleared. * * * * INPUT: target -- The target object to remove references to. * * * * OUTPUT: none * * * * WARNINGS: none * * * * HISTORY: * * 07/30/1996 JLB : Created. * *=============================================================================================*/ void TeamTypeClass::Detach(TARGET target, bool) { if (Is_Target_TriggerType(target) && Trigger.Is_Valid() && Trigger == As_TriggerType(target)) { Trigger = NULL; } } /*************************************************************************** * 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(CCINIClass & ini) { TeamTypeClass * team; // Working team pointer. char buf[500]; // INI entry buffer int len = ini.Entry_Count(INI_Name()); /* ** Loop for all team entries, create and fill in. */ for (int index = 0; index < len; index++) { team = new TeamTypeClass(); if (team != NULL) { char const * entry = ini.Get_Entry(INI_Name(), index); ini.Get_String(INI_Name(), entry, NULL, buf, sizeof(buf)); team->Fill_In((char *)entry, buf); } } } /*********************************************************************************************** * 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. * * 11/29/1995 JLB : Revamped to use new team class. * *=============================================================================================*/ void TeamTypeClass::Fill_In(char * name, char * entry) { assert(TeamTypes.ID(this) == ID); /* ** Set its name */ Set_Name(name); House = HousesType(atoi(strtok(entry, ","))); int code; switch (NewINIFormat) { default: code = atoi(strtok(NULL, ",")); IsRoundAbout = ((code & 0x0001) != 0); IsSuicide = ((code & 0x0002) != 0); IsAutocreate = ((code & 0x0004) != 0); IsPrebuilt = ((code & 0x0008) != 0); IsReinforcable = ((code & 0x0010) != 0); break; case 0: case 1: IsRoundAbout = atoi(strtok(NULL, ",")); IsSuicide = atoi(strtok(NULL, ",")); IsAutocreate = atoi(strtok(NULL, ",")); IsPrebuilt = atoi(strtok(NULL, ",")); IsReinforcable = atoi(strtok(NULL, ",")); break; } RecruitPriority = atoi(strtok(NULL, ",")); InitNum = atoi(strtok(NULL, ",")); MaxAllowed = atoi(strtok(NULL, ",")); Origin = atoi(strtok(NULL, ",")); switch (NewINIFormat) { default: Trigger.Set_Raw(atoi(strtok(NULL, ","))); break; case 0: case 1: // Throw this token away -- it isn't used. strtok(NULL, ","); break; } /* ** Fetch the team member types and quantity values. */ ClassCount = atoi(strtok(NULL, ",")); for (int index = 0; index < ClassCount; index++) { char * p1 = strtok(NULL, ",:"); char * p2 = strtok(NULL, ",:"); TechnoTypeClass const * otype = NULL; /* ** See if this is an infantry name */ InfantryType i_id = InfantryTypeClass::From_Name(p1); if (i_id != INFANTRY_NONE) { otype = &InfantryTypeClass::As_Reference(i_id); } else { /* ** See if this is a unit name */ UnitType u_id = UnitTypeClass::From_Name(p1); if (u_id != UNIT_NONE) { otype = &UnitTypeClass::As_Reference(u_id); } else { /* ** See if this is an aircraft name */ AircraftType a_id = AircraftTypeClass::From_Name(p1); if (a_id != AIRCRAFT_NONE) { otype = &AircraftTypeClass::As_Reference(a_id); } else { /* ** See if this is a vessel name. */ VesselType v_id = VesselTypeClass::From_Name(p1); if (v_id != VESSEL_NONE) { otype = &VesselTypeClass::As_Reference(v_id); } } } } /* ** If the name was resolved, add this class */ if (otype) { if (index < MAX_TEAM_CLASSCOUNT) { Members[index].Class = otype; Members[index].Quantity = atoi(p2); } } else { ClassCount--; if (index == 0) break; index--; } } ClassCount = min(MAX_TEAM_CLASSCOUNT, ClassCount); /* ** Fetch the missions assigned to this team type. */ MissionCount = atoi(strtok(NULL, ",")); for (int index = 0; index < MissionCount; index++) { MissionList[index].Mission = TeamMissionType(atoi(strtok(NULL, ",:"))); MissionList[index].Data.Value = atoi(strtok(NULL, ",:")); } if (NewINIFormat < 2) { /* ** Fetch the trigger ID. */ Trigger.Set_Raw(atoi(strtok(NULL, ","))); } } /*********************************************************************************************** * TeamTypeClass::Write_INI -- Write out the team types to the INI database. * * * * This routine will take all team types and write them out to the INI database specified. * * * * INPUT: ini -- Reference to the INI database that will hold al the teams. * * * * OUTPUT: none * * * * WARNINGS: All preexisting team data in the database will be erased by this routine. * * * * HISTORY: * * 07/30/1996 JLB : Created. * *=============================================================================================*/ void TeamTypeClass::Write_INI(CCINIClass & ini) { ini.Clear("TeamTypes"); ini.Clear(INI_Name()); /* ** Now write all the team data out */ for (int index = 0; index < TeamTypes.Count(); index++) { // for (int index = TeamTypes.Count()-1; index >= 0; index--) { TeamTypeClass * team = TeamTypes.Ptr(index); char buf[256]; buf[0] = 0; team->Build_INI_Entry(buf); ini.Put_String(INI_Name(), team->IniName, buf); } } /*********************************************************************************************** * TeamTypeClass::Build_INI_Entry -- Builds the INI entry for this team type. * * * * This routine is used to build the text string that will go into the INI database for * * a team of this type. This text string will be parsed back into a team object when the * * scenario INI is read in. * * * * INPUT: buf -- Pointer to a buffer that will hold the team text entry. * * * * OUTPUT: none * * * * WARNINGS: Be sure that the buffer can hold the string build. A size of 80 or so is * * usually sufficient. * * * * HISTORY: * * 07/30/1996 JLB : Created. * *=============================================================================================*/ void TeamTypeClass::Build_INI_Entry(char * buf) { int code = 0; code |= IsRoundAbout ? 0x0001 : 0; code |= IsSuicide ? 0x0002 : 0; code |= IsAutocreate ? 0x0004 : 0; code |= IsPrebuilt ? 0x0008 : 0; code |= IsReinforcable ? 0x0010 : 0; /* ** Output the general data for this team type. */ sprintf(buf, "%d,%d,%d,%d,%d,%d,%d", House, code, RecruitPriority, InitNum, MaxAllowed, Origin, TriggerTypes.Logical_ID(Trigger) ); buf += strlen(buf); /* ** For every class in the team, record the class's name & desired count */ sprintf (buf, ",%d", ClassCount); buf += strlen(buf); for (int i = 0; i < ClassCount; i++) { sprintf (buf, ",%s:%d", Members[i].Class->IniName, Members[i].Quantity); buf += strlen(buf); } /* ** Record the # of missions, and each mission name & argument value. */ sprintf(buf, ",%d", MissionCount); buf += strlen(buf); for (int i = 0; i < MissionCount; i++) { sprintf (buf, ",%d:%d", MissionList[i].Mission, MissionList[i].Data.Value); buf += strlen(buf); } }