#include "pch.h"
class TeleportPane :
public IItemEvent::Sink,
public EventTargetContainer<TeleportPane>,
public TrekClientEventSink
{
protected:
TRef<ButtonPane> m_pbuttonTeleport;
TRef<ButtonPane> m_pbuttonBack;
TRef<ButtonBarPane> m_pbuttonbarDestinations;
TRef<ListPane> m_plistPaneDestinations;
TRef<IItemEvent::Source> m_peventDestinations;
TRef<IItemEvent::Sink> m_psinkDestinations;
TVector<int> m_viColumns;
TRef<TListListWrapper<ImodelIGC*> > m_plistDestinations;
enum
{
sortName,
sortType,
sortSector,
} m_sortDestination;
public:
class DestinationPainter : public ItemPainter
{
const TVector<int>& m_viColumns;
public:
DestinationPainter(const TVector<int>& viColumns)
: m_viColumns(viColumns) {};
int GetXSize()
{
return m_viColumns[3];
}
int GetYSize()
{
return 14;
}
void Paint(ItemID pitemArg, Surface* psurface, bool bSelected, bool bFocus)
{
ImodelIGC* pDestination = (ImodelIGC*)pitemArg;
IshipIGC* pship = NULL;
IstationIGC* pstation = NULL;
if (pDestination == NULL || trekClient.MyMission() == NULL)
return;
if (pDestination->GetObjectType() == OT_ship)
{
CastTo(pship, pDestination);
}
else
{
assert(pDestination->GetObjectType() == OT_station);
CastTo(pstation, pDestination);
}
if (bSelected) {
psurface->FillRect(
WinRect(0, 0, GetXSize(), GetYSize()),
Color::Red()
);
}
TRef<IEngineFont> pfont;
if (pship && pship == trekClient.GetShip()->GetParentShip()
|| pstation && pstation == trekClient.GetShip()->GetStation())
{
pfont = TrekResources::SmallBoldFont();
}
else
{
pfont = TrekResources::SmallFont();
}
Color color;
if (CanKeepCurrentShip(pDestination))
{
color = Color::White();
}
else
{
color = 0.75f * Color::White();
}
psurface->DrawString(
pfont,
color,
WinPoint(0, 0),
pship ? pship->GetName() : pstation->GetName()
);
if (pship)
{
psurface->DrawString(
pfont,
color,
WinPoint(m_viColumns[0], 0),
HullName(pDestination)
);
}
psurface->DrawString(
pfont,
color,
WinPoint(m_viColumns[1] + 2, 0),
SectorName(pDestination)
);
if (pship && NumTurrets(pship))
{
int nNumTurrets = NumTurrets(pship);
if (nNumTurrets != 0)
{
psurface->DrawString(
pfont,
color,
WinPoint(m_viColumns[2] + 2, 0),
ZString((int)MannedTurrets(pship)) + ZString("/") + ZString(nNumTurrets)
);
}
}
}
};
public:
TeleportPane(Modeler* pmodeler)
: m_peventDestinations(NULL), m_sortDestination(sortName)
{
TRef<IObject> pobjColumns;
if (trekClient.MyMission() == NULL)
return;
TRef<INameSpace> pns = pmodeler->GetNameSpace("teleportpane");
CastTo(m_pbuttonTeleport, pns->FindMember("teleportTeleportButtonPane"));
CastTo(m_pbuttonBack, pns->FindMember("teleportBackButtonPane"));
CastTo(m_plistPaneDestinations, (Pane*)pns->FindMember("teleportPaneDestinationListPane"));
CastTo(pobjColumns, pns->FindMember("teleportPaneDestinationColumns"));
CastTo(m_pbuttonbarDestinations, pns->FindMember("teleportPaneDestinationListHeader"));
AddEventTarget(&TeleportPane::OnButtonTeleport, m_pbuttonTeleport->GetEventSource());
AddEventTarget(&TeleportPane::OnButtonBack, m_pbuttonBack->GetEventSource());
AddEventTarget(&TeleportPane::OnButtonBar, m_pbuttonbarDestinations->GetEventSource());
ParseIntVector(pobjColumns, m_viColumns);
m_plistPaneDestinations->SetItemPainter(new DestinationPainter(m_viColumns));
m_peventDestinations = m_plistPaneDestinations->GetSelectionEventSource();
if (m_psinkDestinations)
m_peventDestinations->RemoveSink(m_psinkDestinations);
m_peventDestinations->AddSink(m_psinkDestinations = new IItemEvent::Delegate(this));
AddEventTarget(&TeleportPane::OnButtonTeleport, m_plistPaneDestinations->GetDoubleClickEventSource());
RebuildList();
}
~TeleportPane()
{
if (m_peventDestinations)
{
m_peventDestinations->RemoveSink(m_psinkDestinations);
}
}
bool OnEvent(IItemEvent::Source *pevent, ItemID pitem)
{
if (pevent == m_peventDestinations) {
OnSelectDestination(pitem);
}
return true;
}
void OnShipStatusChange(PlayerInfo* pPlayer)
{
RebuildList();
}
void OnAddPlayer(MissionInfo* pMissionInfo, SideID sideID, PlayerInfo* pPlayerInfo)
{
RebuildList();
}
void OnDelPlayer(MissionInfo* pMissionInfo, SideID sideID, PlayerInfo* pPlayerInfo, QuitSideReason reason, const char* szMessageParam)
{
RebuildList(pPlayerInfo->GetShip());
}
void OnStationCaptured(StationID stationID, SideID sideID)
{
RebuildList();
}
void OnTechTreeChanged(SideID sideID)
{
if (sideID == trekClient.GetSideID())
{
RebuildList();
}
}
void OnModelTerminated(ImodelIGC* pmodel)
{
if (pmodel->GetSide() == trekClient.GetSide())
RebuildList(pmodel);
}
void OnDiscoveredStation(IstationIGC* pstation)
{
if (pstation->GetSide() == trekClient.GetSide())
RebuildList();
}
bool OnSelectDestination(ItemID pitem)
{
return true;
}
void OnBoardFailed(IshipIGC* pshipRequestedParent)
{
if (trekClient.GetShip()->GetCluster() == NULL)
{
if (pshipRequestedParent
&& MannedTurrets(pshipRequestedParent) < NumTurrets(pshipRequestedParent))
{
TRef<IMessageBox> pmsgBox = CreateMessageBox(
"Teleportation canceled - no turret positions were open.");
trekClient.PlaySoundEffect(noTurretsSound);
GetWindow()->GetPopupContainer()->OpenPopup(pmsgBox, false);
}
else
{
TRef<IMessageBox> pmsgBox = CreateMessageBox("Teleportation failed.");
GetWindow()->GetPopupContainer()->OpenPopup(pmsgBox, false);
}
}
}
bool OnButtonTeleport()
{
ImodelIGC* pDestination = (ImodelIGC*)(m_plistPaneDestinations->GetSelection());
IstationIGC* pstation = NULL;
if (pDestination == NULL || trekClient.MyMission() == NULL
|| trekClient.GetShip()->GetCluster() != NULL)
return true;
if (pDestination->GetObjectType() == OT_ship)
{
IshipIGC* pship;
CastTo(pship, pDestination);
if (trekClient.GetShip()->GetParentShip() != NULL)
{
trekClient.DisembarkAndBoard(pship);
}
else
{
trekClient.BoardShip(pship);
}
trekClient.PlaySoundEffect(personalJumpSound);
}
else
{
IstationIGC* pstation;
CastTo(pstation, pDestination);
if (trekClient.GetShip()->GetParentShip() != NULL)
{
if (pstation == trekClient.GetShip()->GetParentShip()->GetStation())
{
trekClient.BoardShip(NULL);
}
else
{
trekClient.DisembarkAndTeleport(pstation);
}
}
else
{
if (pstation != trekClient.GetShip()->GetStation())
{
trekClient.SetMessageType(BaseClient::c_mtGuaranteed);
BEGIN_PFM_CREATE(trekClient.m_fm, pfmDocked, C, DOCKED)
END_PFM_CREATE
pfmDocked->stationID = pstation->GetObjectID();
trekClient.StartLockDown(
"Teleporting to " + ZString(pstation->GetName()) + "....",
BaseClient::lockdownTeleporting);
}
}
}
GetWindow()->TurnOffOverlayFlags(ofTeleportPane);
return true;
}
bool OnButtonBack()
{
GetWindow()->TurnOffOverlayFlags(ofTeleportPane);
return true;
}
bool OnButtonBar(int iButton)
{
return true;
}
static bool CanBoard(IshipIGC* pship)
{
PlayerInfo* pPlayer = (PlayerInfo*)pship->GetPrivateData();
if (pship != trekClient.GetShip()
&& pship->GetSide() == trekClient.GetSide()
&& pPlayer->LastSeenState() == c_ssDocked
&& pship->GetPilotType() >= c_ptPlayer)
{
HullID hid = pPlayer->LastSeenShipType();
assert (hid != NA);
IhullTypeIGC* pht = trekClient.m_pCoreIGC->GetHullType(hid);
assert (pht);
if ((trekClient.GetShip()->GetPilotType() == c_ptCheatPlayer) ||
(pht->GetMaxFixedWeapons() != pht->GetMaxWeapons()))
{
return true;
}
}
return false;
}
void RebuildList(ImodelIGC* pmodelExclude = NULL)
{
TRef<TListListWrapper<ImodelIGC*> > plistNew = new TListListWrapper<ImodelIGC*>();
IsideIGC* pside = trekClient.GetSide();
if (pside && trekClient.GetSideID() != SIDE_TEAMLOBBY)
{
for (ShipLinkIGC* pshiplink = pside->GetShips()->first();
(pshiplink != NULL);
pshiplink = pshiplink->next())
{
IshipIGC* pship = pshiplink->data();
if (pship != pmodelExclude && CanBoard(pship))
{
plistNew->PushEnd(pship);
}
}
for (StationLinkIGC* pstationlink = pside->GetStations()->first();
(pstationlink != NULL);
pstationlink = pstationlink->next())
{
IstationIGC* pstation = pstationlink->data();
if (pstation != pmodelExclude
&& pstation->GetBaseStationType()->HasCapability(c_sabmRestart))
{
plistNew->PushEnd(pstation);
}
}
}
m_plistDestinations = plistNew;
m_plistPaneDestinations->SetList(m_plistDestinations);
}
static ZString HullName(ImodelIGC* pmodel)
{
if (pmodel->GetObjectType() == OT_ship)
{
PlayerInfo* pPlayer = (PlayerInfo*)((IshipIGC*)pmodel)->GetPrivateData();
IhullTypeIGC* phull = trekClient.GetCore()->GetHullType(pPlayer->LastSeenShipType());
if (phull == NULL)
return "<bug>";
else
return phull->GetName();
}
else
{
return "";
}
}
static bool CanKeepCurrentShip(ImodelIGC* pmodel)
{
if (pmodel->GetObjectType() == OT_ship)
{
return trekClient.GetShip()->GetParentShip() != NULL
|| trekClient.GetShip()->GetBaseHullType()->HasCapability(c_habmLifepod);
}
else
{
IstationIGC* pstation;
CastTo(pstation, pmodel);
IhullTypeIGC* pht = trekClient.GetShip()->GetBaseHullType();
return trekClient.GetShip()->GetStation() == pstation
|| pht && pstation->CanBuy(pht);
}
}
static ZString SectorName(ImodelIGC* pmodel)
{
IclusterIGC* psector;
if (pmodel->GetObjectType() == OT_ship)
{
PlayerInfo* pplayer = (PlayerInfo*)((IshipIGC*)pmodel)->GetPrivateData();
psector = trekClient.GetCore()->GetCluster(pplayer->LastSeenSector());
}
else
{
psector = pmodel->GetCluster();
}
if (psector == NULL)
return "unknown";
else
return psector->GetName();
}
static int MannedTurrets(IshipIGC* pshipParent)
{
int cMannedTurrets = 0;
const ShipListIGC* shipList = pshipParent->GetSide()->GetShips();
for (const ShipLinkIGC* lShip = shipList->first(); lShip; lShip = lShip->next())
{
IshipIGC* pship = lShip->data();
PlayerInfo* pplayer = (PlayerInfo*)pship->GetPrivateData();
if (pplayer->LastSeenState() == c_ssTurret)
{
PlayerInfo* pplayerParent = trekClient.FindPlayer(pplayer->LastSeenParent());
if (pplayerParent && pplayerParent->GetShip() == pshipParent)
cMannedTurrets++;
}
}
return cMannedTurrets;
}
static int NumTurrets(IshipIGC* pship)
{
PlayerInfo* pPlayer = (PlayerInfo*)pship->GetPrivateData();
const IhullTypeIGC* pHullType = trekClient.GetCore()->GetHullType(pPlayer->LastSeenShipType());
if (pHullType)
return pHullType->GetMaxWeapons() - pHullType->GetMaxFixedWeapons();
else
return 0;
}
};
TRef<IObject> CreateTeleportPane(Modeler* pmodeler)
{
return (IItemEvent::Sink*)new TeleportPane(pmodeler);
}