/*
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 .
*/
// CliffModifier.cpp: Implementierung der Klasse CCliffModifier.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "stdafx.h"
#include "CliffModifier.h"
#include "variables.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////
CCliffModifier::CCliffModifier()
{
}
CCliffModifier::~CCliffModifier()
{
}
BOOL CCliffModifier::PlaceCliff(DWORD dwXFrom, DWORD dwYFrom, DWORD dwXDest, DWORD dwYDest, BOOL bAlternative)
{
m_bAlternative = bAlternative;
int x_diff, y_diff;
x_diff = dwXDest - dwXFrom;
y_diff = dwYDest - dwYFrom;
if (x_diff > 0 && y_diff > 0 && ((float)y_diff) / ((float)x_diff) > 1.33f) {
x_diff = 0;
dwXDest = dwXFrom;
}
if (x_diff < 0 && y_diff>0 && ((float)y_diff) / (-(float)x_diff) > 1.33f) {
x_diff = 0;
dwXDest = dwXFrom;
}
if (x_diff > 0 && y_diff < 0 && ((float)-y_diff) / ((float)x_diff) > 1.33f) {
x_diff = 0;
dwXDest = dwXFrom;
}
if (x_diff < 0 && y_diff < 0 && (-(float)y_diff) / (-(float)x_diff) > 1.33f) {
x_diff = 0;
dwXDest = dwXFrom;
}
if (y_diff > 0 && x_diff > 0 && ((float)x_diff) / ((float)y_diff) > 2) {
y_diff = 0;
dwYDest = dwYFrom;
}
if (y_diff < 0 && x_diff>0 && ((float)x_diff) / (-(float)y_diff) > 2) {
y_diff = 0;
dwYDest = dwYFrom;
}
if (y_diff > 0 && x_diff < 0 && ((float)-x_diff) / ((float)y_diff) > 2) {
y_diff = 0;
dwYDest = dwYFrom;
}
if (y_diff < 0 && x_diff < 0 && (-(float)x_diff) / (-(float)y_diff) > 2) {
y_diff = 0;
dwYDest = dwYFrom;
}
m_dwFrom = dwXFrom + dwYFrom * Map->GetIsoSize();
m_dwTo = dwXDest + dwYDest * Map->GetIsoSize();
if (!x_diff && !y_diff) return FALSE;
if (x_diff && y_diff) {
if ((x_diff > 0 && y_diff > 0)) {
m_direction = cd_verticdiag_bottom;
} else if ((x_diff < 0 && y_diff < 0)) {
m_direction = cd_verticdiag_top;
} else if ((x_diff < 0 && y_diff>0)) {
m_direction = cd_horizdiag_right;
} else if (x_diff > 0 && y_diff < 0) {
m_direction = cd_horizdiag_left;
}
} else if (y_diff < 0) {
m_direction = cd_horiz_left;
} else if (y_diff > 0) {
m_direction = cd_horiz_right;
} else if (x_diff < 0) {
m_direction = cd_vertic_top;
} else if (x_diff > 0) {
m_direction = cd_vertic_bottom;
}
switch (m_direction) {
case cd_horiz_left:
m_addx = 0;
m_addy = -1;
break;
case cd_horiz_right:
m_addx = 0;
m_addy = 1;
break;
case cd_horizdiag_left:
m_addx = 1;
m_addy = -1;
break;
case cd_horizdiag_right:
m_addx = -1;
m_addy = 1;
break;
case cd_vertic_top:
m_addx = -1;
m_addy = 0;
break;
case cd_vertic_bottom:
m_addx = 1;
m_addy = 0;
break;
case cd_verticdiag_top:
m_addx = -1;
m_addy = -1;
break;
case cd_verticdiag_bottom:
m_addx = 1;
m_addy = 1;
break;
}
int i, e;
DWORD dwCurPos = m_dwFrom;
int startheight = Map->GetHeightAt(dwCurPos);
DWORD dwLastTile = -1;
FIELDDATA* fd = Map->GetFielddataAt(dwCurPos);
int ground = fd->wGround;
int subtile = fd->bSubTile;
if (ground == 0xFFFF) ground = 0;
startheight -= (*tiledata)[ground].tiles[subtile].bZHeight;
ModifyStartPos(&dwCurPos, FALSE);
BOOL bSmall = FALSE;
DWORD dwFirstStartPos = dwCurPos;
DWORD dwTile = GetTileToPlace(dwCurPos, &bSmall);
BOOL bFirstPos = TRUE;
while (dwCurPos != m_dwTo) {
ModifyCurrentPos(&dwCurPos, TRUE, bSmall);
if (!bFirstPos) {
dwTile = GetTileToPlace(dwCurPos, &bSmall);
dwLastTile = dwTile;
} else
bFirstPos = FALSE;
if (dwTile == -1) break;
TILEDATA* t = &(*tiledata)[dwTile];
if (m_addx < 0) dwCurPos += t->cx * m_addx;
if (m_addy < 0) dwCurPos += t->cy * m_addy * Map->GetIsoSize();
int o = 0;
DWORD dwTmpTile = dwTile;
while (dwFirstStartPos != dwCurPos && dwTile == dwLastTile) {
o++;
if (o == 10) break;
dwTmpTile = GetTileToPlace(dwCurPos, &bSmall);
if ((*tiledata)[dwTmpTile].cx == (*tiledata)[dwTile].cx && (*tiledata)[dwTile].cy == (*tiledata)[dwTmpTile].cy)
dwTile = dwTmpTile;
}
t = &(*tiledata)[dwTile];
int p = 0;
for (i = 0; i < t->cx; i++) {
for (e = 0; e < t->cy; e++) {
if (t->tiles[p].pic != NULL) {
Map->SetHeightAt(dwCurPos + i + e * Map->GetIsoSize(), startheight + t->tiles[p].bZHeight);
Map->SetTileAt(dwCurPos + i + e * Map->GetIsoSize(), dwTile, p);
}
p++;
}
}
if (m_addx > 0) dwCurPos += t->cx * m_addx;
if (m_addy > 0) dwCurPos += t->cy * m_addy * Map->GetIsoSize();
ModifyCurrentPos(&dwCurPos, FALSE, bSmall);
dwLastTile = dwTile;
}
return TRUE;
}
void CCliffModifier::ModifyStartPos(DWORD* dwStartPos, BOOL bSmall)
{
}
void CCliffModifier::ModifyCurrentPos(DWORD* dwPos, BOOL bBeforePlacing, BOOL bSmall)
{
}
DWORD CCliffModifier::GetTileToPlace(DWORD dwPos, BOOL* bSmall)
{
vector careables;
vector useables;
map notusedascliff;
CString type;
int count = 0;
switch (m_direction) {
case cd_horiz_left:
case cd_horiz_right:
type = "horiz_";
break;
case cd_horizdiag_left:
case cd_horizdiag_right:
type = "horiz_diag_";
break;
case cd_vertic_top:
case cd_vertic_bottom:
type = "vertic_";
break;
case cd_verticdiag_top:
case cd_verticdiag_bottom:
type = "vertic_diag_";
break;
}
CString sec = GetDataSection();
CIniFile& ini = Map->GetIniFile();
auto const& theaterID = g_data.GetString("Map", "Theater");
if (!theaterID.IsEmpty()) {
sec += theaterID;
}
count = g_data.GetInteger(sec, type + "c");
int i;
DWORD dwStartSet = 0;
/*for(i=0;i<(*tiledata_count);i++)
{
if( (!m_bAlternative && (*tiledata)[i].wTileSet==cliffset) || (m_bAlternative && (*tiledata)[i].wTileSet==cliff2set))
{
dwStartSet=i;
break;
}
}*/
// a bit faster:
if (m_bAlternative) dwStartSet = cliff2set_start;
else dwStartSet = cliffset_start;
for (i = 0; i < count; i++) {
char c[50];
itoa(i, c, 10);
CString cur = type;
cur += c;
notusedascliff[dwStartSet + g_data.GetInteger(sec, cur)] = TRUE;
}
CString corner_searched = "";
DWORD dwCurPos = dwPos;
int isosize = Map->GetIsoSize();
ModifyStartPos(&dwCurPos, FALSE);
int e;
for (i = -1; i < 2; i++) {
for (e = -1; e < 2; e++) {
FIELDDATA* fd = Map->GetFielddataAt(dwCurPos + i + e * isosize);
int ground = fd->wGround;
if (ground == 0xFFFF) ground = 0;
if ((*tiledata)[ground].wTileSet == cliffset && notusedascliff.find(ground) == notusedascliff.end()) {
if (i == 0 && e == -1) { corner_searched = "cornerleft_"; break; }
if (i == 0 && e == 1) { corner_searched = "cornerright_"; break; }
if (i == -1 && e == 0) { corner_searched = "cornertop_"; break; }
if (i == 1 && e == 0) { corner_searched = "cornerbottom_"; break; }
/*if(e==-1) {corner_searched="cornerleft_";break;}
if(e==1) {corner_searched="cornerright_";break;}
if(i==-1) {corner_searched="cornertop_";break;}
if(i==1) {corner_searched="cornerbottom_";break;}*/
}
}
if (corner_searched.GetLength() > 0) break;
}
BOOL bCornerFound = FALSE;;
if (int icount = g_data.GetInteger(sec, type + corner_searched + "c")) {
bCornerFound = TRUE;
count = icount;
}
if (!bCornerFound) corner_searched = "";
if (count == 0) return -1;
DWORD dwX = dwPos % Map->GetIsoSize();
DWORD dwY = dwPos / Map->GetIsoSize();
DWORD dwDX = m_dwTo % Map->GetIsoSize();
DWORD dwDY = m_dwTo / Map->GetIsoSize();
for (i = 0; i < count; i++) {
char c[50];
itoa(i, c, 10);
careables.push_back(dwStartSet + g_data.GetInteger(sec, type + corner_searched + c));
}
for (i = 0; i < careables.size(); i++) {
TILEDATA& t = (*tiledata)[careables[i]];
if (m_addx > 0 && dwX + m_addx * t.cx > dwDX) continue;
if (m_addy > 0 && dwY + m_addy * t.cy > dwDY) continue;
if (m_addx < 0 && dwX + m_addx * t.cx < dwDX) continue;
if (m_addy < 0 && dwY + m_addy * t.cy < dwDY) continue;
useables.push_back(careables[i]);
}
if (useables.size() < 1) return -1;
*bSmall = FALSE;
int k;
k = rand() % (useables.size());
TILEDATA& t1 = (*tiledata)[useables[k]];
for (i = 0; i < careables.size(); i++) {
TILEDATA& t = (*tiledata)[careables[i]];
if (t.cx > t1.cx || t.cy > t1.cy) { *bSmall = TRUE; break; }
}
// check for water
BOOL bWater = FALSE;
for (i = 0; i < t1.cx; i++) {
for (e = 0; e < t1.cy; e++) {
FIELDDATA* fd = Map->GetFielddataAt(dwPos + i + e * Map->GetIsoSize());
int ground = fd->wGround;
if (ground == 0xFFFF) ground = 0;
if ((i == t1.cx - 1 || e == t1.cy - 1) && (*tiledata)[ground].tiles[fd->bSubTile].bHackedTerrainType == TERRAINTYPE_WATER) {
bWater = TRUE;
break;
}
}
if (bWater) break;
}
if (bWater && useables[k] - dwStartSet < 22) {
CString tset;
char c[50];
int watercliffs = tiles->GetInteger("General", "WaterCliffs");
if (m_bAlternative) {
watercliffs = cliffwater2set;
}
itoa(watercliffs, c, 10);
int e;
for (e = 0; e < 4 - strlen(c); e++) {
tset += "0";
}
tset += c;
CString sec = "TileSet";
sec += tset;
auto const pSec = tiles->TryGetSection(sec);
if (!pSec) {
return useables[k];
}
if (pSec->GetInteger("TilesInSet") > useables[k] - dwStartSet) {
DWORD dwStartWaterSet = 0;
for (i = 0; i < (*tiledata_count); i++) {
if ((*tiledata)[i].wTileSet == watercliffs) {
dwStartWaterSet = i;
return dwStartWaterSet + (useables[k] - dwStartSet);
}
}
}
}
return useables[k];
}