hostile-takeover/game/Research.cpp
Nathan Fulton 4aadbf87cb strings.h -> wistrings.h
Change strings.h to wistrings.h to prevent SDL.h from including it
while trying to include the CRT strings.h
2016-08-24 21:40:38 -04:00

595 lines
15 KiB
C++

#include "ht.h"
#include "wistrings.h"
namespace wi {
const int kcUpdateCost = 3; //TUNE: - credits of upgrade per update
class UpgradeForm : public Form
{
public:
ResearchGob *GetOwner() {
return m_pgobOwner;
}
void SetOwner(ResearchGob *pgobOwner) secStructures;
void UpdateUpgradeInfo(ListItem *pli) secStructures;
// Form overrides
void EndForm(int nResult = kidcCancel) secStructures;
virtual void OnControlSelected(word idc) secStructures;
virtual void OnPaintBackground(DibBitmap *pbm, UpdateMap *pupd) secStructures;
private:
ResearchGob *m_pgobOwner;
};
// UNDONE: migrate from wfUpgrade (kfUpgrade*)
// UNDONE: v2 upgrade infrastructure
// UNDONE: implement increase mining speed upgrade
// UNDONE: new action for setting upgrades and allowed upgrades
// UNDONE: initialize this from upgrades.ini (mirror gobtemplates.ini structure)
// UNDONE: tapping '?' icon hangs
// Single player upgrades
Upgrade gaupg[kupgtMax] = {
{
kupgmAdvancedHRC,
"Advanced HRC",
"hrc1",
0, kumHumanResourceCenter,
750, 4500,
"Upgrade the HRC to gain access to more advanced infantry.",
"This upgrade requires a HRC."
},
{
kupgmAdvancedVTS,
"Advanced VTS",
"vts1",
0, kumVehicleTransportStation,
1150, 4500,
"Upgrade the VTS to gain access to more advanced vehicles.",
"This upgrade requires a VTS."
},
};
// Multiplayer upgrades
Upgrade gaupgMP[kupgtMax] = {
{
kupgmAdvancedHRC,
"Advanced HRC",
"hrc1",
0, kumHumanResourceCenter,
1500, 4500,
"Upgrade the HRC to gain access to more advanced infantry.",
"This upgrade requires a HRC."
},
{
kupgmAdvancedVTS,
"Advanced VTS",
"vts1",
0, kumVehicleTransportStation,
3000, 4500,
"Upgrade the VTS to gain access to more advanced vehicles.",
"This upgrade requires a VTS."
},
#if 0
{
kupgmIncreasedBullpupSpeed,
"Increased Bullpup Speed",
"bullpup1",
0, kumProcessor,
3000, 4500,
"Increase Bullpup movement and mining speed by 10%. All existing and future Bullpups will "
"be retrofited with high efficiency triple-buffered fuel cores.",
"This upgrade requires a Processor."
}
#endif
};
//
// ResearchGob implementation
//
static StructConsts gConsts;
static UpgradeForm *s_pfrmUpgrade = NULL;
static AnimationData *s_panidUpgradeIcons = NULL;
//
// Gob methods
//
bool ResearchGob::InitClass(IniReader *pini)
{
gConsts.gt = kgtResearchCenter;
gConsts.ut = kutResearchCenter;
//TUNE:
gConsts.umPrerequisites = kumReactor;
// Sound effects
gConsts.sfxAbortRepair = ksfxResearchCenterAbortRepair;
gConsts.sfxRepair = ksfxResearchCenterRepair;
gConsts.sfxDamaged = ksfxResearchCenterDamaged;
gConsts.sfxSelect = ksfxResearchCenterSelect;
gConsts.sfxDestroyed = ksfxResearchCenterDestroyed;
gConsts.sfxImpact = ksfxNothing;
gConsts.sfxAbortUpgrade = ksfxResearchCenterAbortRepair;
gConsts.sfxUpgrade = ksfxResearchCenterRepair;
// Wants power notification
gConsts.wf |= kfUntcNotifyPowerLowHigh;
// Preload the Upgrade form
s_pfrmUpgrade = new UpgradeForm();
if (s_pfrmUpgrade == NULL) {
Assert("fatal error");
return false;
}
if (!s_pfrmUpgrade->Init(gpmfrmm, gpiniForms, kidfUpgrade)) {
Assert("unable to init Upgrade form");
return false;
}
gpmfrmm->RemoveForm(s_pfrmUpgrade);
// Initialize animation that contains the upgrade icons
s_panidUpgradeIcons = LoadAnimationData("upgrades.anir");
Assert(s_panidUpgradeIcons != NULL, "Upgrade icons failed to load");
if (s_panidUpgradeIcons == NULL)
return false;
return StructGob::InitClass(&gConsts, pini);
}
void ResearchGob::ExitClass()
{
delete s_panidUpgradeIcons;
s_panidUpgradeIcons = NULL;
delete s_pfrmUpgrade;
s_pfrmUpgrade = NULL;
StructGob::ExitClass(&gConsts);
}
ResearchGob::ResearchGob() : StructGob(&gConsts)
{
m_utTarget = kutNone;
m_nCreditsSpentOnUpgrade = 0;
}
#define knVerResearchGobState 3
bool ResearchGob::LoadState(Stream *pstm)
{
byte nVer = pstm->ReadByte();
if (nVer != knVerResearchGobState)
return false;
m_utTarget = (UnitType)(char)pstm->ReadByte();
//temp fix me - 255 check is because CW compiler isn't sign extending
// m_utTarget in the up-cast from char to UnitType (which is short).
// Even forcing (UnitType)(short)(signed char) results in 255!
if (m_utTarget == 255)
m_utTarget = kutNone;
if (m_utTarget != kutNone) {
m_nCreditsSpentOnUpgrade = (int)pstm->ReadWord();
}
return StructGob::LoadState(pstm);
}
bool ResearchGob::SaveState(Stream *pstm)
{
pstm->WriteByte(knVerResearchGobState);
pstm->WriteByte((byte)m_utTarget);
if (m_utTarget != kutNone) {
pstm->WriteWord(m_nCreditsSpentOnUpgrade);
}
return StructGob::SaveState(pstm);
}
void ResearchGob::InitMenu(Form *pfrm)
{
bool fUpgradeInProgress = (m_pplr->GetUpgrades() & (kfUpgradeHrcInProgress | kfUpgradeVtsInProgress)) > 0;
Control *pctl = pfrm->GetControlPtr(kidcResearch);
pctl->Show(!fUpgradeInProgress);
pctl = pfrm->GetControlPtr(kidcAbortUpgrade);
pctl->Show(fUpgradeInProgress);
StructGob::InitMenu(pfrm);
}
void ResearchGob::OnMenuItemSelected(int idc)
{
switch (idc) {
case kidcResearch:
{
s_pfrmUpgrade->SetOwner(this);
gpmfrmm->AddForm(s_pfrmUpgrade);
int idc;
s_pfrmUpgrade->DoModal(&idc);
gpmfrmm->RemoveForm(s_pfrmUpgrade);
if (idc == kidcCancel)
break;
// this must be enqueued because it begins the consumption of credits
Message msg;
memset(&msg, 0, sizeof(msg));
msg.mid = kmidUpgradeCommand;
msg.smidReceiver = m_gid;
msg.smidSender = ksmidNull;
msg.UpgradeCommand.wfUpgrade = idc == kupgmAdvancedHRC ? kfUpgradeHrc : kfUpgradeVts;
gcmdq.Enqueue(&msg);
if (m_pplr == gpplrLocal)
gsndm.PlaySfx(gConsts.sfxUpgrade);
}
break;
case kidcAbortUpgrade:
// terminate the consumption of credits and restore
// we can only do one upgrade at a time so don't need to say which
gcmdq.Enqueue(kmidAbortUpgradeCommand, m_gid);
if (m_pplr == gpplrLocal)
gsndm.PlaySfx(gConsts.sfxAbortUpgrade);
break;
default:
StructGob::OnMenuItemSelected(idc);
break;
}
}
//
// StateMachine methods
//
#if defined(DEBUG_HELPERS)
char *ResearchGob::GetName()
{
return "ResearchCenter";
}
#endif
int ResearchGob::ProcessStateMachineMessage(State st, Message *pmsg)
{
BeginStateMachine
//-----------------------------------------------------------------------
State(kstIdle)
OnMsg(kmidUpgradeCommand)
// the upgrade basically applies to the player - they now build/have
// fancier versions of the same old structures in question.
// it's up to the structures themselves to check for the upgrade
// or its progress and behave appropriately
if (pmsg->UpgradeCommand.wfUpgrade & kfUpgradeVts) {
if (!(m_pplr->GetUpgrades() & (kfUpgradeVts | kfUpgradeVtsInProgress))) {
m_pplr->SetUpgrades(m_pplr->GetUpgrades() | kfUpgradeVtsInProgress);
Assert(m_utTarget == kutNone);
m_utTarget = kutVehicleTransportStation;
}
}
if (pmsg->UpgradeCommand.wfUpgrade & kfUpgradeHrc) {
if (!(m_pplr->GetUpgrades() & (kfUpgradeHrc | kfUpgradeHrcInProgress))) {
m_pplr->SetUpgrades(m_pplr->GetUpgrades() | kfUpgradeHrcInProgress);
Assert(m_utTarget == kutNone);
m_utTarget = kutHumanResourceCenter;
}
}
// Cause the current state to wake up and start costing the upgrade
m_unvl.MinSkip();
OnMsg(kmidAbortUpgradeCommand)
AbortUpgrade();
OnMsg(kmidSelfDestructCommand)
AbortUpgrade();
SelfDestruct();
OnUpdate
// Don't animate if power is too low
// This relies on kmidPowerLowHigh to wake up if power situation changes
if (!m_pplr->IsPowerLow())
AdvanceAnimation(&m_ani);
if (m_utTarget != kutNone) {
UpgradeUpdate();
MarkRedraw();
m_unvl.MinSkip();
}
DefUpdate();
#if 0
EndStateMachineInherit(StructGob)
#else
return knHandled;
}
} else {
return (int)StructGob::ProcessStateMachineMessage(st, pmsg);
}
return (int)StructGob::ProcessStateMachineMessage(st, pmsg);
#endif
}
void ResearchGob::UpgradeUpdate()
{
int nCost = ((StructConsts *)gapuntc[m_utTarget])->nUpgradeCost;
// God can upgrade things instantly and for free
if (gfGodMode && !ggame.IsMultiplayer()) {
m_nCreditsSpentOnUpgrade = nCost;
WaitingForCredits(false);
} else {
// calc update as either a default amount or what's left
int nCostPerUpdate = nCost - m_nCreditsSpentOnUpgrade;
if (nCostPerUpdate > kcUpdateCost)
nCostPerUpdate = kcUpdateCost; //TUNE:
// update if the player has enough credits to cover it
int nCredits = m_pplr->GetCredits() - nCostPerUpdate;
if (nCredits >= 0) {
m_pplr->SetCredits(nCredits, true);
m_nCreditsSpentOnUpgrade += nCostPerUpdate;
Assert(m_nCreditsSpentOnUpgrade <= nCost);
}
WaitingForCredits(nCredits < 0);
}
if (m_nCreditsSpentOnUpgrade == nCost) {
// fix up the player flags
// play the appropriate noises
// reset our state
word wFlagOn, wFlagOff;
if (m_utTarget == kutHumanResourceCenter) {
wFlagOn = kfUpgradeHrc;
wFlagOff = kfUpgradeHrcInProgress;
} else {
wFlagOn = kfUpgradeVts;
wFlagOff = kfUpgradeVtsInProgress;
}
word wUpgrades = m_pplr->GetUpgrades();
wUpgrades &= ~wFlagOff;
m_pplr->SetUpgrades(wUpgrades | wFlagOn);
if (m_pplr == gpplrLocal) {
gsndm.PlaySfx(m_utTarget == kutHumanResourceCenter ? ksfxGameNewRecruitOptions : ksfxGameNewVehicleOptions);
ShowAlert(m_utTarget == kutHumanResourceCenter ? kidsNewRecruitOptions : kidsNewVehicleOptions);
}
m_utTarget = kutNone;
m_nCreditsSpentOnUpgrade = 0;
WaitingForCredits(false);
}
}
void ResearchGob::Draw(DibBitmap *pbm, int xViewOrigin, int yViewOrigin, int nLayer)
{
StructGob::Draw(pbm, xViewOrigin, yViewOrigin, nLayer);
if (nLayer == knLayerDepthSorted) {
if (m_utTarget != kutNone) {
Rect rcT;
rcT.FromWorldRect(&m_puntc->wrcUIBounds);
rcT.Offset(-xViewOrigin + PcFromWc(m_wx), -yViewOrigin + PcFromWc(m_wy));
DrawBuildProgressIndicator(pbm, &rcT, m_nCreditsSpentOnUpgrade, ((StructConsts *)gapuntc[m_utTarget])->nUpgradeCost); // passing into fix params?
}
}
}
void ResearchGob::AbortUpgrade()
{
// abandon upgrade and restore spent credits
if (m_utTarget != kutNone) {
m_pplr->SetCredits(m_pplr->GetCredits() + m_nCreditsSpentOnUpgrade, false);
m_pplr->ModifyTotalCreditsConsumed(-m_nCreditsSpentOnUpgrade);
m_pplr->SetUpgrades(m_pplr->GetUpgrades() & ~(kfUpgradeVtsInProgress | kfUpgradeHrcInProgress));
m_utTarget = kutNone;
m_nCreditsSpentOnUpgrade = 0;
WaitingForCredits(false);
m_unvl.MinSkip();
}
}
void ResearchGob::Deactivate()
{
// for both takeover and destruction the upgrade should be abandoned w/o restoring credits
if (m_utTarget != kutNone)
{
m_pplr->SetUpgrades(m_pplr->GetUpgrades() & ~(kfUpgradeVtsInProgress | kfUpgradeHrcInProgress));
m_utTarget = kutNone;
m_nCreditsSpentOnUpgrade = 0;
}
StructGob::Deactivate();
}
//===========================================================================
// UpgradeForm implementation
void UpgradeForm::SetOwner(ResearchGob *pgobOwner)
{
Size sizDib;
m_pfrmm->GetDib()->GetSize(&sizDib);
Rect rc;
rc.left = ((sizDib.cx - m_rc.Width()) / 2) & ~1;
rc.top = 0; // (sizDib.cy - m_rc.Height()) / 2;
rc.right = rc.left + m_rc.Width();
rc.bottom = rc.top + m_rc.Height();
SetRect(&rc);
m_wf |= kfFrmAutoTakedown;
m_pgobOwner = pgobOwner;
BuildListControl *plstc = (BuildListControl *)GetControlPtr(kidcList);
plstc->Clear();
// Initialize list with available upgrade types.
// UNDONE: need to link list to dynamic build capability
Player *pplr = pgobOwner->GetOwner();
UpgradeMask upgmOwned = pplr->GetUpgradeMask();
UpgradeMask upgmAllowed = pplr->GetAllowedUpgrades();
int cUpgrades = 0;
Upgrade *pupg = gfMultiplayer ? gaupgMP : gaupg;
for (int i = 0; i < kupgtMax; i++, pupg++) {
// Has the player already acquired this upgrade? If so, don't add it to the list
if (pplr->GetUpgradeMask() & pupg->upgm)
continue;
// Does this player have what it takes to perform this upgrade?
bool fDisabled = true;
if (gfGodMode || ((upgmOwned & pupg->upgmPrerequisites) == pupg->upgmPrerequisites &&
(pplr->GetUnitMask() & pupg->umPrerequisites) == pupg->umPrerequisites))
fDisabled = false;
// Is this one of the upgrades this player is allowed?
if (gfGodMode || (pupg->upgm & upgmAllowed)) {
// Yep, add it to the list
cUpgrades++;
int nStripIcon = s_panidUpgradeIcons->GetStripIndex(pupg->szIconName);
if (nStripIcon != -1) {
plstc->Add(s_panidUpgradeIcons, nStripIcon, 0, (void *)pupg, fDisabled);
}
}
}
if (cUpgrades == 0) {
// Hide the "Research" button if no upgrades are available
ButtonControl *pbtn = (ButtonControl *)GetControlPtr(kidcOk);
pbtn->Show(false);
LabelControl *plbl = (LabelControl *)GetControlPtr(kidcCost);
plbl->SetText("");
PipMeterControl *pmtr = (PipMeterControl *)GetControlPtr(kidcCostMeter);
pmtr->SetValue(0);
plbl = (LabelControl *)GetControlPtr(kidcName);
plbl->SetText("NO UPGRADES AVAILABLE");
plbl = (LabelControl *)GetControlPtr(kidcDescription);
plbl->SetText("");
plbl = (LabelControl *)GetControlPtr(kidcPrerequisites);
plbl->SetText("");
plbl = (LabelControl *)GetControlPtr(kidcCostLabel);
plbl->Show(false);
plbl = (LabelControl *)GetControlPtr(kidcPrerequisitesLabel);
plbl->Show(false);
}
// Select the first upgrade by default
plstc->Select(0);
plstc->SetQueueInfo(NULL, NULL);
}
void UpgradeForm::UpdateUpgradeInfo(ListItem *pli)
{
Upgrade *pupg = (Upgrade *)pli->pvData;
// Update Cost
LabelControl *plbl = (LabelControl *)GetControlPtr(kidcCost);
char szT[20];
itoa(pupg->nCost, szT, 10);
plbl->SetText(szT);
PipMeterControl *pmtr = (PipMeterControl *)GetControlPtr(kidcCostMeter);
pmtr->SetValue((pupg->nCost * 100) / 3000);
plbl = (LabelControl *)GetControlPtr(kidcCostLabel);
plbl->Show(true);
// Update Name
plbl = (LabelControl *)GetControlPtr(kidcName);
plbl->SetText(pupg->szName);
// Update Description
plbl = (LabelControl *)GetControlPtr(kidcDescription);
plbl->SetText(pupg->szDescription);
// Update prerequisites
plbl = (LabelControl *)GetControlPtr(kidcPrerequisites);
plbl->SetText(pupg->szPrerequisites);
plbl = (LabelControl *)GetControlPtr(kidcPrerequisitesLabel);
plbl->Show(true);
// Hide the "Research" button if this upgrade is disabled
ButtonControl *pbtn = (ButtonControl *)GetControlPtr(kidcOk);
pbtn->Show(!pli->fDisabled);
}
void UpgradeForm::EndForm(int nResult)
{
m_pgobOwner = NULL;
Form::EndForm(nResult);
}
void UpgradeForm::OnControlSelected(word idc)
{
switch (idc) {
case kidcCancel:
EndForm(kidcCancel);
return;
case kidcHelp:
// UNDONE: upgrade help text
Help("upgrades", !ggame.IsMultiplayer());
break;
case kidcList:
{
ListControl *plstc = (ListControl *)GetControlPtr(kidcList);
ListItem *pli = plstc->GetSelectedItem();
if (pli != NULL)
UpdateUpgradeInfo(pli);
}
break;
case kidcOk:
ListControl *plstc = (ListControl *)GetControlPtr(kidcList);
EndForm(((Upgrade *)plstc->GetSelectedItemData())->upgm);
return;
}
}
void UpgradeForm::OnPaintBackground(DibBitmap *pbm, UpdateMap *pupd)
{
RawBitmap *prbm = LoadRawBitmap("buildformbkgd.rbm");
BltHelper(pbm, prbm, pupd, m_rc.left, m_rc.top);
delete prbm;
}
} // namespace wi