#include "pch.h"
#include "trekmdl.h"
#include "trekctrls.h"
const int c_iClusterHasNoRipcord = 0;
const int c_iClusterHasStationRipcord = 1;
const int c_iClusterHasShipRipcord = 2;
const Color c_rgColorNeutral(0.5f, 0.5f, 0.5f);
static void GetClusterOwners(IclusterIGC* pcluster, SideID& sideOwner, SideID& sideSecondaryOwner)
{
assert (c_cSidesMax == 6);
int nStations[c_cSidesMax] = {0, 0, 0, 0, 0, 0};
for (StationLinkIGC* psl = pcluster->GetStations()->first();
(psl != NULL);
psl = psl->next())
{
if (!psl->data()->GetStationType()->HasCapability(c_sabmPedestal))
nStations[psl->data()->GetSide()->GetObjectID()]++;
}
int nStationsOwner = 0;
int nStationsSecondaryOwner = 0;
sideOwner = NA;
sideSecondaryOwner = NA;
SideID sideID;
for (sideID = 0; sideID < c_cSidesMax; sideID++)
{
if (nStations[sideID] > nStationsOwner)
{
sideSecondaryOwner = sideOwner;
nStationsSecondaryOwner = nStationsOwner;
sideOwner = sideID;
nStationsOwner = nStations[sideID];
}
else if (nStations[sideID] > nStationsSecondaryOwner)
{
sideSecondaryOwner = sideID;
nStationsSecondaryOwner = nStations[sideID];
}
}
}
static int GetClusterPopulation(IclusterIGC* pcluster, IsideIGC* pside)
{
int n = 0;
SectorID sectorID = pcluster->GetObjectID();
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* pship = psl->data();
if (pship->GetSide() == pside)
{
PlayerInfo* ppi = (PlayerInfo*)(pship->GetPrivateData());
if (trekClient.m_fm.IsConnected())
{
if (ppi && (ppi->LastSeenSector() == sectorID) && (ppi->StatusIsCurrent()))
{
if (ppi->LastSeenState() != c_ssObserver && ppi->LastSeenState() != c_ssTurret)
{
IhullTypeIGC* pht = trekClient.GetCore()->GetHullType(ppi->LastSeenShipType());
if (pht != NULL && !(pht->GetCapabilities() & c_habmLifepod))
n++;
}
}
}
else
{
if (pship->GetCluster() == pcluster)
n++;
}
}
}
return n;
}
struct StoredIcon
{
Surface* psurfaceIcon;
IsideIGC* pside;
int count;
int sortOrder;
StoredIcon(void)
:
count(1)
{
}
};
typedef Slist_utl<StoredIcon> IconList;
typedef Slink_utl<StoredIcon> IconLink;
static void AddIcon(IObject* psurfaceIcon,
IsideIGC* pside,
int sortOrder,
int sideID,
IconList* picons)
{
for (IconLink* pil = picons->first(); (pil != NULL); pil = pil->next())
{
if ((pil->data().psurfaceIcon == (Surface*)psurfaceIcon) &&
(pil->data().pside == pside))
{
pil->data().count++;
return;
}
}
IconLink* p = new IconLink;
p->data().psurfaceIcon = (Surface*)psurfaceIcon;
p->data().pside = pside;
p->data().sortOrder = sortOrder += ((int)sideID) * 0x10000;
{
for (IconLink* pil = picons->first(); (pil != NULL); pil = pil->next())
{
if (sortOrder < pil->data().sortOrder)
{
pil->txen(p);
return;
}
}
}
picons->last(p);
}
class SectorInfoPane : public Image
{
private:
TRef<Image> m_pimageBkgnd;
TRef<Image> m_pimageSmallBkgnd;
TRef<Image> m_pimageLargeBkgnd;
TRef<Image> m_pimageExpand;
TRef<IclusterIGC> m_pClusterSel;
TRef<IclusterIGC> m_pClusterMouseOver;
public:
SectorInfoPane()
{
m_pimageSmallBkgnd = GetModeler()->LoadImage("consectorinfobmp", true);
m_pimageLargeBkgnd = GetModeler()->LoadImage("conesectorinfobmp", true);
m_pimageExpand = GetModeler()->LoadImage("consectorexpandbmp", true);
m_pimageBkgnd = m_pimageSmallBkgnd;
}
void CalcBounds()
{
m_bounds = m_pimageBkgnd->GetBounds();
}
void ClearCluster(void)
{
m_pClusterSel = NULL;
m_pClusterMouseOver = NULL;
}
void SelectCluster(IclusterIGC* pClusterSel)
{
m_pClusterSel = pClusterSel;
Changed();
}
void SelectMouseOverCluster(IclusterIGC* pClusterMouseOver)
{
m_pClusterMouseOver = pClusterMouseOver;
Changed();
}
MouseResult HitTest(IInputProvider* pprovider, const Point& point, bool bCaptured)
{
Surface* psurfaceBackground = m_pimageBkgnd->GetSurface();
Surface* psurfaceExpand = m_pimageExpand->GetSurface();
WinPoint pntButton = psurfaceBackground->GetSize() - psurfaceExpand->GetSize();
pntButton = pntButton - WinPoint(16, 4);
if (point.X() > pntButton.X() && point.Y() > pntButton.Y()
&& point.X() < psurfaceBackground->GetSize().X()
&& point.Y() < psurfaceBackground->GetSize().Y())
{
return MouseResultHit();
}
return m_pimageBkgnd->HitTest(pprovider, point, bCaptured);
}
WinPoint GetButtonOffset()
{
Surface* psurfaceBackground = m_pimageBkgnd->GetSurface();
Surface* psurfaceExpand = m_pimageExpand->GetSurface();
WinPoint pntButton = psurfaceBackground->GetSize() - psurfaceExpand->GetSize();
return pntButton - WinPoint(16, 4);
}
MouseResult Button(IInputProvider* pprovider, const Point& point, int button, bool bCaptured, bool bInside, bool bDown)
{
if (button == 0 && !bDown)
{
WinPoint pntButton = GetButtonOffset();
if (point.X() > pntButton.X() && point.Y() > pntButton.Y())
{
if (m_pimageBkgnd == m_pimageSmallBkgnd)
{
m_pimageBkgnd = m_pimageLargeBkgnd;
}
else
{
m_pimageBkgnd = m_pimageSmallBkgnd;
}
Changed();
}
}
return MouseResult();
}
void DrawAsteroidIcons(Context* pcontext, IEngineFont* pfont, IclusterIGC* pcluster,
const Point& ptAsteroids)
{
Point ptNext = ptAsteroids;
TMap<AsteroidAbilityBitMask, int> mapSpecialAsteroids;
TMap<AsteroidAbilityBitMask, Surface*> mapSpecialAsteroidIcons;
for (AsteroidLinkIGC* asteroidLink = pcluster->GetAsteroids()->first();
asteroidLink != NULL; asteroidLink = asteroidLink->next())
{
AsteroidAbilityBitMask aabm = asteroidLink->data()->GetCapabilities();
if ((aabm & ~c_aabmBuildable) != 0)
{
int nCount = 0;
mapSpecialAsteroids.Find(aabm, nCount);
mapSpecialAsteroids.Set(aabm, nCount+1);
mapSpecialAsteroidIcons.Set(aabm, (Surface*)asteroidLink->data()->GetIcon());
}
}
TMap<AsteroidAbilityBitMask, int>::Iterator iterCount(mapSpecialAsteroids);
TMap<AsteroidAbilityBitMask, Surface*>::Iterator iterIcon(mapSpecialAsteroidIcons);
while (!iterCount.End())
{
pcontext->DrawImage3D(iterIcon.Value(), Color::White(), false, ptNext);
pcontext->DrawString(
pfont,
Color::White(),
ptNext + Point(iterIcon.Value()->GetSize().X() + 4, 0),
ZString(iterCount.Value())
);
ptNext = ptNext - Point(0, iterIcon.Value()->GetSize().Y());
iterCount.Next();
iterIcon.Next();
}
}
float GetHeliumInCluster(IclusterIGC* pcluster)
{
float fOre = 0;
for (AsteroidLinkIGC* asteriodLink = pcluster->GetAsteroids()->first();
asteriodLink != NULL; asteriodLink = asteriodLink->next())
{
AsteroidAbilityBitMask aabm = asteriodLink->data()->GetCapabilities();
if ((aabm & c_aabmMineHe3) != 0)
{
fOre += asteriodLink->data()->GetOre();
}
}
return fOre;
}
void Render(Context* pcontext)
{
Surface* psurfaceBackground = m_pimageBkgnd->GetSurface();
pcontext->DrawImage(psurfaceBackground);
TRef<IEngineFont> pfont = TrekResources::SmallFont();
Surface* psurfaceExpand = m_pimageExpand->GetSurface();
pcontext->DrawImage(psurfaceExpand, false,
Point::Cast(psurfaceBackground->GetSize() - psurfaceExpand->GetSize() - WinPoint(16, 4)));
if (m_pClusterSel)
{
const int xBorder = 4;
float yTop = m_pimageBkgnd->GetBounds().GetRect().YSize();
Point ptSectorName(xBorder + 20, yTop - 13);
Point ptStations(xBorder, yTop - 26);
pcontext->DrawString(
pfont,
Color::White(),
ptSectorName,
ZString(m_pClusterSel->GetName()) + " Sector"
);
{
IconList icons;
IsideIGC* psideMe = trekClient.GetSide();
{
for (StationLinkIGC* psl = m_pClusterSel->GetStations()->first(); (psl != NULL); psl = psl->next())
{
if (!psl->data()->GetStationType()->HasCapability(c_sabmPedestal))
{
IsideIGC* pside = psl->data()->GetSide();
AddIcon(psl->data()->GetIcon(), pside, NA,
(pside == psideMe) ? (c_cSidesMax * 2) : (c_cSidesMax + pside->GetObjectID()), &icons);
}
}
}
{
SectorID sid = m_pClusterSel->GetObjectID();
for (ShipLinkIGC* psl = trekClient.m_pCoreIGC->GetShips()->first(); (psl != NULL); psl = psl->next())
{
PlayerInfo* ppi = (PlayerInfo*)(psl->data()->GetPrivateData());
if (ppi &&
ppi->StatusIsCurrent() &&
(ppi->LastSeenState() == c_ssFlying) &&
(ppi->LastSeenSector() == sid))
{
HullID hid = ppi->LastSeenShipType();
IhullTypeIGC* pht = trekClient.m_pCoreIGC->GetHullType(hid);
if (pht)
{
IsideIGC* pside = psl->data()->GetSide();
AddIcon(pht->GetIcon(), pside, hid,
(pside == psideMe) ? c_cSidesMax : pside->GetObjectID(), &icons);
}
}
}
}
{
Point ptNext = ptStations;
for (IconLink* pil = icons.first(); (pil != NULL); pil = pil->next())
{
if (ptNext.X() < GetButtonOffset().X())
{
const Color& color = pil->data().pside->GetColor();
pcontext->DrawImage3D(pil->data().psurfaceIcon,
color,
false, ptNext);
ptNext += Point(pil->data().psurfaceIcon->GetSize().X(), 0);
if (pil->data().count > 1)
{
TRef<IEngineFont> pfont = TrekResources::SmallFont();
ZString strCount = pil->data().count;
WinPoint pt = pfont->GetTextExtent(strCount);
pcontext->DrawString(pfont, Color::White(),
ptNext + Point(0, (pil->data().psurfaceIcon->GetSize().Y() - pt.Y())/2),
strCount);
ptNext += Point(pt.X() + 2, 0);
}
}
}
}
}
if (m_pimageBkgnd == m_pimageLargeBkgnd)
{
const int xSecondColumn = m_pimageSmallBkgnd->GetBounds().GetRect().XSize() + xBorder - 15;
Point ptHelium(xSecondColumn, yTop - 30);
Point ptAsteroids(xSecondColumn, yTop - 45);
pcontext->DrawString(
pfont,
Color::White(),
ptHelium,
"He3: " + ZString(int(GetHeliumInCluster(m_pClusterSel)))
);
DrawAsteroidIcons(pcontext, pfont, m_pClusterSel, ptAsteroids);
}
if (m_pClusterMouseOver)
{
assert(m_pClusterMouseOver == m_pClusterSel);
AssetMask am = m_pClusterMouseOver->GetClusterSite()->GetClusterAssetMask();
ClusterWarning cw = GetClusterWarning(am,
trekClient.MyMission()->GetMissionParams().bInvulnerableStations);
if (cw > c_cwNoThreat)
{
pcontext->DrawString(
pfont,
Color::White(),
Point(0,0),
GetClusterWarningText(cw)
);
}
}
}
}
};
TRef<IObject> SectorInfoPaneFactory::Apply(ObjectStack& stack)
{
TRef<SectorInfoPane> psectorinfo = new SectorInfoPane();
return (Value*)psectorinfo;
}
class SectorMapPane : public Image, public IEventSink, public TrekClientEventSink
{
private:
TRef<Image> m_pimageSectorEmpty;
TRef<Image> m_pimageOwnerHighlight;
TRef<Image> m_pimageSecondaryOwnerHighlight;
TRef<Image> m_pimageBkgnd;
TRef<Image> m_pimageSectorHighlight;
TRef<Image> m_pimageSectorTargetHighlight;
TRef<Image> m_pimageSectorSel;
TRef<Image> m_pimageSectorPickable;
TRef<Image> m_pimageSectorPickTarget;
TRef<Image> m_pimageSectorPickableStation;
TRef<Image> m_pimageSectorPickStationTarget;
TRef<Image> m_pimageSectorQueued;
TRef<Image> m_pimageCapitalWarning;
TRef<Image> m_pimageSectorEnemy;
TRef<Image> m_pimageSectorMiner;
TRef<Image> m_pimageSectorWarning;
TRef<Image> m_pimageBomberWarning;
TRef<Image> m_pimageSectorCombat;
TRef<IclusterIGC> m_pClusterSel;
TRef<IEventSink> m_peventSinkTimer;
TRef<SectorInfoPane> m_pSectorInfoPane;
float m_xMin;
float m_xMax;
float m_yMin;
float m_yMax;
float m_xClusterMin;
float m_xClusterMax;
float m_yClusterMin;
float m_yClusterMax;
bool m_bVisible;
int m_nMaskModeActive;
float m_xDrag;
float m_yDrag;
bool m_bDragging;
bool m_bHovering;
bool m_bCanDrag;
Point m_pointLastDrag;
WinRect m_rectMap;
bool m_bFlashFrame;
public:
enum { c_nXBorder = 4, c_nYBorder = 4 };
SectorMapPane(SectorInfoPane* pSectorInfoPane, Number* pvalueMode, int nMaskModeActive) :
Image(pvalueMode),
m_nMaskModeActive(nMaskModeActive),
m_pSectorInfoPane(pSectorInfoPane),
m_bVisible(false),
m_xDrag(0),
m_yDrag(0),
m_bDragging(false),
m_bHovering(false),
m_bCanDrag(false),
m_bFlashFrame(true)
{
pvalueMode->Update();
Modeler* pmodeler = GetModeler();
m_pimageBkgnd = pmodeler->LoadImage("sectormapbkgndbmp", false);
m_pimageSectorHighlight = pmodeler->LoadImage("sectorhighlightbmp", true);
m_pimageSectorTargetHighlight = pmodeler->LoadImage("sectortargetbmp", true);
m_pimageSectorSel = pmodeler->LoadImage("sectorselbmp", true);
m_peventSinkTimer = IEventSink::CreateDelegate(this);
m_rectMap = WinRect::Cast(m_pimageBkgnd->GetBounds().GetRect());
m_pimageSectorEmpty = pmodeler->LoadImage("sectoremptybmp", true);
m_pimageOwnerHighlight = pmodeler->LoadImage("sectorownerbmp", true);
m_pimageSecondaryOwnerHighlight = pmodeler->LoadImage("sectorinvaderbmp", true);
m_pimageSectorPickable = pmodeler->LoadImage("sectorripcordbmp", true);
m_pimageSectorPickTarget = pmodeler->LoadImage("sectorripcordtargetbmp", true);
m_pimageSectorPickableStation = pmodeler->LoadImage("sectorripcordstationbmp", true);
m_pimageSectorPickStationTarget = pmodeler->LoadImage("sectorripcordstationtargetbmp", true);
m_pimageSectorQueued = pmodeler->LoadImage("sectorqueuedbmp", true);
m_pimageCapitalWarning = pmodeler->LoadImage("sectorcapitalbmp", true);
m_pimageSectorCombat = pmodeler->LoadImage("sectorcombatbmp", true);
m_pimageSectorWarning = pmodeler->LoadImage("sectorwarningbmp", true);
m_pimageBomberWarning = pmodeler->LoadImage("sectorbomberbmp", true);
m_pimageSectorMiner = pmodeler->LoadImage("sectorminerbmp", true);
m_pimageSectorEnemy = pmodeler->LoadImage("sectorenemybmp", true);
}
~SectorMapPane()
{
SetVisible(false);
}
void CalcBounds()
{
m_bounds = m_pimageBkgnd->GetBounds();
}
MouseResult HitTest(IInputProvider* pprovider, const Point& point, bool bCaptured)
{
return m_pimageBkgnd->HitTest(pprovider, point, bCaptured);
}
void OnDelPlayer(MissionInfo* pMissionInfo, SideID sideID, PlayerInfo* pPlayerInfo, QuitSideReason reason, const char* szMessageParam)
{
if (pPlayerInfo == trekClient.GetPlayerInfo())
{
SetVisible(false);
m_pClusterSel = NULL;
m_pSectorInfoPane->ClearCluster();
}
}
void SelectCluster(IclusterIGC* pClusterSel)
{
if (pClusterSel == NULL)
{
IstationIGC* pstation = trekClient.GetShip()->GetStation();
if (pstation)
pClusterSel = pstation->GetCluster();
}
if (pClusterSel != m_pClusterSel)
{
m_pClusterSel = pClusterSel;
ZAssert(m_pSectorInfoPane);
m_pSectorInfoPane->SelectCluster(pClusterSel);
Changed();
}
}
void SetVisible(bool bVisible)
{
if (m_bVisible != bVisible)
{
m_bVisible = bVisible;
if (bVisible)
{
GetWindow()->GetTimer()->AddSink(m_peventSinkTimer, 0.2f);
SelectCluster(trekClient.GetChatCluster());
m_pSectorInfoPane->SelectMouseOverCluster(NULL);
}
else
{
m_pClusterSel = NULL;
ZAssert(m_pSectorInfoPane);
m_pSectorInfoPane->SelectCluster(NULL);
m_pSectorInfoPane->SelectMouseOverCluster(NULL);
GetWindow()->GetTimer()->RemoveSink(m_peventSinkTimer);
}
}
}
bool OnEvent(IEventSource* pevent)
{
Changed();
const int cDivisor = 2;
static int nTick = 0;
++nTick;
if (nTick == cDivisor)
{
m_bFlashFrame = !m_bFlashFrame;
nTick = 0;
}
return true;
}
void CalculateScreenMinAndMax()
{
bool bFirstCluster = true;
const ClusterListIGC* clusters = trekClient.m_pCoreIGC->GetClusters();
for (ClusterLinkIGC* cLink = clusters->first(); cLink != NULL; cLink = cLink->next())
{
IclusterIGC* pCluster = cLink->data();
if (pCluster->GetModels()->n() != 0)
{
float x = pCluster->GetScreenX();
float y = pCluster->GetScreenY();
if (bFirstCluster)
{
bFirstCluster = false;
m_xClusterMin = m_xClusterMax = x;
m_yClusterMin = m_yClusterMax = y;
}
else
{
if (x < m_xClusterMin)
m_xClusterMin = x;
else if (x > m_xClusterMax)
m_xClusterMax = x;
if (y < m_yClusterMin)
m_yClusterMin = y;
else if (y > m_yClusterMax)
m_yClusterMax = y;
}
}
}
const float c_bfr = 0.1f *
max(0.0001, max(m_xClusterMax - m_xClusterMin,
m_yClusterMax - m_yClusterMin));
m_xClusterMin -= c_bfr;
m_xClusterMax += c_bfr;
m_yClusterMin -= c_bfr;
m_yClusterMax += c_bfr;
m_xMin = m_xClusterMin;
m_xMax = m_xClusterMax;
m_yMin = m_yClusterMin;
m_yMax = m_yClusterMax;
float fDesiredAspectRatio = float(m_rectMap.XSize() - 2*c_nXBorder)/(m_rectMap.YSize() - 2*c_nYBorder);
const float fMapmakerHeight = 2.2f; const float fMaxHeight = fMapmakerHeight;
const float fMaxWidth = fMaxHeight * fDesiredAspectRatio;
if (m_xMax - m_xMin > fMaxWidth || m_yMax - m_yMin > fMaxHeight)
{
m_bCanDrag = true;
m_xMax = m_xMin + min(m_xMax - m_xMin, fMaxWidth);
m_yMax = m_yMin + min(m_yMax - m_yMin, fMaxHeight);
}
else
{
m_bCanDrag = false;
}
float fAspectRatio = (m_xMax - m_xMin) / (m_yMax - m_yMin);
if (fAspectRatio < fDesiredAspectRatio)
{
float fXGrowth = (fDesiredAspectRatio / fAspectRatio - 1) * (m_xMax - m_xMin);
m_xMax += fXGrowth / 2;
m_xMin -= fXGrowth / 2;
}
else if (fAspectRatio > fDesiredAspectRatio)
{
float fYGrowth = (fAspectRatio / fDesiredAspectRatio - 1) * (m_yMax - m_yMin);
m_yMax += fYGrowth / 2;
m_yMin -= fYGrowth / 2;
}
m_xMin += m_xDrag;
m_xMax += m_xDrag;
m_yMin += m_yDrag;
m_yMax += m_yDrag;
}
int ClusterHasFriendlyRipcord(IclusterIGC* pcluster, IsideIGC* pside, const ClusterListIGC& clustersRipcord)
{
const StationListIGC* stationList = pcluster->GetStations();
for (StationLinkIGC* stationLink = stationList->first();
stationLink; stationLink=stationLink->next())
{
IstationIGC* pstation = stationLink->data();
if (pstation->GetStationType()->HasCapability(c_sabmRipcord) &&
(pstation->GetSide() == pside))
{
return c_iClusterHasStationRipcord;
}
}
float ripcordSpeed;
{
IshipIGC* pss = trekClient.GetShip()->GetSourceShip();
if (pss->GetBaseHullType())
ripcordSpeed = pss->GetHullType()->GetRipcordSpeed();
else
ripcordSpeed = -1.0f;
}
for (ProbeLinkIGC* ppl = pcluster->GetProbes()->first(); (ppl != NULL); ppl = ppl->next())
{
IprobeIGC* pprobe = ppl->data();
if ((pprobe->GetSide() == pside) && pprobe->GetCanRipcord(ripcordSpeed))
return c_iClusterHasStationRipcord;
}
return clustersRipcord.find(pcluster) != NULL ? c_iClusterHasShipRipcord : c_iClusterHasNoRipcord;
}
IstationIGC* FindFriendlyStation(IclusterIGC* pcluster, IsideIGC* pside)
{
const StationListIGC* stationList = pcluster->GetStations();
for (StationLinkIGC* stationLink = stationList->first();
stationLink; stationLink=stationLink->next())
{
IstationIGC* pstation = stationLink->data();
if (pstation->GetStationType()->HasCapability(c_sabmRestart) &&
(pstation->GetSide() == pside))
{
return pstation;
}
}
return NULL;
}
bool HasBuildableAsteroid(IclusterIGC* pcluster,
AsteroidAbilityBitMask aabm1,
AsteroidAbilityBitMask aabm2)
{
AsteroidAbilityBitMask aabm = (aabm1 != 0) ? aabm1 : aabm2;
if ((aabm & ~c_aabmBuildable) != 0)
{
aabm &= ~c_aabmBuildable;
for (AsteroidLinkIGC* pal = pcluster->GetAsteroids()->first(); (pal != NULL); pal = pal->next())
{
if (pal->data()->HasCapability(aabm))
return true;
}
}
else if (aabm == c_aabmBuildable)
{
for (AsteroidLinkIGC* pal = pcluster->GetAsteroids()->first(); (pal != NULL); pal = pal->next())
{
if (pal->data()->HasCapability(aabm))
return true;
}
}
return false;
}
bool HasCommandTarget(IclusterIGC* pCluster, Command cmd)
{
ImodelIGC* ptarget = trekClient.GetShip()->GetCommandTarget(cmd);
if (ptarget)
{
if (ptarget->GetCluster() == pCluster)
return true;
else if (ptarget->GetObjectType() == OT_ship)
{
IshipIGC* pship = (IshipIGC*)ptarget;
PlayerInfo* ppi = (PlayerInfo*)(pship->GetPrivateData());
if (ppi->LastSeenSector() == pCluster->GetObjectID())
return true;
}
}
return false;
}
void Render(Context* pcontext)
{
pcontext->SetShadeMode(ShadeModeFlat);
Rect rectClip = m_bounds.GetRect();
rectClip.Expand(-1);
pcontext->Clip(rectClip);
CalculateScreenMinAndMax();
pcontext->DrawImage(m_pimageBkgnd->GetSurface());
{
const WarpListIGC* warps = trekClient.m_pCoreIGC->GetWarps();
TVector<VertexL> vertices(warps->n(), 0);
TVector<WORD> indices(warps->n(), 0);
for (WarpLinkIGC* warpLink = warps->first(); warpLink != NULL; warpLink = warpLink->next())
{
IwarpIGC* pWarp = warpLink->data();
IwarpIGC* pwarpDestination = pWarp->GetDestination();
assert (pwarpDestination != NULL);
if (pWarp->GetObjectID() > pwarpDestination->GetObjectID())
{
Color colorWarp = 0.5f * Color::White();
WinPoint point1 = GetClusterPoint(pWarp->GetCluster());
WinPoint point2 = GetClusterPoint(pwarpDestination->GetCluster());
indices.PushEnd(vertices.GetCount());
vertices.PushEnd(VertexL(Vector(point1.x, point1.y, 0), colorWarp));
indices.PushEnd(vertices.GetCount());
vertices.PushEnd(VertexL(Vector(point2.x, point2.y, 0), colorWarp));
}
}
if (vertices.GetCount() != 0)
{
pcontext->SetLineWidth(1.0f);
pcontext->DrawLines(vertices, indices);
}
}
ImodelIGC* pmodelRipcord = trekClient.GetShip()->GetRipcordModel();
IclusterIGC* pclusterRipcord;
IsideIGC* pside = trekClient.GetSide();
ClusterListIGC clustersRipcord;
if (pmodelRipcord)
{
{
IshipIGC* pshipSource = trekClient.GetShip()->GetSourceShip();
IhullTypeIGC* phtSource = pshipSource->GetBaseHullType();
HullAbilityBitMask habm = (phtSource && phtSource->HasCapability(c_habmCanLtRipcord))
? (c_habmIsRipcordTarget | c_habmIsLtRipcordTarget)
: c_habmIsRipcordTarget;
for (ShipLinkIGC* psl = pside->GetShips()->first(); (psl != NULL); psl = psl->next())
{
IshipIGC* pship = psl->data();
if (pship != pshipSource)
{
IclusterIGC* pc = trekClient.GetRipcordCluster(pship, habm);
if (pc)
clustersRipcord.last(pc);
}
}
}
pclusterRipcord = pmodelRipcord->GetCluster();
if ((pclusterRipcord == NULL) && (pmodelRipcord->GetObjectType() == OT_ship))
{
PlayerInfo* ppi = (PlayerInfo*)(((IshipIGC*)pmodelRipcord)->GetPrivateData());
if (ppi->StatusIsCurrent())
pclusterRipcord = trekClient.m_pCoreIGC->GetCluster(ppi->LastSeenSector());
}
}
const ClusterListIGC* clusters = trekClient.m_pCoreIGC->GetClusters();
for (ClusterLinkIGC* cLink = clusters->first(); cLink != NULL; cLink = cLink->next())
{
IclusterIGC* pCluster = cLink->data();
if (pCluster->GetModels()->n() != 0)
{
Point xy = Point::Cast(GetClusterPoint(pCluster));
pcontext->DrawImage3D(m_pimageSectorEmpty->GetSurface(), Color::White(), true, xy);
SideID sideOwner;
SideID sideSecondaryOwner;
GetClusterOwners(pCluster, sideOwner, sideSecondaryOwner);
AssetMask am = pCluster->GetClusterSite()->GetClusterAssetMask();
ClusterWarning warn = GetClusterWarning(am,
trekClient.MyMission()->GetMissionParams().bInvulnerableStations);
if (warn >= c_cwStationThreatened)
{
if (m_bFlashFrame)
pcontext->DrawImage3D(m_pimageSectorWarning->GetSurface(), Color::White(), true, xy);
}
else if (warn >= c_cwCapitalInCluster)
{
if (m_bFlashFrame)
pcontext->DrawImage3D(m_pimageCapitalWarning->GetSurface(), Color::White(), true, xy);
}
else if (warn >= c_cwBomberInCluster)
{
if (m_bFlashFrame)
pcontext->DrawImage3D(m_pimageBomberWarning->GetSurface(), Color::White(), true, xy);
}
else if (warn >= c_cwMinerThreatened)
{
if (m_bFlashFrame)
pcontext->DrawImage3D(m_pimageSectorMiner->GetSurface(), Color::White(), true, xy);
}
else if (warn >= c_cwCombatInCluster)
{
if (m_bFlashFrame)
pcontext->DrawImage3D(m_pimageSectorCombat->GetSurface(), Color::White(), true, xy);
}
if (trekClient.GetChatCluster() == pCluster)
pcontext->DrawImage3D(m_pimageSectorHighlight->GetSurface(), Color::White(), true, xy);
else if (m_pClusterSel == pCluster)
pcontext->DrawImage3D(m_pimageSectorSel->GetSurface(), Color::White(), true, xy);
bool bHasCurrentCommand = HasCommandTarget(pCluster, c_cmdAccepted);
bool bHasQueuedCommand = HasCommandTarget(pCluster, c_cmdQueued);
if (bHasCurrentCommand)
pcontext->DrawImage3D(m_pimageSectorTargetHighlight->GetSurface(), Color::White(), true, xy);
else if (bHasQueuedCommand)
pcontext->DrawImage3D(m_pimageSectorQueued->GetSurface(), Color::White(), true, xy);
if (pmodelRipcord)
{
if (pmodelRipcord->GetObjectType() == OT_ship)
{
if (pCluster == pclusterRipcord)
{
if (m_bFlashFrame)
pcontext->DrawImage3D(m_pimageSectorPickTarget->GetSurface(), Color::White(), true, xy);
else
pcontext->DrawImage3D(m_pimageSectorPickable->GetSurface(), Color::White(), true, xy);
}
else
{
int cfr = ClusterHasFriendlyRipcord(pCluster, pside, clustersRipcord);
if (cfr != c_iClusterHasNoRipcord)
{
pcontext->DrawImage3D(cfr == c_iClusterHasStationRipcord
? m_pimageSectorPickableStation->GetSurface()
: m_pimageSectorPickable->GetSurface(),
Color::White(), true, xy);
}
}
}
else
{
if (pCluster == pclusterRipcord)
{
if (m_bFlashFrame)
pcontext->DrawImage3D(m_pimageSectorPickStationTarget->GetSurface(), Color::White(), true, xy);
else
pcontext->DrawImage3D(m_pimageSectorPickableStation->GetSurface(), Color::White(), true, xy);
}
else
{
int cfr = ClusterHasFriendlyRipcord(pCluster, pside, clustersRipcord);
if (cfr != c_iClusterHasNoRipcord)
{
pcontext->DrawImage3D(cfr == c_iClusterHasStationRipcord
? m_pimageSectorPickableStation->GetSurface()
: m_pimageSectorPickable->GetSurface(),
Color::White(), true, xy);
}
}
}
}
else if (GetWindow()->GetOverlayFlags() & ofTeleportPane)
{
IstationIGC* pstation = trekClient.GetShip()->GetStation();
if (pstation && (pstation->GetCluster() != pCluster) &&
(FindFriendlyStation(pCluster, pside) != NULL))
{
pcontext->DrawImage3D(m_pimageSectorPickable->GetSurface(), Color::White(), true, xy);
}
}
else if (HasBuildableAsteroid(pCluster,
GetWindow()->GetCommandAsteroid(),
GetWindow()->GetInvestAsteroid()))
{
pcontext->DrawImage3D(m_pimageSectorPickable->GetSurface(), Color::White(), true, xy);
}
if (sideOwner != NA)
{
pcontext->DrawImage3D(
m_pimageOwnerHighlight->GetSurface(),
trekClient.GetCore()->GetSide(sideOwner)->GetColor(),
true,
xy
);
}
if (sideSecondaryOwner != NA)
{
pcontext->DrawImage3D(
m_pimageSecondaryOwnerHighlight->GetSurface(),
trekClient.GetCore()->GetSide(sideSecondaryOwner)->GetColor(),
true,
xy
);
}
{
int vnSidePopCount[c_cSidesMax];
int nSidesPresent = 0;
{
for (SideLinkIGC* psl = trekClient.m_pCoreIGC->GetSides()->first();
(psl != NULL);
psl = psl->next())
{
SideID sideID = psl->data()->GetObjectID();
vnSidePopCount[sideID] = GetClusterPopulation(pCluster, psl->data());
if (vnSidePopCount[sideID] != 0)
++nSidesPresent;
}
}
if (nSidesPresent > 0)
{
const int nDotHeight = 2;
const int nDotWidth = 2;
const int nShipWidth = 1;
const int nDotPitch = 1;
const int nRowPitch = 1;
const int nMaxPop = 7;
int nY = xy.Y() - (nSidesPresent * (nDotHeight + nDotPitch) - nRowPitch)/2;
for (SideLinkIGC* psl = trekClient.m_pCoreIGC->GetSides()->first();
(psl != NULL);
psl = psl->next())
{
int nPopulation = min(nMaxPop, vnSidePopCount[psl->data()->GetObjectID()]);
int nX = xy.X() + 6;
if (nPopulation > 0)
{
while (nPopulation > 0)
{
int nDotPopulation = min(nPopulation, nDotWidth/nShipWidth);
pcontext->FillRect(
WinRect(
nX,
nY,
nX + nDotPopulation * nShipWidth,
nY + nDotHeight
),
psl->data()->GetColor()
);
nX += nDotWidth + nDotPitch;
nPopulation -= nDotPopulation;
}
nY += nDotHeight + nRowPitch;
}
}
}
}
}
}
}
private:
WinPoint GetClusterPoint(IclusterIGC* pcluster)
{
WinPoint pt = WinPoint(
(int)(m_rectMap.XMin() + ((pcluster->GetScreenX() - m_xMin)/(m_xMax - m_xMin))*(m_rectMap.XSize() - 2*c_nXBorder) + c_nXBorder),
(int)(m_rectMap.YMin() + ((pcluster->GetScreenY() - m_yMin)/(m_yMax - m_yMin))*(m_rectMap.YSize() - 2*c_nYBorder) + c_nYBorder)
);
return pt;
}
IclusterIGC* GetClusterAtPoint(const Point& point)
{
const ClusterListIGC* clusters = trekClient.m_pCoreIGC->GetClusters();
IclusterIGC* pClusterFound = NULL;
int nMinDistance = 15;
for (ClusterLinkIGC* cLink = clusters->first(); cLink != NULL; cLink = cLink->next())
{
IclusterIGC* pCluster = cLink->data();
if (pCluster->GetModels()->n() != 0)
{
WinPoint xy = GetClusterPoint(pCluster);
Point pointSector((float)xy.X(), (float)xy.Y());
Point offset = point - pointSector;
int nDistance = sqrt(offset.LengthSquared());
if (nDistance < nMinDistance)
{
pClusterFound = pCluster;
nMinDistance = nDistance;
}
}
}
return pClusterFound;
}
void AttemptTeleportTo(IclusterIGC* pcluster)
{
IstationIGC* pstation = FindFriendlyStation(pcluster, trekClient.GetSide());
if (NULL == trekClient.GetShip()->GetStation())
{
}
else if (trekClient.GetShip()->GetStation()->GetCluster() == pcluster)
{
trekClient.PostText(false, "You are already in this cluster.");
trekClient.PlaySoundEffect(errorSound);
}
else if (pstation == NULL)
{
trekClient.PostText(false, "You do not have an appropriate station in this cluster.");
trekClient.PlaySoundEffect(errorSound);
}
else if (trekClient.GetShip()->GetParentShip() != NULL)
{
trekClient.DisembarkAndTeleport(pstation);
GetWindow()->TurnOffOverlayFlags(ofTeleportPane);
}
else
{
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);
}
}
void ChildChanged(Value* pvalue, Value* pvalueNew)
{
ZAssert(NULL == pvalueNew);
ZAssert(GetChild(0) == pvalue);
pvalue->Update();
if (trekClient.GetShip()->GetCluster() || trekClient.GetShip()->GetStation())
SetVisible((((int)Number::Cast(pvalue)->GetValue()) & m_nMaskModeActive) != 0);
}
const char* GetClusterCursor()
{
if (trekClient.GetShip()->fRipcordActive()
|| (GetWindow()->GetOverlayFlags() & ofTeleportPane))
return AWF_CURSOR_DEFAULT;
else if (GetWindow()->GetConsoleImage()->GetConsoleData()->IsComposingCommand()
|| trekClient.GetShip()->GetCluster() != NULL)
return "goto";
else
return AWF_CURSOR_DEFAULT;
}
void MouseMove(IInputProvider* pprovider, const Point& point, bool bCaptured, bool bInside)
{
if (bCaptured)
{
ZAssert(m_bDragging && m_bCanDrag);
float fScale = (m_xMax - m_xMin)/m_rectMap.XSize();
float fDeltaX = fScale * (m_pointLastDrag.X() - point.X());
float fDeltaY = fScale * (m_pointLastDrag.Y() - point.Y());
m_xDrag = max(min((m_xClusterMax - m_xClusterMin) - (m_xMax - m_xMin), m_xDrag + fDeltaX), 0);
m_yDrag = max(min((m_yClusterMax - m_yClusterMin) - (m_yMax - m_yMin), m_yDrag + fDeltaY), 0);
m_pointLastDrag = point;
GetWindow()->SetCursor(AWF_CURSOR_DRAG);
Changed();
}
else
{
IclusterIGC* pClusterFound = GetClusterAtPoint(point);
m_pSectorInfoPane->SelectMouseOverCluster(pClusterFound);
if (pClusterFound)
{
m_bHovering = true;
if (m_pClusterSel != pClusterFound)
trekClient.PlaySoundEffect(mouseoverSound);
SelectCluster(pClusterFound);
GetWindow()->SetCursor(GetClusterCursor());
}
else
{
m_bHovering = false;
SelectCluster(trekClient.GetChatCluster());
if (m_bCanDrag)
{
GetWindow()->SetCursor(AWF_CURSOR_DRAG);
}
else
{
GetWindow()->SetCursor(AWF_CURSOR_DEFAULT);
}
}
}
Changed();
}
virtual void MouseLeave(IInputProvider* pprovider)
{
m_bHovering = false;
SelectCluster(trekClient.GetChatCluster());
m_pSectorInfoPane->SelectMouseOverCluster(NULL);
if (!m_bDragging)
GetWindow()->SetCursor(AWF_CURSOR_DEFAULT);
Changed();
}
MouseResult Button(IInputProvider* pprovider, const Point& point, int button, bool bCaptured, bool bInside, bool bDown)
{
IclusterIGC* pClusterFound = GetClusterAtPoint(point);
if (bDown)
{
if (0 == button)
{
if (pClusterFound)
{
trekClient.PlaySoundEffect(mouseclickSound);
SelectCluster(pClusterFound);
if (trekClient.GetShip()->fRipcordActive() && !trekClient.GetShip()->GetAutopilot())
{
trekClient.RequestRipcord(trekClient.GetShip(), pClusterFound);
}
else if (GetWindow()->GetOverlayFlags() & ofTeleportPane)
{
AttemptTeleportTo(pClusterFound);
}
else
{
if (trekClient.GetShip()->GetCluster() == NULL)
{
ZAssert(trekClient.GetShip()->GetStation() != NULL);
trekClient.RequestViewCluster(pClusterFound);
GetWindow()->SetViewMode(TrekWindow::vmCommand);
}
else if (pClusterFound == trekClient.GetShip()->GetCluster())
{
}
else if (true) {
DataBuoyIGC db;
db.position = Vector(0, 0, 0);
db.clusterID = pClusterFound->GetObjectID();
db.type = c_buoyCluster;
IbuoyIGC* b = (IbuoyIGC*)(trekClient.m_pCoreIGC->CreateObject(trekClient.m_now, OT_buoy, &db, sizeof(db)));
assert (b);
b->AddConsumer();
trekClient.SendChat(trekClient.GetShip(),
CHAT_INDIVIDUAL, trekClient.GetShipID(),
NA, NULL,
c_cidGoto, OT_buoy, b->GetObjectID(), b);
b->ReleaseConsumer();
b->Release();
}
}
}
else if (m_bCanDrag)
{
m_bDragging = true;
m_pointLastDrag = point;
GetWindow()->SetCursor(AWF_CURSOR_DRAG);
Changed();
return MouseResultCapture();
}
}
else if (1 == button && pClusterFound)
{
trekClient.PlaySoundEffect(mouseclickSound);
TrekWindow* pWindow = GetWindow ();
pWindow->GetConsoleImage()->GetConsoleData()->PickCluster(pClusterFound, button);
pWindow->GetInput ()->SetFocus (false);
}
}
else
{
if (m_bDragging && 0 == button)
{
m_bDragging = false;
if (pClusterFound)
{
GetWindow()->SetCursor(GetClusterCursor());
}
else if (!bInside)
{
GetWindow()->SetCursor(AWF_CURSOR_DEFAULT);
}
else
{
GetWindow()->SetCursor(AWF_CURSOR_DRAG);
}
Changed();
return MouseResultRelease();
}
}
Changed();
return MouseResult();
}
void OnClusterChanged(IclusterIGC* pcluster)
{
if (!m_bHovering)
{
SelectCluster(pcluster);
}
}
};
TRef<IObject> SectorMapPaneFactory::Apply(ObjectStack& stack)
{
TRef<SectorInfoPane> pinfoPane; CastTo(pinfoPane, (Pane*)(IObject*)stack.Pop());
TRef<Number> pnumberMode; CastTo(pnumberMode, (IObject*)stack.Pop());
TRef<Number> pnumberMaskModeActive; CastTo(pnumberMaskModeActive, (IObject*)stack.Pop());
TRef<Image> psectormap = new SectorMapPane(pinfoPane, pnumberMode, (int)pnumberMaskModeActive->GetValue());
return (Value*)psectormap;
}