/* FinalSun/FinalAlert 2 Mission Editor Copyright (C) 1999-2024 Electronic Arts, Inc. Authored by Matthias Wagner 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 . */ // Map->h: Interface for the class CMap. // // CMap holds all information for the current map // ////////////////////////////////////////////////////////////////////// #include "structs.h" #include #include "variables.h" #include "macros.h" #include "ovrlinline.h" #include "Tube.h" extern TILEDATA** tiledata; extern DWORD* tiledata_count; extern ofstream errstream; extern map tilesets_start; extern CIniFile* tiles; extern CFinalSunApp theApp; extern int shoreset; extern CIniFile rules; extern TILEDATA* un_tiledata; extern CIniFile g_data; extern int ramp2set; extern int pave2set; extern int ramp2set_start; extern int pave2set_start; extern int rampset_start; extern int rampset; #if !defined(AFX_MAP_H__9278CAC0_D4E7_11D3_B63B_444553540001__INCLUDED_) #define AFX_MAP_H__9278CAC0_D4E7_11D3_B63B_444553540001__INCLUDED_ #include "IniFile.h" // Hinzugefügt von der Klassenansicht #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include #define MAPDATA_UPDATE_FROM_INI 0 #define MAPDATA_UPDATE_TO_INI 1 #define MAPDATA_UPDATE_TO_INI_ALL 2 #define MAPDATA_UPDATE_TO_INI_ALL_PREVIEW 4 #define MAPDATA_UPDATE_TO_INI_ALL_COMPRESSED 8 struct NODEDATA { NODEDATA(); int type; int index; CString house; }; // mapfielddata is the data of every field in an extracted isomappack! struct MAPFIELDDATA { unsigned short wX; unsigned short wY; WORD wGround; BYTE bData[3]; BYTE bHeight; BYTE bData2[1]; }; #define MAPFIELDDATA_SIZE 11 /* struct TILEDATA{}; contains the information needed for one field of the map. */ struct FIELDDATA { FIELDDATA(); short unit; // unit number short infantry[SUBPOS_COUNT]; // infantry number short aircraft; // aircraft number short structure; // structure number short structuretype; // structure type id short terrain; // terrain number int terraintype; // terrain type id #ifdef SMUDGE_SUPP short smudge; int smudgetype; #endif short waypoint; // waypoint number NODEDATA node; // node info BYTE overlay; // overlay number BYTE overlaydata; // overlay data info WORD wGround; // ground type (tile) WORD bMapData; // add. data BYTE bSubTile; BYTE bHeight; // height of tile BYTE bMapData2; // add. data2 short celltag; // celltag uses //std::uint16_t wTubeId; // tube ID //char cTubePart; // 0 is start, 1 is exit, and 2-101 are tube parts unsigned bReserved : 1; // for program usage unsigned bHide : 1; unsigned bRedrawTerrain : 1; // force redraw unsigned bCliffHack : 1; unsigned bRNDImage : 4; // for using a,b,c of tmp tiles }; struct SNAPSHOTDATA { SNAPSHOTDATA(); int left; int top; int bottom; int right; BOOL* bRedrawTerrain; BYTE* overlay; BYTE* overlaydata; WORD* wGround; WORD* bMapData; BYTE* bSubTile; BYTE* bHeight; BYTE* bMapData2; BYTE* bRNDData; //CIniFile mapfile; }; class CMapData { public: BOOL m_noAutoObjectUpdate; void SetFielddataAt(DWORD dwPos, FIELDDATA* lpFd) { if (dwPos >= fielddata_size) return; RemoveOvrlMoney(fielddata[dwPos].overlay, fielddata[dwPos].overlaydata); fielddata[dwPos] = (*lpFd); AddOvrlMoney(fielddata[dwPos].overlay, fielddata[dwPos].overlaydata); }; DWORD GetMapPos(int mapX, int mapY) const { return mapX + mapY * m_IsoSize; } DWORD GetMapPos(const MapCoords& coords) const { return coords.x + coords.y * m_IsoSize; } bool hasLat(WORD wTileSet) const; void HideField(DWORD dwPos, BOOL bHide); void SetReserved(DWORD dwPos, BYTE val); DWORD GetTileID(DWORD dwTileSet, int iTile); int GetNecessarySlope(DWORD dwPos); void CreateSlopesAt(DWORD dwPos) { //OutputDebugString("CreateSlopes()\n"); FIELDDATA m = *GetFielddataAt(dwPos); if (m.wGround == 0xFFFF) m.wGround = 0; TILEDATA& d = (*tiledata)[m.wGround]; int ns = -1; int i, e, p = 0; int h[3][3]; for (i = 0;i < 3; i++) { for (e = 0;e < 3;e++) { int pos = dwPos + (i - 1) + (e - 1) * m_IsoSize; if (pos < 0 || pos >= m_IsoSize * m_IsoSize) { h[i][e] = 0; } else { FIELDDATA m2 = *GetFielddataAt(pos); h[i][e] = m.bHeight - m2.bHeight; } } } // check if the current tile must be heightened anyway if (!theApp.m_Options.bDisableSlopeCorrection && d.bMorphable) { if ((h[0][1] < 0 && h[2][1] < 0) || (h[1][0] < 0 && h[1][2] < 0) || (h[1][0] < 0 && h[0][2] < 0 && h[0][1] >= 0) || (h[1][0] < 0 && h[2][2] < 0 && h[2][1] >= 0) || (h[0][1] < 0 && h[2][0] < 0 && h[1][0] >= 0) || (h[0][1] < 0 && h[2][2] < 0 && h[1][2] >= 0) || (h[1][2] < 0 && h[0][0] < 0 && h[0][1] >= 0) || (h[1][2] < 0 && h[2][0] < 0 && h[2][1] >= 0) || (h[2][1] < 0 && h[0][0] < 0 && h[1][0] >= 0) || (h[2][1] < 0 && h[0][2] < 0 && h[1][2] >= 0) || (h[1][0] < 0 && h[0][1] < 0 && h[0][0] >= 0) || (h[0][1] < 0 && h[1][2] < 0 && h[0][2] >= 0) || (h[1][2] < 0 && h[2][1] < 0 && h[2][2] >= 0) || (h[2][1] < 0 && h[1][0] < 0 && h[2][0] >= 0) ) { SetHeightAt(dwPos, m.bHeight + 1); for (i = -1;i < 2;i++) for (e = -1;e < 2;e++) CreateSlopesAt(dwPos + i + e * m_IsoSize); return; } } BOOL checkOtherSlopes = FALSE; if (h[0][0] == -1 && h[2][2] == -1 && h[2][0] >= 0 && h[0][2] >= 0 && h[1][0] >= 0 && h[1][2] >= 0 && h[0][1] >= 0 && h[2][1] >= 0) ns = SLOPE_UP_LEFTTOP_AND_RIGHTBOTTOM; if (h[0][2] == -1 && h[2][0] == -1 && h[0][0] >= 0 && h[2][2] >= 0 && h[0][1] >= 0 && h[1][0] >= 0 && h[1][2] >= 0 && h[2][1] >= 0) ns = SLOPE_UP_LEFTBOTTOM_AND_RIGHTTOP; if (ns == -1) if (h[1][0] == -1 && h[0][1] != -1 && h[1][2] != -1 && h[2][1] != -1) { ns = SLOPE_UP_LEFT; } else if (h[0][1] == -1 && h[1][0] != -1 && h[2][1] != -1 && h[1][2] != -1) { ns = SLOPE_UP_TOP; } else if (h[1][2] == -1 && h[0][1] != -1 && h[1][0] != -1 && h[2][1] != -1) { ns = SLOPE_UP_RIGHT; } else if (h[2][1] == -1 && h[0][1] != -1 && h[1][0] != -1 && h[1][2] != -1) { ns = SLOPE_UP_BOTTOM; } if (ns == -1) { if (h[0][0] == -2) ns = SLOPE_DOWN_BOTTOM; if (h[2][0] == -2) ns = SLOPE_DOWN_RIGHT; if (h[0][2] == -2) ns = SLOPE_DOWN_LEFT; if (h[2][2] == -2) ns = SLOPE_DOWN_TOP; } if (ns == -1 && h[0][0] == -1) { if (h[1][0] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_RIGHTBOTTOM; else if (h[1][0] == 0 && h[0][1] == 0) ns = SLOPE_UP_LEFTTOP; //else if(h[2][2]==1) ns=SLOPE_DOWN_BOTTOM; } if (ns == -1 && h[2][0] == -1) { if (h[1][0] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_RIGHTTOP; else if (h[1][0] == 0 && h[2][1] == 0) ns = SLOPE_UP_LEFTBOTTOM; //else if(h[0][2]==1) ns=SLOPE_DOWN_RIGHT; } if (ns == -1 && h[0][2] == -1) { if (h[1][2] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_LEFTBOTTOM; else if (h[1][2] == 0 && h[0][1] == 0) ns = SLOPE_UP_RIGHTTOP; //else if(h[2][0]==1) ns=SLOPE_DOWN_LEFT; } if (ns == -1 && h[2][2] == -1) { if (h[1][2] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_LEFTTOP; else if (h[1][2] == 0 && h[2][1] == 0) ns = SLOPE_UP_RIGHTBOTTOM; //else if(h[0][0]==1) ns=SLOPE_DOWN_TOP; } if (ns == -1 && h[1][0] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_RIGHTTOP; if (ns == -1 && h[1][2] == -1 && h[2][1] == -1) ns = SLOPE_DOWN_LEFTTOP; if (ns == -1 && h[1][0] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_RIGHTBOTTOM; if (ns == -1 && h[1][2] == -1 && h[0][1] == -1) ns = SLOPE_DOWN_LEFTBOTTOM; int rampbase = rampset_start;//atoi((*tiles).sections["General"].values["RampBase"]); int rampsmooth = atoi((*tiles).sections["General"].AccessValueByName("RampSmooth")); if (ns == -1 && (d.wTileSet == rampset || d.wTileSet == rampsmooth) && d.bMorphable) { SetTileAt(dwPos, 0, 0); } if (tiledata == &un_tiledata) { int r = ramp2set; int m = pave2set; if (ns == -1 && (d.wTileSet == r || d.wTileSet == m) && d.bMorphable) { SetTileAt(dwPos, pave2set_start/*GetTileID(m,0)*/, 0); } } if (d.bMorphable && ns != -1) { if (tiledata == &un_tiledata) // NEW URBAN FIX FOR URBAN PAVEMENT { //[NewUrbanInfo] //Morphable2=114 //Ramps2=117 int r = ramp2set; int m = pave2set; if (d.wTileSet == r || d.wTileSet == m) rampbase = ramp2set_start; } SetTileAt(dwPos, rampbase + ns - 1, 0); } } void CreateMap(DWORD dwWidth, DWORD dwHeight, LPCTSTR lpTerrainType, DWORD dwGroundHeight); BOOL SetTileAt(DWORD dwPos, DWORD dwID, DWORD dwTile) { if (dwPos > fielddata_size) return FALSE; int replacement = 0; // MW fix: ignore for bridges if ((*tiledata)[dwID].bReplacementCount && atoi((*tiles).sections["General"].AccessValueByName("BridgeSet")) != (*tiledata)[dwID].wTileSet) { replacement = rand() * (1 + (*tiledata)[dwID].bReplacementCount) / RAND_MAX; } fielddata[dwPos].wGround = dwID; fielddata[dwPos].bSubTile = dwTile; fielddata[dwPos].bRNDImage = replacement; int e; fielddata[dwPos].bRedrawTerrain = FALSE; int xx, yy; for (xx = -2;xx < 0;xx++) { for (yy = -2;yy < 0;yy++) { int npos = dwPos + xx + yy * m_IsoSize; if (npos > 0 && fielddata[dwPos].bHeight - fielddata[npos].bHeight >= 4) { fielddata[dwPos].bRedrawTerrain = TRUE; break; } } if (fielddata[dwPos].bRedrawTerrain) break; } Mini_UpdatePos(dwPos % m_IsoSize, dwPos / m_IsoSize, IsMultiplayer()); return TRUE; } void SetHeightAt(DWORD dwPos, BYTE bHeight) { int height = (char)bHeight; if (height > MAXHEIGHT) height = MAXHEIGHT; // too high else if (height < 0) height = 0; if (dwPos < fielddata_size) fielddata[dwPos].bHeight = height; } int GetBuildingID(LPCSTR lpBuildingName); void ImportRUL(LPCTSTR lpFilename); void ExportRulesChanges(const char* filename); void DeleteRulesSections(); DWORD GetWaypointCount() const; DWORD GetCelltagCount() const; WCHAR* GetUnitName(LPCTSTR lpID) const; DWORD GetTerrainCount() const; DWORD GetAircraftCount() const; DWORD GetStructureCount() const; DWORD GetUnitCount() const; DWORD GetInfantryCount() const; void GetStdUnitData(DWORD dwIndex, STDOBJECTDATA* lpStdUnit) const; void GetStdAircraftData(DWORD dwIndex, STDOBJECTDATA* lpStdAircraft) const; void GetWaypointData(DWORD dwIndex, CString* lpID, DWORD* lpdwPos) const; BOOL IsGroundObjectAt(DWORD dwPos) const; BOOL AddTerrain(LPCTSTR lpType, DWORD dwPos, int suggestedIndex = -1); void GetTerrainData(DWORD dwIndex, CString* lpType) const; void GetTerrainData(DWORD dwIndex, TERRAIN* lpTerrain) const; BOOL AddUnit(UNIT* lpUnit, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, CString suggestedID = ""); BOOL AddAircraft(AIRCRAFT* lpAircraft, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, CString suggestedID = ""); void GetCelltagData(DWORD dwIndex, CString* lpTag, DWORD* lpdwPos) const; BOOL AddCelltag(LPCTSTR lpTag, DWORD dwPos); void GetAircraftData(DWORD dwIndex, AIRCRAFT* lpAircraft) const; void GetUnitData(DWORD dwIndex, UNIT* lpUnit) const; void GetInfantryData(DWORD dwIndex, INFANTRY* lpInfantry) const; void GetStdInfantryData(DWORD dwIndex, STDOBJECTDATA* lpStdInfantry) const; INT GetUnitTypeID(LPCTSTR lpType); void InitializeUnitTypes(); BOOL AddStructure(STRUCTURE* lpStructure, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, CString suggestedID = ""); BOOL AddInfantry(INFANTRY* lpInfantry, LPCTSTR lpType = NULL, LPCTSTR lpHouse = NULL, DWORD dwPos = 0, int suggestedIndex = -1); BOOL AddNode(NODE* lpNode, WORD dwPos); void GetStdStructureData(DWORD dwIndex, STDOBJECTDATA* lpStdStructure) const; void GetStructureData(DWORD dwIndex, STRUCTURE* lpStructure) const; BOOL AddWaypoint(CString lpID, DWORD dwPos); void DeleteNode(LPCTSTR lpHouse, DWORD dwIndex); void DeleteTerrain(DWORD dwIndex); void DeleteAircraft(DWORD dwIndex); void DeleteStructure(DWORD dwIndex); void DeleteUnit(DWORD dwIndex); void DeleteCelltag(DWORD dwIndex); void DeleteWaypoint(DWORD dwIndex); void DeleteInfantry(DWORD dwIndex); INT GetCelltagAt(DWORD dwPos) const { return fielddata[dwPos].celltag; } INT GetCelltagAt(MapCoords pos) const { return GetCelltagAt(GetMapPos(pos)); } INT GetWaypointAt(DWORD dwPos) const { return fielddata[dwPos].waypoint; } INT GetWaypointAt(MapCoords pos) const { return GetWaypointAt(GetMapPos(pos)); } INT GetTerrainAt(DWORD dwPos) const { return fielddata[dwPos].terrain; } INT GetTerrainAt(MapCoords pos) const { return GetTerrainAt(GetMapPos(pos)); } INT GetAirAt(DWORD dwPos) const { return fielddata[dwPos].aircraft; } INT GetAirAt(MapCoords pos) const { return GetAirAt(GetMapPos(pos)); } INT GetStructureAt(DWORD dwPos) const { if (fielddata[dwPos].structure > -1) return fielddata[dwPos].structure; return -1; } INT GetStructureAt(MapCoords pos) const { return GetStructureAt(GetMapPos(pos)); } INT GetUnitAt(DWORD dwPos) const { return fielddata[dwPos].unit; } INT GetUnitAt(MapCoords pos) const { return GetUnitAt(GetMapPos(pos)); } INT GetInfantryAt(DWORD dwPos, DWORD dwSubPos = 0xFFFFFFFF) const { if (dwSubPos == 0xFFFFFFFF) { int i; for (i = 0;i < SUBPOS_COUNT;i++) if (fielddata[dwPos].infantry[i] != -1) return fielddata[dwPos].infantry[i]; return -1; } return fielddata[dwPos].infantry[dwSubPos]; } INT GetInfantryAt(MapCoords pos, DWORD dwSubPos = 0xFFFFFFFF) { return GetInfantryAt(GetMapPos(pos), dwSubPos); } INT GetNodeAt(DWORD dwPos, CString& lpHouse) const; INT GetNodeAt(MapCoords pos, CString& lpHouse) const { return GetNodeAt(GetMapPos(pos), lpHouse); } INT GetHeightAt(DWORD dwPos) const { return fielddata[dwPos].bHeight; } INT GetHeightAt(const MapCoords& coords) const { return GetHeightAt(GetMapPos(coords)); } const FIELDDATA* GetFielddataAt(DWORD dwPos) const { if (dwPos >= fielddata_size) { outside_f.bReserved = 1; return &outside_f; } return &fielddata[dwPos]; }; FIELDDATA* GetFielddataAt(DWORD dwPos) { if (dwPos >= fielddata_size) { outside_f.bReserved = 1; return &outside_f; } return &fielddata[dwPos]; }; const FIELDDATA* GetFielddataAt(const MapCoords& pos) const { auto dwPos = GetMapPos(pos); if (dwPos >= fielddata_size) { outside_f.bReserved = 1; return &outside_f; } return &fielddata[dwPos]; }; FIELDDATA* GetFielddataAt(const MapCoords& pos) { auto dwPos = GetMapPos(pos); if (dwPos >= fielddata_size) { outside_f.bReserved = 1; return &outside_f; } return &fielddata[dwPos]; }; BYTE GetOverlayDataAt(DWORD dwPos); void SetOverlayDataAt(DWORD dwPos, BYTE bValue); BYTE GetOverlayAt(DWORD dwPos); void SetOverlayAt(DWORD dwPos, BYTE bValue); void ClearOverlay(); void ClearOverlayData(); const std::vector>& GetTubes() const { return m_tubes; } DWORD GetIsoSize() const { return m_IsoSize; } void LoadMap(const std::string& file); void UpdateIniFile(DWORD dwFlags = MAPDATA_UPDATE_TO_INI); CIniFile& GetIniFile(); CString GetAITriggerTypeID(DWORD dwAITriggerType); DWORD GetAITriggerTypeIndex(LPCTSTR lpID); WORD GetHouseIndex(LPCTSTR lpHouse); void GetAITriggerType(DWORD dwAITriggerType, AITRIGGERTYPE* pAITrg); DWORD GetAITriggerTypeCount(); CString GetHouseID(WORD wHouse, BOOL bCountry = FALSE); WORD GetHousesCount(BOOL bCountries = FALSE); WORD GetHeight() const { return m_maprect.bottom; }; WORD GetWidth() const { return m_maprect.right; }; BOOL IsRulesSection(LPCTSTR lpSection); CMapData(); virtual ~CMapData(); void Pack(BOOL bCreatePreview = FALSE, BOOL bCompression = FALSE); void Unpack(); void UpdateTreeInfo(LPCSTR lpTreeType = NULL); void UpdateBuildingInfo(LPCSTR lpUnitType = NULL); void CalcMapRect(); // MW change: UpdateStructures() public, so that houses dialog can access it void UpdateStructures(BOOL bSave = FALSE); MapCoords ToMapCoords(ProjectedCoords xy) const; MapCoords ToMapCoords3d(ProjectedCoords xy, int mapZ) const; MapCoords ToMapCoords3d(ProjectedCoords xy, bool bAllowAccessBehindCliffs=false, bool ignoreHideFlagsAndOutside=false) const; ProjectedCoords ProjectCoords(MapCoords xy) const; ProjectedCoords ProjectCoords3d(MapCoords xy) const; ProjectedCoords ProjectCoords3d(MapCoords xy, int z) const; bool isInside(MapCoords xy) const; __forceinline CPoint GetMiniMapPos(MapCoords mapCoords) { int x, y; GetMiniMapPos(mapCoords.x, mapCoords.y, x, y); return CPoint(static_cast(x), static_cast(y)); } private: void UpdateTubes(BOOL bSave); MAPFIELDDATA* GetMappackPointer(DWORD dwPos); void UpdateMapFieldData(BOOL bSave = FALSE); DWORD m_IsoSize; mutable FIELDDATA outside_f; BOOL isInitialized; void UpdateCelltags(BOOL bSave = FALSE); void UpdateOverlay(BOOL bSave = FALSE); void UpdateNodes(BOOL bSave = FALSE); void UpdateWaypoints(BOOL bSave = FALSE); void UpdateUnits(BOOL bSave = FALSE); void UpdateTerrain(BOOL bSave = FALSE, int num = -1); void UpdateInfantry(BOOL bSave = FALSE); void UpdateAircraft(BOOL bSave = FALSE); map buildingid; map terrainid; #ifdef SMUDGE_SUPP map smudgeid; #endif BYTE m_Overlay[262144]; // overlay byte values (extracted) BYTE m_OverlayData[262144]; // overlay data byte values (extracted) BYTE* m_mfd; // map field data buffer DWORD dwIsoMapSize; CIniFile m_mapfile; RECT m_maprect; RECT m_vismaprect; FIELDDATA* fielddata; int fielddata_size; SNAPSHOTDATA* m_snapshots; DWORD dwSnapShotCount; int m_cursnapshot; int m_money; vector m_structurepaint; protected: void InitMinimap(); vector> m_tubes; // vectors for terrain, infantry, structures and units, as those need to be displayed very fast. // we don´t need them for aircraft right now, as there won´t be many aircrafts on the map anyway. #ifdef SMUDGE_SUPP vector m_smudges; #endif vector m_terrain; vector m_infantry; vector m_units; vector m_structures; // we use a dib to draw the minimap std::vector m_mini_colors; BITMAPINFO m_mini_biinfo; int m_mini_pitch; enum OverlayCreditsType { OverlayCredits_Riparius = 0, OverlayCredits_Cruentus = 1, OverlayCredits_Vinifera = 2, OverlayCredits_Aboreus = 3, OverlayCredits_NumOf }; std::array m_overlayCredits; __forceinline void RemoveOvrlMoney(unsigned char ovrl, unsigned char ovrld) { if (ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) { m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Riparius]; } if (ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) { m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Cruentus]; } if (ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) { m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Vinifera]; } if (ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END) { m_money -= (ovrld + 1) * m_overlayCredits[OverlayCredits_Aboreus]; } } __forceinline void AddOvrlMoney(unsigned char ovrl, unsigned char ovrld) { if (ovrl >= RIPARIUS_BEGIN && ovrl <= RIPARIUS_END) { m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Riparius]; } if (ovrl >= CRUENTUS_BEGIN && ovrl <= CRUENTUS_END) { m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Cruentus]; } if (ovrl >= VINIFERA_BEGIN && ovrl <= VINIFERA_END) { m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Vinifera]; } if (ovrl >= ABOREUS_BEGIN && ovrl <= ABOREUS_END) { m_money += (ovrld + 1) * m_overlayCredits[OverlayCredits_Aboreus]; } } __forceinline void GetMiniMapPos(int i, int e, int& x, int& y) { const int pheight = m_mini_biinfo.bmiHeader.biHeight; const DWORD dwIsoSize = m_IsoSize; y = e / 2 + i / 2; x = dwIsoSize - i + e; int tx, ty; tx = GetWidth(); ty = GetHeight(); ty = ty / 2 + tx / 2; tx = dwIsoSize - GetWidth() + GetHeight(); x -= tx; y -= ty; x += pheight; y += pheight / 2; } __forceinline void Mini_UpdatePos(const int i, const int e, bool isMultiplayer) { const int pwidth = m_mini_biinfo.bmiHeader.biWidth; const int pheight = m_mini_biinfo.bmiHeader.biHeight; if (m_mini_colors.empty() || !tiledata) return; const DWORD dwIsoSize = m_IsoSize; const int pitch = m_mini_pitch; int x = 0; int y = 0; GetMiniMapPos(i, e, x, y); y = pheight - y - 1; int xiso = i; int yiso = e; if (xiso >= m_IsoSize) xiso = m_IsoSize - 1; if (yiso >= m_IsoSize) yiso = m_IsoSize - 1; if (xiso < 0) xiso = 0; if (yiso < 0) yiso = 0; DWORD dwPos = xiso + yiso * dwIsoSize; int dwDrawPos = (x * 3 + y * pitch); int size = pitch * pheight; if (dwDrawPos >= size || x >= pwidth || y >= pheight || x < 0 || y < 0) return; if (dwPos >= m_IsoSize * m_IsoSize) return; if (dwDrawPos + 3 >= m_mini_colors.size()) return; RGBTRIPLE& col = (RGBTRIPLE&)m_mini_colors[dwDrawPos]; RGBTRIPLE& col_r = (RGBTRIPLE&)m_mini_colors[(dwDrawPos + sizeof(RGBTRIPLE)) < size ? dwDrawPos + sizeof(RGBTRIPLE) : dwDrawPos]; FIELDDATA td; td = *GetFielddataAt(dwPos); STDOBJECTDATA sod; sod.house = ""; int ic; for (ic = 0;ic < SUBPOS_COUNT;ic++) { if (td.infantry[ic] >= 0) { GetStdInfantryData(td.infantry[ic], &sod); } } if (td.structure >= 0) { GetStdStructureData(td.structure, &sod); } if (td.aircraft >= 0) { GetStdAircraftData(td.aircraft, &sod); } if (td.unit >= 0) { GetStdUnitData(td.unit, &sod); } int ground = (td.wGround >= (*tiledata_count)) ? 0 : td.wGround; int subt = td.bSubTile; int ttype = 0; if (subt < (*tiledata)[ground].wTileCount) ttype = (*tiledata)[ground].tiles[subt].bTerrainType; // mw added check: if (subt >= (*tiledata)[ground].wTileCount) return; RGBTRIPLE& l = (*tiledata)[ground].tiles[subt].rgbLeft; RGBTRIPLE& r = (*tiledata)[ground].tiles[subt].rgbRight; int pos = GetHeightAt(dwPos); col.rgbtBlue = l.rgbtBlue; col.rgbtGreen = l.rgbtGreen; col.rgbtRed = l.rgbtRed; col_r.rgbtBlue = r.rgbtBlue; col_r.rgbtGreen = r.rgbtGreen; col_r.rgbtRed = r.rgbtRed; if (isGreenTiberium(td.overlay)) { #ifndef RA2_MODE col.rgbtBlue = 0; col.rgbtGreen = 200; col.rgbtRed = 0; col_r = col; #else col.rgbtBlue = 0; col.rgbtGreen = 250; col.rgbtRed = 250; col_r = col; #endif } else if (td.overlay == OVRL_VEINS) { col.rgbtBlue = 120; col.rgbtGreen = 180; col.rgbtRed = 190; col_r = col; } else if (td.overlay == OVRL_VEINHOLE || td.overlay == OVRL_VEINHOLEBORDER) { col.rgbtBlue = 120; col.rgbtGreen = 160; col.rgbtRed = 165; col_r = col; } else if (td.overlay != 0xFF) { col.rgbtBlue = 20; col.rgbtGreen = 20; col.rgbtRed = 20; col_r = col; } if (sod.house.GetLength() > 0) { /* if(strstr(sod.house, houses[1].name)) { col.rgbtRed=255; col.rgbtGreen=0; col.rgbtBlue=0; } else if(strstr(sod.house,houses[0].name)) { col.rgbtRed=180; col.rgbtGreen=180; col.rgbtBlue=0; } else { col.rgbtRed=200; col.rgbtGreen=200; col.rgbtBlue=200; }*/ COLORREF c = ((CFinalSunDlg*)theApp.m_pMainWnd)->m_view.m_isoview->GetColor(sod.house); col.rgbtRed = GetRValue(c); col.rgbtBlue = GetBValue(c); col.rgbtGreen = GetGValue(c); col_r = col; } // MW: ADD: make red start pos dots if (isMultiplayer) { CString id; DWORD p; int wp = td.waypoint; BOOL startpos = FALSE; int i, e; for (i = -1;i < 2;i++) { for (e = -1;e < 2;e++) { if (dwPos + i + e * m_IsoSize < fielddata_size) { int w = GetWaypointAt(dwPos + i + e * m_IsoSize); if (w >= 0) { GetWaypointData(w, &id, &p); if (atoi(id) < 8) { startpos = TRUE; break; } } } } if (startpos) break; } if (startpos) { col.rgbtBlue = 0; col.rgbtGreen = 0; col.rgbtRed = 255; col_r = col; } } } // helper function. Is val==iSet1 or val=iSet2? __forceinline BOOL st(int val, int iSet) { if (val == iSet) return TRUE; return FALSE; } public: void RedrawMinimap(); BOOL GetInfantryINIData(int index, CString* lpINI); #ifdef SMUDGE_SUPP void UpdateSmudges(BOOL bSave = FALSE, int num = -1); void DeleteSmudge(DWORD dwIndex); BOOL AddSmudge(SMUDGE* lpSmudge); void GetSmudgeData(DWORD dwIndex, SMUDGE* lpData) const; void UpdateSmudgeInfo(LPCSTR lpSmudgeType = NULL); #endif BOOL IsYRMap(); BOOL IsMapSection(LPCSTR lpSectionName); void ResizeMap(int iLeft, int iTop, DWORD dwNewWidth, DWORD dwNewHeight); void SmoothTiberium(DWORD dwPos); int GetPowerOfHouse(LPCTSTR lpHouse); int GetMoneyOnMap() const; int CalcMoneyOnMap(); void GetMinimap(BYTE** lpData, BITMAPINFO* lpBI, int* pitch); void GetStructurePaint(int index, STRUCTUREPAINT* lpStructurePaint) const; void Paste(int x, int y, int z_mod); void Copy(int left = 0, int top = 0, int right = 0, int bottom = 0); CString GetTheater(); BOOL IsMultiplayer(); void CreateShore(int left, int top, int right, int bottom, BOOL bRemoveUseless = TRUE); void Redo(); void SmoothAllAt(DWORD dwPos); __forceinline void SmoothAt(DWORD dwPos, int iSmoothSet, int iLatSet, int iTargetSet, BOOL bIgnoreShore = TRUE) { int i; int its, iss, ils; int iLatGround = tilesets_start[iLatSet]; int iSmoothGround = tilesets_start[iSmoothSet]; its = (*tiledata)[tilesets_start[iTargetSet]].tiles[0].bTerrainType; iss = (*tiledata)[iSmoothGround].tiles[0].bTerrainType; ils = (*tiledata)[iLatGround].tiles[0].bTerrainType; FIELDDATA m = *GetFielddataAt(dwPos); if (m.wGround == 0xFFFF) m.wGround = 0; // do we have that certain LAT tile here? if ((*tiledata)[m.wGround].wTileSet != iSmoothSet && (*tiledata)[m.wGround].wTileSet != iLatSet) return; //if(m.wGround==iLatGround) m.wGround=iSmoothGround; if (its == iss && (*tiledata)[m.wGround].wTileSet == iSmoothSet) m.wGround = iLatGround; if (its == iss) ils += 1; BOOL bOnlyLat = TRUE; //BOOL bNoLat=TRUE; int ns = -1; int e, p = 0; int ts[3][3]; // terrain info int set = (*tiledata)[m.wGround].wTileSet; for (i = 0;i < 3; i++) { for (e = 0;e < 3;e++) { int pos = dwPos + (i - 1) + (e - 1) * m_IsoSize; if (pos < 0 || pos >= fielddata_size) { ts[i][e] = 0; } else { FIELDDATA m2 = *GetFielddataAt(pos); if (m2.wGround == 0xFFFF) m2.wGround = 0; int cur_set = (*tiledata)[m2.wGround].wTileSet; //if(cur_set==iSmoothSet) bNoLat=FALSE; // if (its == iss && cur_set == iSmoothSet) { m2.wGround = iLatGround; cur_set = iLatSet; } if (cur_set == iSmoothSet || cur_set == iTargetSet) bOnlyLat = FALSE; /*if(cur_set != iSmoothSet && cur_set!= iLatSet && cur_set!=iTargetSet) { ts[i][e]=(*tiledata)[m2.wGround].tiles[m2.bSubTile].bTerrainType; if((*tiledata)[m2.wGround].wTileSet!=shoreset) { ts[i][e]=0;//ts[i][e]+1; // make sure you don´t smooth at it except it´s shore } //if(bIgnoreShore && (*tiledata)[m2.wGround].wTileSet==shoreset) // ts[i][e]=0;//ts[i][e]+1; } else*/ if (its == iss && cur_set != set) { if (cur_set == shoreset && !bIgnoreShore) ts[i][e] = its; else if (cur_set != iSmoothSet && cur_set != iTargetSet && cur_set != iLatSet) ts[i][e] = 0; else ts[i][e] = its; } else if (its == iss && cur_set == set) ts[i][e] = ils; else { ts[i][e] = (*tiledata)[m2.wGround].tiles[m2.bSubTile].bTerrainType; if (cur_set != shoreset && cur_set != iLatSet && cur_set != iSmoothSet) { ts[i][e] = 0;//ts[i][e]+1; // make sure you don´t smooth at it except it´s shore } } } } } //if(bOnlyLat) return; int needed = -1; // 1/1 is smoothed tile if (ts[1][1] == ils) { // single lat if (ts[0][1] != ils && ts[1][0] != ils && ts[1][2] != ils && ts[2][1] != ils) needed = 16; else if (ts[0][1] == ils && ts[1][0] == ils && ts[1][2] == ils && ts[2][1] == ils) needed = 0; else if (ts[0][1] == ils && ts[2][1] == ils && ts[1][0] != ils && ts[1][2] != ils) needed = 11; else if (ts[1][0] == ils && ts[1][2] == ils && ts[0][1] != ils && ts[2][1] != ils) needed = 6; else if (ts[1][0] != ils && ts[0][1] == ils && ts[2][1] == ils) needed = 9; else if (ts[2][1] != ils && ts[1][0] == ils && ts[1][2] == ils) needed = 5; else if (ts[1][2] != ils && ts[0][1] == ils && ts[2][1] == ils) needed = 3; else if (ts[0][1] != ils && ts[1][0] == ils && ts[1][2] == ils) needed = 2; else if (ts[0][1] == ils && ts[1][0] != ils && ts[1][2] != ils && ts[2][1] != ils) needed = 15; else if (ts[1][2] == ils && ts[1][0] != ils && ts[0][1] != ils && ts[2][1] != ils) needed = 14; else if (ts[2][1] == ils && ts[1][0] != ils && ts[0][1] != ils && ts[1][2] != ils) needed = 12; else if (ts[1][0] == ils && ts[0][1] != ils && ts[1][2] != ils && ts[2][1] != ils) needed = 8; else if (ts[1][0] != ils && ts[2][1] != ils) needed = 13; else if (ts[1][0] != ils && ts[0][1] != ils) needed = 10; else if (ts[2][1] != ils && ts[1][2] != ils) needed = 7; else if (ts[0][1] != ils && ts[1][2] != ils) needed = 4; } else if (ts[1][1] == its) { // replace target set instead of smooth set //if(st(ts[0][0], && ts[0][1] } needed -= 1; if (needed >= 0) { /*for(i=0;i<*tiledata_count;i++) { if((*tiledata)[i].wTileSet==iLatSet) { break; } }*/ i = tilesets_start[iLatSet]; // i is first lat tile int e; for (e = 0;e < needed;e++) { i += (*tiledata)[i].wTileCount; } SetTileAt(dwPos, i, 0); } else if (needed == -1) { /*for(i=0;i<*tiledata_count;i++) { if((*tiledata)[i].wTileSet==iSmoothSet) { break; } }*/ i = tilesets_start[iSmoothSet]; // i is first lat tile SetTileAt(dwPos, i, 0); } } BOOL GetLocalSize(RECT* rect) const; void Undo(); void TakeSnapshot(BOOL bEraseFollowing = TRUE, int left = 0, int top = 0, int right = 0, int bottom = 0); BOOL CheckMapPackData(); int GetInfantryCountAt(DWORD dwPos); void DeleteTube(std::uint16_t wID); // void SetTube(WORD wID, CTube *lpTI); void SetTube(CTube* lpTI); CTube* GetTube(std::uint16_t wID); }; inline bool CMapData::isInside(MapCoords xy) const { return xy.x >= 0 && xy.y >= 0 && xy.x < m_IsoSize && xy.y < m_IsoSize; } inline MapCoords CMapData::ToMapCoords(ProjectedCoords xy) const { return ToMapCoords3d(xy, 0); } inline MapCoords CMapData::ToMapCoords3d(ProjectedCoords xy, int mapZ) const { float cx = xy.x, cy = xy.y + mapZ * f_y / 2; return MapCoords( cy / (float)f_y - cx / (float)f_x + (float)(m_IsoSize - 2) / 2 + (float)0.5, cy / (float)f_y + cx / (float)f_x - (float)(m_IsoSize - 2) / 2.0f - (float)0.5 ); } inline MapCoords CMapData::ToMapCoords3d(const ProjectedCoords xy, bool bAllowAccessBehindCliffs, bool ignoreHideFlagsAndOutside) const { auto xy2d = ToMapCoords(xy); static const auto fxy = ProjectedVec(f_x, f_y).convertT(); auto ret = ignoreHideFlagsAndOutside ? xy2d : MapCoords(-1, -1); for (int i = 15; i >= 0; i--) { for (int e = 0; e < 3; e++) { const MapVec off(i, i); // this is a vertical line starting from the bottom const MapVec off2(e == 1 ? -1 : 0, e == 2 ? -1 : 0); // increase x or y or neither in map coordinates by one so that we have a broader area to check const MapCoords cur = xy2d + off + off2; if (isInside(cur)) { const auto& mfd = *GetFielddataAt(GetMapPos(cur)); const int ground = mfd.wGround == 0xFFFF ? 0 : mfd.wGround; if (ignoreHideFlagsAndOutside || (!mfd.bHide && !(tiledata && (*tiledata)[ground].bHide))) { const auto curProj = ProjectCoords3d(cur); // now projCoords hold the logical pixel coordinates for the current field... // we now need to check if cx and cy are in this field //if(*x >= m && *x<= m+f_x && *y>=n && *y<=n+f_y) { auto df1 = (xy - curProj).convertT(); auto dfScaled = df1 / fxy; auto d = Vec2(dfScaled.y - dfScaled.x + 0.5f, dfScaled.y + dfScaled.x - 0.5f); if (d.x >= 0.0f && d.y >= 0.0f && d.x <= 1.0f && d.y <= 1.0f)// || (!bAllowAccessBehindCliffs && xy.y >= curProj.y))) //if (d == MapCoords(0, 0)) { if (bAllowAccessBehindCliffs) ret = cur; else return cur; } } } } } } return ret; } inline ProjectedCoords CMapData::ProjectCoords(MapCoords xy) const { return ProjectCoords3d(xy, 0); } inline ProjectedCoords CMapData::ProjectCoords3d(MapCoords xy, int z) const { return ProjectedCoords( (m_IsoSize - 2 - xy.x + xy.y) * f_x / 2, (xy.y + xy.x - z) * f_y / 2 ); } inline ProjectedCoords CMapData::ProjectCoords3d(MapCoords xy) const { return ProjectCoords3d(xy, isInside(xy) ? GetHeightAt(xy) : 0); } #endif // !defined(AFX_MAP_H__9278CAC0_D4E7_11D3_B63B_444553540001__INCLUDED_)