/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program 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. * * This program 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 this program. If not, see . * */ #include "bagel/spacebar/sraf_computer.h" #include "bagel/spacebar/sraf_msg.h" #include "bagel/spacebar/sraf_file.h" #include "bagel/spacebar/boflib/app.h" #include "bagel/spacebar/baglib/bagel.h" #include "bagel/boflib/sound.h" #include "bagel/spacebar/baglib/link_object.h" #include "bagel/bagel.h" #include "bagel/boflib/file_functions.h" #include "bagel/spacebar/boflib/std_keys.h" namespace Bagel { namespace SpaceBar { #define SRAF_DIR "$SBARDIR\\SRAFFA\\CLOSEUP\\COMPUTER\\" #define SRAF_MALE_DIR "$SBARDIR\\SRAFFA\\char\\GMALE\\" #define SRAF_FEMALE_DIR "$SBARDIR\\SRAFFA\\char\\GFEMALE\\" #define SRAF_AUDIO_DIR "$SBARDIR\\SRAFFA\\AUDIO\\EVENTS\\" #define SRAF_TIMEOUT "SFTIMOUT.WAV" #define USE_TEXT_WIDTHS true // Local constants // // Deal summary constants #define kUnknownTermStr "(Unknown)" #define kRightColumnAlign 25 // Sraffan flashback max turns... #define kSrafMaxTurns 200 // Amount of time to figure out who is driving... #define kDrivingTime 5 // Constants not linked to any one screen #define kCheckMark 'x' #define kStandardIndentation 4 #define kStandardDoubleIndentation 8 // Buyer bids summary #define kFirstMineralColumn 12 #define kBuyerBidsPointSize 14 #define kOtherPointSize 13 #define kMineralColWidth 4 #define kBuyerBidsPointWidth 6 #define kLineItemHeight (kBuyerBidsPointSize + 4) // Add instructions to the main screen #define kActivateFooterStr1 "NOTE: On any subsequent screens where the information displayed does" #define kActivateFooterStr2 "not fit on the screen, scroll up or down one line using up-arrow and" #define kActivateFooterStr3 "down-arrow. Scroll up or down a page using page-up or page-down." #define kBuyerBidsHeaderStr "BUYER Zn Ba Rg Ut Pn Sz 0 H20 LH CH ME TE AS PD ACCEPT" #define kBuyerBidsMessage1 "Click on any buyer to see their biography. Click in the 'ACCEPT' column " #define kBuyerBidsMessage2 "to incorporate that buyer into the current offer." // EMail constants #define kEmailHeaderStr "SUBJECT FROM TO" #define kMessageFromColumn 25 #define kMessageToColumn 48 // Audio constants #define kAudioHeaderStr "TITLE AUTHOR PLANET" #define kAudioAuthorCol 32 #define kAudioPlanetCol 53 // Robobutler constants #define kRobobutlerHeaderStr " TODAY'S SPECIAL OFFERINGS" #define kRobobutlerCol 20 // Check teams constants #define kCheckTeamHeaderStr1 "MEETING DISPATCH YOUR STAFF ATTENDING MEETING" #define kCheckTeamHeaderStr2 "WITH TIME" // 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 #define kCheckTeamTimeCol 18 #define kCheckTeamStaffCol 28 #define kCheckDispatchTeamFooter1 "To check the status of a meeting, click in the 'MEETING WITH' column" #define kCheckDispatchTeamFooter2 "on the same line as the meeting attendees." // Staffer constants #define kMaxStafferNameLen 9 // Dispatch negotiating team constants #define kDispatchHeaderStr "MEET WITH: TEAM TO INCLUDE: AVAILABLE INCLUDE ON TEAM" #define kMeetTitleColumn 5 #define kMeetSubColumn 9 #define kTeamMemberColumn 36 #define kTeamAvailableColumn 56 #define kTeamIncludeColumn 73 #define kDispatchFooterStr1 "To meet with an individual, click in the 'MEET WITH' column to the" #define kDispatchFooterStr2 "left of the name. To read an individual's biography, click on that" #define kDispatchFooterStr3 "individual's name. To include a staff member on the negotiating " #define kDispatchFooterStr4 "team, click in the 'INCLUDE ON TEAM' column. Click on 'Dispatch " #define kDispatchFooterStr5 "Team' when the negotiating team is fully assembled." // Code word constants #define kCodeWordsHeader1 "Your offer was accepted by the sellers! Please choose a code name" #define kCodeWordsHeader2 "for the deal by selecting one word from each group." #define kCodeWordsHeader3 " ***GROUP ONE*** ***GROUP TWO***" // 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 #define kGroup1Col2 15 #define kGroup2Col1 45 #define kGroup2Col2 60 // Have to know some mineral constants in the grid enum { ZINC = 0, BARIUM, RIGELLIUM, UPTITE, PLATINUM, SANZIUM, OXYGEN, WATER, LUMBER, CROP, MEDICINE, TURF, STRUCTURE, POLLUTION, WEAPONS }; // Main menu items enum { DEALSUMMARY = 0, BUYERBIDS, DEALBACKGROUND, SELLERBIOS, OTHERBIOS, STAFFBIOS, DISPATCHTEAM, CURRENTEMAIL, AUDIOSETTINGS, ROBOBUTLER, CHECKTEAMS }; // Local structs struct ST_BUTTONS { const char *_pszName; const char *_pszUp; const char *_pszDown; const char *_pszFocus; const char *_pszDisabled; int _nLeft; int _nTop; int _nWidth; int _nHeight; int _nID; }; #define SRAF_NO_MEETING 0 #define SRAF_GOOD_MEETING 1 #define SRAF_BAD_MEETING 2 struct SELLERITEM { const char *_pszName; int16 _nAmount; SELLERS _nSellerID; const char *_pszSellerBio; bool _bMeetWith; bool _bAvailable; int16 _nMeetingResult; }; // Struct for email messages struct EMAILITEM { const char *_pszMessageSubj; const char *_pszMessageFrom; const char *_pszMessageTo; const char *_pszMessageFile; }; // Struct for buyer bids grid struct BUYERBIDSREC { const char *_pszName; int16 _nMineralVal[NUM_MINERALS]; int16 _nBidSum; bool _bAccept; BUYERS _nBuyerID; const char *_pszBuyerBio; bool _bMeetWith; bool _bAvailable; int16 _nFlags; int16 _nMeetingResult; }; // Mineral information struct MINERAL_NAMES { const char *_pszMineralName; const char *_pszMineralAbbrev; }; // Staffer bio information struct STAFFERITEM { const char *_pszStafferName; const char *_pszStafferBio; const char *_pszStafferBmp; bool _bAvailable; bool _bOnCurrentTeam; int _nFlags; int _nNegotiatingStrength; int _nMeetingTime; }; // Staffer bio information struct OTHERITEM { const char *_pszName; const char *_pszOtherPartyBio; bool _bMeetWith; bool _bAvailable; int16 _nPaymentAmount; int16 _nMeetingResult; }; struct AUDIOITEM { const char *_pszTitle; const char *_pszAuthor; const char *_pszPlanet; const char *_pszAudioFile; CBofSound *_pMidiTrack; }; #define kRandomPlayTime 15 struct OFFERINGITEM { const char *_pszType; const char *_pszOffering; const char *_pszFile; const char *_pszRcvOfferingFile; }; // Codewords struct CODEWORDITEM { const char *_pszCodeWord1; const char *_pszCodeWord2; const char *_pszCodeWord3; const char *_pszCodeWord4; }; // Local globals // // there are 6 regular staffers, but durteen, the 7th, is the one that notifies deven that // time has run out... we need room in the structure for him also, although he won't be // doing any negotiating or meetings for us. static STAFFERITEM g_staffers[NUM_STAFFERS + 1] = { { "Norg-72", "nor72bio.txt", "sanenorg.bmp", true, false, mStafferMale, 1, 30 }, { "Pnurth-81", "Pnu81bio.txt", "sanepnur.bmp", true, false, mStafferFemale, 3, 30 }, { "Zig-64", "Zig64bio.txt", "sanezig.bmp", true, false, mStafferFemale, 6, 18 }, { "Lentil-24", "Len24bio.txt", "sanelent.bmp", true, false, mStafferFemale, 5, 15 }, { "Vargas-20", "Var20bio.txt", "sanevarg.bmp", true, false, mStafferMale, 10, 25 }, { "Churg-53", "Chu53bio.txt", "sanechur.bmp", true, false, mStafferMale, 5, 22 }, { "Durteen-97", "DUR97bio.txt", "sanedurt.bmp", true, false, mStafferMale, 0, 0 }, }; static const char *g_stMainItems[NUM_MAIN_ITEMS] = { "* Deal Summary", "* Buyer Bids and Biographies", "* Deal Background Data", "* Seller Biographies", "* Biographies of Other Parties", "* Staff Biographies", "* Dispatch Negotiating Team", "* Current E-Mail", "* Household Audio", "* Robobutler Service", "* Status of Negotiations" }; static SELLERITEM g_stSellerNames[NUM_SELLERS] = { { "Irk-4", -1, IRK4, "IRK4BIO.TXT", false, true, SRAF_NO_MEETING }, { "Yeef-8", 38, YEEF8, "YEE8BIO.TXT", false, true, SRAF_NO_MEETING }, { "Quosh-23", -1, QUOSH23, "QUO11BIO.TXT", false, true, SRAF_NO_MEETING }, }; // Yeef can be talked down! #define kYeefTalkedDownAmount 33 #define mBuyerMale 0x0001 #define mBuyerFemale 0x0002 // Can talk these buyers up... here are there amounts. #define kSinjinTalkedUpAmount 7 #define kSinjinMineralID STRUCTURE #define kGungTalkedUpAmount 8 #define kGungMineralID BARIUM #define kDorkTalkedUpAmount 8 #define kDorkMineralID UPTITE #define kGildTalkedUpAmount1 11 #define kGildTalkedUpAmount2 8 #define kGildMineralID1 ZINC #define kGildMineralID2 PLATINUM #define MIN_MART_ENTRIES 6 // Buyer bids grid, dork, gung sinjin and gild can be talked up, but the // rest of them are non-negotiable. Only dork and gung are part of the // final solution. static BUYERBIDSREC g_stBuyerBids[NUM_BUYERS] = { { "Pylon-3", { 0, 0, 0, 0, 0, 0, 7, 9, 2, 3, 4, 8, 0, 0 }, 33, false, PYLON3, "PYL3BIO.TXT", false, true, mBuyerFemale, SRAF_NO_MEETING }, { "Dippik-10", { 0, 0, 0, 0, 0, 0, 5, 4, 0, 0, 0, 0, 6, 8 }, 23, false, DIPPIK10, "DIP10BIO.TXT", false, true, mBuyerMale, SRAF_NO_MEETING }, { "Vebbil-18", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0 }, 7, false, VEBBIL18, "VEB18BIO.TXT", false, true, mBuyerFemale, SRAF_NO_MEETING }, { "Gung-14", { 0, 4, 2, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0 }, 16, false, GUNG14, "GUN14BIO.TXT", false, true, mBuyerMale, SRAF_NO_MEETING }, { "Reyes-24", { 10, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 17, false, REYES24, "REY24BIO.TXT", false, true, mBuyerMale, SRAF_NO_MEETING }, { "Gild-13", { 6, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 10, false, GILD13, "GIL13BIO.TXT", false, true, mBuyerFemale, SRAF_NO_MEETING }, { "Hem-20", { 0, 0, 3, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 8, false, HEM20, "HEM20BIO.TXT", false, true, mBuyerFemale, SRAF_NO_MEETING }, { "Dork-44", { 0, 6, 0, 4, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0 }, 21, false, DORK44, "DOR44BIO.TXT", false, true, mBuyerMale, SRAF_NO_MEETING }, { "Rawley-23", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 }, 8, false, RAWLEY23, "RAW23BIO.TXT", false, true, mBuyerFemale, SRAF_NO_MEETING }, { "Jella-37", { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0 }, 4, false, JELLA37, "JEL37BIO.TXT", false, true, mBuyerFemale, SRAF_NO_MEETING }, { "Sinjin-11", { 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 5, 6 }, 23, false, SINJIN11, "SIN11BIO.TXT", false, true, mBuyerMale, SRAF_NO_MEETING }, { "Hundey-42", { 0, 0, 4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 6 }, 13, false, HUNDEY42, "HUN42BIO.TXT", false, true, mBuyerMale, SRAF_NO_MEETING }, { "Chandra-15", { 0, 0, 0, 0, 0, 0, 0, 13, 0, 2, 4, 0, 0, 0 }, 19, false, CHANDRA15, "CHA15BIO.TXT", false, true, mBuyerFemale, SRAF_NO_MEETING }, { "Clang-2", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 }, 9, false, CLANG2, "CLA2BIO.TXT", false, true, mBuyerMale, SRAF_NO_MEETING }, { "Min. Mart", { 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 4, false, MINMARTZN, "MINBIO.TXT", false, true, 0, SRAF_NO_MEETING }, { "Min. Mart", { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 3, false, MINMARTBA, "MINBIO.TXT", false, true, 0, SRAF_NO_MEETING }, { "Min. Mart", { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 1, false, MINMARTRG, "MINBIO.TXT", false, true, 0, SRAF_NO_MEETING }, { "Min. Mart", { 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 3, false, MINMARTUT, "MINBIO.TXT", false, true, 0, SRAF_NO_MEETING }, { "Min. Mart", { 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 3, false, MINMARTPN, "MINBIO.TXT", false, true, 0, SRAF_NO_MEETING }, { "Min. Mart", { 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0 }, 7, false, MINMARTSZ, "MINBIO.TXT", false, true, 0, SRAF_NO_MEETING }, }; static MINERAL_NAMES g_stMinerals[NUM_MINERALS] = { { "Zinc Mining Rights", "Zn" }, { "Barium Mining Rights", "Ba" }, { "Rigellium Mining Rights", "Rg" }, { "Uptite Mining Rights", "Ut" }, { "Pandemonium Mining Rights", "Pn" }, { "Sanzium Mining Rights", "Sz" }, { "Oxygen Mining Rights", "O" }, { "Water Extraction Rights", "H2O" }, { "Lumber Harvesting Rights", "LH" }, { "Crop Harvesting Rights", "CH" }, { "Medicine Extraction Rights", "ME" }, { "Turf Extraction Rights", "TE" }, { "Artificial Structure Ownership and Removal Rights", "AS" }, { "Exclusive Pollution Dumping Rights", "PD" }, }; static EMAILITEM g_stEmailMessages[NUM_MAIL_MESSAGES] = { { "Armpit III", "Irk-4", "Deven-7", "SRAMAIL1.TXT" }, { "Pool", "Devo-185", "Deven-7", "SRAMAIL2.TXT" }, { "Rumor", "Durteen-97", "Deven-7", "SRAMAIL3.TXT" }, { "Mona Lisa", "Fezint-40", "Deven-7", "SRAMAIL4.TXT" }, { "A Special Offer", "Acme Upholstery Corp", "Deven-7", "SRAMAIL5.TXT" }, { "Swonza-5", "Churg-53", "Deven-7", "SRAMAIL6.TXT" }, { "Pinna-6C", "Chippik-9", "Deven-7", "SRAMAIL7.TXT" }, { "Armpit III", "Yeef-8", "Deven-7", "SRAMAIL8.TXT" }, }; enum OTHERPARTYS { SWONZA5 = 0, POLITICIANS, ENVIRONMENTALISTS }; static OTHERITEM g_stOtherPartys[NUM_OTHER_PARTYS] = { { "Swonza-5", "SWO5BIO.TXT", false, true, -1, SRAF_NO_MEETING }, { "Politicians", "POLITBIO.TXT", false, true, -30, SRAF_NO_MEETING }, { "Environmentalists", "ENVIRBIO.TXT", false, true, -1, SRAF_NO_MEETING }, }; // Sraffin computer buttons #define ON_BUTTON 0 #define OFF_BUTTON 1 #define QUIT_BUTTON 2 #define RETURN_TO_MAIN_BUTTON 3 #define SUBMIT_BUTTON 4 #define DISPLAY_KEY_BUTTON 5 #define DISPATCH_TEAM_BUTTON 6 #define NO_MUSIC_BUTTON 7 #define DONE_BUTTON 8 #define ORDER_BEVERAGE_BUTTON 9 #define ORDER_SNACK_BUTTON 10 // Define our buttons to go on the bottom of the main screen static ST_BUTTONS g_stButtons[NUM_SRAFCOMPBUTT] = { { "On", "onup.bmp", "ondn.bmp", "onup.bmp", "onup.bmp", 20, 445, 200, 30, ON_BUTTON }, { "Off", "offup.bmp", "offdn.bmp", "offup.bmp", "offup.bmp", 20, 445, 200, 30, OFF_BUTTON }, { "Quit", "quitup.bmp", "quitdn.bmp", "quitup.bmp", "quitup.bmp", 407, 445, 200, 30, QUIT_BUTTON }, { "Return to Main", "mainup.bmp", "maindn.bmp", "mainup.bmp", "mainup.bmp", 430, 445, 200, 30, RETURN_TO_MAIN_BUTTON }, { "Submit Offer", "offerup.bmp", "offerdn.bmp", "offerup.bmp", "offerup.bmp", 220, 445, 200, 30, SUBMIT_BUTTON }, { "Display the Key", "keyup.bmp", "keydn.bmp", "keyup.bmp", "keyup.bmp", 220, 445, 200, 30, DISPLAY_KEY_BUTTON }, { "Dispatch Team", "teamup.bmp", "teamdn.bmp", "teamup.bmp", "teamup.bmp", 220, 445, 200, 30, DISPATCH_TEAM_BUTTON }, { "No Music", "musicup.bmp", "musicdn.bmp", "musicup.bmp", "musicup.bmp", 220, 445, 200, 30, NO_MUSIC_BUTTON }, { "Done", "doneup.bmp", "donedn.bmp", "doneup.bmp", "doneup.bmp", 430, 445, 200, 30, DONE_BUTTON }, { "Order Beverage", "bevup.bmp", "bevdn.bmp", "bevup.bmp", "bevup.bmp", 20, 445, 200, 30, ORDER_BEVERAGE_BUTTON }, { "Order Snack", "snackup.bmp", "snackdn.bmp", "snackup.bmp", "snackup.bmp", 225, 445, 200, 30, ORDER_SNACK_BUTTON } }; static AUDIOITEM g_audioTracks[NUM_MUSICAL_SCORES] = { { "Harpsichord Invention #1", "J. S. Bach", "Earth", "SRAFFAN1.MID", nullptr }, { "Jazz Theme #44981", "Urgon-Thmo", "Thelbia", "SRAFFAN2.MID", nullptr }, { "Bamboo Breeze", "H. Fugimachi", "Earth", "SRAFFAN3.MID", nullptr }, { "Power of Crystal, OP. 12", "Brak-44", "H'poctyl", "SRAFFAN4.MID", nullptr }, { "String Quartet", "J. Salesin", "Earth", "SRAFFAN5.MID", nullptr }, { "The Womp Song", "The Womps", "Armpit IV", "SRAFFAN6.MID", nullptr }, { "Mixed Selections", " ", " ", nullptr, nullptr }, }; static AUDIOITEM g_chickenDance = \ { "Chicken Dance", "Unknown Origin", "Mars", "CHIKDANC.MID", nullptr }; // Pointers to the g_audioTracks entries. For the Mac, The Womp Song // is replaced with the Chicken Dance static AUDIOITEM *g_stAudioSetting[NUM_MUSICAL_SCORES] = { &g_audioTracks[0], &g_audioTracks[1], &g_audioTracks[2], &g_audioTracks[3], &g_audioTracks[4], &g_audioTracks[5], &g_audioTracks[6] }; static OFFERINGITEM g_stOfferings[NUM_OFFERINGS] = { { "BEVERAGE:", "Distilled Fleeblunx Sap", "BEVDESC.TXT", "DRINKRCV.TXT" }, { "LIGHT SNACK:", "Br'thl'gian Centipede Legs", "SNKDESC.TXT", "SNACKRCV.TXT" } }; // Codewords static CODEWORDITEM g_stCodeWords[NUM_CODE_WORDS] = { { "ANGRY", "LUCKY", "BAGPIPE", "MOSS" }, { "BRASS", "MELTED", "BANANA", "MUFFIN" }, { "BURNT", "MOIST", "BANSHEE", "PAJAMAS" }, { "DEAD", "NOISY", "BULLET", "PUCK" }, { "ELVISH", "POINTY", "COOKIE", "SHRUB" }, { "ENCRUSTED", "SIMPLE", "FRISBEE", "SWORD" }, { "FUZZY", "SMOKY", "GALOSHES", "TORPEDO" }, { "GIGGLING", "TWITCHING", "GUITAR", "TUNIC" }, { "HUNGRY", "UNITED", "HYENA", "UMBRELLA" }, { "HURLING", "VARNISHED", "LANTERN", "ZUCCHINI" } }; static bool gTextScreenFrontmost = false; static int gDispatchCurState = 0; // Retain current state of dispatch negotiating team screen static int gTurncountLineNo = 0; // Keep track of turncount line number // Member static initializations bool SrafComputer::_bSwonzaEnlightened = false; SrafComputer *SrafComputer::_pHead = nullptr; // Only sraffan computer int SrafComputer::_nStartingTime = 0; bool SrafComputer::_bRandomAudio = false; int SrafComputer::_nRandomTime = 0; bool SrafComputer::_bFailureNotified = false; // States that the dispatch negotiating team can take on #define mSellersExpanded 0x01 #define mBuyersExpanded 0x02 #define mOthersExpanded 0x04 CBofWindow *SrafTextScreen::_pSaveActiveWin = nullptr; // Local prototype functions const char *buildSrafDir(const char *pszFile); const char *buildAudioDir(const char *pszFile); const char *buildMaleSrafDir(const char *pszFile); const char *buildFemaleSrafDir(const char *pszFile); // Local prototypes SrafComputer::SrafComputer() : gCompDisplay(40, 40, 600, 440), gTextWindow(0, 0, 640 - 1, 480 - 1), gStafferDisplay(0, 0, 640 - 1, 480 - 1), gSrafTextWindow(0, 440, 640 - 1, 480 - 1) { int i; _cTextColor = CTEXT_WHITE; // Start out with white as our text color _cTextHiliteColor = RGB(255, 255, 255); // and some other color as our hilite _cTextLineColor = CTEXT_YELLOW; // Computer starts as off and at the main screen _eMode = SC_OFF; _eCurScreen = SC_MAIN; // initialize our three buttons for (i = 0; i < NUM_SRAFCOMPBUTT; i++) { _pButtons[i] = nullptr; } // initialize bitmaps (one extra staffer, durteen) for (i = 0; i < (NUM_STAFFERS + 1); i++) { _pStafferBmp[i] = nullptr; } // List and text box _pLBox = nullptr; _pMainList = nullptr; _nSelection = -1; _nListPointSize = kOtherPointSize; _nListItemHeight = 20; // Subscreen initializations _pSellerSummaryList = nullptr; _pBuyerSummaryList = nullptr; _pTeamList = nullptr; // Text only screen initializations _pTextOnlyScreen = nullptr; _pszGroup1Word = nullptr; _pszGroup2Word = nullptr; _bSrafAttached = false; _pHead = this; } // FYI: It only uses the seller summary list to build the onscreen // list, we use the global to store intermediate data. void SrafComputer::recalcSellerSummaryList() { // initialize the initial state of the seller summary if (_pSellerSummaryList == nullptr) { _pSellerSummaryList = new CBofList; } else { delete _pSellerSummaryList; _pSellerSummaryList = nullptr; } // Lets verify that its all set before we go to use it if (_pSellerSummaryList == nullptr) { _pSellerSummaryList = new CBofList; } int i = 0; while (i < NUM_SELLERS) { DealSummarySellerItem sellerItem; sellerItem._eSellerID = g_stSellerNames[i]._nSellerID; sellerItem._nSellerOffer = g_stSellerNames[i]._nAmount; sellerItem._pSellerName = g_stSellerNames[i]._pszName; _pSellerSummaryList->addToTail(sellerItem); i++; } } void SrafComputer::recalcBuyerSummaryList() { // initialize the initial state of the deal summary if (_pBuyerSummaryList == nullptr) { _pBuyerSummaryList = new CBofList; } else { delete _pBuyerSummaryList; _pBuyerSummaryList = nullptr; } // Lets verify that its all set before we go to use it if (_pBuyerSummaryList == nullptr) { _pBuyerSummaryList = new CBofList; } int i = 0; while (i < NUM_BUYERS) { if (g_stBuyerBids[i]._bAccept) { DealSummaryBuyerItem *pBuyerItem = new DealSummaryBuyerItem(); pBuyerItem->_eBuyerID = g_stBuyerBids[i]._nBuyerID; pBuyerItem->_nBuyerOffer = g_stBuyerBids[i]._nBidSum; pBuyerItem->_pBuyerName = g_stBuyerBids[i]._pszName; _pBuyerSummaryList->addToTail(*pBuyerItem); delete pBuyerItem; } i++; } } bool SrafComputer::verifyDispatchTeam() { bool bValidTeam = true; char szFailureReason[256]; int nTeam = 0; // Make sure that we have someone to meet int nMeetOthers = getMeetMember(kOthersList); int nMeetSellers = getMeetMember(kSellersList); int nMeetBuyers = getMeetMember(kBuyersList); if (nMeetOthers == -1 && nMeetSellers == -1 && nMeetBuyers == -1) { bool bStafferSelected = false; // Nobody to meet with, see if we have any team members selected. // This changes the error message. for (int i = 0; i < NUM_STAFFERS; i++) { if (g_staffers[i]._bOnCurrentTeam) { bStafferSelected = true; break; } } if (bStafferSelected == false) { Common::strcpy_s(szFailureReason, kszNotEvenClose); } else { Common::strcpy_s(szFailureReason, kszNoNegotiators); } bValidTeam = false; } if (bValidTeam) { if ((nMeetOthers != -1 && nMeetSellers != -1 && nMeetBuyers != -1)) { Common::sprintf_s(szFailureReason, ksz3MeetingTargets, g_stSellerNames[nMeetSellers]._pszName, g_stOtherPartys[nMeetOthers]._pszName, g_stBuyerBids[nMeetBuyers]._pszName); bValidTeam = false; } } if (bValidTeam) { if ((nMeetOthers != -1 && nMeetSellers != -1)) { Common::sprintf_s(szFailureReason, ksz2MeetingTargets, g_stSellerNames[nMeetSellers]._pszName, g_stOtherPartys[nMeetOthers]._pszName); bValidTeam = false; } } if (bValidTeam) { if ((nMeetSellers != -1 && nMeetBuyers != -1)) { Common::sprintf_s(szFailureReason, ksz2MeetingTargets, g_stSellerNames[nMeetSellers]._pszName, g_stBuyerBids[nMeetBuyers]._pszName); bValidTeam = false; } } if (bValidTeam) { if ((nMeetOthers != -1 && nMeetBuyers != -1)) { Common::sprintf_s(szFailureReason, ksz2MeetingTargets, g_stOtherPartys[nMeetOthers]._pszName, g_stBuyerBids[nMeetBuyers]._pszName); bValidTeam = false; } } // Make sure at least one staff member is sent on this mission if (bValidTeam) { for (int i = 0; i < NUM_STAFFERS; i++) { if (g_staffers[i]._bOnCurrentTeam) { nTeam |= (1 << (i + 3)); } } if (nTeam == 0) { Common::strcpy_s(szFailureReason, kszNoTeamMembers); bValidTeam = false; } } // No meetings with irk or quosh allowed. if (bValidTeam) { if (nMeetSellers == IRK4) { Common::strcpy_s(szFailureReason, kszCantMeetIrk); bValidTeam = false; } if (nMeetSellers == QUOSH23) { Common::strcpy_s(szFailureReason, kszCantMeetQuosh); bValidTeam = false; } } // Don't allow repeat negotiations with someone that // has already been successfully negotiated with. if (bValidTeam) { if (nMeetSellers != -1) { if (g_stSellerNames[nMeetSellers]._nMeetingResult == SRAF_GOOD_MEETING) { Common::strcpy_s(szFailureReason, kszCantRenegSeller); bValidTeam = false; } } if (nMeetOthers != -1) { if (g_stOtherPartys[nMeetOthers]._nMeetingResult == SRAF_GOOD_MEETING) { Common::strcpy_s(szFailureReason, kszCantRenegOther); bValidTeam = false; } } if (nMeetBuyers != -1) { if (g_stBuyerBids[nMeetBuyers]._nMeetingResult == SRAF_GOOD_MEETING) { Common::strcpy_s(szFailureReason, kszCantRenegBuyer); bValidTeam = false; } } } // Build a valid meeting list element. DispatchedTeamItem *pTeamItem = nullptr; if (bValidTeam) { int nDispatchFlags = (nMeetOthers != -1 ? mOtherParty : (nMeetSellers != -1 ? mSeller : mBuyer)); int nMeetingWith = (nMeetOthers != -1 ? nMeetOthers : (nMeetSellers != -1 ? nMeetSellers : nMeetBuyers)); if (_pTeamList == nullptr) { _pTeamList = new CBofList; } pTeamItem = new DispatchedTeamItem(); pTeamItem->_nFlags = nTeam | nDispatchFlags; pTeamItem->_nMeetWithID = nMeetingWith; CBagVar *pVar = g_VarManager->getVariable("SRATURNCOUNT"); assert(pVar != nullptr); pTeamItem->_nDispatchTime = pVar->getNumValue(); pTeamItem->_nMeetingTime = calculateMeetingTime(pTeamItem->_nFlags); // Pick a team captain, must be same sex as the announcer. pTeamItem->_nTeamCaptain = getTeamCaptain(pTeamItem->_nFlags); // Team gender is based on sex of captain. pTeamItem->_nFlags |= getTeamGender(pTeamItem->_nFlags); _pTeamList->addToTail(*pTeamItem); // Finally, since we have a valid team, set those team members who are attending to // be unavailable for any other staff meetings, also reset them to false for // on current team for (int i = 0; i < NUM_STAFFERS; i++) { if (g_staffers[i]._bOnCurrentTeam) { g_staffers[i]._bOnCurrentTeam = false; g_staffers[i]._bAvailable = false; } } } // There are all kinds of ways to screw up a meeting, but we address those in some kind of // staff meeting grid (search StaffMeeting) if (bValidTeam == false) { displayMessage(szFailureReason); } else { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // We're very excited, we notified the user, now clear up the globals and reset. if (nMeetOthers != -1) { g_stOtherPartys[nMeetOthers]._bMeetWith = false; g_stOtherPartys[nMeetOthers]._bAvailable = false; } else if (nMeetSellers != -1) { g_stSellerNames[nMeetSellers]._bMeetWith = false; g_stSellerNames[nMeetSellers]._bAvailable = false; } else { g_stBuyerBids[nMeetBuyers]._bMeetWith = false; g_stBuyerBids[nMeetBuyers]._bAvailable = false; } // Redraw the screen with the meeting with column collapsed and // the checkmarks out of the staffer columns. This assures that // any screen capture will come back to us ready for display to the // user. initDispatchTeam(); activateDispatchTeam(); // Also have to give the boss a sound or text file to play. if (pTeamItem->_nFlags & mStafferMale) { sStr = buildMaleSrafDir(kGSM1SraMaleStr); } else { sStr = buildFemaleSrafDir(kGSM1SraFemStr); } // Notify Deven... notifyBoss(sStr, pTeamItem->_nTeamCaptain); // All done with our team item, trash it. delete pTeamItem; updateWindow(); } return bValidTeam; } SrafComputer::~SrafComputer() { // These lists are persistent across turning the computer on and off, so // delete them only at the end of the game, not when you turn on/off the // computer (attach/detach) delete _pSellerSummaryList; _pSellerSummaryList = nullptr; delete _pBuyerSummaryList; _pBuyerSummaryList = nullptr; delete _pTeamList; _pTeamList = nullptr; delete _pLBox; _pLBox = nullptr; // We grab these bad babies in the attach sequence, but since // we need them to live past having the computer on, we need to // destruct them in the destructor. for (int i = 0; i < (NUM_MUSICAL_SCORES - 1); i++) { delete g_stAudioSetting[i]->_pMidiTrack; g_stAudioSetting[i]->_pMidiTrack = nullptr; } _pTextOnlyScreen = nullptr; _pHead = nullptr; } void SrafComputer::onMainLoop() { if (_bFirstPaint) { _bFirstPaint = false; attachActiveObjects(); } } void SrafComputer::onPaint(CBofRect *pRect) { if (getBackdrop()) { assert(getWorkBmp() != nullptr); // erase everything from the background getWorkBmp()->paint(getBackdrop(), pRect, pRect); // paint all the objects to the background paintStorageDevice(nullptr, getBackdrop(), pRect); } // Paint the backdrop if (getBackdrop()) { paintBackdrop(); } if (_eMode == SC_OFF) { _pButtons[ON_BUTTON]->paint(nullptr); } else { _pButtons[OFF_BUTTON]->paint(nullptr); } } ErrorCode SrafComputer::attach() { ErrorCode errorCode = CBagStorageDevWnd::attach(); if (errorCode == ERR_NONE) { // Build our main menu list assert(_pMainList == nullptr); _pMainList = new CBofList; fillMain(); // If we're on the Mac version, slot in the Chicken Dance song if (g_engine->getPlatform() == Common::kPlatformMacintosh) g_stAudioSetting[5] = &g_chickenDance; // Bring in all our audio tracks for (int i = 0; i < (NUM_MUSICAL_SCORES - 1); i++) { if (g_stAudioSetting[i]->_pMidiTrack == nullptr) { g_stAudioSetting[i]->_pMidiTrack = new CBofSound(this, buildAudioDir(g_stAudioSetting[i]->_pszAudioFile), SOUND_MIDI | SOUND_ASYNCH | SOUND_LOOP, 32000); } } // Must have a valid backdrop by now assert(_pBackdrop != nullptr); CBofPalette *pPal = _pBackdrop->getPalette(); for (int i = 0; i < NUM_SRAFCOMPBUTT; i++) { _pButtons[i] = new CBofBmpButton; CBofBitmap *pUp = loadBitmap(buildSrafDir(g_stButtons[i]._pszUp), pPal); CBofBitmap *pDown = loadBitmap(buildSrafDir(g_stButtons[i]._pszDown), pPal); CBofBitmap *pFocus = loadBitmap(buildSrafDir(g_stButtons[i]._pszFocus), pPal); CBofBitmap *pDis = loadBitmap(buildSrafDir(g_stButtons[i]._pszDisabled), pPal); _pButtons[i]->loadBitmaps(pUp, pDown, pFocus, pDis); _pButtons[i]->create(g_stButtons[i]._pszName, g_stButtons[i]._nLeft, g_stButtons[i]._nTop, g_stButtons[i]._nWidth, g_stButtons[i]._nHeight, this, g_stButtons[i]._nID); if (i != QUIT_BUTTON) _pButtons[i]->hide(); } // Get our code words _pszGroup1Word = new CBofString(); _pszGroup2Word = new CBofString(); // Set the starting time... if (_nStartingTime == 0) { CBagVar *pVar = g_VarManager->getVariable("SRATURNCOUNT"); assert(pVar != nullptr); _nStartingTime = pVar->getNumValue(); } setOn(); show(); updateWindow(); // Finally, use our regular system cursor, not the custom ones CBagCursor::showSystemCursor(); // Bring in all the external variables restoreSraffanVars(); // Finally, if we're hallucinating, turn off the hallucination filter. CBagVar *pVar = g_VarManager->getVariable("HALLUCINATE"); if (pVar && pVar->getNumValue() > 0) { pVar->setValue(0); } } _bSrafAttached = true; _bFailureNotified = false; // No start state for dispatch screen gDispatchCurState = 0; return ERR_NONE; } ErrorCode SrafComputer::detach() { // Computer gets turned off _eMode = SC_OFF; // Get rid of the system cursor if (_bSrafAttached) { CBagCursor::hideSystemCursor(); _bSrafAttached = false; } // Remove any capture/focus CBofApp::getApp()->setCaptureControl(nullptr); CBofApp::getApp()->setFocusControl(nullptr); // save all the external variables saveSraffanVars(); // Delete our computer buttons for (int i = 0; i < NUM_SRAFCOMPBUTT; i++) { delete _pButtons[i]; _pButtons[i] = nullptr; } delete _pLBox; _pLBox = nullptr; // (one extra staffer, durteen) for (int i = 0; i < (NUM_STAFFERS + 1); i++) { delete _pStafferBmp[i]; _pStafferBmp[i] = nullptr; } // Get rid of our codewords... delete _pszGroup1Word; _pszGroup1Word = nullptr; delete _pszGroup2Word; _pszGroup2Word = nullptr; delete _pMainList; _pMainList = nullptr; // The attach method will restore the state of the dispatched teams..., // we can trash that info here. delete _pTeamList; _pTeamList = nullptr; CBagStorageDevWnd::detach(); return ERR_NONE; } void SrafComputer::onLButtonUp(uint32 /*nFlags*/, CBofPoint */*xPoint*/, void *) { } void SrafComputer::onLButtonDown(uint32 /*nFlags*/, CBofPoint */*xPoint*/, void *) { } void SrafComputer::onKeyHit(uint32 lKey, uint32 nRepCount) { switch (lKey) { case BKEY_BACK: // Temporary, go back to main screen. deleteListBox(); _eCurScreen = SC_MAIN; break; case BKEY_ALT_q: // Don't allow a quit from the sraf computer. //quit(); break; case ' ': // Increment turn count each time screen is updated. incrementTurnCount(); break; default: CBagStorageDevWnd::onKeyHit(lKey, nRepCount); break; } } void SrafComputer::onBofButton(CBofObject *pObject, int nState) { assert(isValidObject(this)); assert(pObject != nullptr); // Count a turn if we have been clicked // Mouse downs on button clicks were causing too many weird // problems with meeting results... so get rid of them. CBofButton *pButton = (CBofButton *)pObject; switch (_eCurScreen) { case SC_MAIN: onButtonMainScreen(pButton, nState); break; case SC_DEAL: onButtonDealSummary(pButton, nState); break; case SC_BIDS: onButtonBuyerBids(pButton, nState); break; case SC_BACKGROUND_DATA: onButtonDealBackground(pButton, nState); break; case SC_SELLER_BIOS: onButtonSellerBios(pButton, nState); break; case SC_OTHER_BIOS: onButtonOtherBios(pButton, nState); break; case SC_STAFF_BIOS: onButtonStaffBios(pButton, nState); break; case SC_DISPATCH: onButtonDispatchTeam(pButton, nState); break; case SC_EMAIL: onButtonCurrentEMail(pButton, nState); break; case SC_AUDIO: onButtonAudioSettings(pButton, nState); break; case SC_ORDER: onButtonRoboButler(pButton, nState); break; case SC_CHECK_TEAMS: onButtonCheckTeams(pButton, nState); break; case SC_CODE_WORDS: onButtonCodeWords(pButton, nState); break; default: break; } } void SrafComputer::setOn() { _eMode = SC_ON; activateMainScreen(); } void SrafComputer::setOff() { if (_eMode != SC_OFF) { _eMode = SC_OFF; _pButtons[QUIT_BUTTON]->hide(); _pButtons[OFF_BUTTON]->hide(); _pButtons[ON_BUTTON]->show(); setFocus(); } deleteListBox(); invalidateRect(&gCompDisplay); updateWindow(); } void SrafComputer::setQuit() { close(); } ErrorCode SrafComputer::createListBox() { ErrorCode errorCode = ERR_NONE; if (_pLBox == nullptr) { // We need to create one _pLBox = new CBofListBox; errorCode = _pLBox->create("ListBox", &gCompDisplay, this); if (errorCode != ERR_NONE) { return errorCode; } } _pLBox->setPointSize(_nListPointSize); _pLBox->setItemHeight(_nListItemHeight); _pLBox->setTextColor(_cTextColor); _pLBox->setHighlightColor(_cTextHiliteColor); _pLBox->setFont(FONT_MONO); _pLBox->setFocus(); return errorCode; } void SrafComputer::deleteListBox() { if (_pLBox) { _pLBox->deleteAll(); // Clears all in the text box } } void SrafComputer::fillMain() { int i = 0; while (i < NUM_MAIN_ITEMS) { SrafCompItem *pCompItem = new SrafCompItem(); pCompItem->_pItem = g_stMainItems[i]; _pMainList->addToTail(*pCompItem); delete pCompItem; i++; } } void SrafComputer::onBofListBox(CBofObject * /*pListBox*/, int nItemIndex) { _nSelection = nItemIndex; // Do all kinds of neat things based on our current screen. switch (_eCurScreen) { case SC_MAIN: onListMainScreen(); break; case SC_DEAL: onListDealSummary(); break; case SC_BIDS: onListBuyerBids(); break; case SC_BACKGROUND_DATA: onListDealBackground(); break; case SC_SELLER_BIOS: onListSellerBios(); break; case SC_OTHER_BIOS: onListOtherBios(); break; case SC_STAFF_BIOS: onListStaffBios(); break; case SC_DISPATCH: onListDispatchTeam(); break; case SC_EMAIL: onListCurrentEMail(); break; case SC_AUDIO: onListAudioSettings(); break; case SC_ORDER: onListRoboButler(); break; case SC_CHECK_TEAMS: onListCheckTeams(); break; case SC_CODE_WORDS: onListCodeWords(); break; default: break; } incrementTurnCount(); updateWindow(); } void SrafComputer::activateDealSummary() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // Current screen is now the DEAL screen. _eCurScreen = SC_DEAL; // initialize point size and item height _nListPointSize = kBuyerBidsPointSize; _nListItemHeight = kLineItemHeight; // This screen, like most of the subscreens, will be implemented // as a text box. The only event that we care about on this screen // is a mouse down on our "Make current offer to sellers" deactivateMainScreen(); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Retrieve IRK's and QUOSH's terms CBagVar *pVar = g_VarManager->getVariable("IRKSTERMS"); if (pVar != nullptr) { g_stSellerNames[IRK4]._nAmount = pVar->getNumValue(); } pVar = g_VarManager->getVariable("QUOSHSTERMS"); if (pVar != nullptr) { g_stSellerNames[QUOSH23]._nAmount = pVar->getNumValue(); } recalcSellerSummaryList(); recalcBuyerSummaryList(); assert(_pSellerSummaryList != nullptr); assert(_pBuyerSummaryList != nullptr); // load up the main list now with our deal summary data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Populate first line of list with header sStr = "DEAL SUMMARY: Armpit III"; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Align text with others in column sStr = "COSTS"; alignAtColumn(sStr, "CURRENT TERMS", kRightColumnAlign); _pLBox->addToTail(sStr, false); // Populate the listbox with the sellers int numItems = _pSellerSummaryList->getCount(); int totalAsking = 0; char szRightCol[128]; bool bAskKnown = true; for (int i = 0; i < numItems; i++) { DealSummarySellerItem sellerItem = _pSellerSummaryList->getNodeItem(i); sStr = sellerItem._pSellerName; // Put the appropriate info in the right hand column if (sellerItem._nSellerOffer == -1) { Common::strcpy_s(szRightCol, kUnknownTermStr); bAskKnown = false; } else { Common::sprintf_s(szRightCol, "%2dgZ", sellerItem._nSellerOffer); totalAsking += sellerItem._nSellerOffer; } alignAtColumn(sStr, szRightCol, kRightColumnAlign); _pLBox->addToTail(sStr, false); } for (int i = 0; i < NUM_OTHER_PARTYS; i++) { switch (i) { case POLITICIANS: case ENVIRONMENTALISTS: sStr = g_stOtherPartys[i]._pszName; if (g_stOtherPartys[i]._nPaymentAmount == -1) { Common::strcpy_s(szRightCol, kUnknownTermStr); bAskKnown = false; } else { totalAsking += -g_stOtherPartys[i]._nPaymentAmount; Common::sprintf_s(szRightCol, "%2dgZ", -g_stOtherPartys[i]._nPaymentAmount); } alignAtColumn(sStr, szRightCol, kRightColumnAlign); _pLBox->addToTail(sStr, false); break; case SWONZA5: default: break; } } sStr = "TOTAL COSTS"; if (bAskKnown) { Common::sprintf_s(szRightCol, "%2dgZ", totalAsking); } else { Common::strcpy_s(szRightCol, kUnknownTermStr); } alignAtColumn(sStr, szRightCol, kRightColumnAlign); _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); sStr = "BUYERS"; alignAtColumn(sStr, "CURRENT OFFER", kRightColumnAlign); _pLBox->addToTail(sStr, false); // Populate the listbox with the buyers numItems = _pBuyerSummaryList->getCount(); totalAsking = 0; for (int i = 0; i < numItems; i++) { DealSummaryBuyerItem buyerItem = _pBuyerSummaryList->getNodeItem(i); sStr = buyerItem._pBuyerName; // Put the appropriate info in the right hand column, don't want it // if it's zero though. if (buyerItem._nBuyerOffer != 0) { Common::sprintf_s(szRightCol, "%2dgZ", buyerItem._nBuyerOffer); totalAsking += buyerItem._nBuyerOffer; alignAtColumn(sStr, szRightCol, kRightColumnAlign); _pLBox->addToTail(sStr, false); } } // Just take care of swonza here. // Don't even list swonza if we have not resolved his terms yet. if (g_stOtherPartys[SWONZA5]._nPaymentAmount != -1) { sStr = g_stOtherPartys[SWONZA5]._pszName; totalAsking += g_stOtherPartys[SWONZA5]._nPaymentAmount; Common::sprintf_s(szRightCol, "%2dgZ", g_stOtherPartys[SWONZA5]._nPaymentAmount); alignAtColumn(sStr, szRightCol, kRightColumnAlign); _pLBox->addToTail(sStr, false); } // Update the asking with the bribes sStr = "TOTAL OFFER PRICE "; Common::sprintf_s(szRightCol, "%2dgZ", totalAsking); alignAtColumn(sStr, szRightCol, kRightColumnAlign); _pLBox->addToTail(sStr, false); // Show list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[SUBMIT_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::activateBuyerBids() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // Current screen is now the BIDS screen. _eCurScreen = SC_BIDS; // initialize point size and item height _nListPointSize = kBuyerBidsPointSize; _nListItemHeight = kLineItemHeight; // This screen, like most of the subscreens, will be implemented // as a text box. The only event that we care about on this screen // is a mouse down on our "Make current offer to sellers" deactivateMainScreen(); // Load up the main list now with our bid data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Put up the column header sStr = kBuyerBidsHeaderStr; _pLBox->addToTail(sStr, false); // Walk through the grid and build individual strings and add to the list. for (int i = 0; i < NUM_BUYERS; i++) { sStr = buildBidString(i); _pLBox->addToTail(sStr, false); if (g_stBuyerBids[i]._bAccept) { _pLBox->setTextLineColor(i + 1, _cTextLineColor); } } sStr = " "; _pLBox->addToTail(sStr, false); sStr = kBuyerBidsMessage1; _pLBox->addToTail(sStr, false); sStr = kBuyerBidsMessage2; _pLBox->addToTail(sStr, false); // Show the list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[DISPLAY_KEY_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); } CBofString &SrafComputer::buildBidString(int index) { char szRightCol[256]; gBidStr = g_stBuyerBids[index]._pszName; for (int j = 0; j < NUM_MINERALS; j++) { // Don't display zeroes. if (g_stBuyerBids[index]._nMineralVal[j] == 0) { Common::strcpy_s(szRightCol, " "); } else { Common::sprintf_s(szRightCol, "%2d", g_stBuyerBids[index]._nMineralVal[j]); } alignAtColumn(gBidStr, szRightCol, kFirstMineralColumn + j * kMineralColWidth); } Common::strcpy_s(szRightCol, (g_stBuyerBids[index]._bAccept ? "[X]" : "[ ]")); alignAtColumn(gBidStr, szRightCol, kFirstMineralColumn + NUM_MINERALS * kMineralColWidth + 2); return gBidStr; } void SrafComputer::activateDealBackground() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); _eCurScreen = SC_BACKGROUND_DATA; sStr = buildSrafDir("SRAFDEAL.TXT"); displayTextScreen(sStr); } void SrafComputer::hideAllButtons() { assert(isValidObject(this)); for (int i = 0; i < NUM_SRAFCOMPBUTT; i++) { if (_pButtons[i] != nullptr) { _pButtons[i]->hide(); } } } void SrafComputer::activateSellerBios() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // Current screen is now the SELLER BIOS screen. _eCurScreen = SC_SELLER_BIOS; // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = 20; // Get rid of the main screen, who needs it anyway!!! deactivateMainScreen(); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Load up the main list now with our deal summary data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Populate first line of list with header sStr = "SELLER BIOGRAPHIES"; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Populate the listbox with the staff names for (int i = 0; i < NUM_SELLERS; i++) { sStr = g_stSellerNames[i]._pszName; _pLBox->addToTail(sStr, false); } // Show list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::activateOtherBios() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // Current screen is now the OTHER BIOS screen. _eCurScreen = SC_OTHER_BIOS; // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = 20; // Get rid of the main screen, who needs it anyway!!! deactivateMainScreen(); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Load up the main list now with our deal summary data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Populate first line of list with header sStr = "OTHER BIOGRAPHIES"; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Populate the listbox with the other names for (int i = 0; i < NUM_OTHER_PARTYS; i++) { sStr = g_stOtherPartys[i]._pszName; _pLBox->addToTail(sStr, false); } // Show list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::activateStaffBios() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // Current screen is now the STAFF BIOS screen. _eCurScreen = SC_STAFF_BIOS; // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = 20; // Get rid of the main screen, who needs it anyway!!! deactivateMainScreen(); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Load up the main list now with our deal summary data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Populate first line of list with header sStr = "STAFF BIOGRAPHIES"; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Populate the listbox with the staff names for (int i = 0; i < NUM_STAFFERS; i++) { sStr = g_staffers[i]._pszStafferName; _pLBox->addToTail(sStr, false); } // Show list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::activateDispatchTeam() { // Current screen is now the DISPATCH screen. _eCurScreen = SC_DISPATCH; // initialize point size and item height _nListPointSize = kBuyerBidsPointSize; _nListItemHeight = kLineItemHeight; // This screen, like most of the subscreens, is implemented as a text box. deactivateMainScreen(); // Load up the main list now with our bid data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } recalcDispatchList(gDispatchCurState); // Show the list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[DISPATCH_TEAM_BUTTON]->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->paint(); _pButtons[DISPATCH_TEAM_BUTTON]->paint(); _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::recalcDispatchList(int mExpansionFlag) { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); char szRightCol[256]; bool bDone = false; int nListEntries = 0; const char *pMeetWith[3] = { "A Seller", "A Buyer", "Other Interested Party" }; int nMeetWithEntries = 3; bool baddToTail = true; int nSkipped = 0; // Put up the column header and a blank line sStr = kDispatchHeaderStr; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Keep track of the currently expanded state gDispatchCurState = mExpansionFlag; // Figure out how big our list will be switch (mExpansionFlag) { case mSellersExpanded: case mOthersExpanded: case 0: nListEntries = NUM_STAFFERS; break; case mBuyersExpanded: nListEntries = NUM_BUYERS - MIN_MART_ENTRIES + 3; break; } // Walk through the grid and build individual strings and add to the list. int i = 0; while (!bDone) { // First line is a special case... if any of the lists are expanded, then // start with that for a header. sStr = " "; switch (mExpansionFlag) { case 0: if (i < nMeetWithEntries) sStr += pMeetWith[i]; break; case mSellersExpanded: switch (i) { case 0: sStr += pMeetWith[0]; break; case NUM_SELLERS + 1: sStr += pMeetWith[1]; break; case NUM_SELLERS + 2: sStr += pMeetWith[2]; break; default: if (i <= NUM_SELLERS) { // Only include those that are not being met with already. if (g_stSellerNames[i - 1]._bAvailable == true) { sStr += "[ ] "; sStr += g_stSellerNames[i - 1]._pszName; if (g_stSellerNames[i - 1]._bMeetWith) { sStr.replaceCharAt(kStandardIndentation + 1, kCheckMark); } } else { baddToTail = false; } } } break; case mBuyersExpanded: switch (i) { case 0: case 1: sStr += pMeetWith[i]; break; case NUM_BUYERS - MIN_MART_ENTRIES + 2: sStr += pMeetWith[2]; break; default: // Don't display the min mart entries, there's really no reason to // show them. // щnly include those that are not being met with already. if (g_stBuyerBids[i - 2]._bAvailable == true) { if (i <= (NUM_BUYERS - MIN_MART_ENTRIES + 1)) { sStr += "[ ] "; sStr += g_stBuyerBids[i - 2]._pszName; if (g_stBuyerBids[i - 2]._bMeetWith) { sStr.replaceCharAt(kStandardIndentation + 1, kCheckMark); } } } else { baddToTail = false; } } break; case mOthersExpanded: switch (i) { case 0: case 1: case 2: sStr += pMeetWith[i]; break; default: if (i <= NUM_OTHER_PARTYS + 2) { if (g_stOtherPartys[i - 3]._bAvailable == true) { sStr += "[ ] "; sStr += g_stOtherPartys[i - 3]._pszName; if (g_stOtherPartys[i - 3]._bMeetWith) { sStr.replaceCharAt(kStandardIndentation + 1, kCheckMark); } } else { baddToTail = false; } } } break; } // Add the right hand column if (baddToTail == true) { if ((i - nSkipped) < NUM_STAFFERS) { Common::strcpy_s(szRightCol, g_staffers[i - nSkipped]._pszStafferName); alignAtColumn(sStr, szRightCol, kTeamMemberColumn); Common::strcpy_s(szRightCol, (g_staffers[i - nSkipped]._bAvailable ? "YES" : "NO ")); alignAtColumn(sStr, szRightCol, kTeamAvailableColumn); Common::strcpy_s(szRightCol, (g_staffers[i - nSkipped]._bOnCurrentTeam ? "[X]" : "[ ]")); alignAtColumn(sStr, szRightCol, kTeamIncludeColumn - 1); } _pLBox->addToTail(sStr, false); } else { nSkipped++; } baddToTail = true; // Find out if we're done i++; if ((i - nSkipped) >= nListEntries) { bDone = true; } } // Include our footer in this list sStr = ""; _pLBox->addToTail(sStr, false); sStr = kDispatchFooterStr1; _pLBox->addToTail(sStr, false); sStr = kDispatchFooterStr2; _pLBox->addToTail(sStr, false); sStr = kDispatchFooterStr3; _pLBox->addToTail(sStr, false); sStr = kDispatchFooterStr4; _pLBox->addToTail(sStr, false); sStr = kDispatchFooterStr5; _pLBox->addToTail(sStr, false); } void SrafComputer::activateCurrentEMail() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); char szRightCol[256]; // Current screen is now the EMAIL screen. _eCurScreen = SC_EMAIL; // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = kLineItemHeight; // This screen, like most of the subscreens, will be implemented // as a text box. The only event that we care about on this screen // is a mouse down on our "Make current offer to sellers" deactivateMainScreen(); // load up the main list now with our bid data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Put up the column header and a blank line sStr = kEmailHeaderStr; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Walk through the grid and build individual strings and add to the list. for (int i = 0; i < NUM_MAIL_MESSAGES; i++) { sStr = g_stEmailMessages[i]._pszMessageSubj; Common::strcpy_s(szRightCol, g_stEmailMessages[i]._pszMessageFrom); alignAtColumn(sStr, szRightCol, kMessageFromColumn); Common::strcpy_s(szRightCol, g_stEmailMessages[i]._pszMessageTo); alignAtColumn(sStr, szRightCol, kMessageToColumn); _pLBox->addToTail(sStr, false); } // Show the list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::activateAudioSettings() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // current screen is now the AUDIO screen. _eCurScreen = SC_AUDIO; // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = kLineItemHeight; // This screen, like most of the subscreens, will be implemented // as a text box. The only event that we care about on this screen // is a mouse down on our "Make current offer to sellers" deactivateMainScreen(); // Load up the main list now with our bid data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Put up the column header and a blank line sStr = kAudioHeaderStr; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Walk through the titles and build the list char szRightCol[256]; for (int i = 0; i < NUM_MUSICAL_SCORES; i++) { sStr = g_stAudioSetting[i]->_pszTitle; Common::strcpy_s(szRightCol, g_stAudioSetting[i]->_pszAuthor); alignAtColumn(sStr, szRightCol, kAudioAuthorCol); Common::strcpy_s(szRightCol, g_stAudioSetting[i]->_pszPlanet); alignAtColumn(sStr, szRightCol, kAudioPlanetCol); _pLBox->addToTail(sStr, false); } // Show the list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); // Only show the no music button if music is playing. bool bAnythingPlaying = CBofSound::midiSoundPlaying(); if (bAnythingPlaying) { _pButtons[NO_MUSIC_BUTTON]->show(); } _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::activateRoboButler() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); char szRightCol[256]; // Current screen is now the robobutler screen. _eCurScreen = SC_ORDER; // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = kLineItemHeight; // This screen, like most of the subscreens, will be implemented // as a text box. The only event that we care about on this screen // is a mouse down on our "Make current offer to sellers" deactivateMainScreen(); // Load up the main list now with our bid data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Put up the column header and a blank line sStr = kRobobutlerHeaderStr; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); // Walk through the titles and build the list for (int i = 0; i < NUM_OFFERINGS; i++) { sStr = g_stOfferings[i]._pszType; Common::strcpy_s(szRightCol, g_stOfferings[i]._pszOffering); alignAtColumn(sStr, szRightCol, kRobobutlerCol); _pLBox->addToTail(sStr, false); } // Show the list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); doShowChowButtons(); updateWindow(); } void SrafComputer::doShowChowButtons() { // Only list this stuff if it has not already been ordered. bool bAllowBeverage = true; bool bAllowSnack = true; CBagStorageDev *pSDev = g_SDevManager->getStorageDevice("INV_WLD"); if (pSDev) { CBagObject *pBevObj = pSDev->getObject("SZTB", true); CBagObject *pSnackObj = pSDev->getObject("SZTA", true); if (pSnackObj) { bAllowSnack = false; } if (pBevObj) { bAllowBeverage = false; } } if (bAllowBeverage) { _pButtons[ORDER_BEVERAGE_BUTTON]->show(); } else { _pButtons[ORDER_BEVERAGE_BUTTON]->hide(); } if (bAllowSnack) { _pButtons[ORDER_SNACK_BUTTON]->show(); } else { _pButtons[ORDER_SNACK_BUTTON]->hide(); } } void SrafComputer::activateCheckTeams() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); char szAttendeesBuff[256]; szAttendeesBuff[0] = '\0'; CBofString aStr(szAttendeesBuff, 256); // Current screen is now the Check teams screen. _eCurScreen = SC_CHECK_TEAMS; // initialize point size and item height // // Set this stuff to a tiny point size so that it won't flow over the // right hand side of the screen. _nListPointSize = kBuyerBidsPointSize; _nListItemHeight = kLineItemHeight; // This screen, like most of the subscreens, will be implemented // as a text box. The only event that we care about on this screen // is a mouse down on our "Make current offer to sellers" deactivateMainScreen(); // Load up the main list now with our bid data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Put up the column header and a blank line sStr = kCheckTeamHeaderStr1; _pLBox->addToTail(sStr, false); sStr = kCheckTeamHeaderStr2; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); int numItems = (_pTeamList == nullptr ? 0 : _pTeamList->getCount()); // Walk through the list and build individual strings and add to the list. int nNumAttendees = 0; int nMaxNumAttendees = 0; for (int i = 0; i < numItems; i++) { DispatchedTeamItem teamListItem = _pTeamList->getNodeItem(i); // Figure out who they are meeting with... if (teamListItem._nFlags & mOtherParty) { sStr = g_stOtherPartys[teamListItem._nMeetWithID]._pszName; } else if (teamListItem._nFlags & mBuyer) { sStr = g_stBuyerBids[teamListItem._nMeetWithID]._pszName; } else { sStr = g_stSellerNames[teamListItem._nMeetWithID]._pszName; } // List the dispatch time char szRightCol[256]; Common::sprintf_s(szRightCol, "%02d:%02d", teamListItem._nDispatchTime / 100, teamListItem._nDispatchTime % 100); alignAtColumn(sStr, szRightCol, kCheckTeamTimeCol); // Now build the list of attendees. bool bFirstAttendee = true; int mFlag = 0; // Count number of attendees first, this will help us format our list for (int j = 0; j < NUM_STAFFERS; j++) { switch (j) { case 0: mFlag = mNorg72; break; case 1: mFlag = mPnurth81; break; case 2: mFlag = mZig64; break; case 3: mFlag = mLentil24; break; case 4: mFlag = mVargas20; break; case 5: mFlag = mChurg53; break; } if (teamListItem._nFlags & mFlag) { nNumAttendees++; } } for (int j = 0; j < NUM_STAFFERS; j++) { switch (j) { case 0: mFlag = mNorg72; break; case 1: mFlag = mPnurth81; break; case 2: mFlag = mZig64; break; case 3: mFlag = mLentil24; break; case 4: mFlag = mVargas20; break; case 5: mFlag = mChurg53; break; } if (teamListItem._nFlags & mFlag) { if (bFirstAttendee) { aStr = g_staffers[j]._pszStafferName; bFirstAttendee = false; } else { aStr += ", "; aStr += g_staffers[j]._pszStafferName; } } } // save high water mark. if (nNumAttendees > nMaxNumAttendees) { nMaxNumAttendees = nNumAttendees; } nNumAttendees = 0; alignAtColumn(sStr, szAttendeesBuff, kCheckTeamStaffCol); _pLBox->addToTail(sStr, false); } // Decrease point size if we got too much for one screen if (nMaxNumAttendees > 4) { _nListPointSize = kOtherPointSize; _nListItemHeight = kLineItemHeight; _pLBox->setPointSize(_nListPointSize); _pLBox->setItemHeight(_nListItemHeight); } // Display the current time... sStr = " "; _pLBox->addToTail(sStr, false); // Add a dummy line so we can overwrite it with the current turncount. sStr = " "; _pLBox->addToTail(sStr, false); int nLineNo = _pLBox->getNumItems(); displayTurnCount(nLineNo - 1); sStr = " "; _pLBox->addToTail(sStr, false); #define kCheckSuccessfulNegotiations "SUCCESSFUL NEGOTIATIONS: " #define kCheckUnsuccessfulNegotiations "UNSUCCESSFUL NEGOTIATIONS: " // Add a few lines indicating who has succeeded and who has failed. char szGoodMeetings[256]; char szBadMeetings[256]; CBofString sGoodMeetings(szGoodMeetings, 256); CBofString sBadMeetings(szBadMeetings, 256); bool bSFirstTime = true; bool bUFirstTime = true; sGoodMeetings = ""; sBadMeetings = ""; for (int i = 0; i < NUM_SELLERS; i++) { if (g_stSellerNames[i]._nMeetingResult != SRAF_NO_MEETING) { if (g_stSellerNames[i]._nMeetingResult == SRAF_GOOD_MEETING) { if (bSFirstTime == true) { bSFirstTime = false; } else { sGoodMeetings += ", "; } sGoodMeetings += g_stSellerNames[i]._pszName; } else { if (bUFirstTime == true) { bUFirstTime = false; } else { sBadMeetings += ", "; } sBadMeetings += g_stSellerNames[i]._pszName; } } } // Scan the buyers for meetings for (int i = 0; i < NUM_BUYERS; i++) { if (g_stBuyerBids[i]._nMeetingResult != SRAF_NO_MEETING) { if (g_stBuyerBids[i]._nMeetingResult == SRAF_GOOD_MEETING) { if (bSFirstTime == true) { bSFirstTime = false; } else { sGoodMeetings += ", "; } sGoodMeetings += g_stBuyerBids[i]._pszName; } else { if (bUFirstTime == true) { bUFirstTime = false; } else { sBadMeetings += ", "; } sBadMeetings += g_stBuyerBids[i]._pszName; } } } // Scan the other partys for meetings for (int i = 0; i < NUM_OTHER_PARTYS; i++) { if (g_stOtherPartys[i]._nMeetingResult != SRAF_NO_MEETING) { if (g_stOtherPartys[i]._nMeetingResult == SRAF_GOOD_MEETING) { if (bSFirstTime == true) { bSFirstTime = false; } else { sGoodMeetings += ", "; } sGoodMeetings += g_stOtherPartys[i]._pszName; } else { if (bUFirstTime == true) { bUFirstTime = false; } else { sBadMeetings += ", "; } sBadMeetings += g_stOtherPartys[i]._pszName; } } } // Display all this info we just calculated... sStr = kCheckSuccessfulNegotiations; _pLBox->addToTail(sStr, false); _pLBox->addToTail(sGoodMeetings, false); sStr = " "; _pLBox->addToTail(sStr, false); sStr = kCheckUnsuccessfulNegotiations; _pLBox->addToTail(sStr, false); _pLBox->addToTail(sBadMeetings, false); sStr = " "; _pLBox->addToTail(sStr, false); sStr = kCheckDispatchTeamFooter1; _pLBox->addToTail(sStr, false); sStr = kCheckDispatchTeamFooter2; _pLBox->addToTail(sStr, false); // show the list box _pLBox->show(); _pButtons[RETURN_TO_MAIN_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); } void SrafComputer::activateCodeWords() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); char szRightCol[128]; // Current screen is now the CODE WORDS screen. _eCurScreen = SC_CODE_WORDS; // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = kLineItemHeight; // Get rid of the main screen, who needs it anyway!!! deactivateMainScreen(); // Make sure we start with the correct computer background if (getBackdrop()) { paintBackdrop(); } // Load up the main list now with our deal summary data. ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); // Populate first line of list with header sStr = kCodeWordsHeader1; _pLBox->addToTail(sStr, false); sStr = kCodeWordsHeader2; _pLBox->addToTail(sStr, false); sStr = " "; _pLBox->addToTail(sStr, false); sStr = kCodeWordsHeader3; _pLBox->addToTail(sStr, false); // Populate the listbox with the staff names for (int i = 0; i < NUM_CODE_WORDS; i++) { sStr = g_stCodeWords[i]._pszCodeWord1; Common::strcpy_s(szRightCol, g_stCodeWords[i]._pszCodeWord2); alignAtColumn(sStr, szRightCol, kGroup1Col2); Common::strcpy_s(szRightCol, g_stCodeWords[i]._pszCodeWord3); alignAtColumn(sStr, szRightCol, kGroup2Col1); Common::strcpy_s(szRightCol, g_stCodeWords[i]._pszCodeWord4); alignAtColumn(sStr, szRightCol, kGroup2Col2); _pLBox->addToTail(sStr, false); } // Blank line and add to end sStr = " "; _pLBox->addToTail(sStr, false); sStr = "CODE uint16 PAIR: (,)"; _pLBox->addToTail(sStr, false); // Show list box _pLBox->show(); // Use the done button instead of return to main. _pButtons[DONE_BUTTON]->show(); _pButtons[QUIT_BUTTON]->hide(); updateWindow(); } void SrafComputer::initDealSummary() { // initialize the initial state of the deal summary recalcSellerSummaryList(); recalcBuyerSummaryList(); } // Allocate everything we need here... void SrafComputer::initBuyerBids() { } void SrafComputer::initDealBackground() { } void SrafComputer::initSellerBios() { } void SrafComputer::initOtherBios() { } void SrafComputer::initStaffBios() { } int SrafComputer::getMeetMember(int nListToSearch) { switch (nListToSearch) { case 0: break; case kOthersList: for (int i = 0; i < NUM_OTHER_PARTYS; i++) { if (g_stOtherPartys[i]._bMeetWith) return i; } break; case kSellersList: for (int i = 0; i < NUM_SELLERS; i++) { if (g_stSellerNames[i]._bMeetWith) return i; } break; case kBuyersList: for (int i = 0; i < NUM_BUYERS; i++) { if (g_stBuyerBids[i]._bMeetWith) return i; } break; case kStaffersList: for (int i = 0; i < NUM_STAFFERS; i++) { if (g_staffers[i]._bOnCurrentTeam) return i; } break; } return -1; } int SrafComputer::getAdjustedIndex(int nListToSearch, int nElementIndex, bool bScreenToIndex) { int nTotalNotAvail = 0; int nOrigElementIndex = nElementIndex; switch (nListToSearch) { case 0: break; case kOthersList: // Adjust for out of range. nElementIndex = (nElementIndex >= NUM_OTHER_PARTYS ? (NUM_OTHER_PARTYS - 1) : nElementIndex); for (int i = 0; i < NUM_OTHER_PARTYS; i++) { // Get all consecutive that are not available. while (i < NUM_OTHER_PARTYS && g_stOtherPartys[i]._bAvailable == false) { nTotalNotAvail++; i++; } // If we exceeded our bounds, or our counter, minus the number out is // the element index, then we're done. if (i >= NUM_OTHER_PARTYS || (i - nTotalNotAvail) >= nElementIndex) { break; } } break; case kSellersList: // Adjust for out of range. nElementIndex = (nElementIndex >= NUM_SELLERS ? (NUM_SELLERS - 1) : nElementIndex); for (int i = 0; i < NUM_BUYERS; i++) { // get all consecutive that are not available. while (i < NUM_SELLERS && g_stSellerNames[i]._bAvailable == false) { nTotalNotAvail++; i++; } // If we exceeded our bounds, or our counter, minus the number out is // the element index, then we're done. if (i >= NUM_SELLERS || (i - nTotalNotAvail) >= nElementIndex) { break; } } break; case kBuyersList: // Adjust for out of range. nElementIndex = (nElementIndex >= NUM_BUYERS ? (NUM_BUYERS - 1) : nElementIndex); for (int i = 0; i < NUM_BUYERS; i++) { // Get all consecutive that are not available. while (i < NUM_BUYERS && g_stBuyerBids[i]._bAvailable == false) { nTotalNotAvail++; i++; } // If we exceeded our bounds, or our counter, minus the number out is // the element index, then we're done. if (i >= NUM_BUYERS || (i - nTotalNotAvail) >= nElementIndex) { break; } } break; case kStaffersList: // Adjust for out of range. nElementIndex = (nElementIndex >= NUM_STAFFERS ? (NUM_STAFFERS - 1) : nElementIndex); for (int i = 0; i < NUM_STAFFERS; i++) { // Get all consecutive that are not available. while (i < NUM_STAFFERS && g_staffers[i]._bAvailable == false) { nTotalNotAvail++; i++; } // If we exceeded our bounds, or our counter, minus the number out is // the element index, then we're done. if (i >= NUM_STAFFERS || (i - nTotalNotAvail) >= nElementIndex) { break; } } break; } if (bScreenToIndex) { return nOrigElementIndex + nTotalNotAvail; } return nOrigElementIndex - nTotalNotAvail; } void SrafComputer::initDispatchTeam() { // Go through the entire list and make sure that they are all not on the // current team. for (int i = 0; i < NUM_STAFFERS; i++) { g_staffers[i]._bOnCurrentTeam = false; } for (int i = 0; i < NUM_SELLERS; i++) { g_stSellerNames[i]._bMeetWith = false; } for (int i = 0; i < NUM_BUYERS; i++) { g_stBuyerBids[i]._bMeetWith = false; } for (int i = 0; i < NUM_OTHER_PARTYS; i++) { g_stOtherPartys[i]._bMeetWith = false; } } void SrafComputer::initCurrentEMail() { } void SrafComputer::initAudioSettings() { } void SrafComputer::initRoboButler() { } void SrafComputer::onListMainScreen() { switch (_nSelection) { case DEALSUMMARY: activateDealSummary(); break; case BUYERBIDS: activateBuyerBids(); break; case DEALBACKGROUND: activateDealBackground(); break; case SELLERBIOS: activateSellerBios(); break; case OTHERBIOS: activateOtherBios(); break; case STAFFBIOS: activateStaffBios(); break; case DISPATCHTEAM: initDispatchTeam(); activateDispatchTeam(); break; case CURRENTEMAIL: activateCurrentEMail(); break; case AUDIOSETTINGS: activateAudioSettings(); break; case ROBOBUTLER: activateRoboButler(); break; case CHECKTEAMS: activateCheckTeams(); break; default: break; } _nSelection = -1; } void SrafComputer::onListDealSummary() { } void SrafComputer::onListBuyerBids() { CBofPoint cPoint = getPrevMouseDown(); // Already in local coords int index = _nSelection - 1; // Make sure that this is not out of range. if (index >= NUM_BUYERS) { return; } char szLocalBuff[256]; CBofString sStr(szLocalBuff, 256); // Calculate the text width based on the attributes of the text // rather than guessing to where they are. sStr = " ACCEPT "; CBofRect cAcceptBidRect = calculateTextRect(this, &sStr, kBuyerBidsPointSize, FONT_MONO); alignAtColumn(sStr, "", kFirstMineralColumn + NUM_MINERALS * kMineralColWidth); CBofRect cDummyRect = calculateTextRect(this, &sStr, kBuyerBidsPointSize, FONT_MONO); CBofPoint cStartPoint(cDummyRect.right, 0); cAcceptBidRect.offsetRect(cStartPoint); cAcceptBidRect.bottom = 1000; // Based on the location of the mouse determine if we should check/uncheck // the "accept bid" field or present a bio on he who was checked. if (cAcceptBidRect.ptInRect(cPoint)) { // Negate the current value g_stBuyerBids[index]._bAccept = !g_stBuyerBids[index]._bAccept; // Redraw with the new one checked/unchecked CBofString cStr = buildBidString(index); _pLBox->setText(_nSelection, cStr); if (g_stBuyerBids[index]._bAccept) { _pLBox->setTextLineColor(_nSelection, _cTextLineColor); } else { _pLBox->setTextLineColor(_nSelection, (COLORREF) - 1); // Restore default } _pLBox->repaintItem(_nSelection); } else { szLocalBuff[0] = '\0'; CBofString sStr2(szLocalBuff, 256); if (index >= 0) { sStr2 = buildSrafDir(g_stBuyerBids[index]._pszBuyerBio); displayTextScreen(sStr2); } } } void SrafComputer::onListDealBackground() { } void SrafComputer::onListSellerBios() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); if (_nSelection >= 2) { sStr = buildSrafDir(g_stSellerNames[_nSelection - 2]._pszSellerBio); displayTextScreen(sStr); } } void SrafComputer::onListOtherBios() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); if (_nSelection >= 2) { sStr = buildSrafDir(g_stOtherPartys[_nSelection - 2]._pszOtherPartyBio); displayTextScreen(sStr); } } void SrafComputer::onListStaffBios() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); if (_nSelection >= 2) { sStr = buildSrafDir(g_staffers[_nSelection - 2]._pszStafferBio); displayTextScreen(sStr); } } void SrafComputer::onListDispatchTeam() { CBofPoint cPoint = getPrevMouseDown(); // Already in local coords CBofRect cMeetWithRect(0, 0, (kTeamMemberColumn - kStandardIndentation) * kBuyerBidsPointWidth, gCompDisplay.height()); CBofRect cTeamMembersRect((kTeamMemberColumn - kStandardIndentation) * kBuyerBidsPointWidth, 0, gCompDisplay.width(), gCompDisplay.height()); char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); int nElementIndex; // First two entries in list mean nothing to us... if (_nSelection < 2) return; // Check if we're in the left hand column, if we are, then determine // if we're left of the list or in the list itself. if (cMeetWithRect.ptInRect(cPoint)) { nElementIndex = _nSelection - 3; // three header lines before data starts bool bDeleteAll = false; int nrecalcVal = 0; CBofRect cMeetBio(cMeetWithRect.left + kStandardDoubleIndentation * kBuyerBidsPointWidth, cMeetWithRect.top, cMeetWithRect.right, cMeetWithRect.bottom); CBofRect cMeetMember(0, 0, cMeetWithRect.left + kStandardDoubleIndentation * kBuyerBidsPointWidth, cMeetWithRect.bottom); int nMeetMember = -1; bool bInMeetMemberColumn = false; int nPreceedingHeaders = 0; int nListToCheck = 0; switch (gDispatchCurState) { case 0: bDeleteAll = true; nrecalcVal = (nElementIndex == -1 ? mSellersExpanded : (nElementIndex == 0 ? mBuyersExpanded : (nElementIndex == 1 ? mOthersExpanded : 0))); break; case mOthersExpanded: nListToCheck = kOthersList; // List to check nPreceedingHeaders = 2; // Buyers and sellers come before this guy... switch (nElementIndex) { case -1: bDeleteAll = true; nrecalcVal = mSellersExpanded; // Collapse list, expand sellers break; case 0: bDeleteAll = true; nrecalcVal = mBuyersExpanded; // Collapse list, expand buyers break; case 1: bDeleteAll = true; nrecalcVal = 0; // Collapse list break; default: nElementIndex -= nPreceedingHeaders; // Account for headers // Account for those guys out on meetings that we have not displayed // recalc first... nElementIndex = getAdjustedIndex(nListToCheck, nElementIndex, true); if (nElementIndex >= NUM_OTHER_PARTYS) break; if (cMeetBio.ptInRect(cPoint)) { // if so, bring up biography. sStr = buildSrafDir(g_stOtherPartys[nElementIndex]._pszOtherPartyBio); displayTextScreen(sStr); } else if (cMeetMember.ptInRect(cPoint)) { // if so, put a checkmark in that column. // Uncheck any member we already have checked, this is a singular operation nMeetMember = getMeetMember(nListToCheck); if (nMeetMember != -1 && nMeetMember < NUM_OTHER_PARTYS) { g_stOtherPartys[nMeetMember]._bMeetWith = false; } // Now put the check mark in the column for the new guy to meet if (nMeetMember != nElementIndex && nMeetMember < NUM_OTHER_PARTYS) { g_stOtherPartys[nElementIndex]._bMeetWith = true; bInMeetMemberColumn = true; } } break; } break; case mSellersExpanded: nListToCheck = kSellersList; // No headers above this guy nPreceedingHeaders = 0; if (nElementIndex == -1) { bDeleteAll = true; // Collapse list nrecalcVal = 0; } else { nElementIndex -= nPreceedingHeaders; // Account for headers // Account for those guys out on meetings that we have not displayed // recalc first... nElementIndex = getAdjustedIndex(nListToCheck, nElementIndex, true); if (nElementIndex >= NUM_SELLERS) { if (nElementIndex == (NUM_SELLERS - nPreceedingHeaders)) { bDeleteAll = true; // collapse list, expand buyers nrecalcVal = mBuyersExpanded; } if (nElementIndex == (NUM_SELLERS + 1 - nPreceedingHeaders)) { bDeleteAll = true; // collapse list, expand others nrecalcVal = mOthersExpanded; } } else if (cMeetBio.ptInRect(cPoint)) { // If so, bring up biography. sStr = buildSrafDir(g_stSellerNames[nElementIndex]._pszSellerBio); displayTextScreen(sStr); } else if (cMeetMember.ptInRect(cPoint)) { // If so, put a check mark in that column. // Uncheck any member we already have checked, this is a singular operation nMeetMember = getMeetMember(nListToCheck); if (nMeetMember != -1 && nMeetMember < NUM_SELLERS) { g_stSellerNames[nMeetMember]._bMeetWith = false; } // Now put the check mark in the column for the new guy to meet if (nMeetMember != nElementIndex && nMeetMember < NUM_SELLERS) { g_stSellerNames[nElementIndex]._bMeetWith = true; bInMeetMemberColumn = true; } } } break; case mBuyersExpanded: // recalc first... nListToCheck = kBuyersList; nPreceedingHeaders = 1; switch (nElementIndex) { case -1: bDeleteAll = true; nrecalcVal = mSellersExpanded; // Collapse list, expand sellers break; case 0: bDeleteAll = true; nrecalcVal = 0; // Collapse list break; default: nElementIndex -= nPreceedingHeaders; // Correct for other headers nElementIndex = getAdjustedIndex(nListToCheck, nElementIndex, true); if (nElementIndex >= (NUM_BUYERS - MIN_MART_ENTRIES)) { if (nElementIndex == (NUM_BUYERS - MIN_MART_ENTRIES + 1 - nPreceedingHeaders)) { bDeleteAll = true; nrecalcVal = mOthersExpanded; // Collapse list, expand others } break; } // Account for those guys out on meetings that we have not displayed if (cMeetBio.ptInRect(cPoint)) { // if so, bring up biography. sStr = buildSrafDir(g_stBuyerBids[nElementIndex]._pszBuyerBio); displayTextScreen(sStr); } else if (cMeetMember.ptInRect(cPoint)) { // if so, put a checkmark in that column. // Uncheck any member we already have checked, this is a singular operation nMeetMember = getMeetMember(nListToCheck); if (nMeetMember != -1) { g_stBuyerBids[nMeetMember]._bMeetWith = false; } // Now put the check mark in the column for the new guy to meet if (nMeetMember != nElementIndex) { g_stBuyerBids[nElementIndex]._bMeetWith = true; bInMeetMemberColumn = true; } } break; } break; } // If we have to uncheck a column, do that here. if (nMeetMember != -1) { int nThisItemAt = getAdjustedIndex(nListToCheck, nMeetMember, false) + 3 + nPreceedingHeaders; sStr = _pLBox->getText(nThisItemAt); sStr.replaceCharAt(kStandardIndentation + 1, ' '); _pLBox->setText(nThisItemAt, sStr); _pLBox->repaintItem(nThisItemAt); } // If we have a new column to check, do that here. if (bInMeetMemberColumn) { sStr = _pLBox->getText(_nSelection); sStr.replaceCharAt(kStandardIndentation + 1, kCheckMark); // ??? works fine on mac, not sure what check mark is for pc _pLBox->setText(_nSelection, sStr); _pLBox->repaintItem(_nSelection); } if (bDeleteAll) { _pLBox->deleteAll(); recalcDispatchList(nrecalcVal); _pLBox->show(); } } // Handle if we're in the right hand side of the screen. We only care about // two columns, the staff member names and the guys check boxes on the right. if (cTeamMembersRect.ptInRect(cPoint)) { nElementIndex = _nSelection - 2; // two header lines before data starts if (nElementIndex >= 0 && nElementIndex < NUM_STAFFERS) { CBofRect cStaffNames(cTeamMembersRect.left + kStandardIndentation * kBuyerBidsPointWidth, cTeamMembersRect.top, cTeamMembersRect.left + (kStandardIndentation + kMaxStafferNameLen) * kBuyerBidsPointWidth + 60, cTeamMembersRect.bottom); CBofRect cStaffInclude((kTeamIncludeColumn - kStandardIndentation) * kBuyerBidsPointWidth, cTeamMembersRect.top, cTeamMembersRect.right, cTeamMembersRect.bottom); // If in the staff names column, then show the biography if (cStaffNames.ptInRect(cPoint)) { sStr = buildSrafDir(g_staffers[nElementIndex]._pszStafferBio); displayTextScreen(sStr); } else { // if in the "include on team" column, then handle appropriately if (cStaffInclude.ptInRect(cPoint)) { // Make sure that this dude is available if (g_staffers[nElementIndex]._bAvailable) { char cNewChar = ' '; if (g_staffers[nElementIndex]._bOnCurrentTeam == false) { cNewChar = kCheckMark; } // Negate g_staffers[nElementIndex]._bOnCurrentTeam = !g_staffers[nElementIndex]._bOnCurrentTeam; sStr = _pLBox->getText(_nSelection); sStr.replaceCharAt(kTeamIncludeColumn, cNewChar); _pLBox->setText(_nSelection, sStr); _pLBox->repaintItem(_nSelection); } } } } } } void SrafComputer::onListCurrentEMail() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); if (_nSelection >= 2) { sStr = buildSrafDir(g_stEmailMessages[_nSelection - 2]._pszMessageFile); displayTextScreen(sStr); } } void SrafComputer::onListAudioSettings() { int nTrackSelection = _nSelection - 2; // Reject out of range selections if (nTrackSelection < 0 || nTrackSelection >= NUM_MUSICAL_SCORES) { return; } // Start the new track (will stop any track playing) // // Add a selection for random play. if (g_stAudioSetting[nTrackSelection]->_pszAudioFile == nullptr) { _bRandomAudio = true; CBagVar *pVar = g_VarManager->getVariable("SRATURNCOUNT"); _nRandomTime = pVar->getNumValue(); nTrackSelection = g_engine->getRandomNumber() % (NUM_MUSICAL_SCORES - 1); } else { _bRandomAudio = false; } // Now start playing... if (g_stAudioSetting[nTrackSelection]->_pMidiTrack != nullptr) { g_stAudioSetting[nTrackSelection]->_pMidiTrack->play(); } // If state changes, then change the button also bool bAnythingPlaying = CBofSound::midiSoundPlaying(); if (bAnythingPlaying) { _pButtons[NO_MUSIC_BUTTON]->show(); } else { _pButtons[NO_MUSIC_BUTTON]->hide(); } } void SrafComputer::onListRoboButler() { int nSelection = _nSelection - 2; if (nSelection < 0 || nSelection >= NUM_OFFERINGS) { return; } char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); sStr = buildSrafDir(g_stOfferings[nSelection]._pszFile); displayTextScreen(sStr); } // Here are the constants that define how strong a team must be in order // to succeed with any given buyer, seller or other interested party // // Here's the negotiating constant associated with each... // // Norg-72 1 // Pnurth-81 3 // Zig-64 6 // Lentil-24 5 (double this when sent alone) // Vargas-20 10 // Churg-53 5 #define YEEF8_REQUIRED_TEAM_STRENGTH 10 #define SINJIN11_REQUIRED_TEAM_STRENGTH 12 #define GUNG14_REQUIRED_TEAM_STRENGTH 13 #define GILD13_REQUIRED_TEAM_STRENGTH 14 #define DORK44_REQUIRED_TEAM_STRENGTH 11 bool SrafComputer::reportMeetingStatus(int nTeamNumber) { const char *pszFailureFile = nullptr; const char *pszSuccessFile = nullptr; bool bDone = false; int nTeamCaptain = 0; char szLocalResponse[256]; szLocalResponse[0] = '\0'; CBofString sResponse(szLocalResponse, 256); bool bTimeElapsed = true; bool bNeedRedraw = false; // If the text screen is frontmost, then don't report meeting status if (gTextScreenFrontmost == true) { return bNeedRedraw; } // Could possibly have no list established. if (_pTeamList == nullptr) { return bNeedRedraw; } int numItems = _pTeamList->getCount(); // Handle out of range case first. if (nTeamNumber < 0 || nTeamNumber >= numItems) { return bNeedRedraw; } DispatchedTeamItem teamListItem = _pTeamList->getNodeItem(nTeamNumber); // Start by counting the number of team members. Count up how powerful this team // is in terms of negotiating strength. int nTeamStrength = 0; int nTeamMembers = 0; for (int i = 0; i < NUM_STAFFERS; i++) { if ((1 << (i + 3)) & teamListItem._nFlags) { nTeamMembers++; nTeamStrength += g_staffers[i]._nNegotiatingStrength; } } // Get the current time... CBagVar *pVar = g_VarManager->getVariable("SRATURNCOUNT"); assert(pVar != nullptr); int nCurTime = pVar->getNumValue(); // If less then 5 turns have elapsed, then we're still in the driving stage... if ((teamListItem._nDispatchTime + kDrivingTime) >= nCurTime) { bDone = true; bTimeElapsed = false; if (teamListItem._nFlags & mStafferMale) { if (nTeamMembers == 1) { pszFailureFile = kGSM21SraMaleStr; } else { pszFailureFile = kGSM22SraMaleStr; } } else if (nTeamMembers == 1) { pszFailureFile = kGSM21SraFemStr; } else { pszFailureFile = kGSM22SraFemStr; } } // Meeting not done yet, let 'em know it. if (bDone == false) { if (teamListItem._nDispatchTime + teamListItem._nMeetingTime > pVar->getNumValue()) { bDone = true; bTimeElapsed = false; if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM19SraMaleStr; } else { pszFailureFile = kGSM19SraFemStr; } } } // If Swonza has already been enlightened to the plans for the planet, // then reject this meeting right away. if (bDone == false) { if (_bSwonzaEnlightened && (teamListItem._nFlags & mOtherParty) && teamListItem._nMeetWithID == SWONZA5) { bDone = true; if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM18SraMaleStr; } else { pszFailureFile = kGSM18SraFemStr; } } } // Need to have a driver, {Norg, Zig and Lentil} if (bDone == false) { if (!((teamListItem._nFlags & mNorg72) || (teamListItem._nFlags & mZig64) || (teamListItem._nFlags & mLentil24))) { bDone = true; if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM6SraMaleStr; } else { pszFailureFile = kGSM6SraFemStr; } } } // Now handle all the resultant cases, get rid of the easy ones first. // // - Norg and Lentil can't work together, automatic failure // - Need to have a driver, {Norg, Zig and Lentil} // - Need to have someone who can hold their voltage {Norg, Lentil and Churg} // - Pnurth must be teamed up with Lentil, Vargas or Churg (still learning) // - Need a good negotiator Norg (1), Pnurth (3), Zig (6), Lentil (8), (4) // when with someone else, Vargas (10), Churg (5) // // There are many more cases, which we'll handle as they come up. // Norg and Lentil can't work together, automatic failure if ((bDone == false) && (teamListItem._nFlags & mNorg72) && (teamListItem._nFlags & mLentil24)) { bDone = true; if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM8SraMaleStr; } else { pszFailureFile = kGSM8SraFemStr; } } // Need to have someone who can hold their voltage {Norg, Lentil and Churg} if ((bDone == false) && !((teamListItem._nFlags & mNorg72) || (teamListItem._nFlags & mLentil24) || (teamListItem._nFlags & mChurg53))) { bDone = true; if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM7SraMaleStr; } else { pszFailureFile = kGSM7SraFemStr; } } // - Pnurth must be teamed up with Lentil, Vargas or Churg (still learning) if ((bDone == false) && (teamListItem._nFlags & mPnurth81) && !((teamListItem._nFlags & mLentil24) || (teamListItem._nFlags & mVargas20) || (teamListItem._nFlags & mChurg53))) { bDone = true; if (teamListItem._nFlags & mStafferMale) { if (nTeamMembers == 1) { pszFailureFile = kGSM20SraMaleStr; } else { pszFailureFile = kGSM15SraMaleStr; } } else if (nTeamMembers == 1) { pszFailureFile = kGSM20SraFemStr; } else { pszFailureFile = kGSM15SraFemStr; } } if (!bDone) { // Special rule, if lentil is on her own, then she is twice as effective. if (nTeamMembers == 1 && (teamListItem._nFlags & mLentil24)) { nTeamStrength *= 2; } if (teamListItem._nFlags & mOtherParty) { switch (teamListItem._nMeetWithID) { case SWONZA5: // Swonza-5 is a sucker, but Norg is not trustworthy, so if he tells, then // the flashback is over, well, not really, but it can't be won without // Swonza-5 on board. if (teamListItem._nFlags & mNorg72) { _bSwonzaEnlightened = true; if (nTeamMembers == 1) { pszFailureFile = kGSM17SraMaleStr; } else if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM16SraMaleStr; } else { pszFailureFile = kGSM16SraFemStr; } } else { // Update the other party bids... g_stOtherPartys[SWONZA5]._nPaymentAmount = 20; if (teamListItem._nFlags & mStafferMale) { pszSuccessFile = kGSM9SraMaleStr; } else { pszSuccessFile = kGSM9SraFemStr; } } break; case POLITICIANS: // Need to have either vargas or pnurth on this team if ((teamListItem._nFlags & mVargas20) || (teamListItem._nFlags & mPnurth81)) { if (teamListItem._nFlags & mStafferMale) { pszSuccessFile = kGSM11SraMaleStr; } else { pszSuccessFile = kGSM11SraFemStr; } // Update the other party bids... g_stOtherPartys[POLITICIANS]._nPaymentAmount = -15; } else if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM5SraMaleStr; } else { pszFailureFile = kGSM5SraFemStr; } break; case ENVIRONMENTALISTS: // Need to have either lentil or pnurth on this team if ((teamListItem._nFlags & mLentil24) || (teamListItem._nFlags & mPnurth81)) { if (teamListItem._nFlags & mStafferMale) { pszSuccessFile = kGSM12SraMaleStr; } else { pszSuccessFile = kGSM12SraFemStr; } // Update the other party bids... g_stOtherPartys[ENVIRONMENTALISTS]._nPaymentAmount = -2; } else if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM5SraMaleStr; } else { pszFailureFile = kGSM5SraFemStr; } break; default: assert(false); } } if (pszFailureFile == nullptr && (teamListItem._nFlags & mBuyer)) { int nRequiredStrength = 0; int nTalkedUpAmount1 = 0, nTalkedUpAmount2 = 0; int nMineralID1 = 0, nMineralID2 = 0; switch (teamListItem._nMeetWithID) { case SINJIN11: // Can up structures from 5 to (7gZ) nRequiredStrength = SINJIN11_REQUIRED_TEAM_STRENGTH; nTalkedUpAmount1 = kSinjinTalkedUpAmount; nMineralID1 = kSinjinMineralID; // fallthrough case GUNG14: // This guy can be talked up by a good negotiating team to (8gZ) if (nRequiredStrength == 0) { nRequiredStrength = GUNG14_REQUIRED_TEAM_STRENGTH; nTalkedUpAmount1 = kGungTalkedUpAmount; nMineralID1 = kGungMineralID; } // fallthrough case GILD13: // Gild can be talked up on zinc from 6 to 11 and on // platinum from 4 to 6 if (nRequiredStrength == 0) { nRequiredStrength = GILD13_REQUIRED_TEAM_STRENGTH; nTalkedUpAmount1 = kGildTalkedUpAmount1; nMineralID1 = kGildMineralID1; nTalkedUpAmount2 = kGildTalkedUpAmount2; nMineralID2 = kGildMineralID2; } // fallthrough case DORK44: { // Negotiating team must be at least half female. if (teamListItem._nMeetWithID == DORK44) { int nMale = 0; int nFemale = 0; for (int k = 0; k < NUM_STAFFERS; k++) { switch (k) { case 0: nMale += (teamListItem._nFlags & mNorg72) ? 1 : 0; break; case 1: nFemale += (teamListItem._nFlags & mPnurth81) ? 1 : 0; break; case 2: nFemale += (teamListItem._nFlags & mZig64) ? 1 : 0; break; case 3: nFemale += (teamListItem._nFlags & mLentil24) ? 1 : 0; break; case 4: nMale += (teamListItem._nFlags & mVargas20) ? 1 : 0; break; case 5: nMale += (teamListItem._nFlags & mChurg53) ? 1 : 0; break; } } if (nFemale < nMale) { if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM23SraMaleStr; } else { pszFailureFile = kGSM23SraFemStr; } bDone = true; break; } } // Dork's uptite bid can be upped from 4 to 8 if a negotiating // team visits him. if (nRequiredStrength == 0) { nRequiredStrength = DORK44_REQUIRED_TEAM_STRENGTH; nTalkedUpAmount1 = kDorkTalkedUpAmount; nMineralID1 = kDorkMineralID; } // These 4 guys can all be talked up // // If they've already been talked up, then fail. if (nTeamStrength >= nRequiredStrength && g_stBuyerBids[teamListItem._nMeetWithID]._nMineralVal[nMineralID1] != nTalkedUpAmount1) { int nDiff1 = nTalkedUpAmount1 - g_stBuyerBids[teamListItem._nMeetWithID]._nMineralVal[nMineralID1]; int nDiff2 = nTalkedUpAmount2 - g_stBuyerBids[teamListItem._nMeetWithID]._nMineralVal[nMineralID2]; // Set new values in the buyer bids static g_stBuyerBids[teamListItem._nMeetWithID]._nMineralVal[nMineralID1] = (int16)nTalkedUpAmount1; g_stBuyerBids[teamListItem._nMeetWithID]._nBidSum += nDiff1; if (nTalkedUpAmount2) { g_stBuyerBids[teamListItem._nMeetWithID]._nMineralVal[nMineralID2] = (int16)nTalkedUpAmount2; g_stBuyerBids[teamListItem._nMeetWithID]._nBidSum += nDiff2; } // Determine the voice file to give back... if (teamListItem._nFlags & mStafferMale) { pszSuccessFile = kGSM4SraMaleStr; } else { pszSuccessFile = kGSM4SraFemStr; } } else if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM5SraMaleStr; } else { pszFailureFile = kGSM5SraFemStr; } break; } case RAWLEY23: // 25% chance that medicine bid will be upped case CLANG2: // 40% chance of increasing Clang's dumping bid of 9 to ... case VEBBIL18: // Design says vebbil can be talked up from 7 for te, but doesn't // tell by how much. // Just talked to sm, he says that the bios say they can possibly // be talked up, but they' can't no matter how hard we try... if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM5SraMaleStr; } else { pszFailureFile = kGSM5SraFemStr; } break; case PYLON3: case DIPPIK10: case REYES24: case HEM20: case JELLA37: case HUNDEY42: case CHANDRA15: // These guys are happy to be part of the deal, but won't budge any on their // offer. if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM5SraMaleStr; } else { pszFailureFile = kGSM5SraFemStr; } break; case MINMARTZN: case MINMARTBA: case MINMARTRG: case MINMARTUT: case MINMARTPN: case MINMARTSZ: // Mineral mart doesn't budge. Don't even bother negotiating with them, // tell the user they wouldn't budge. if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM5SraMaleStr; } else { pszFailureFile = kGSM5SraFemStr; } break; default: assert(false); } } if (pszFailureFile == nullptr && (teamListItem._nFlags & mSeller)) { switch (teamListItem._nMeetWithID) { case IRK4: // Irk can't be talked down and will only talk to Deven in person if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM14SraMaleStr; } else { pszFailureFile = kGSM14SraFemStr; } break; case QUOSH23: // Quosh can't be talked down and will only talk to Deven in person if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM13SraMaleStr; } else { pszFailureFile = kGSM13SraFemStr; } break; case YEEF8: // Yeef can be talked down but requires a really sharp negotiating // team. // // if they've already talked Yeef down, then reply with // a fail message. if (nTeamStrength >= YEEF8_REQUIRED_TEAM_STRENGTH && g_stSellerNames[YEEF8]._nAmount != kYeefTalkedDownAmount) { g_stSellerNames[YEEF8]._nAmount = kYeefTalkedDownAmount; if (teamListItem._nFlags & mStafferMale) { pszSuccessFile = kGSM3SraMaleStr; } else { pszSuccessFile = kGSM3SraFemStr; } } else if (teamListItem._nFlags & mStafferMale) { pszFailureFile = kGSM5SraMaleStr; } else { pszFailureFile = kGSM5SraFemStr; } break; default: assert(false); } } } // If we failed or succeeded, remove it from the list of meetings if (pszFailureFile || pszSuccessFile) { setMeetingResult(teamListItem._nFlags, teamListItem._nMeetWithID, (pszSuccessFile != nullptr)); if (bTimeElapsed) { for (int i = 0; i < NUM_STAFFERS; i++) { if (teamListItem._nFlags & (1 << (i + 3))) { g_staffers[i]._bAvailable = true; } } } // Pick the team captain and build the response file. nTeamCaptain = teamListItem._nTeamCaptain; if (teamListItem._nFlags & mStafferMale) { sResponse = buildMaleSrafDir(pszFailureFile == nullptr ? pszSuccessFile : pszFailureFile); } else { sResponse = buildFemaleSrafDir(pszFailureFile == nullptr ? pszSuccessFile : pszFailureFile); } if (bTimeElapsed) { // Mark the 'meetee' as available. if (teamListItem._nFlags & mOtherParty) { g_stOtherPartys[teamListItem._nMeetWithID]._bAvailable = true; } else if (teamListItem._nFlags & mSeller) { g_stSellerNames[teamListItem._nMeetWithID]._bAvailable = true; } else if (teamListItem._nFlags & mBuyer) { g_stBuyerBids[teamListItem._nMeetWithID]._bAvailable = true; } _pTeamList->remove(nTeamNumber); bNeedRedraw = true; } // Failure file, a text file for now. // We'll want to play a sound file, for now, just put the text to the screen notifyBoss(sResponse, nTeamCaptain); } return bNeedRedraw; } void SrafComputer::onListCheckTeams() { int nTeamNumber = _nSelection - 3; if (reportMeetingStatus(nTeamNumber)) { activateCheckTeams(); } } void SrafComputer::onListCodeWords() { int nCodeWordLine = _nSelection - 4; int nLastLine = NUM_CODE_WORDS + 5; // Reject out of range selections if (nCodeWordLine < 0 || nCodeWordLine >= NUM_CODE_WORDS) { return; } CBofString sStr; // Calculate the text width based on the attributes of the text // rather than guessing to where they are. alignAtColumn(sStr, "", kGroup1Col2); CBofRect cCol1Rect = calculateTextRect(this, &sStr, kOtherPointSize, FONT_MONO); CBofRect cCol2Rect = cCol1Rect; CBofPoint cStartPoint(cCol1Rect.right, 0); cCol2Rect.offsetRect(cStartPoint); // Second bunch of code words start at column 45, create a dummy string and then // start offsetting from there. alignAtColumn(sStr, "", kGroup2Col1); CBofRect cDummyRect = calculateTextRect(this, &sStr, kOtherPointSize, FONT_MONO); cStartPoint.x = cDummyRect.right; CBofRect cCol3Rect = cCol1Rect; cCol3Rect.offsetRect(cStartPoint); CBofRect cCol4Rect = cCol1Rect; cStartPoint.x = cCol3Rect.right; cCol4Rect.offsetRect(cStartPoint); // Extend each rectangle to the bottom of the screen. cCol1Rect.bottom = cCol2Rect.bottom = cCol3Rect.bottom = cCol4Rect.bottom = 1000; // Figure out which words were picked const char *pszWord = nullptr; int nWordGroup = 0; CBofPoint cPoint = getPrevMouseDown(); // already in local coords // Find the rect that it was in. if (cCol1Rect.ptInRect(cPoint)) { nWordGroup = 1; pszWord = g_stCodeWords[nCodeWordLine]._pszCodeWord1; } else if (cCol2Rect.ptInRect(cPoint)) { nWordGroup = 2; pszWord = g_stCodeWords[nCodeWordLine]._pszCodeWord2; } else if (cCol3Rect.ptInRect(cPoint)) { nWordGroup = 3; pszWord = g_stCodeWords[nCodeWordLine]._pszCodeWord3; } else if (cCol4Rect.ptInRect(cPoint)) { nWordGroup = 4; pszWord = g_stCodeWords[nCodeWordLine]._pszCodeWord4; } // Find out if a new word was picked. if (pszWord) { if (nWordGroup == 1 || nWordGroup == 2) { *_pszGroup1Word = pszWord; } else { *_pszGroup2Word = pszWord; } sStr = "CODE uint16 PAIR: ("; if (_pszGroup1Word) { sStr += *_pszGroup1Word; } sStr += ","; if (_pszGroup2Word) { sStr += *_pszGroup2Word; } sStr += ")"; _pLBox->setText(nLastLine, sStr); _pLBox->repaintItem(nLastLine); } } void SrafComputer::deactivateMainScreen() { deleteListBox(); // Hide the on/off button if (_eMode == SC_ON) { _pButtons[ON_BUTTON]->hide(); } else { _pButtons[OFF_BUTTON]->hide(); } } void SrafComputer::activateMainScreen() { char szLocalStr[256]; szLocalStr[0] = '\0'; CBofString sStr(szLocalStr, 256); // Current screen is now the MAIN screen. _eCurScreen = SC_MAIN; // Delete the list box deleteListBox(); // Hide the return to main if it's been created show(); if (getBackdrop()) { paintBackdrop(); } hideAllButtons(); _pButtons[QUIT_BUTTON]->show(); // initialize point size and item height _nListPointSize = kOtherPointSize; _nListItemHeight = kLineItemHeight; ErrorCode errorCode = createListBox(); assert(errorCode == ERR_NONE); int numItems = _pMainList->getCount(); // Populate listbox for (int i = 0; i < numItems; i++) { SrafCompItem compItem = _pMainList->getNodeItem(i); _pLBox->addToTail(CBofString(compItem._pItem), false); } // Add instructions to the bottom of the list... sStr = ""; _pLBox->addToTail(sStr, false); sStr = kActivateFooterStr1; _pLBox->addToTail(sStr, false); sStr = kActivateFooterStr2; _pLBox->addToTail(sStr, false); sStr = kActivateFooterStr3; _pLBox->addToTail(sStr, false); // Display the current time... sStr = " "; _pLBox->addToTail(sStr, false); // Add a dummy line so we can overwrite it with the // current turncount. sStr = " "; _pLBox->addToTail(sStr, false); int nLineNo = _pLBox->getNumItems(); displayTurnCount(nLineNo - 1); // Show list box _pLBox->show(); updateWindow(); } void SrafComputer::alignAtColumn(CBofString &sStr, const char *szRightText, int nAlignAt) { int nAppendLen = strlen(szRightText); while (sStr.getLength() < nAlignAt) { sStr += " "; } // Now right justify and get rid of any zeros if (nAppendLen == 2 && *szRightText == '0') { if (szRightText[1] == '0') { sStr += '-'; sStr += szRightText + 2; } else { sStr += szRightText + 1; } } else { sStr += szRightText; } } void SrafComputer::displayTextScreen(CBofString &sStr) { // Use a global to determine if we can give meeting reports or not. gTextScreenFrontmost = true; _pTextOnlyScreen = new SrafTextScreen(sStr); _pTextOnlyScreen->createTextScreen(this); _pTextOnlyScreen->doModal(); delete _pTextOnlyScreen; _pTextOnlyScreen = nullptr; // if we have a list, then return focus to it. if (_pLBox) { _pLBox->setFocus(); } gTextScreenFrontmost = false; } void SrafComputer::onButtonMainScreen(CBofButton *pButton, int nState) { if (nState != BUTTON_CLICKED) return; switch (pButton->getControlID()) { case ON_BUTTON: setOn(); break; case OFF_BUTTON: setOff(); break; case QUIT_BUTTON: setQuit(); break; default: break; } } void SrafComputer::onButtonDealSummary(CBofButton *pButton, int nState) { if (nState != BUTTON_CLICKED) return; switch (pButton->getControlID()) { case RETURN_TO_MAIN_BUTTON: _pButtons[SUBMIT_BUTTON]->hide(); activateMainScreen(); break; case SUBMIT_BUTTON: if (onButtonSubmitOffer()) { _pButtons[SUBMIT_BUTTON]->hide(); _pButtons[RETURN_TO_MAIN_BUTTON]->hide(); activateCodeWords(); } break; default: break; } } bool SrafComputer::onButtonSubmitOffer() { bool bOfferAccepted = true; char szFailureReason[256]; int nTotalOffer = 0; int i = 0; // First, make sure that we know the terms of the sellers. If they're // not all resolved, then we can't continue. int nAskingPrice = 0; while (i < NUM_SELLERS) { if (g_stSellerNames[i]._nAmount == -1) { Common::sprintf_s(szFailureReason, kszUnresolvedSeller, g_stSellerNames[i]._pszName); bOfferAccepted = false; break; } nAskingPrice += g_stSellerNames[i]._nAmount; i++; } // Check that all the terms have been resolved for the buyers... all we really // need to check here is the environmentalists. if (bOfferAccepted && (g_stOtherPartys[ENVIRONMENTALISTS]._nPaymentAmount == -1)) { Common::strcpy_s(szFailureReason, kszUnresolvedEnriro); bOfferAccepted = false; } // If we didn't fail because of the seller, let's now check the buyer // grid. First check is that we didn't give the same mining right away // to more than a single party. if (bOfferAccepted) { int bMinerals[NUM_MINERALS]; // Clear out the mineral accepted array. If a mining right is given // away to more than one party, then the array will have a non-zero // value for that party. for (i = 0; i < NUM_MINERALS; i++) { bMinerals[i] = -1; } nTotalOffer = 0; for (i = 0; i < NUM_BUYERS; i++) { if (g_stBuyerBids[i]._bAccept) { nTotalOffer += g_stBuyerBids[i]._nBidSum; // We've chose to accept this bid, so make sure that we have not // already promised these mining rights to somebody else. for (int j = 0; j < NUM_MINERALS; j++) { if (g_stBuyerBids[i]._nMineralVal[j] != 0) { if (bMinerals[j] != -1) { Common::sprintf_s(szFailureReason, kszMiningConflict, g_stMinerals[j]._pszMineralName, g_stBuyerBids[i]._pszName, g_stBuyerBids[bMinerals[j]]._pszName); bOfferAccepted = false; break; } else { bMinerals[j] = i; } } } // If we found a dup, then get out of here. if (bOfferAccepted == false) { break; } } } } // Now check and make sure that they came up with enough gigaZoks. if (bOfferAccepted) { // Add in the conditions of the other parties... we know that by now the // environmentatlists have been resolved. for (i = 0; i < NUM_OTHER_PARTYS; i++) { nTotalOffer += (g_stOtherPartys[i]._nPaymentAmount == -1 ? 0 : g_stOtherPartys[i]._nPaymentAmount); } if (nAskingPrice > nTotalOffer) { Common::sprintf_s(szFailureReason, kszOfferNotEnough, nAskingPrice - nTotalOffer); bOfferAccepted = false; } } // Now check that the weirdness of each of the buyers is met, here is a // list of them: // // Gung-14 won't go into a deal with anyone with an '8' in their name // Hem-20 won't go in on a deal with Dippik // Dork-44 insists backer group is 50% female. // Jella-37's lumber bid includes crop mining rights // Sinjin and Dork won't participate in the same deal. if (bOfferAccepted) { for (i = 0; i < NUM_BUYERS; i++) { switch (g_stBuyerBids[i]._nBuyerID) { case GUNG14: // Make sure that there are no backers with the number '8' // in their name. if (g_stBuyerBids[GUNG14]._bAccept && g_stBuyerBids[VEBBIL18]._bAccept) { Common::sprintf_s(szFailureReason, kszGungNotHappy, g_stBuyerBids[VEBBIL18]._pszName); bOfferAccepted = false; break; } break; case HEM20: // Hem-20 won't do business with dippik. if (g_stBuyerBids[HEM20]._bAccept && g_stBuyerBids[DIPPIK10]._bAccept) { Common::strcpy_s(szFailureReason, kszHemNotHappy); bOfferAccepted = false; break; } break; case DORK44: { // Dork-44 insists that at least half the backers are female. int16 nMale = 0; int16 nFemale = 0; if (g_stBuyerBids[DORK44]._bAccept) { for (int j = 0; j < NUM_BUYERS; j++) { if (g_stBuyerBids[j]._bAccept) { if (g_stBuyerBids[j]._nFlags & mBuyerMale) { nMale++; } else if (g_stBuyerBids[j]._nFlags & mBuyerFemale) { nFemale++; } } } if (nMale > nFemale) { Common::strcpy_s(szFailureReason, kszDorkNotHappy); bOfferAccepted = false; break; } } break; } case JELLA37: // If we accepted Jella-37's lumber bid, then we also have to reserve // crop harvesting rights for her. if (g_stBuyerBids[JELLA37]._bAccept) { for (int j = 0; j < NUM_BUYERS; j++) { if (g_stBuyerBids[j]._bAccept && g_stBuyerBids[j]._nMineralVal[CROP] != 0) { Common::sprintf_s(szFailureReason, kszJellaNotHappy, g_stBuyerBids[j]._pszName); bOfferAccepted = false; break; } } } break; case SINJIN11: // Sinjin-11 won't do business with Dork-44. if (g_stBuyerBids[SINJIN11]._bAccept && g_stBuyerBids[DORK44]._bAccept) { Common::strcpy_s(szFailureReason, kszSinjinNotHappy); bOfferAccepted = false; break; } break; case PYLON3: case DIPPIK10: case VEBBIL18: case REYES24: case GILD13: case RAWLEY23: case HUNDEY42: case CHANDRA15: case CLANG2: case MINMARTZN: case MINMARTBA: case MINMARTRG: case MINMARTUT: case MINMARTPN: case MINMARTSZ: break; } if (bOfferAccepted == false) { break; } } } if (bOfferAccepted == false) { displayMessage(szFailureReason); } return bOfferAccepted; } void SrafComputer::onButtonBuyerBids(CBofButton *pButton, int nState) { if (nState != BUTTON_CLICKED) return; switch (pButton->getControlID()) { case RETURN_TO_MAIN_BUTTON: activateMainScreen(); break; case DISPLAY_KEY_BUTTON: { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); sStr = buildSrafDir("KEYINFO.TXT"); displayTextScreen(sStr); break; } default: break; } } void SrafComputer::onButtonDealBackground(CBofButton *pButton, int nState) { if ((nState == BUTTON_CLICKED) && (pButton->getControlID() == RETURN_TO_MAIN_BUTTON)) activateMainScreen(); } void SrafComputer::onButtonSellerBios(CBofButton *pButton, int nState) { if ((nState == BUTTON_CLICKED) && (pButton->getControlID() == RETURN_TO_MAIN_BUTTON)) activateMainScreen(); } void SrafComputer::onButtonOtherBios(CBofButton *pButton, int nState) { if ((nState == BUTTON_CLICKED) && (pButton->getControlID() == RETURN_TO_MAIN_BUTTON)) activateMainScreen(); } void SrafComputer::onButtonStaffBios(CBofButton *pButton, int nState) { if ((nState == BUTTON_CLICKED) && (pButton->getControlID() == RETURN_TO_MAIN_BUTTON)) activateMainScreen(); } void SrafComputer::onButtonDispatchTeam(CBofButton *pButton, int nState) { if (nState != BUTTON_CLICKED) return; switch (pButton->getControlID()) { case RETURN_TO_MAIN_BUTTON: activateMainScreen(); break; case DISPATCH_TEAM_BUTTON: verifyDispatchTeam(); default: break; } } // Apply staffer meeting rules to figure out how long a meeting should take. int SrafComputer::calculateMeetingTime(int nFlags) { int mFlag = 0; int nTeamMembers = 0; int nTotalTime = 0; // Handle the failure case first... that is, if no driver was sent {Norg, // Zig and Lentil} Try seeing if 5 is a good thing. if (!((nFlags & mNorg72) || (nFlags & mZig64) || (nFlags & mLentil24))) { return kDrivingTime; } // Add up the total time. for (int i = 0; i < NUM_STAFFERS; i++) { switch (i) { case 0: mFlag = mNorg72; break; case 1: mFlag = mPnurth81; break; case 2: mFlag = mZig64; break; case 3: mFlag = mLentil24; break; case 4: mFlag = mVargas20; break; case 5: mFlag = mChurg53; break; } if (nFlags & mFlag) { nTeamMembers++; nTotalTime += g_staffers[i]._nMeetingTime; } } // Done adding up, now apply the following special rules. // // If Lentil not on her own, then double her time. // If Pnurth on her own, double her time. if ((nFlags & mLentil24) && nTeamMembers > 1) { nTotalTime += g_staffers[LENTIL24]._nMeetingTime; } if ((nFlags & mPnurth81) && ((nFlags & mChurg53) || (nFlags & mVargas20) || (nFlags & mLentil24))) { nTotalTime -= (g_staffers[PNURTH81]._nMeetingTime / 2); } return nTotalTime / nTeamMembers; } void SrafComputer::notifyBoss(CBofString &sSoundFile, int nStafferID) { // Must be a full file spec CBofBitmap *pSaveBackground = nullptr; // Allow for no staffer screen if (nStafferID != -1) { pSaveBackground = new CBofBitmap(gTextWindow.width(), gTextWindow.height(), (CBofPalette *)nullptr, false); pSaveBackground->captureScreen(this, &gTextWindow); if (_pStafferBmp[nStafferID] == nullptr) { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); sStr = buildSrafDir(g_staffers[nStafferID]._pszStafferBmp); _pStafferBmp[nStafferID] = new CBofBitmap(szLocalBuff); } // Guaranteed to have it now. Paste it to the screen. _pStafferBmp[nStafferID]->paint(this, &gStafferDisplay); } // Play the voice file... Depends on if we have a voice file or a text file... // the last three will tell us. if (sSoundFile.find(".WAV") != -1 || sSoundFile.find(".wav") != -1) { CBofCursor::hide(); BofPlaySound(sSoundFile.getBuffer(), SOUND_WAVE); CBofCursor::show(); } else if (sSoundFile.find(".TXT") || sSoundFile.find(".txt")) { // Make sure the file is there, read it in to our own buffer. CBofFile fTxtFile(sSoundFile, CBF_BINARY | CBF_READONLY); uint32 nLength = fTxtFile.getLength(); if (nLength == 0) { reportError(ERR_FREAD, "Unexpected empty file %s", sSoundFile.getBuffer()); } else { char *pszBuf = (char *)bofCleanAlloc(nLength + 1); fTxtFile.read(pszBuf, nLength); // Put it up on the screen displayMessage(pszBuf); bofFree(pszBuf); } fTxtFile.close(); } // allow for no staffer screen if (nStafferID != -1) { pSaveBackground->paint(this, &gTextWindow); delete pSaveBackground; } } // Most experienced person is captain. int SrafComputer::getTeamCaptain(int nFlags) { int nStaffCaptain = NORG72; if (nFlags & mVargas20) { nStaffCaptain = VARGAS20; } else if (nFlags & mLentil24) { nStaffCaptain = LENTIL24; } else if (nFlags & mChurg53) { nStaffCaptain = CHURG53; } else if (nFlags & mZig64) { nStaffCaptain = ZIG64; } else if (nFlags & mNorg72) { nStaffCaptain = NORG72; } else if (nFlags & mPnurth81) { nStaffCaptain = PNURTH81; } return nStaffCaptain; } // Most experienced person determines sex of team. int SrafComputer::getTeamGender(int nFlags) { int nStaffGender = 0; if (nFlags & mVargas20) { nStaffGender = mStafferMale; } else if (nFlags & mLentil24) { nStaffGender = mStafferFemale; } else if (nFlags & mChurg53) { nStaffGender = mStafferMale; } else if (nFlags & mZig64) { nStaffGender = mStafferFemale; } else if (nFlags & mNorg72) { nStaffGender = mStafferMale; } else if (nFlags & mPnurth81) { nStaffGender = mStafferFemale; } return nStaffGender; } void SrafComputer::onButtonCurrentEMail(CBofButton *pButton, int nState) { if ((nState == BUTTON_CLICKED) && (pButton->getControlID() == RETURN_TO_MAIN_BUTTON)) activateMainScreen(); } void SrafComputer::onButtonAudioSettings(CBofButton *pButton, int nState) { if (nState != BUTTON_CLICKED) return; switch (pButton->getControlID()) { case RETURN_TO_MAIN_BUTTON: activateMainScreen(); break; case NO_MUSIC_BUTTON: CBofSound::stopSounds(); _pButtons[NO_MUSIC_BUTTON]->hide(); activateMainScreen(); break; default: break; } } void SrafComputer::onButtonRoboButler(CBofButton *pButton, int nState) { if (nState != BUTTON_CLICKED) return; switch (pButton->getControlID()) { case RETURN_TO_MAIN_BUTTON: activateMainScreen(); break; case ORDER_BEVERAGE_BUTTON: doOrderBeverage(); break; case ORDER_SNACK_BUTTON: doOrderSnack(); break; default: break; } } void SrafComputer::doOrderBeverage() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); g_SDevManager->addObject("INV_WLD", "SZTB"); g_SDevManager->addObject("INVZ_WLD", "SZTB"); // Build the string to indicate that the beverage has been stashed sStr = buildSrafDir(g_stOfferings[0]._pszRcvOfferingFile); notifyBoss(sStr, -1); // state of buttons has changed activateRoboButler(); } void SrafComputer::doOrderSnack() { char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); g_SDevManager->addObject("INV_WLD", "SZTA"); g_SDevManager->addObject("INVZ_WLD", "SZTA"); // Build the string to indicate that the beverage has been stashed sStr = buildSrafDir(g_stOfferings[1]._pszRcvOfferingFile); notifyBoss(sStr, -1); // state of buttons has changed activateRoboButler(); } void SrafComputer::onButtonCheckTeams(CBofButton *pButton, int nState) { if ((nState == BUTTON_CLICKED) && (pButton->getControlID() == RETURN_TO_MAIN_BUTTON)) activateMainScreen(); } void SrafComputer::onButtonCodeWords(CBofButton *pButton, int nState) { if ((nState == BUTTON_CLICKED) && (pButton->getControlID() == DONE_BUTTON)) { // Normally we'd return to the main screen, but in this instance, we're // done with the flashback... that is, as long as they've picked two // code words. onButtonFinished(true); } } void SrafComputer::onButtonFinished(bool bVictorious) { CBagVar *pVar; // Make sure the user selected two code words. if (bVictorious == true) { if (_pszGroup1Word->getLength() == 0 || _pszGroup2Word->getLength() == 0) { // Put up an error... displayMessage(kszFinishCodeWords); return; } // Pass our codewords back to the bar... pVar = g_VarManager->getVariable("DEVENCODE1"); assert(pVar != nullptr); if (pVar) pVar->setValue(_pszGroup1Word->getBuffer()); pVar = g_VarManager->getVariable("DEVENCODE2"); assert(pVar != nullptr); if (pVar) pVar->setValue(_pszGroup2Word->getBuffer()); } // Setting the flashback variable will trigger the // event world condition which gets us back to the bar. pVar = g_VarManager->getVariable("RFLASHBACK"); assert(pVar != nullptr); if (pVar) { if (bVictorious == true) { pVar->setValue(2); } else { pVar->setValue(1); } } close(); } // Display's a message at the bottom of the screen. void SrafComputer::displayMessage(const char *szMsg) { // Use a global to determine if we can give meeting reports or not. gTextScreenFrontmost = true; _pTextOnlyScreen = new SrafTextScreen(szMsg, true); _pTextOnlyScreen->createTextScreen(this); _pTextOnlyScreen->doModal(); delete _pTextOnlyScreen; _pTextOnlyScreen = nullptr; // if we have a list, then return focus to it. if (_pLBox) { _pLBox->setFocus(); } gTextScreenFrontmost = false; updateWindow(); } void SrafComputer::setMainScreen() { if (_pHead == nullptr) { return; } SrafComputer *srafComp = _pHead; if (srafComp->_eCurScreen == SC_BACKGROUND_DATA) { srafComp->_eCurScreen = SC_MAIN; } } void SrafComputer::incrementTurnCount() { CBagVar *pVar = g_VarManager->getVariable("SRATURNCOUNT"); int nTurncount = 0; assert(pVar != nullptr); // If the puzzle is already solved, then don't increment. if (_eCurScreen == SC_CODE_WORDS) { return; } if (pVar != nullptr) { nTurncount = pVar->getNumValue(); pVar->setValue(++nTurncount); } // If we're in a screen that has a time count, then update it here... if (_eCurScreen == SC_CHECK_TEAMS || _eCurScreen == SC_MAIN) { displayTurnCount(gTurncountLineNo); } // Automatically give the user the status of the meeting if the // meeting time has expired... if (_pTeamList) { int nTeams = _pTeamList->getCount(); for (int i = 0; i < nTeams; i++) { DispatchedTeamItem teamListItem = _pTeamList->getNodeItem(i); if (nTurncount > (teamListItem._nDispatchTime + teamListItem._nMeetingTime)) { if (reportMeetingStatus(i)) { // If current screen is the check teams screen, then make sure we update // it. switch (_eCurScreen) { case SC_CHECK_TEAMS: activateCheckTeams(); break; // update the buyer bids screen if that's our underlying // guy. case SC_BIDS: activateBuyerBids(); break; case SC_DEAL: activateDealSummary(); break; case SC_DISPATCH: activateDispatchTeam(); break; default: break; } } // Only report one meeting per turn... break; } } } // If we got to our max, then put durteen up and snap out of the flashback... // // hack around the problem where the user is notified twice // about failure. if (_bFailureNotified == false) { if (nTurncount > (_nStartingTime + kSrafMaxTurns)) { _bFailureNotified = true; char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sResponse(szLocalBuff, 256); sResponse = buildMaleSrafDir(SRAF_TIMEOUT); notifyBoss(sResponse, DURTEEN97); onButtonFinished(false); } } // add random play function (5676) if (_bRandomAudio == true && (nTurncount > _nRandomTime + kRandomPlayTime)) { int nTrackSelection = g_engine->getRandomNumber() % (NUM_MUSICAL_SCORES - 1); // Now start playing... if (g_stAudioSetting[nTrackSelection]->_pMidiTrack != nullptr) { g_stAudioSetting[nTrackSelection]->_pMidiTrack->play(); } _nRandomTime += kRandomPlayTime; } } void SrafComputer::displayTurnCount(int nLineNo) { CBagVar *pVar = g_VarManager->getVariable("SRATURNCOUNT"); assert(pVar != nullptr); char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); int nCurrentTime = pVar->getNumValue(); Common::sprintf_s(szLocalBuff, "CURRENT TIME: %02d:%02d", nCurrentTime / 100, nCurrentTime % 100); // Get whatever is on that line... if (_pLBox) { CBofString cStr = _pLBox->getText(nLineNo); // reset the value on that line. if (cStr.getLength() != 0) { _pLBox->setText(nLineNo, sStr); } } // Keep track of the line number that it's stored on... might need this again. gTurncountLineNo = nLineNo; } CBofBitmap *SrafComputer::getComputerBackdrop() { if (_pHead == nullptr) { return nullptr; } SrafComputer *srafComp = _pHead; return srafComp->getBackdrop(); } // Sraffin text screen classes. This class is used to read a text file in // and post it to the full screen with a "done" button in the lower right // hand corner of the screen. SrafTextScreen::SrafTextScreen(const CBofString &str, bool isText) : gCompDisplay(40, 40, 600, 440), gTextWindow(0, 0, 640 - 1, 480 - 1), gStafferDisplay(0, 0, 640 - 1, 480 - 1), gSrafTextWindow(0, 440, 640 - 1, 480 - 1) { if (isText) { _text = str; } else { CBofFile file(str, CBF_BINARY | CBF_READONLY); size_t len = file.getLength(); char *tmp = new char[len + 1]; file.read(tmp, len); tmp[len] = '\0'; _text = CBofString(tmp); delete[] tmp; } // save the currently active window _pSaveActiveWin = getActiveWindow(); } int SrafTextScreen::createTextScreen(CBofWindow *pParent) { CBofRect cRect; char szLocalBuff[256]; szLocalBuff[0] = '\0'; CBofString sStr(szLocalBuff, 256); // Create our parent window create("Sraffin Text", &gTextWindow, pParent, 0); // Needs the computer bitmap for a backdrop setBackdrop(SrafComputer::getComputerBackdrop(), false); assert(_pBackdrop != nullptr); CBofPalette *pPal = _pBackdrop->getPalette(); // Create our OK button _pOKButton = new CBofBmpButton; CBofBitmap *pUp = loadBitmap(buildSrafDir(g_stButtons[DONE_BUTTON]._pszUp), pPal); CBofBitmap *pDown = loadBitmap(buildSrafDir(g_stButtons[DONE_BUTTON]._pszDown), pPal); CBofBitmap *pFocus = loadBitmap(buildSrafDir(g_stButtons[DONE_BUTTON]._pszFocus), pPal); CBofBitmap *pDis = loadBitmap(buildSrafDir(g_stButtons[DONE_BUTTON]._pszDisabled), pPal); _pOKButton->loadBitmaps(pUp, pDown, pFocus, pDis); _pOKButton->create(g_stButtons[DONE_BUTTON]._pszName, g_stButtons[DONE_BUTTON]._nLeft, g_stButtons[DONE_BUTTON]._nTop, g_stButtons[DONE_BUTTON]._nWidth, g_stButtons[DONE_BUTTON]._nHeight, this, g_stButtons[DONE_BUTTON]._nID); // Create our text box. cRect.setRect(gCompDisplay.left, gCompDisplay.top, gCompDisplay.right, gCompDisplay.bottom); _pTextBox = new CBofTextBox(this, &cRect, _text); _pTextBox->setPageLength(24); _pTextBox->setColor(CTEXT_WHITE); _pTextBox->setFont(FONT_MONO); _pTextBox->setPointSize(FONT_14POINT); return ERR_NONE; } void SrafTextScreen::displayTextScreen() { show(); if (getBackdrop()) paintBackdrop(); setFocus(); _pOKButton->show(); _pTextBox->display(); } SrafTextScreen::~SrafTextScreen() { // Trash everything! if (_pTextBox) { delete _pTextBox; _pTextBox = nullptr; } if (_pOKButton) { delete _pOKButton; _pOKButton = nullptr; } // Make sure the underlying window gets focus back if (_pSaveActiveWin) { _pSaveActiveWin->setFocus(); } } // Called to delete our text object void SrafTextScreen::onClose() { CBofDialog::onClose(); // Set the backdrop to nullptr so that it doesn't get trashed (we borrowed it from // the sraf computer. clearBackdrop(); } void SrafTextScreen::onPaint(CBofRect * /*pRect*/) { displayTextScreen(); validateAnscestors(); } void SrafTextScreen::onBofButton(CBofObject *pObject, int nState) { assert(isValidObject(this)); assert(pObject != nullptr); CBofButton *pButton = (CBofButton *)pObject; if (nState == BUTTON_CLICKED && pButton->getControlID() == DONE_BUTTON) { close(); SrafComputer::setMainScreen(); } } const char *buildAudioDir(const char *pszFile) { return formPath(SRAF_AUDIO_DIR, pszFile); } const char *buildSrafDir(const char *pszFile) { return formPath(SRAF_DIR, pszFile); } const char *buildMaleSrafDir(const char *pszFile) { return formPath(SRAF_MALE_DIR, pszFile); } const char *buildFemaleSrafDir(const char *pszFile) { return formPath(SRAF_FEMALE_DIR, pszFile); } void SrafComputer::restoreSraffanVars() { // Retrieve sellers terms const char *pVarName = nullptr; // Save sellers terms SELLERS nSellerID = IRK4; int nNumToRestore = 3; CBagVar *pVar; for (int i = 0; i < nNumToRestore; i++) { switch (i) { case 0: pVarName = "IRKSTERMS"; nSellerID = IRK4; break; case 1: pVarName = "YEEFSTERMS"; nSellerID = YEEF8; break; case 2: pVarName = "QUOSHSTERMS"; nSellerID = QUOSH23; break; } pVar = g_VarManager->getVariable(pVarName); if (pVar != nullptr) { g_stSellerNames[nSellerID]._nAmount = pVar->getNumValue(); } } // Retrieve buyer terms nNumToRestore = 5; BUYERS nBuyerID = PYLON3; int nMineralID = 0; for (int i = 0; i < nNumToRestore; i++) { switch (i) { case 0: pVarName = "SINJINSTTERMS"; nBuyerID = SINJIN11; nMineralID = kSinjinMineralID; break; case 1: pVarName = "GUNGBATERMS"; nBuyerID = GUNG14; nMineralID = kGungMineralID; break; case 2: pVarName = "GILDZITERMS"; nBuyerID = GILD13; nMineralID = kGildMineralID1; break; case 3: pVarName = "GILDPLTERMS"; nBuyerID = GILD13; nMineralID = kGildMineralID2; break; case 4: pVarName = "DORKUPTERMS"; nBuyerID = DORK44; nMineralID = kDorkMineralID; break; } pVar = g_VarManager->getVariable(pVarName); if (pVar != nullptr) { g_stBuyerBids[nBuyerID]._nMineralVal[nMineralID] = pVar->getNumValue(); // total each one... int nBidSum = 0; for (int j = 0; j < NUM_MINERALS; j++) { nBidSum += g_stBuyerBids[nBuyerID]._nMineralVal[j]; } g_stBuyerBids[nBuyerID]._nBidSum = nBidSum; } } // Save the list of who is in on this deal... use a bit to indicate if they are in or not. uint32 nBuyersMask = 0; pVar = g_VarManager->getVariable("BUYERSMASK"); if (pVar != nullptr) { nBuyersMask = pVar->getNumValue(); } for (int i = 0; i < NUM_BUYERS; i++) { if (nBuyersMask & (1 << i)) { g_stBuyerBids[i]._bAccept = true; } else { g_stBuyerBids[i]._bAccept = false; } } // Restore the list of who is available and who is not. // Do this using a mask. uint32 nAvailMask = 0; uint32 nIndex = 0; pVar = g_VarManager->getVariable("AVAILABLEMASK"); if (pVar != nullptr) { nAvailMask = pVar->getNumValue(); } for (int i = 0; i < NUM_BUYERS; i++, nIndex++) { if (nAvailMask & (1 << nIndex)) { g_stBuyerBids[i]._bAvailable = false; } else { g_stBuyerBids[i]._bAvailable = true; } } for (int i = 0; i < NUM_SELLERS; i++, nIndex++) { if (nAvailMask & (1 << nIndex)) { g_stSellerNames[i]._bAvailable = false; } else { g_stSellerNames[i]._bAvailable = true; } } for (int i = 0; i < NUM_OTHER_PARTYS; i++, nIndex++) { if (nAvailMask & (1 << nIndex)) { g_stOtherPartys[i]._bAvailable = false; } else { g_stOtherPartys[i]._bAvailable = true; } } assert(nIndex < 32); // Restore other party's info OTHERPARTYS nOtherID = SWONZA5; nNumToRestore = 3; for (int i = 0; i < nNumToRestore; i++) { switch (i) { case 0: pVarName = "SWONZATERMS"; nOtherID = SWONZA5; break; case 1: pVarName = "POLITTERMS"; nOtherID = POLITICIANS; break; case 2: pVarName = "ENVIROTERMS"; nOtherID = ENVIRONMENTALISTS; break; } pVar = g_VarManager->getVariable(pVarName); if (pVar != nullptr) { g_stOtherPartys[nOtherID]._nPaymentAmount = pVar->getNumValue(); } } // Retrieve swonza's state pVar = g_VarManager->getVariable("SWONZAENLIGHTENED"); if (pVar != nullptr) { _bSwonzaEnlightened = pVar->getNumValue(); } // Mark each of our staffers as available before we start. for (int i = 0; i < NUM_STAFFERS; i++) { g_staffers[i]._bAvailable = true; } // Now the real pain in the ass... restoring team information... nNumToRestore = 6; DispatchedTeamItem teamListItem; char szFLAGS[20]; char szMEETWITH[20]; char szDISPATCHTIME[20]; char szCAPTAIN[20]; char szMEETINGTIME[20]; for (int i = 0; i < nNumToRestore; i++) { // Build the variable names with default values. Common::sprintf_s(szFLAGS, "%s%d%s", "TEAM", i + 1, "FLAGS"); Common::sprintf_s(szMEETWITH, "%s%d%s", "TEAM", i + 1, "MEETWITH"); Common::sprintf_s(szDISPATCHTIME, "%s%d%s", "TEAM", i + 1, "DISPATCHTIME"); Common::sprintf_s(szCAPTAIN, "%s%d%s", "TEAM", i + 1, "CAPTAIN"); Common::sprintf_s(szMEETINGTIME, "%s%d%s", "TEAM", i + 1, "MEETINGTIME"); // Restore the whole block... pVar = g_VarManager->getVariable(szFLAGS); if (pVar != nullptr) { teamListItem._nFlags = pVar->getNumValue(); // If we have a meeting going on, then mark that // sraffan staffer as unavailable. if (teamListItem._nFlags != 0) { for (int j = 0; j < NUM_STAFFERS; j++) { if ((1 << (j + 3)) & teamListItem._nFlags) { g_staffers[j]._bAvailable = false; } } } } pVar = g_VarManager->getVariable(szMEETWITH); if (pVar != nullptr) { teamListItem._nMeetWithID = pVar->getNumValue(); } pVar = g_VarManager->getVariable(szDISPATCHTIME); if (pVar != nullptr) { teamListItem._nDispatchTime = pVar->getNumValue(); } pVar = g_VarManager->getVariable(szCAPTAIN); if (pVar != nullptr) { teamListItem._nTeamCaptain = pVar->getNumValue(); } pVar = g_VarManager->getVariable(szMEETINGTIME); if (pVar != nullptr) { teamListItem._nMeetingTime = pVar->getNumValue(); } // If we have a list established, then add this item to it if there's anything // there. if (_pTeamList == nullptr) { _pTeamList = new CBofList; } if (teamListItem._nFlags != 0) { _pTeamList->addToTail(teamListItem); } } // Save the successful and unsuccessful meeting status. Here's how we're gonna do // this. For each negotiating target, we will save a bit in "METWITH", 0 => no // meeting occurred, 1 => a meeting happened with this dude. There will be a // second variable, "MEETINGRESULTS", there will be a bit that is synonymous with // the "METWITH" var indicating the result of the meeting, i.e. 0=>meeting was a // success and 1=> meeting was a failure. // // Now get the variables int nMetWithVal = 0; int nMeetingResultVal = 0; pVar = g_VarManager->getVariable("METWITH"); if (pVar != nullptr) { nMetWithVal = pVar->getNumValue(); } pVar = g_VarManager->getVariable("MEETINGRESULTS"); if (pVar != nullptr) { nMeetingResultVal = pVar->getNumValue(); } int nBitNo = 0; // Restore seller meeting history for (int i = 0; i < NUM_SELLERS; i++, nBitNo++) { if (nMetWithVal & (1 << nBitNo)) { g_stSellerNames[i]._nMeetingResult = (((1 << nBitNo) & nMeetingResultVal) ? SRAF_GOOD_MEETING : SRAF_BAD_MEETING); } else { g_stSellerNames[i]._nMeetingResult = 0; } } // Save buyer meeting history for (int i = 0; i < NUM_BUYERS; i++, nBitNo++) { if (nMetWithVal & (1 << nBitNo)) { g_stBuyerBids[i]._nMeetingResult = (((1 << nBitNo) & nMeetingResultVal) ? SRAF_GOOD_MEETING : SRAF_BAD_MEETING); } else { g_stBuyerBids[i]._nMeetingResult = 0; } } // Save other party meeting history for (int i = 0; i < NUM_OTHER_PARTYS; i++, nBitNo++) { if (nMetWithVal & (1 << nBitNo)) { g_stOtherPartys[i]._nMeetingResult = (((1 << nBitNo) & nMeetingResultVal) ? SRAF_GOOD_MEETING : SRAF_BAD_MEETING); } else { g_stOtherPartys[i]._nMeetingResult = 0; } } // All done! } void SrafComputer::saveSraffanVars() { const char *pVarName = nullptr; // Save sellers terms SELLERS nSellerID = IRK4; int nNumToSave = 3; for (int i = 0; i < nNumToSave; i++) { switch (i) { case 0: pVarName = "IRKSTERMS"; nSellerID = IRK4; break; case 1: pVarName = "YEEFSTERMS"; nSellerID = YEEF8; break; case 2: pVarName = "QUOSHSTERMS"; nSellerID = QUOSH23; break; } CBagVar *pVar = g_VarManager->getVariable(pVarName); if (pVar != nullptr) { pVar->setValue(g_stSellerNames[nSellerID]._nAmount); } } // Retrieve buyer terms nNumToSave = 5; BUYERS nBuyerID = PYLON3; int nMineralID = 0; CBagVar *pVar; for (int i = 0; i < nNumToSave; i++) { switch (i) { case 0: pVarName = "SINJINSTTERMS"; nBuyerID = SINJIN11; nMineralID = kSinjinMineralID; break; case 1: pVarName = "GUNGBATERMS"; nBuyerID = GUNG14; nMineralID = kGungMineralID; break; case 2: pVarName = "GILDZITERMS"; nBuyerID = GILD13; nMineralID = kGildMineralID1; break; case 3: pVarName = "GILDPLTERMS"; nBuyerID = GILD13; nMineralID = kGildMineralID2; break; case 4: pVarName = "DORKUPTERMS"; nBuyerID = DORK44; nMineralID = kDorkMineralID; break; } pVar = g_VarManager->getVariable(pVarName); if (pVar != nullptr) { pVar->setValue(g_stBuyerBids[nBuyerID]._nMineralVal[nMineralID]); } } // Save the list of who is in on this deal... use a bit to indicate if they are in or not. uint32 nBuyersMask = 0; for (int i = 0; i < NUM_BUYERS; i++) { if (g_stBuyerBids[i]._bAccept == true) { nBuyersMask |= (1 << i); } } pVar = g_VarManager->getVariable("BUYERSMASK"); if (pVar != nullptr) { pVar->setValue(nBuyersMask); } // Save the list of who is available and who is not. // Do this using a mask. uint32 nAvailMask = 0; uint32 nIndex = 0; for (int i = 0; i < NUM_BUYERS; i++, nIndex++) { if (g_stBuyerBids[i]._bAvailable == false) { nAvailMask |= (1 << nIndex); } } for (int i = 0; i < NUM_SELLERS; i++, nIndex++) { if (g_stSellerNames[i]._bAvailable == false) { nAvailMask |= (1 << nIndex); } } for (int i = 0; i < NUM_OTHER_PARTYS; i++, nIndex++) { if (g_stOtherPartys[i]._bAvailable == false) { nAvailMask |= (1 << nIndex); } } assert(nIndex < 32); pVar = g_VarManager->getVariable("AVAILABLEMASK"); if (pVar != nullptr) { pVar->setValue(nAvailMask); } // Save other party's info OTHERPARTYS nOtherID = SWONZA5; nNumToSave = 3; for (int i = 0; i < nNumToSave; i++) { switch (i) { case 0: pVarName = "SWONZATERMS"; nOtherID = SWONZA5; break; case 1: pVarName = "POLITTERMS"; nOtherID = POLITICIANS; break; case 2: pVarName = "ENVIROTERMS"; nOtherID = ENVIRONMENTALISTS; break; } pVar = g_VarManager->getVariable(pVarName); if (pVar != nullptr) { pVar->setValue(g_stOtherPartys[nOtherID]._nPaymentAmount); } } // Save swonza's state pVar = g_VarManager->getVariable("SWONZAENLIGHTENED"); if (pVar != nullptr) { pVar->setValue(_bSwonzaEnlightened); } // Now the real pain in the ass... saving team information... nNumToSave = 6; DispatchedTeamItem teamListItem; int nOutstandingTeams = 0; char szFLAGS[20]; char szMEETWITH[20]; char szDISPATCHTIME[20]; char szCAPTAIN[20]; char szMEETINGTIME[20]; // Get the number of outstanding teams, we don't want to overkill if (_pTeamList) { nOutstandingTeams = _pTeamList->getCount(); } for (int i = 0; i < nNumToSave; i++) { // Build the variable names with default values. Common::sprintf_s(szFLAGS, "%s%d%s", "TEAM", i + 1, "FLAGS"); Common::sprintf_s(szMEETWITH, "%s%d%s", "TEAM", i + 1, "MEETWITH"); Common::sprintf_s(szDISPATCHTIME, "%s%d%s", "TEAM", i + 1, "DISPATCHTIME"); Common::sprintf_s(szCAPTAIN, "%s%d%s", "TEAM", i + 1, "CAPTAIN"); Common::sprintf_s(szMEETINGTIME, "%s%d%s", "TEAM", i + 1, "MEETINGTIME"); if (i < nOutstandingTeams) { teamListItem = _pTeamList->getNodeItem(i); } else { teamListItem._nFlags = 0; teamListItem._nMeetWithID = 0; teamListItem._nDispatchTime = 0; teamListItem._nTeamCaptain = 0; teamListItem._nMeetingTime = 0; } pVar = g_VarManager->getVariable(szFLAGS); if (pVar != nullptr) { pVar->setValue(teamListItem._nFlags); } pVar = g_VarManager->getVariable(szMEETWITH); if (pVar != nullptr) { pVar->setValue(teamListItem._nMeetWithID); } pVar = g_VarManager->getVariable(szDISPATCHTIME); if (pVar != nullptr) { pVar->setValue(teamListItem._nDispatchTime); } pVar = g_VarManager->getVariable(szCAPTAIN); if (pVar != nullptr) { pVar->setValue(teamListItem._nTeamCaptain); } pVar = g_VarManager->getVariable(szMEETINGTIME); if (pVar != nullptr) { pVar->setValue(teamListItem._nMeetingTime); } } // Save the successful and unsuccessful meeting status. Here's how we're gonna do // this. For each negotiating target, we will save a bit in "METWITH", 0 => no // meeting occurred, 1 => a meeting happened with this dude. There will be a // second variable, "MEETINGRESULTS", there will be a bit that is synonymous with // the "METWITH" var indicating the result of the meeting, i.e. 0=>meeting was a // success and 1=> meeting was a failure. // // I am writing this code as a response to bug number 7619 which just requested // that the results of each meeting be displayed on the negotiations screen, I // am willing to bet a months paycheck that someone comes back and requests that // the attendees of each meeting be listed with the success/failure of each. int nBitNo = 0; int nMetWithVal = 0; int nMeetingResultVal = 0; // Save seller meeting history for (int i = 0; i < NUM_SELLERS; i++, nBitNo++) { if (g_stSellerNames[i]._nMeetingResult != SRAF_NO_MEETING) { nMetWithVal |= (1 << nBitNo); nMeetingResultVal |= (g_stSellerNames[i]._nMeetingResult == SRAF_GOOD_MEETING ? 1 << nBitNo : 0); } } // Save buyer meeting history for (int i = 0; i < NUM_BUYERS; i++, nBitNo++) { if (g_stBuyerBids[i]._nMeetingResult != SRAF_NO_MEETING) { nMetWithVal |= (1 << nBitNo); nMeetingResultVal |= (g_stBuyerBids[i]._nMeetingResult == SRAF_GOOD_MEETING ? 1 << nBitNo : 0); } } // Save other party meeting history for (int i = 0; i < NUM_OTHER_PARTYS; i++, nBitNo++) { if (g_stOtherPartys[i]._nMeetingResult != SRAF_NO_MEETING) { nMetWithVal |= (1 << nBitNo); nMeetingResultVal |= (g_stOtherPartys[i]._nMeetingResult == SRAF_GOOD_MEETING ? 1 << nBitNo : 0); } } // Now save the variables pVar = g_VarManager->getVariable("METWITH"); if (pVar != nullptr) { pVar->setValue(nMetWithVal); } pVar = g_VarManager->getVariable("MEETINGRESULTS"); if (pVar != nullptr) { pVar->setValue(nMeetingResultVal); } // All done! } void SrafComputer::setMeetingResult(int nFlags, int nMetWith, bool bSucceeded) { if ((nFlags & mSeller) && nMetWith < NUM_SELLERS) { g_stSellerNames[nMetWith]._nMeetingResult = (bSucceeded ? SRAF_GOOD_MEETING : SRAF_BAD_MEETING); } if ((nFlags & mBuyer) && nMetWith < NUM_BUYERS) { g_stBuyerBids[nMetWith]._nMeetingResult = (bSucceeded ? SRAF_GOOD_MEETING : SRAF_BAD_MEETING); } if ((nFlags & mOtherParty) && nMetWith < NUM_OTHER_PARTYS) { g_stOtherPartys[nMetWith]._nMeetingResult = (bSucceeded ? SRAF_GOOD_MEETING : SRAF_BAD_MEETING); } } } // namespace SpaceBar } // namespace Bagel