/* 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