#include "Main.h"
DatabaseHeader::DatabaseHeader(const String &Str)
{
Str.Partition('\t', Words);
}
UINT DatabaseHeader::GetFieldIndex(const String &FieldName) const
{
for(UINT i = 0; i < Words.Length(); i++)
{
if(Words[i] == FieldName)
{
return i;
}
}
g_Context->Files.Assert << "Field not found: " << FieldName << endl;
return 0;
}
UnitEntry::UnitEntry(const String &Str, const DatabaseHeader &Header)
{
Vector<String> Words;
Str.Partition('\t', Words);
const float FastestGameSpeedFactor = 0.73f;
Name = Words[Header.GetFieldIndex("Name")];
Prims = Words[Header.GetFieldIndex("Prims")].ConvertToInteger();
Race = GetRaceTypeFromString(String("Race") + Words[Header.GetFieldIndex("Race")]);
PrimaryType = GetUnitPrimaryTypeFromString(String("UnitPrimary") + Words[Header.GetFieldIndex("Primary Type")]);
SecondaryType = GetUnitSecondaryTypeFromString(String("UnitSecondary") + Words[Header.GetFieldIndex("Secondary Type")]);
BuildClass = GetBuildClassTypeFromString(String("BuildClass") + Words[Header.GetFieldIndex("Build Class")]);
BuiltAt = Words[Header.GetFieldIndex("Built At")];
Requirement = Words[Header.GetFieldIndex("Requirement")];
Complexity = GetComplexityTypeFromString(String("Complexity") + Words[Header.GetFieldIndex("Complexity")]);
Hostile = Words[Header.GetFieldIndex("Hostile")].MakeLowercase().ConvertToBoolean();
AttackAir = Words[Header.GetFieldIndex("AttackAir")].MakeLowercase().ConvertToBoolean();
AttackGround = Words[Header.GetFieldIndex("AttackGround")].MakeLowercase().ConvertToBoolean();
Flying = Words[Header.GetFieldIndex("Flying")].MakeLowercase().ConvertToBoolean();
Range = Words[Header.GetFieldIndex("Range")].MakeLowercase().ConvertToInteger();
MineralCost = Words[Header.GetFieldIndex("Mineral Cost")].ConvertToUnsignedInteger();
GasCost = Words[Header.GetFieldIndex("Gas Cost")].ConvertToUnsignedInteger();
SupplyCost = Words[Header.GetFieldIndex("Supply Cost")].ConvertToUnsignedInteger();
BuildTime = Words[Header.GetFieldIndex("Build Time")].ConvertToUnsignedInteger() * FastestGameSpeedFactor;
Hotkey = Words[Header.GetFieldIndex("Hotkey")][0];
Detector = (Name == "Observer" || Name == "PhotonCannon" || Name == "Raven" || Name == "MissleTurret" || Name == "Overseer" || Name == "SporeCrawler");
}
void MinimapEntry::LoadBasesFromFile(const String &Filename)
{
Vector<String> Lines, Words;
Utility::GetFileLines(Filename, Lines);
Lines[0].Partition(' ', Words);
Bases.Allocate(Words[1].ConvertToUnsignedInteger());
for(UINT BaseIndex = 0; BaseIndex < Bases.Length(); BaseIndex++)
{
BaseInfo &CurBase = Bases[BaseIndex];
CurBase.ExtractorCount = 2;
CurBase.Player = PlayerInvalid;
CurBase.MyStartLocation = false;
CurBase.EnemyStartLocation = false;
}
for(UINT LineIndex = 0; LineIndex < Lines.Length(); LineIndex++)
{
const String &CurLine = Lines[LineIndex];
CurLine.Partition(' ', Words);
if(Words.Length() == 4 || Words.Length() == 5)
{
UINT BaseIndex = Words[1].ConvertToUnsignedInteger();
BaseInfo &CurBase = Bases[BaseIndex];
const String &Property = Words[2];
if(Words.Length() == 4)
{
bool Value = Words[3].MakeLowercase().ConvertToBoolean();
if(Property == "Debris") CurBase.Debris = Value;
else if(Property == "StartLocation") CurBase.StartLocation = Value;
else if(Property == "Island") CurBase.Island = Value;
else g_Context->Files.Assert << "Unexpected field property\n";
}
if (Words.Length() == 5)
{
Vec2f Value;
Value.x = Words[3].ConvertToFloat();
Value.y = Words[4].ConvertToFloat();
if (Property == "AssaultLocation") CurBase.AssaultLocation = Value;
else if (Property == "BaseLocation") CurBase.BaseLocation = Value;
else if (Property == "BuildLocation") CurBase.BuildLocation = Value;
else if (Property == "ExtractorLocation0") CurBase.ExtractorLocations[0] = Value;
else if (Property == "ExtractorLocation1") CurBase.ExtractorLocations[1] = Value;
else if (Property == "RampLocation") CurBase.RampLocation = Value;
else g_Context->Files.Assert << "Unexpected field property\n";
}
}
}
}
void DatabaseManager::Init()
{
LoadUnitEntries(g_Context->Parameters.DatabaseLoadDirectory + String("Units.txt"));
LoadMinimapEntries();
}
void DatabaseManager::LoadUnitEntries(const String &DatabaseFilename)
{
if(Utility::FileExists(DatabaseFilename))
{
Vector<String> Lines;
Utility::GetFileLines(DatabaseFilename, Lines);
DatabaseHeader Header(Lines[0]);
for(UINT LineIndex = 1; LineIndex < Lines.Length(); LineIndex++)
{
String &CurLine = Lines[LineIndex];
if(CurLine.Length() > 3)
{
_UnitEntries.PushEnd(new UnitEntry(CurLine, Header));
}
}
}
else
{
g_Context->Files.Assert << "Unit database " << DatabaseFilename << " not found\n";
}
}
void DatabaseManager::LoadMinimapEntries()
{
String BaseDirectory = g_Context->Parameters.BaseDataDirectory + String("Minimaps\\");
Directory Dir(BaseDirectory);
for(UINT FileIndex = 0; FileIndex < Dir.Files().Length(); FileIndex++)
{
const String &CurFilename = Dir.Files()[FileIndex];
if(CurFilename.EndsWith(".png"))
{
String Name = Dir.Files()[FileIndex].RemoveSuffix(".png");
String CurDataFilename = Name + String(".txt");
if(Utility::FileExists(Dir.DirectoryPath() + CurDataFilename))
{
MinimapEntry *NewEntry = new MinimapEntry;
NewEntry->Bmp.LoadPNG(Dir.DirectoryPath() + CurFilename);
NewEntry->Name = Name;
NewEntry->LoadBasesFromFile(Dir.DirectoryPath() + CurDataFilename);
_MinimapEntries.PushEnd(NewEntry);
}
else
{
g_Context->Files.Assert << "Minimap annotation not found: " << Name << endl;
}
}
}
}
UnitEntry* DatabaseManager::GetUnitEntry(const String &Name) const
{
for(UINT UnitIndex = 0; UnitIndex < _UnitEntries.Length(); UnitIndex++)
{
if(_UnitEntries[UnitIndex]->Name == Name)
{
return _UnitEntries[UnitIndex];
}
}
g_Context->Files.Assert << "Unit not found: " << Name << endl;
return NULL;
}
UINT ComputeMinimapMatchError(const Bitmap &A, const Bitmap &B)
{
if(A.Dimensions() != B.Dimensions())
{
g_Context->Files.Assert << "Minimap dimensions do not match\n";
return 200 * 200;
}
const UINT Width = A.Width();
const UINT Height = A.Height();
UINT Error = 0;
for(UINT Y = 0; Y < Height; Y++)
{
for(UINT X = 0; X < Width; X++)
{
bool ATest = (A[Y][X] == MinimapResourceColor);
bool BTest = (B[Y][X] == MinimapResourceColor);
if(ATest && !BTest)
{
Error++;
}
if(!ATest && BTest)
{
Error++;
}
}
}
return Error;
}
MinimapEntry* DatabaseManager::FindClosestMinimap(const Bitmap &Bmp) const
{
MinimapEntry *BestMinimap = NULL;
UINT BestError = 200 * 200;
for(UINT MinimapIndex = 0; MinimapIndex < _MinimapEntries.Length(); MinimapIndex++)
{
MinimapEntry *CurMinimap = _MinimapEntries[MinimapIndex];
UINT CurError = ComputeMinimapMatchError(Bmp, CurMinimap->Bmp);
if(CurError < BestError)
{
BestError = CurError;
BestMinimap = CurMinimap;
}
}
if(BestMinimap != NULL)
{
g_Context->WriteConsole(String("Minimap matched:") + BestMinimap->Name + String(",") + String(BestError), RGBColor::Yellow, OverlayPanelSystem);
}
return BestMinimap;
}