Пример #1
0
Gdiplus::Color CBottomBaseView::GetFontColorForSmallButton(void)
{
	AssertBotE((CBotEDoc*)GetDocument());

	CMajor* pPlayer = m_pPlayersRace;
	AssertBotE(pPlayer);

	Color color;
	color.SetFromCOLORREF(pPlayer->GetDesign()->m_clrSmallBtn);
	return color;
}
/// Funktion lädt die rassenspezifischen Grafiken.
void CShipDesignMenuView::LoadRaceGraphics()
{
	CBotEDoc* pDoc = resources::pDoc;
	ASSERT(pDoc);

	CMajor* pMajor = m_pPlayersRace;
	ASSERT(pMajor);

	CreateButtons();

	CString sPrefix = pMajor->GetPrefix();
	bg_designmenu	= pDoc->GetGraphicPool()->GetGDIGraphic("Backgrounds\\" + sPrefix + "designmenu.boj");
}
/// Funktion überprüft ob das in der Designansicht angeklickte Schiff in einem unserer Systeme gerade gebaut wird
/// Man benötigt diesen Check da man keine Schiffe ändern kann, welche gerade gebaut werden.
/// @param pShipInfo Zeiger des zu prüfenden Schiffes aus der Schiffsliste
/// @return CString mit dem Namen des Systems, wird das Schiff nirgends gebaut ist der String leer
CString CShipDesignMenuView::CheckIfShipIsBuilding(const CShipInfo* pShipInfo) const
{
	if (!pShipInfo)
		return "";

	CBotEDoc* pDoc = resources::pDoc;
	ASSERT(pDoc);

	CMajor* pMajor = m_pPlayersRace;
	ASSERT(pMajor);
	if (!pMajor)
		return "";

	USHORT ID = pShipInfo->GetID();
	// alle eigenen Systeme durchgehen und schauen, ob an erster Stelle in der Bauliste so ein Schiff steht
	for (int y = 0; y < STARMAP_SECTORS_VCOUNT; y++)
		for (int x = 0; x < STARMAP_SECTORS_HCOUNT; x++)
			if (pDoc->GetSystem(x,y).GetOwnerOfSystem() == pMajor->GetRaceID())
				for (int i = 0; i < ALE; i++)
					if (pDoc->GetSystem(x,y).GetAssemblyList()->GetAssemblyListEntry(i) == ID)
						return pDoc->GetSector(x,y).GetName();

	return "";
}
Пример #4
0
void CIntelBottomView::OnDraw(CDC* dc)
{
	CBotEDoc* pDoc = resources::pDoc;
	AssertBotE(pDoc);

	if (!pDoc->m_bDataReceived)
		return;

	CMajor* pMajor = m_pPlayersRace;
	AssertBotE(pMajor);
	if (!pMajor)
		return;
	// TODO: add draw code here

	// Doublebuffering wird initialisiert
	CMyMemDC pDC(dc);
	CRect client;
	GetClientRect(&client);

	// Graphicsobjekt, in welches gezeichnet wird anlegen
	Graphics g(pDC->GetSafeHdc());

	g.Clear(static_cast<Gdiplus::ARGB>(Color::Black));
	g.SetSmoothingMode(SmoothingModeHighSpeed);
	g.SetInterpolationMode(InterpolationModeLowQuality);
	g.SetPixelOffsetMode(PixelOffsetModeHighSpeed);
	g.SetCompositingQuality(CompositingQualityHighSpeed);
	g.ScaleTransform((REAL)client.Width() / (REAL)m_TotalSize.cx, (REAL)client.Height() / (REAL)m_TotalSize.cy);

	CString fontName = "";
	Gdiplus::REAL fontSize = 0.0;
	StringFormat fontFormat;
	SolidBrush fontBrush(static_cast<Gdiplus::ARGB>(Color::White));

	Color color;
	color.SetFromCOLORREF(pMajor->GetDesign()->m_clrGalaxySectorText);

	fontBrush.SetColor(color);
	Bitmap* graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Backgrounds\\" + pMajor->GetPrefix() + "diplomacyV3.boj");

	// Grafik zeichnen
	if (graphic)
	{
		g.DrawImage(graphic, 0, 0, 1075, 249);
		graphic = NULL;
	}

	// Nur in bestimmten Submenüs werden in der View3 Berichte angezeigt
	BYTE curIntelSubMenu = resources::pMainFrame->GetSubMenu(RUNTIME_CLASS(CIntelMenuView));
	if (curIntelSubMenu == 4 || curIntelSubMenu == 5)
	{
		CRect r;
		r.SetRect(0,0,m_TotalSize.cx,m_TotalSize.cy);
		short n = pMajor->GetEmpire()->GetIntelligence()->GetIntelReports()->GetActiveReport();
		if (n != -1)
		{
			CFontLoader::CreateGDIFont(pMajor, 4, fontName, fontSize);
			fontFormat.SetAlignment(StringAlignmentNear);
			fontFormat.SetLineAlignment(StringAlignmentNear);
			fontFormat.SetFormatFlags(StringFormatFlagsNoWrap);
			CIntelObject* report = pMajor->GetEmpire()->GetIntelligence()->GetIntelReports()->GetReport(n);
			CString s;
			if (report->GetIsSpy())
				s = CLoc::GetString("SPY");
			else
				s = CLoc::GetString("SABOTAGE");
			g.DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40, 40, r.right-100, r.bottom-20), &fontFormat, &fontBrush);

			CFontLoader::CreateGDIFont(pMajor, 2, fontName, fontSize);
			fontBrush.SetColor(Color(200,200,250));
			fontFormat.SetFormatFlags(!StringFormatFlagsNoWrap);
			if (report->GetOwner() == pMajor->GetRaceID())
				s = *report->GetOwnerDesc();
			else
				s = *report->GetEnemyDesc();
			g.DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40, 100, r.right-250, r.bottom-20), &fontFormat, &fontBrush);
		}
	}
	g.ReleaseHDC(pDC->GetSafeHdc());
}
Пример #5
0
void CRandomEventCtrl::CalcShipEvents() const
{
	if (!IsActivated())
		return;

	CBotEDoc* pDoc = resources::pDoc;
	AssertBotE(pDoc);

	// Hüllenvirus
	for (int x = 0; x < STARMAP_SECTORS_HCOUNT; x++)
	{
		for (int y = 0; y < STARMAP_SECTORS_VCOUNT; y++)
		{
			// 0.1% Wahrscheinlichkeit für einen Hüllenvirus pro Sektor
			if (rand()%1000 != 0)
				continue;

			// gibt es keine Schiffe im Sektor, dann macht ein Hüllenvirus auch nichts
			CSector* pSector = &(pDoc->GetSystem(x, y));
			if (!pSector->GetIsShipInSector())
				continue;

			// allen Schiffe im Sektor die Hülle auf 1 reduzieren (außer Aliens)
			for (CShipMap::iterator i = pDoc->m_ShipMap.begin(); i != pDoc->m_ShipMap.end(); ++i)
			{
				if (i->second->IsAlien())
					continue;

				if (i->second->GetCo() != pSector->GetCo())
					continue;

				int nCurrentHull = i->second->GetHull()->GetCurrentHull();
				i->second->GetHull()->SetCurrentHull(-(nCurrentHull - 1), true);

				// allen Schiffen in der Flotte ebenfalls die Hülle auf 1 setzen
				for (CShips::iterator j = i->second->begin(); j != i->second->end(); ++j)
				{
					nCurrentHull = j->second->GetHull()->GetCurrentHull();
					j->second->GetHull()->SetCurrentHull(-(nCurrentHull - 1), true);
				}
			}

			// Nachrichten an alle Major welche Schiffe in diesem Sektor hatten
			const std::map<CString, CMajor*>* pmMajors = pDoc->GetRaceCtrl()->GetMajors();
			for (map<CString, CMajor*>::const_iterator it = pmMajors->begin(); it != pmMajors->end(); ++it)
			{
				if (!pSector->GetOwnerOfShip(it->first, true))
					continue;

				CMajor* pMajor = it->second;
				if (!pMajor)
					continue;

				const CString& sSectorName = pSector->CoordsName(true);

				CString sMessageText = CLoc::GetString("EVENTHULLVIRUS", false, sSectorName);
				CEmpireNews message;
				message.CreateNews(sMessageText,EMPIRE_NEWS_TYPE::MILITARY,pSector->GetName(),pSector->GetCo());
				pMajor->GetEmpire()->AddMsg(message);

				if (pMajor->IsHumanPlayer())
				{
					resources::pClientWorker->SetToEmpireViewFor(*pMajor);
					pMajor->GetEmpire()->PushEvent(boost::make_shared<CEventRandom>(pMajor->GetRaceID(), "HullVirus", sMessageText, ""));
				}
			}
		}
	}
}
Пример #6
0
void CResearchBottomView::OnDraw(CDC* dc)
{
	CBotEDoc* pDoc = resources::pDoc;
	AssertBotE(pDoc);

	if (!pDoc->m_bDataReceived)
		return;

	CMajor* pMajor = m_pPlayersRace;
	AssertBotE(pMajor);
	if (!pMajor)
		return;
	// TODO: add draw code here

	// Doublebuffering wird initialisiert
	CMyMemDC pDC(dc);
	CRect client;
	GetClientRect(&client);

	// Graphicsobjekt, in welches gezeichnet wird anlegen
	Graphics g(pDC->GetSafeHdc());

	g.Clear(static_cast<Gdiplus::ARGB>(Color::Black));
	g.SetSmoothingMode(SmoothingModeHighSpeed);
	g.SetInterpolationMode(InterpolationModeLowQuality);
	g.SetPixelOffsetMode(PixelOffsetModeHighSpeed);
	g.SetCompositingQuality(CompositingQualityHighSpeed);
	g.ScaleTransform((REAL)client.Width() / (REAL)m_TotalSize.cx, (REAL)client.Height() / (REAL)m_TotalSize.cy);

	CString fontName = "";
	Gdiplus::REAL fontSize = 0.0;
	StringFormat fontFormat;
	SolidBrush fontBrush(static_cast<Gdiplus::ARGB>(Color::White));
	CRect rect;
	rect.SetRect(0,0,m_TotalSize.cx,m_TotalSize.cy);

	CString sPrefix = pMajor->GetPrefix();
	Color color;
	color.SetFromCOLORREF(pMajor->GetDesign()->m_clrGalaxySectorText);
	fontBrush.SetColor(color);
	Bitmap* graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Backgrounds\\" + sPrefix + "researchV3.boj");

	// gibt es keine Spezialforschung zur Auswahl, so wird auf Standardanzeige umgestellt
	if (m_nCurrentTech == 6 && pMajor->GetEmpire()->GetResearch()->GetUniqueReady() == TRUE)
		m_nCurrentTech = 0;

	// Grafik zeichnen
	if (graphic)
	{
		g.DrawImage(graphic, 0, 0, 1075, 249);
		graphic = NULL;
	}
	switch(m_nCurrentTech)
	{
	case 0:	graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Research\\biotech.bop"); break;
	case 1:	graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Research\\energytech.bop"); break;
	case 2:	graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Research\\computertech.bop"); break;
	case 3:	graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Research\\propulsiontech.bop"); break;
	case 4:	graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Research\\constructiontech.bop"); break;
	case 5:	graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Research\\weapontech.bop"); break;
	case 6:	graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Research\\specialtech.bop"); break;
	}
	if (graphic)
	{
		g.DrawImage(graphic, 790, 25, 240, 200);
		graphic = NULL;
	}
	// Name und Beschreibung der Forschung anzeigen
	CFontLoader::CreateGDIFont(pMajor, 4, fontName, fontSize);
	fontFormat.SetAlignment(StringAlignmentNear);
	fontFormat.SetLineAlignment(StringAlignmentNear);
	fontFormat.SetFormatFlags(StringFormatFlagsNoWrap);

	CString s;
	if (m_nCurrentTech != 6)
		s = pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->GetTechName(m_nCurrentTech);
	else
		s = pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->GetCurrentResearchComplex()->GetComplexName();
	g.DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40, 30, rect.right-325, rect.bottom), &fontFormat, &fontBrush);

	CFontLoader::CreateGDIFont(pMajor, 2, fontName, fontSize);
	fontBrush.SetColor(Color(200,200,250));
	fontFormat.SetFormatFlags(!StringFormatFlagsNoWrap);
	if (m_nCurrentTech != 6)
		s = pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->GetTechDescription(m_nCurrentTech);
	else
		s = pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->GetCurrentResearchComplex()->GetComplexDescription();
	g.DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40, 100, rect.right-325, rect.bottom), &fontFormat, &fontBrush);

	g.ReleaseHDC(pDC->GetSafeHdc());
}
Пример #7
0
//////////////////////////////////////////////////////////////////////
// sonstige Funktionen
//////////////////////////////////////////////////////////////////////
/// Diese Funktion erteilt allen Schiffen aller computergesteuerten Rassen Befehle.
void CShipAI::CalculateShipOrders(CSectorAI* SectorAI)
{
	ASSERT(SectorAI);
	m_pSectorAI = SectorAI;

	// einen möglichen Angriffssektor berechnen lassen
	CalcAttackSector();
	// danach einen möglichen Bombardierungssektor finden
	CalcBombardSector();

	for(CShipMap::iterator i = m_pDoc->m_ShipMap.begin(); i != m_pDoc->m_ShipMap.end(); ++i)
	{
		if(i->second->IsAlien()) {
			CalculateAlienShipOrders(*i->second);
			continue;
		}
		const CString& sOwner	= i->second->GetOwnerOfShip();
		CMajor* pOwner	= dynamic_cast<CMajor*>(m_pDoc->GetRaceCtrl()->GetRace(sOwner));

		// gilt erstmal nur für Majors
		if (!pOwner || !pOwner->IsMajor())
			continue;

		// gilt nicht für menschliche Spieler
		if (pOwner->AHumanPlays())
			continue;

		// Flotte versuchen zu erstellen
		DoMakeFleet(i);

		// Vielleicht haben unsere Schiffe ein Ziel, welches sie angreifen müssen/können
		if (DoAttackMove(i->second, pOwner))
		{
			DoCamouflage(i->second);
			continue;
		}

		// haben Kolonieschiffe einen Sektor zum Terraformen als Ziel, welcher kurz zuvor aber von einer
		// anderen Rasse weggeschnappt wurde, so wird ihr Kurs gelöscht
		if (i->second->GetShipType() == SHIP_TYPE::COLONYSHIP)
		{
			CPoint ptKO = i->second->GetKO();
			// hat das Kolonieschiff den Befehl zum Terraformen, so wird dieser rückgängig gemacht, wenn der Sektor
			// schon einer anderen Rasse gehört
			if (i->second->GetCurrentOrder() == SHIP_ORDER::TERRAFORM)
			{
				if (m_pDoc->GetSector(ptKO.x, ptKO.y).GetOwnerOfSector() != "" && m_pDoc->GetSector(ptKO.x, ptKO.y).GetOwnerOfSector() != sOwner)
				{
					// Terraforming abbrechen
					i->second->UnsetCurrentOrder();
					i->second->SetCombatTactic(COMBAT_TACTIC::CT_AVOID);
				}
			}

			CPoint ptTarget = i->second->GetTargetKO();
			// nur wenn der Sektor noch niemandem gehört bzw. uns selbst ist, sollen Planeten terraformt werden
			if (ptTarget != CPoint(-1,-1) && m_pDoc->GetSector(ptTarget.x, ptTarget.y).GetOwnerOfSector() != "" && m_pDoc->GetSector(ptTarget.x, ptTarget.y).GetOwnerOfSector() != sOwner)
			{
				// nicht weiter fliegen und Kurs löschen
				i->second->SetTargetKO(CPoint(-1, -1));
				i->second->GetPath()->RemoveAll();
			}
		}

		// exisitiert kein aktueller Kurs, so wird dieser hier versucht dem Schiff zu erteilen
		if (i->second->GetPath()->GetSize() == 0)
		{
			// Scouts und Kriegsschiffe fliegen zuerst einmal zu den Minorracesystemen
			if (i->second->GetShipType() > SHIP_TYPE::COLONYSHIP)
			{
				// Zeiger auf Vektor mit Minorracessektoren holen
				vector<CPoint>* vMinorraceSectors = m_pSectorAI->GetMinorraceSectors(sOwner);

				bool bSet = false;
				int nCount = vMinorraceSectors->size() * 2;
				while (vMinorraceSectors->size() && nCount--)
				{
					int j = rand()%vMinorraceSectors->size();
					CPoint ko = vMinorraceSectors->at(j);
					// Wenn Gefahr der anderen Rassen kleiner als die der meinen ist
					if (m_pSectorAI->GetCompleteDanger(sOwner, ko) == NULL ||
						(m_pSectorAI->GetCompleteDanger(sOwner, ko) <= m_pSectorAI->GetDangerOnlyFromCombatShips(sOwner, i->second->GetKO())))
						if (pOwner->GetStarmap()->GetRange(ko) <= i->second->GetRange(false))
						{
							// Zielkoordinate für das Schiff setzen
							i->second->SetTargetKO(ko);
							MYTRACE("shipai")(MT::LEVEL_DEBUG, "Race %s: Ship to Minor: %s (%s) - Target: %d,%d\n",sOwner, i->second->GetShipName(), i->second->GetShipTypeAsString(), ko.x,ko.y);
							vMinorraceSectors->erase(vMinorraceSectors->begin() + j--);
							bSet = true;
							break;
						}
				}

				if (bSet)
				{
					DoCamouflage(i->second);
					continue;
				}
			}

			// Kolonieschiffe zum Terraformen schicken. Andere Schiffe fliegen manchmal auch dort hin, wenn
			// sie gerade keinen anderen Flugauftrag haben.
			if (i->second->GetShipType() >= SHIP_TYPE::COLONYSHIP && i->second->GetCurrentOrder() != SHIP_ORDER::TERRAFORM)
			{
				// Zeiger auf Vektor mit Terraformsektoren holen
				vector<CSectorAI::SectorToTerraform>* vSectorsToTerrform = m_pSectorAI->GetSectorsToTerraform(sOwner);

				for (UINT j = 0; j < vSectorsToTerrform->size(); j++)
				{
					CPoint ko = vSectorsToTerrform->at(j).p;
					// Wenn das Kolonieschiff schon auf einem Sektor für unser Terraforming steht, so fliegt es nicht weiter
					if (i->second->GetShipType() == SHIP_TYPE::COLONYSHIP && i->second->GetKO() == ko)
						break;

					// Wenn Gefahr der anderen Rassen kleiner als die der meinen ist
					if (m_pSectorAI->GetCompleteDanger(sOwner, ko) == NULL || (m_pSectorAI->GetCompleteDanger(sOwner, ko) < m_pSectorAI->GetDanger(sOwner, i->second->GetKO())))
					{
						if (pOwner->GetStarmap()->GetRange(ko) <= i->second->GetRange(false))
						{
							// Zielkoordinate für das Schiff setzen
							i->second->SetTargetKO(ko == i->second->GetKO() ? CPoint(-1, -1) : ko);
							MYTRACE("shipai")(MT::LEVEL_DEBUG, "Race %s: Ship %s (%s) has terraforming target: %d,%d\n",sOwner, i->second->GetShipName(), i->second->GetShipTypeAsString(), ko.x,ko.y);
							break;
						}
					}
				}
			}
			// Truppentransporter zu einem möglichen Sektor fliegen lassen um dort einen Außenposten bauen zu können
			if (m_pSectorAI->GetStationBuildSector(sOwner).points > MINBASEPOINTS && i->second->GetCurrentOrder() != SHIP_ORDER::BUILD_OUTPOST)
			{
				// nur Truppentransporter oder andere Schiffe ohne Ziel fliegen zu diesem Punkt, niemals aber
				// Kolonieschiffe
				if (i->second->GetShipType() == SHIP_TYPE::TRANSPORTER	|| (i->second->GetShipType() != SHIP_TYPE::COLONYSHIP && !i->second->HasTarget()))
				{
					CPoint ko(m_pSectorAI->GetStationBuildSector(sOwner).position.x, m_pSectorAI->GetStationBuildSector(sOwner).position.y);
					// Wenn Gefahr der anderen Rassen kleiner als die der meinen ist
					if (m_pSectorAI->GetCompleteDanger(sOwner, ko) == 0 || (m_pSectorAI->GetCompleteDanger(sOwner, ko) < m_pSectorAI->GetDanger(sOwner, i->second->GetKO())))
					{
						if (pOwner->GetStarmap()->GetRange(ko) <= i->second->GetRange(false))
						{
							// Zielkoordinate für das Schiff setzen
							i->second->SetTargetKO(ko == i->second->GetKO() ? CPoint(-1, -1) : ko);
							MYTRACE("shipai")(MT::LEVEL_DEBUG, "Race %s: Ship %s (%s) has stationbuild target: %d,%d\n",sOwner, i->second->GetShipName(), i->second->GetShipTypeAsString(), ko.x,ko.y);
						}
					}
				}
			}

			DoCamouflage(i->second);
			if (m_pDoc->GetSector(i->second->GetKO().x, i->second->GetKO().y).GetSunSystem())
			{
				if (!DoTerraform(i->second))
					DoColonize(i->second);
			}

			DoStationBuild(i->second);
		}
		else
		{
			DoCamouflage(i->second);
		}
	}
}
Пример #8
0
void CDiplomacyBottomView::OnDraw(CDC* dc)
{
    CBotEDoc* pDoc = resources::pDoc;
    AssertBotE(pDoc);

    if (!pDoc->m_bDataReceived)
        return;

    CMajor* pMajor = m_pPlayersRace;
    AssertBotE(pMajor);
    if (!pMajor)
        return;
    // TODO: add draw code here

    // Doublebuffering wird initialisiert
    CMyMemDC pDC(dc);
    CRect client;
    GetClientRect(&client);

    // Graphicsobjekt, in welches gezeichnet wird anlegen
    Graphics g(pDC->GetSafeHdc());

    g.Clear(static_cast<Gdiplus::ARGB>(Color::Black));
    g.SetSmoothingMode(SmoothingModeHighSpeed);
    g.SetInterpolationMode(InterpolationModeLowQuality);
    g.SetPixelOffsetMode(PixelOffsetModeHighSpeed);
    g.SetCompositingQuality(CompositingQualityHighSpeed);
    g.ScaleTransform((REAL)client.Width() / (REAL)m_TotalSize.cx, (REAL)client.Height() / (REAL)m_TotalSize.cy);

    CString fontName = "";
    Gdiplus::REAL fontSize = 0.0;
    StringFormat fontFormat;
    SolidBrush fontBrush(static_cast<Gdiplus::ARGB>(Color::White));

    // Soll was über die Diplomatie angezeigt werden
    CRect rect;
    rect.SetRect(0,0,m_TotalSize.cx,m_TotalSize.cy);

    CString sPrefix = pMajor->GetPrefix();
    Color color;
    color.SetFromCOLORREF(pMajor->GetDesign()->m_clrGalaxySectorText);
    fontBrush.SetColor(color);
    Bitmap* graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Backgrounds\\" + sPrefix + "diplomacyV3.boj");

    // Grafik zeichnen
    if (graphic)
    {
        g.DrawImage(graphic, 0, 0, 1075, 249);
        graphic = NULL;
    }

    CFontLoader::CreateGDIFont(pMajor, 4, fontName, fontSize);
    fontFormat.SetAlignment(StringAlignmentNear);
    fontFormat.SetLineAlignment(StringAlignmentNear);
    fontFormat.SetFormatFlags(StringFormatFlagsNoWrap);
    g.DrawString(CComBSTR(m_strHeadLine), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40, 30, rect.right, rect.bottom), &fontFormat, &fontBrush);

    if (m_strText.IsEmpty())
        g.DrawString(CComBSTR(CLoc::GetString("NO_DIPLOMATIC_NEWS")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40, 30, rect.right, rect.bottom), &fontFormat, &fontBrush);
    m_strHeadLine = "";

    CFontLoader::CreateGDIFont(pMajor, 2, fontName, fontSize);
    fontBrush.SetColor(Color(200,200,250));
    fontFormat.SetFormatFlags(!StringFormatFlagsNoWrap);
    g.DrawString(CComBSTR(m_strText), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40, 100, rect.right-250, rect.bottom), &fontFormat, &fontBrush);

    g.ReleaseHDC(pDC->GetSafeHdc());
}
Пример #9
0
//////////////////////////////////////////////////////////////////////
// sonstige Funktionen
//////////////////////////////////////////////////////////////////////
/// Funktion berechnet den Umgang mit dem Geheimdienst für die KI. Sie trifft Zuteilungen für die einzelnen Rassen.
void CIntelAI::CalcIntelligence(CBotEDoc* pDoc)
{
	AssertBotE(pDoc);

	// Struktur für eine Liste mit Rassen-ID und Geheimdienstpunkten
	struct INTELLIST {
		CString sRace;
		UINT points;

		bool operator< (const INTELLIST& elem2) const { return points < elem2.points;}
		bool operator> (const INTELLIST& elem2) const { return points > elem2.points;}
		INTELLIST() : sRace(""), points(0) {}
		INTELLIST(const CString& _sRace, UINT _points) : sRace(_sRace), points(_points) {}
	};

	// produzierte Geheimdienstpunkte und Punkte aus allen Geheimdienstlagern einer Rasse zusammenaddieren
	CArray<INTELLIST> intellist;
	std::map<CString, CMajor*>* pmMajors = pDoc->GetRaceCtrl()->GetMajors();
	for (std::map<CString, CMajor*>::const_iterator it = pmMajors->begin(); it != pmMajors->end(); ++it)
	{
		CIntelligence* pIntel = it->second->GetEmpire()->GetIntelligence();
		UINT points = pIntel->GetSecurityPoints() + pIntel->GetInnerSecurityStorage();
		for (map<CString, CMajor*>::const_iterator itt = pmMajors->begin(); itt != pmMajors->end(); ++itt)
			if (itt->first != it->first)
				points += pIntel->GetSPStorage(0, itt->first) + pIntel->GetSPStorage(1, itt->first);
		intellist.Add(INTELLIST(it->first, points));
	}
	// nun Feld nach den gesammten Geheimdienstpunkten absteigend sortiren lassen.
	c_arraysort<CArray<INTELLIST>, INTELLIST> (intellist, sort_desc);
	// unere Priorität ist der Index der Rasse im Feld.
	// wenn die Punkte sich nicht mehr als 10% bzw. 100SP unterscheiden, dann wird die Priorität des vorherigen
	// Indexes benutzt.
	m_byIntelPrio[intellist.GetAt(0).sRace] = rand()%2;
	for (int i = 1; i < intellist.GetSize(); i++)	// beim zweiten Index starten! Da das erste Element eine 0er Priorität hat
	{
		if (intellist.GetAt(i-1).points - intellist.GetAt(i).points > 100
			&& (intellist.GetAt(i).points * 100 / (intellist.GetAt(i-1).points+1) < 90))
			m_byIntelPrio[intellist.GetAt(i).sRace] = i;
		// ansonsten ist die Priorität der des Vorgängers
		else
			m_byIntelPrio[intellist.GetAt(i).sRace] = m_byIntelPrio[intellist.GetAt(i-1).sRace];
	}

	// jeder Geheimdienstbericht mit uns als Ziel aus den letzten 5 Runden erhöht die Priorität nochmal um eins, sofern
	// es sich dabei um eine Sabotageaktion handelte
	std::map<CString, int> badReports;
	for (std::map<CString, CMajor*>::const_iterator it = pmMajors->begin(); it != pmMajors->end(); ++it)
		if (it->second->AHumanPlays() == false)
		{
			CIntelligence* pIntel = it->second->GetEmpire()->GetIntelligence();
			for (int l = 0; l < pIntel->GetIntelReports()->GetNumberOfReports(); l++)
			{
				CIntelObject* intelObj = pIntel->GetIntelReports()->GetReport(l);
				if (intelObj->GetEnemy() == it->first && pDoc->GetCurrentRound() - intelObj->GetRound() < 6 && intelObj->GetIsSabotage())
					badReports[it->first] += 1;
			}
			m_byIntelPrio[it->first] += badReports[it->first];
		}

	for (std::map<CString, CMajor*>::const_iterator it = pmMajors->begin(); it != pmMajors->end(); ++it)
		MYTRACE("intelai")(MT::LEVEL_INFO, "Intel-AI: Intel Prio of %s is %d\n", it->first, m_byIntelPrio[it->first]);

	// nun liegen die Prioritäten und die Listen mit den Punkten vor. Jetzt kann begonnen werde die Rassen zu
	// vergeheimdiensteln. Ab hier kommt die KI für den Geheimdienst richtig ins Spiel.
	for (std::map<CString, CMajor*>::const_iterator it = pmMajors->begin(); it != pmMajors->end(); ++it)
	{
		if (it->second->AHumanPlays() == false)
		{
			CIntelligence* pIntel = it->second->GetEmpire()->GetIntelligence();
			// wenn in den letzten 5 Runden Geheimdienstberichte mit uns als Ziel vorliegen, so wird die innere
			// Sicherheit maximiert
			if (badReports[it->first] > NULL)
			{
				// Es liegt mindst. ein Bericht mit uns als Ziel aus den letzten 5 Runden vor.
				// Dann wird die Innere Sicherheit auf 100% gesetzt
				pIntel->SetAssignment()->SetGlobalPercentage(2, 100, it->second, "", pmMajors);
				continue;
			}

			// wenn die innere Sicherheit nicht verändert werden musste, dann können wir vielleicht selbst aktiv werden
			// KI benutzt nur Sabotage

			// Wie wird ein mögliches Geheimdienstopfer ermittelt?
			// - haben die schlechteste Beziehung zum Opfer
			// - Beziehung unter 50% oder aktueller Vertrag kleiner Freundschaft und kein Verteidigungsbündnis
			USHORT worstRel = MAXBYTE;
			CMajor* pWorstRace = NULL;
			for (std::map<CString, CMajor*>::const_iterator jt = pmMajors->begin(); jt != pmMajors->end(); ++jt)
				if (jt->first != it->first && it->second->IsRaceContacted(jt->first) == true)
				{
					// zufällig wird hier eine bekannte andere Rasse als ResponsibleRace ausgewählt
					pIntel->SetResponsibleRace(it->first);	// erstmal uns wieder auf die ResponsibleRace setzen
					if (jt->second->GetEmpire()->CountSystems() > 0 && rand()%3 == NULL)
					{
						pIntel->SetResponsibleRace(jt->first);
						break;
					}

					// vertragliche Situation und Mindestbeziehung checken
					if ((it->second->GetAgreement(jt->first) < DIPLOMATIC_AGREEMENT::FRIENDSHIP && it->second->GetDefencePact(jt->first) == false)
						||	it->second->GetRelation(jt->first) < 50)
					{
						// schlechteste Beziehung ermitteln
						if (it->second->GetRelation(jt->first) < worstRel)
						{
							worstRel = it->second->GetRelation(jt->first);
							pWorstRace = jt->second;
						}
						// bei Gleichheit zu 50% die neue Rasse mit schlechtester Bezeihung
						else if (it->second->GetRelation(jt->first) == worstRel && rand()%2 == NULL)
						{
							worstRel = it->second->GetRelation(jt->first);
							pWorstRace = jt->second;
						}
					}
				}

			// jetzt der ausgesuchten Rasse Geheimdienstpunkte zuweisen
			if (pWorstRace != NULL)
			{
				CIntelligence* pWorstIntel = pWorstRace->GetEmpire()->GetIntelligence();
				MYTRACE("intelai")(MT::LEVEL_INFO, "Intel-AI: assigned intel victim of %s is %s\n", it->first, pWorstRace->GetRaceID());
				// jede Rasse läßt immer einen bestimmten prozentualen Anteil in der inneren Sicherheit.
				int innerSecPerc = 25;

				if (it->second->IsRaceProperty(RACE_PROPERTY::FINANCIAL))
					innerSecPerc += 15;
				if (it->second->IsRaceProperty(RACE_PROPERTY::WARLIKE))
					innerSecPerc += 25;
				if (it->second->IsRaceProperty(RACE_PROPERTY::AGRARIAN))
					innerSecPerc += 25;
				if (it->second->IsRaceProperty(RACE_PROPERTY::INDUSTRIAL))
					innerSecPerc += 10;
				if (it->second->IsRaceProperty(RACE_PROPERTY::SECRET))
					innerSecPerc -= 10;
				if (it->second->IsRaceProperty(RACE_PROPERTY::SCIENTIFIC))
					innerSecPerc += 0;
				if (it->second->IsRaceProperty(RACE_PROPERTY::PRODUCER))
					innerSecPerc += 5;
				if (it->second->IsRaceProperty(RACE_PROPERTY::PACIFIST))
					innerSecPerc += 35;
				if (it->second->IsRaceProperty(RACE_PROPERTY::SNEAKY))
					innerSecPerc -= 15;
				if (it->second->IsRaceProperty(RACE_PROPERTY::SOLOING))
					innerSecPerc += 40;
				if (it->second->IsRaceProperty(RACE_PROPERTY::HOSTILE))
					innerSecPerc += 0;

				if (innerSecPerc > 100)
					innerSecPerc = 100;
				else if (innerSecPerc < 0)
					innerSecPerc = 0;

				if (pIntel->GetAssignment()->GetGlobalSabotagePercentage(pWorstRace->GetRaceID()) != 100 - innerSecPerc)
					pIntel->SetAssignment()->SetGlobalPercentage(2, 100, it->second, "", pmMajors);
				pIntel->SetAssignment()->SetGlobalPercentage(1, 100 - innerSecPerc, it->second, pWorstRace->GetRaceID(), pmMajors);

				// Wann wird die Geheimdiensaktion gestartet
				// - wenn unsere Geheimdienstpunkte + Punkte aus Depot > gegnerische Innere Sicherheit + deren Inneres Depot

				int type = rand()%4;	// Typ der Aktion (Wirtschaft, Wissenschaft, Militär oder Diplomatie)
				UINT ourPoints = pIntel->GetSecurityPoints()
					* pIntel->GetAssignment()->GetGlobalSabotagePercentage(pWorstRace->GetRaceID()) / 100
					+ pIntel->GetSPStorage(1, pWorstRace->GetRaceID()) * pIntel->GetAssignment()->GetSabotagePercentages(pWorstRace->GetRaceID(), type) / 100;
				ourPoints += ourPoints * pIntel->GetBonus(type, 1) / 100;

				UINT enemyPoints = pWorstIntel->GetSecurityPoints()
					* pWorstIntel->GetAssignment()->GetInnerSecurityPercentage() / 100;
				// + Bonus auf innere Sicherheit
				enemyPoints += enemyPoints * pWorstIntel->GetInnerSecurityBoni() / 100;
				// + Punkte aus dem Lager (darin ist der Bonus schon vorhanden)
				enemyPoints += pWorstIntel->GetInnerSecurityStorage();
				if (ourPoints > enemyPoints + rand()%1500)
				{
					// zuerst komplette Zuteilung ins Lager übernehmen, damit man dann auch wirklich 100% einem einzelnen
					// Ressort zuweisen kann
					pIntel->SetAssignment()->SetSabotagePercentage(4, 100, pWorstRace->GetRaceID());
					pIntel->SetAssignment()->SetSabotagePercentage(type, 100, pWorstRace->GetRaceID());
				}
				else
					pIntel->SetAssignment()->SetSabotagePercentage(4, 100, pWorstRace->GetRaceID());
				MYTRACE("intelai")(MT::LEVEL_INFO, "Intel-AI: our SP: %d - enemies SP: %d\n", ourPoints, enemyPoints);

			}
			// finden wir keine Rasse zum vergeheimdiensteln, so die innere Sicherheit auf 100% stellen
			else
				pIntel->SetAssignment()->SetGlobalPercentage(2, 100, it->second, "", pmMajors);
		}
	}
}
void CShipDesignMenuView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CBotEDoc* pDoc = resources::pDoc;
	ASSERT(pDoc);

	if (!pDoc->m_bDataReceived)
		return;

	CMajor* pMajor = m_pPlayersRace;
	ASSERT(pMajor);
	if (!pMajor)
		return;

	// clicked to DisplayAllShips
	CRect rect;
	rect.SetRect(40,750,80,30);
	if (rect.PtInRect(point))
	{
		AfxMessageBox("Button DisplayAllShips pressed"); 
		m_bDisplayAllShips=!m_bDisplayAllShips;
		AfxMessageBox("Button DisplayAllShips pressed2"); 
		//if (m_bDisplayAllShips)
		//	std::sort(m_vRaceList.begin(), m_vRaceList.end(),ComareRaceAgreement);
		//else
		//	std::sort(m_vRaceList.begin(), m_vRaceList.end(),CompareRaceName);
		Invalidate();
		return;
	}

	CalcLogicalPoint(point);

	// Wenn wir in der Schiffsdesignansicht sind
	CRect r;
	r.SetRect(0,0,m_TotalSize.cx,m_TotalSize.cy);
	// Schiffsinfoarray durchgehen und nach zum Imperium gehörende baubare Schiffe suchen

	short j = 0;
	short counter = m_iClickedOnShip - 23 + m_iOldClickedOnShip;
	short add = 0;

	BYTE researchLevels[6] =
	{
		pMajor->GetEmpire()->GetResearch()->GetBioTech(),
		pMajor->GetEmpire()->GetResearch()->GetEnergyTech(),
		pMajor->GetEmpire()->GetResearch()->GetCompTech(),
		pMajor->GetEmpire()->GetResearch()->GetPropulsionTech(),
		pMajor->GetEmpire()->GetResearch()->GetConstructionTech(),
		pMajor->GetEmpire()->GetResearch()->GetWeaponTech()
	};


	for (int i = 0; i < pDoc->m_ShipInfoArray.GetSize(); i++)
		if (pDoc->m_ShipInfoArray.GetAt(i).GetRace() == pMajor->GetRaceShipNumber())
			if (!pDoc->m_ShipInfoArray.GetAt(i).IsStation())
				if (pDoc->m_ShipInfoArray.GetAt(i).IsThisShipBuildableNow(researchLevels))
				{
					// wurde dieses Schiff durch kein anderes jetzt baubares Schiff schon obsolet?
					BOOLEAN foundObsolet = FALSE;
					for (int m = 0; m < pDoc->m_ShipInfoArray.GetSize(); m++)
						if (pDoc->m_ShipInfoArray.GetAt(m).GetRace() == pMajor->GetRaceShipNumber())
							if (pDoc->m_ShipInfoArray.GetAt(m).GetObsoleteShipClass() == pDoc->m_ShipInfoArray.GetAt(i).GetShipClass())
								if (pDoc->m_ShipInfoArray.GetAt(m).IsThisShipBuildableNow(researchLevels))
								{
									foundObsolet = TRUE;
									break;
								}
					if (foundObsolet)
						continue;

					if (counter > 0)
					{
						add++;
						counter--;
						continue;
					}
					if (j < 24)
					{
						// Müssen später noch die Seitenzahl beachten, bis jetzt aber wie in der Diplomatieansicht
						// geht die Liste nur auf eine Seite
						if (CRect(20,120+j*25,200,145+j*25).PtInRect(point))
						{
							m_iClickedOnShip = j + add;
							m_iOldClickedOnShip = 23-(j)%24;
							m_iBeamWeaponNumber = 0;
							m_iTorpedoWeaponNumber = 0;
							m_bFoundBetterBeam = FALSE;
							m_bFoundWorseBeam  = FALSE;
							Invalidate();
							return;
						}
						if (j + add == m_iClickedOnShip)
							m_pShownShip = &pDoc->m_ShipInfoArray.GetAt(i);
						j++;
					}
				}

			if (m_bDisplayAllShips)
			{
			Invalidate(FALSE);
			return;
			}



	// Bevor wir irgendetwas ändern können müssen wir überprüfen, dass das gerade angeklickte Schiff nicht gerade
	// gebaut wird. Wenn das der Fall sein sollte können wir nix ändern. Es kommt dann eine Meldung in welchem
	// System das Schiff gerade gebaut wird
	if (CRect(r.right-300,80,r.right,r.bottom-80).PtInRect(point))
		if (!CheckIfShipIsBuilding(m_pShownShip).IsEmpty())
		{
			Invalidate(FALSE);
			return;
		}

	counter = 0;
	// Überprüfen ob irgendetwas an den Beamwaffen ändern möchte
	if (m_pShownShip && m_pShownShip->GetBeamWeapons()->GetSize() > 0)
	{
		// Hat das Schiff mehr als eine Beamwaffe können wir auf die nächste zugreifen indem wir hier klicken
		if (CRect(r.right-300,80,r.right,105).PtInRect(point))
		{
			if (m_pShownShip->GetBeamWeapons()->GetUpperBound() > m_iBeamWeaponNumber)
			{
				m_iBeamWeaponNumber++;
				m_bFoundBetterBeam = FALSE;
				m_bFoundWorseBeam  = FALSE;
				Invalidate();
			}
			else if (m_pShownShip->GetBeamWeapons()->GetUpperBound() == m_iBeamWeaponNumber)
			{
				m_iBeamWeaponNumber = 0;
				m_bFoundBetterBeam = FALSE;
				m_bFoundWorseBeam  = FALSE;
				Invalidate();
			}
		}
		// Haben wir auf den Button geklickt um den Typ der Beamwaffe zu verbessern
		else if (m_bFoundBetterBeam == TRUE && CRect(r.right-145,120,r.right-25,150).PtInRect(point))
		{
			// Dann wird der Typ bei der aktuellen Beamwaffe um eins erhöht
			CBeamWeapons* pWeapon = &m_pShownShip->GetBeamWeapons()->GetAt(m_iBeamWeaponNumber);

			BYTE oldType		= pWeapon->GetBeamType();
			USHORT oldPower		= pWeapon->GetBeamPower();
			BYTE oldNumber		= pWeapon->GetBeamNumber();
			BYTE oldShootNumber = pWeapon->GetShootNumber();
			CString oldName		= pWeapon->GetBeamName();
			BYTE oldBonus		= pWeapon->GetBonus();
			BYTE oldLenght		= pWeapon->GetBeamLenght();
			BYTE oldRechargeTime= pWeapon->GetRechargeTime();
			BOOLEAN piercing	= pWeapon->GetPiercing();
			BOOLEAN modulating	= pWeapon->GetModulating();
			// hier aktualisieren -> Reichweite erhöhen
			pWeapon->ModifyBeamWeapon((oldType+1),oldPower,oldNumber,oldName,modulating,piercing,oldBonus,oldLenght,oldRechargeTime,oldShootNumber);
			// Feuerwinkel bleiben alle beim alten
			m_pShownShip->CalculateFinalCosts();
			m_bFoundBetterBeam = FALSE;
			m_bFoundWorseBeam  = FALSE;
			Invalidate();
		}
		// Haben wir auf den Button geklickt um den Typ der Beamwaffe zu verringern
		else if (m_bFoundWorseBeam == TRUE && CRect(r.right-275,120,r.right-155,150).PtInRect(point))
		{
			// Dann wird der Typ bei der aktuellen Beamwaffe um eins erhöht
			CBeamWeapons* pWeapon = &m_pShownShip->GetBeamWeapons()->GetAt(m_iBeamWeaponNumber);

			BYTE oldType		= pWeapon->GetBeamType();
			USHORT oldPower		= pWeapon->GetBeamPower();
			BYTE oldNumber		= pWeapon->GetBeamNumber();
			BYTE oldShootNumber = pWeapon->GetShootNumber();
			CString oldName		= pWeapon->GetBeamName();
			BYTE oldBonus		= pWeapon->GetBonus();
			BYTE oldLenght		= pWeapon->GetBeamLenght();
			BYTE oldRechargeTime= pWeapon->GetRechargeTime();
			BOOLEAN piercing	= pWeapon->GetPiercing();
			BOOLEAN modulating	= pWeapon->GetModulating();

			// hier aktualisieren -> Reichweite erhöhen
			pWeapon->ModifyBeamWeapon((oldType-1),oldPower,oldNumber,oldName,modulating,piercing,oldBonus,oldLenght,oldRechargeTime,oldShootNumber);
			// Feuerwinkel bleiben alle beim alten
			m_pShownShip->CalculateFinalCosts();
			m_bFoundBetterBeam = FALSE;
			m_bFoundWorseBeam  = FALSE;
			Invalidate();
		}
	}
	counter++;

	// Überprüfen ob wir irgendetwas an einer Torpedowaffe ändern möchten
	if (m_pShownShip && m_pShownShip->GetTorpedoWeapons()->GetSize() > 0)
	{
		// Hat das Schiff mehr als eine Torpedowaffe können wir auf die nächste zugreifen indem wir hier klicken
		if (CRect(r.right-300,80+counter*90,r.right,125+counter*90).PtInRect(point))
		{
			if (m_pShownShip->GetTorpedoWeapons()->GetUpperBound() > m_iTorpedoWeaponNumber)
			{
				m_iTorpedoWeaponNumber++;
				Invalidate();
			}
			else if (m_pShownShip->GetTorpedoWeapons()->GetUpperBound() == m_iTorpedoWeaponNumber)
			{
				m_iTorpedoWeaponNumber = 0;
				Invalidate();
			}
		}
		// Haben wir auf den Button geklickt um den Torpedowerfer zu ändern
		else if (CRect(r.right-275,140+counter*90,r.right-145,170+counter*90).PtInRect(point))
		{
			CTorpedoWeapons* pWeapon = &m_pShownShip->GetTorpedoWeapons()->GetAt(m_iTorpedoWeaponNumber);

			BYTE oldTorpType	= pWeapon->GetTorpedoType();
			BYTE oldTupeNumber	= pWeapon->GetNumberOfTupes();
			BYTE oldAcc			= pWeapon->GetAccuracy();
			CString oldTupeName	= pWeapon->GetTupeName();

			TupeWeaponsObserverStruct twos = pMajor->GetWeaponObserver()->GetNextTupe(oldTupeName,oldTorpType);
			// hier aktualisieren
			pWeapon->ModifyTorpedoWeapon(oldTorpType,twos.number,twos.fireRate,oldTupeNumber,twos.TupeName,twos.onlyMicro,oldAcc);
			USHORT nMountPos	= pWeapon->GetFirearc()->GetPosition();
			USHORT nAngle		= twos.fireAngle;
			pWeapon->GetFirearc()->SetValues(nMountPos, nAngle);

			m_pShownShip->CalculateFinalCosts();
			Invalidate();
		}
		// Haben wir auf den Button geklickt um den Torpedotyp zu ändern
		else if (CRect(r.right-145,140+counter*90,r.right-25,170+counter*90).PtInRect(point))
		{
			CTorpedoWeapons* pWeapon = &m_pShownShip->GetTorpedoWeapons()->GetAt(m_iTorpedoWeaponNumber);

			BYTE oldNumber		= pWeapon->GetNumber();
			BYTE oldFirerate	= pWeapon->GetTupeFirerate();
			BYTE oldTupeNumber	= pWeapon->GetNumberOfTupes();
			BOOLEAN oldOnlyMicro= pWeapon->GetOnlyMicroPhoton();
			BYTE oldAcc			= pWeapon->GetAccuracy();
			BYTE oldTorpType	= pWeapon->GetTorpedoType();
			CString oldTupeName	= pWeapon->GetTupeName();

			BYTE newTorpType = pMajor->GetWeaponObserver()->GetNextTorpedo(oldTorpType, oldOnlyMicro);
			// hier aktualisieren
			pWeapon->ModifyTorpedoWeapon(newTorpType,oldNumber,oldFirerate,oldTupeNumber,oldTupeName,oldOnlyMicro,oldAcc);
			// Feuerwinkel bleiben gleich
			m_pShownShip->CalculateFinalCosts();
			Invalidate();
		}
	}
	counter++;

	// Überprüfen ob wir das Hüllenmaterial ändern möchten, also ob wir auf den Button "Hüllenmaterial ändern" geklickt haben
	if (m_pShownShip && CRect(r.right-275,180+counter*120,r.right-155,210+counter*120).PtInRect(point))
	{
		CHull* pHull			= m_pShownShip->GetHull();

		BOOLEAN oldDoubleHull	= pHull->GetDoubleHull();
		ULONG oldBaseHull		= pHull->GetBaseHull();
		BOOLEAN ablative		= pHull->GetAblative();
		BOOLEAN polarisation	 = pHull->GetPolarisation();
		// Dann bekommt das nächste Schiff ein neues Hüllenmaterial
		switch (pHull->GetHullMaterial())
		{
		case TITAN: pHull->ModifyHull(oldDoubleHull,oldBaseHull,DURANIUM,ablative,polarisation);
			break;
		case DURANIUM: pHull->ModifyHull(oldDoubleHull,oldBaseHull,IRIDIUM,ablative,polarisation);
			break;
		case IRIDIUM: pHull->ModifyHull(oldDoubleHull,oldBaseHull,TITAN,ablative,polarisation);
			break;
		}
		m_pShownShip->CalculateFinalCosts();
		Invalidate();
	}
	// Überprüfen ob wir geklickt haben um die Hüllenart zu wechseln (also Einzel- oder Doppelhülle)
	else if (m_pShownShip && CRect(r.right-145,180+counter*120,r.right-25,210+counter*120).PtInRect(point))
	{
		CHull* pHull			= m_pShownShip->GetHull();

		BOOLEAN oldDoubleHull	= pHull->GetDoubleHull();

		// wenn eine Doppelhülle draus gemacht werden soll dann darf die Manövrierbarkeit nicht schon "keine" oder nur 1 sein
		if (oldDoubleHull == FALSE && m_pShownShip->GetManeuverability() <= 1)
			return;
		// wenn eine Einzelhülle draus gemacht werden soll, dann darf die Manövrierbarkeit nicht schon phänomenal sein
		if (oldDoubleHull == TRUE && m_pShownShip->GetManeuverability() == 9)
			return;

		// Wenn die alte Hülle eine Einzelhülle war und man eine Doppelhülle anbaut, dann verringert sich die
		// Manövriebarkeit um -1. Wenn man eine Einzelhülle anbaut, dann kommt zur Manö +1 dazu. Schiffe mit
		// Manö 0 oder Manö 9 sind von dieser Reglung ausgeschlossen.
		if (m_pShownShip->GetManeuverability() >= 0 && m_pShownShip->GetManeuverability() <= 9)
		{
			// wollen Doppelhülle draus machen
			if (oldDoubleHull == FALSE)
				m_pShownShip->SetManeuverability(m_pShownShip->GetManeuverability()-1);
			// wollen eine Einzelhülle draus machen
			else
				m_pShownShip->SetManeuverability(m_pShownShip->GetManeuverability()+1);
		}
		BOOLEAN ablative		= pHull->GetAblative();
		BOOLEAN polarisation	= pHull->GetPolarisation();
		ULONG oldBaseHull		= pHull->GetBaseHull();
		BYTE oldHullMaterial	= pHull->GetHullMaterial();

		pHull->ModifyHull(!oldDoubleHull,oldBaseHull,oldHullMaterial,ablative,polarisation);
		m_pShownShip->CalculateFinalCosts();
		Invalidate();
	}
	// Überprüfen ob ich geklickt habe um den Schildtyp zu verringern
	else if (m_pShownShip && CRect(r.right-275,300+counter*120,r.right-155,325+counter*120).PtInRect(point))
	{
		if (m_pShownShip->GetShield()->GetShieldType() > 0)
		{
			CShield* pShield = m_pShownShip->GetShield();

			UINT oldMaxShield	= pShield->GetMaxShield();
			BYTE oldShieldType	= pShield->GetShieldType();
			BOOLEAN regenerative= pShield->GetRegenerative();

			pShield->ModifyShield(oldMaxShield, (oldShieldType - 1), regenerative);
			m_pShownShip->CalculateFinalCosts();
			Invalidate();
		}
	}
	// Überprüfen ob ich geklickt habe um den Schildtyp zu erhöhen
	else if (m_pShownShip && CRect(r.right-145,300+counter*120,r.right-25,325+counter*120).PtInRect(point))
	{
		CShield* pShield = m_pShownShip->GetShield();

		USHORT oldShieldType = pShield->GetShieldType();
		if (pMajor->GetWeaponObserver()->GetMaxShieldType() > oldShieldType)
		{
			UINT oldMaxShield	= pShield->GetMaxShield();
			BOOLEAN regenerative= pShield->GetRegenerative();

			pShield->ModifyShield(oldMaxShield, (oldShieldType + 1), regenerative);
			m_pShownShip->CalculateFinalCosts();
			Invalidate();
		}
	}

	CMainBaseView::OnLButtonDown(nFlags, point);
}
/////////////////////////////////////////////////////////////////////////////////////////
// Hier die Funktion zum Zeichnen des Schiffsdesignmenüs
/////////////////////////////////////////////////////////////////////////////////////////
void CShipDesignMenuView::DrawShipDesignMenue(Graphics* g)
{
	CBotEDoc* pDoc = resources::pDoc;
	ASSERT(pDoc);

	CMajor* pMajor = m_pPlayersRace;
	ASSERT(pDoc);
	if (!pMajor)
		return;

	CString fontName = "";
	Gdiplus::REAL fontSize = 0.0;

	// Rassenspezifische Schriftart auswählen
	CFontLoader::CreateGDIFont(pMajor, 2, fontName, fontSize);
	// Schriftfarbe wählen
	Gdiplus::Color normalColor;
	CFontLoader::GetGDIFontColor(pMajor, 3, normalColor);

	StringFormat fontFormat;
	fontFormat.SetAlignment(StringAlignmentNear);
	fontFormat.SetLineAlignment(StringAlignmentCenter);
	fontFormat.SetFormatFlags(StringFormatFlagsNoWrap);

	Color penColor;
	penColor.SetFromCOLORREF(pMajor->GetDesign()->m_clrListMarkPenColor);

	Color markColor;
	markColor.SetFromCOLORREF(pMajor->GetDesign()->m_clrListMarkTextColor);

	if (bg_designmenu)
		g->DrawImage(bg_designmenu, 0, 0, 1075, 750);

	SolidBrush fontBrush(normalColor);


	// Links im Bild die veränderbaren Schiffklassen zeichnen (bis jetzt darf man keine Stationen verändern,
	// weil deren Baukosten allein von den Industriekosten berechnet werden. Diese aber nicht steigen wenn
	// man die Hülle oder Schilde verbessert. Somit könnte man bessere Stationen für den gleichen Preis bauen.

	// Schiffsinfoarray durchgehen und nach zum Imperium gehörende baubare Schiffe suchen
	short j = 0;
	short counter = m_iClickedOnShip - 23 + m_iOldClickedOnShip;
	short oldClickedShip = m_iClickedOnShip;

	BYTE researchLevels[6] =
	{
		pMajor->GetEmpire()->GetResearch()->GetBioTech(),
		pMajor->GetEmpire()->GetResearch()->GetEnergyTech(),
		pMajor->GetEmpire()->GetResearch()->GetCompTech(),
		pMajor->GetEmpire()->GetResearch()->GetPropulsionTech(),
		pMajor->GetEmpire()->GetResearch()->GetConstructionTech(),
		pMajor->GetEmpire()->GetResearch()->GetWeaponTech()
	};

	m_pShownShip = NULL;
	m_nSizeOfShipDesignList = 0;
	// Es gehen nur 21 Einträge auf die Seite, deshalb muss abgebrochen werden
	for (int i = 0; i < pDoc->m_ShipInfoArray.GetSize(); i++)
		if (pDoc->m_ShipInfoArray.GetAt(i).GetRace() == pMajor->GetRaceShipNumber())
			if (!pDoc->m_ShipInfoArray.GetAt(i).IsStation())
				if (pDoc->m_ShipInfoArray.GetAt(i).IsThisShipBuildableNow(researchLevels))
				{
					// wurde dieses Schiff durch kein anderes jetzt baubares Schiff schon obsolet?
					BOOLEAN foundObsolet = FALSE;
					for (int m = 0; m < pDoc->m_ShipInfoArray.GetSize(); m++)
						if (pDoc->m_ShipInfoArray.GetAt(m).GetRace() == pMajor->GetRaceShipNumber())
							if (pDoc->m_ShipInfoArray.GetAt(m).GetObsoleteShipClass() == pDoc->m_ShipInfoArray.GetAt(i).GetShipClass())
								if (pDoc->m_ShipInfoArray.GetAt(m).IsThisShipBuildableNow(researchLevels))
								{
									foundObsolet = TRUE;
									break;
								}

					if (foundObsolet)
						continue;

					m_nSizeOfShipDesignList++;
					if (counter > 0)
					{
						m_iClickedOnShip--;
						counter--;
						continue;
					}

					if (j < 24)
					{
						fontBrush.SetColor(normalColor);
						// Wenn wir ein Schiff gefunden haben, dann zeichnen wir dieses in die Liste (max. 21)
						// Wenn wir das Schiff markiert haben, dann die Markierung zeichnen, haben wir kein spezielles Schiff
						// angeklickt, so wird das 1. Schiff in der Liste markiert
						if (j == m_iClickedOnShip || m_iClickedOnShip == -1)
						{
							fontBrush.SetColor(markColor);
							// Wenn wir nix angeklickt haben und nur das erste Schiff markiert war, dann automatisch
							m_iClickedOnShip = j;
							if (oldClickedShip == -1)
								oldClickedShip = j;

							m_pShownShip = &pDoc->m_ShipInfoArray.GetAt(i);

							// Markierung worauf wir geklickt haben
							g->FillRectangle(&SolidBrush(Color(50,200,200,200)), RectF(15,120+j*25,183,25));
							g->DrawLine(&Gdiplus::Pen(penColor), 15, 120+j*25, 198, 120+j*25);
							g->DrawLine(&Gdiplus::Pen(penColor), 15, 145+j*25, 198, 145+j*25);

							// Infos in unteren Schiffsdesignansicht aktualisieren
							if (CShipDesignBottomView* pView = dynamic_cast<CShipDesignBottomView*>(resources::pMainFrame->GetView(RUNTIME_CLASS(CShipDesignBottomView))))
							{
								if (pView->GetCurrentShipInfo() != i)
								{
									pView->SetCurrentShipInfo(i);
									pView->Invalidate(FALSE);
								}
							}
						}
						CString s = pDoc->m_ShipInfoArray.GetAt(i).GetShipClass();
						g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(25, 120 + j * 25, 175, 25), &fontFormat, &fontBrush);
						j++;
					}
				}
	m_iClickedOnShip = oldClickedShip;

	// Hier jetzt Informationen zum angeklickten Schiff anzeigen
	if (m_pShownShip)
	{
		// Bild des Schiffes zeichnen
		CString s;
		s.Format("Ships\\%s.bop",m_pShownShip->GetShipClass());
		Bitmap* graphic = pDoc->GetGraphicPool()->GetGDIGraphic(s);
		if (graphic == NULL)
			graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Ships\\ImageMissing.bop");
		if (graphic)
		{
			g->DrawImage(graphic, 388, 90, 200, 150);
			graphic = NULL;
		}
		// allgemeine Schiffsinformationen anzeigen
		m_pShownShip->DrawShipInformation(g, CRect(220,250,740,440), &Gdiplus::Font(CComBSTR(fontName), fontSize), normalColor, markColor, pMajor->GetEmpire()->GetResearch());
		// Baukosten des Schiffes anzeigen
		fontBrush.SetColor(markColor);
		fontFormat.SetAlignment(StringAlignmentCenter);
		fontFormat.SetLineAlignment(StringAlignmentNear);
		g->DrawString(CComBSTR(CLoc::GetString("BUILDCOSTS")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(190,440,580,25), &fontFormat, &fontBrush);

		fontBrush.SetColor(normalColor);
		s.Format("%s: %d  %s: %d  %s: %d",CLoc::GetString("INDUSTRY"),m_pShownShip->GetNeededIndustry(),
			CLoc::GetString("TITAN"),m_pShownShip->GetNeededTitan(),
			CLoc::GetString("DEUTERIUM"),m_pShownShip->GetNeededDeuterium());
		g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(190,465,580,25), &fontFormat, &fontBrush);

		s.Format("%s: %d  %s: %d  %s: %d  %s: %d",CLoc::GetString("DURANIUM"),m_pShownShip->GetNeededDuranium(),
			CLoc::GetString("CRYSTAL"),m_pShownShip->GetNeededCrystal(),
			CLoc::GetString("IRIDIUM"),m_pShownShip->GetNeededIridium(),
			CLoc::GetString("DERITIUM"),m_pShownShip->GetNeededDeritium());
			g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(190,490,580,25), &fontFormat, &fontBrush);

		// Die Buttons zur Eigenschaftsänderung in der Rechten Seite der Ansicht anzeigen
		// zuerst überprüfen wir die Beamwaffen, wir können den Typ der Beamwaffe verändern, wenn wir mindst. ein anderes
		// Schiff des Imperiums finden, welches DIESE Beamwaffe mit einem höheren Typ oder einem niedrigeren Typ besitzt

		graphic = pDoc->GetGraphicPool()->GetGDIGraphic("Other\\" + pMajor->GetPrefix() + "button_small.bop");
		Color btnColor;
		CFontLoader::GetGDIFontColor(pMajor, 1, btnColor);
		SolidBrush btnBrush(btnColor);

		fontFormat.SetAlignment(StringAlignmentCenter);
		fontFormat.SetLineAlignment(StringAlignmentCenter);

		// Nach Beamwaffen suchen
		if (m_pShownShip->GetBeamWeapons()->GetSize() > m_iBeamWeaponNumber)
		{
			// gibt es schon von dieser Beamwaffe hier auf dem Schiff einen höheren Typ?
			USHORT maxTyp =	pMajor->GetWeaponObserver()->GetMaxBeamType(m_pShownShip->GetBeamWeapons()->GetAt(m_iBeamWeaponNumber).GetBeamName());
			if (maxTyp > m_pShownShip->GetBeamWeapons()->GetAt(m_iBeamWeaponNumber).GetBeamType())
			{
				// Dann können wir den Typ unserer Beamwaffe(n) verbessern
				if (graphic)
					g->DrawImage(graphic, 930, 120, 120, 30);
				g->DrawString(CComBSTR(CLoc::GetString("BTN_STRONGER")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(930,120,120,30), &fontFormat, &btnBrush);
				m_bFoundBetterBeam = TRUE;
			}
			// Wenn wir einen größeren Typ als Typ 1 haben, dann können wir diesen verringern
			if (m_pShownShip->GetBeamWeapons()->GetAt(m_iBeamWeaponNumber).GetBeamType() > 1)
			{
				// Dann können wir den Typ unserer Beamwaffe(n) verkleinern
				if (graphic)
					g->DrawImage(graphic, 800, 120, 120, 30);
				g->DrawString(CComBSTR(CLoc::GetString("BTN_WEAKER")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(800,120,120,30), &fontFormat, &btnBrush);
				m_bFoundWorseBeam = TRUE;
			}

			// Typ und Name der Beamwaffe zeichnen
			fontBrush.SetColor(normalColor);
			s.Format("%s %d %s",CLoc::GetString("TYPE"),m_pShownShip->GetBeamWeapons()->GetAt(m_iBeamWeaponNumber).GetBeamType(),m_pShownShip->GetBeamWeapons()->GetAt(m_iBeamWeaponNumber).GetBeamName());
			fontFormat.SetTrimming(StringTrimmingEllipsisCharacter);
			g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(845,80,160,25), &fontFormat, &fontBrush);
			fontFormat.SetTrimming(StringTrimmingNone);
		}

		// Nach anderer Torpedowaffe suchen
		if (m_pShownShip->GetTorpedoWeapons()->GetSize() > m_iTorpedoWeaponNumber)
		{
			// den aktuellen Torpedotyp holen
			BYTE currentTorpType = m_pShownShip->GetTorpedoWeapons()->GetAt(m_iTorpedoWeaponNumber).GetTorpedoType();
			// Torpedoname zeichnen
			fontBrush.SetColor(normalColor);
			s.Format("%s (%d°)",m_pShownShip->GetTorpedoWeapons()->GetAt(m_iTorpedoWeaponNumber).GetTupeName(), m_pShownShip->GetTorpedoWeapons()->GetAt(m_iTorpedoWeaponNumber).GetFirearc()->GetAngle());
			g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(775,170,300,25), &fontFormat, &fontBrush);

			s.Format("%s (%d)", CTorpedoInfo::GetName(currentTorpType), CTorpedoInfo::GetPower(currentTorpType));
			g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(775,195,300,25), &fontFormat, &fontBrush);

			if (graphic)
				g->DrawImage(graphic, 800, 230, 120, 30);
			g->DrawString(CComBSTR(CLoc::GetString("BTN_LAUNCHER")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(800,230,120,30), &fontFormat, &btnBrush);
			if (graphic)
				g->DrawImage(graphic, 930, 230, 120, 30);
			g->DrawString(CComBSTR(CLoc::GetString("BTN_TORPEDO")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(930,230,120,30), &fontFormat, &btnBrush);
		}

		// hier Möglichkeit anderes Hüllenmaterial anzubringen eingebaut
		CString material;
		switch (m_pShownShip->GetHull()->GetHullMaterial())
		{
			case TITAN:		material = CLoc::GetString("TITAN");; break;
			case DURANIUM:	material = CLoc::GetString("DURANIUM");; break;
			case IRIDIUM:	material = CLoc::GetString("IRIDIUM");; break;
			default: material = "";
		}

		BOOLEAN bDoubleHull = m_pShownShip->GetHull()->GetDoubleHull();
		if (bDoubleHull == TRUE)
			s.Format("%s%s",material, CLoc::GetString("DOUBLE_HULL_ARMOUR"));
		else
			s.Format("%s%s",material, CLoc::GetString("HULL_ARMOR"));
		g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(775,380,300,30), &fontFormat, &fontBrush);

		// Hier kann man den Schildtyp ändern
		// zuerst Anzeige der jetzt aktuellen Schilde. Beim Romulaner eine schwarze Schriftart wählen. Wenn dies
		// später auch bei der Föd heller unterlegt ist kann auch dort eine schwarze Schriftfarbe gewählt werden.
		s.Format("%s %d %s",CLoc::GetString("TYPE"),m_pShownShip->GetShield()->GetShieldType(),CLoc::GetString("SHIELDS"));
		g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(775,490,300,30), &fontFormat, &fontBrush);

		// Ab jetzt die Buttons zum Ändern der jeweiligen Komponenten
		if (graphic)
			g->DrawImage(graphic, 800, 420, 120, 30);
		g->DrawString(CComBSTR(CLoc::GetString("BTN_MATERIAL")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(800,420,120,30), &fontFormat, &btnBrush);

		// wenn eine Doppelhülle draus gemacht werden soll dann darf die Manövrierbarkeit nicht schon "keine" oder nur 1 sein
		// wenn eine Einzelhülle draus gemacht werden soll, dann darf die Manövrierbarkeit nicht schon phänomenal sein
		if ((bDoubleHull == FALSE && m_pShownShip->GetManeuverability() > 1) || (bDoubleHull == TRUE && m_pShownShip->GetManeuverability() < 9))
		{
			if (graphic)
				g->DrawImage(graphic, 930, 420, 120, 30);
			g->DrawString(CComBSTR(CLoc::GetString("BTN_HULLTYPE")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(930,420,120,30), &fontFormat, &btnBrush);
		}

		// Schildtyp schwächer Button einblenden
		if (m_pShownShip->GetShield()->GetShieldType() > 0)
		{
			if (graphic)
				g->DrawImage(graphic, 800, 540, 120, 30);
			g->DrawString(CComBSTR(CLoc::GetString("BTN_WEAKER")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(800,540,120,30), &fontFormat, &btnBrush);
		}
		// Schildtyp stärker Button einblenden
		if (m_pShownShip->GetShield()->GetShieldType() < pMajor->GetWeaponObserver()->GetMaxShieldType())
		{
			if (graphic)
				g->DrawImage(graphic, 930, 540, 120, 30);
			g->DrawString(CComBSTR(CLoc::GetString("BTN_STRONGER")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(930,540,120,30), &fontFormat, &btnBrush);
		}
	}
	// Wenn das Schiff in irgendeinem unserer Systeme gebaut wird, dann großen Text ausgeben, in welchem System das Schiff
	// gerade gebaut wird
	CString systemName = CheckIfShipIsBuilding(m_pShownShip);
	if (!systemName.IsEmpty())
	{
		COverlayBanner *banner = new COverlayBanner(CPoint(200,300), CSize(580, 200),
			CLoc::GetString("NO_CHANGE_POSSIBLE", FALSE, systemName), RGB(220,0,0));
		banner->Draw(g, &Gdiplus::Font(CComBSTR(fontName), fontSize));
		delete banner;
	}

	// draw Button DisplayAllShips
	Bitmap* btnDisplayAllShips = pDoc->GetGraphicPool()->GetGDIGraphic("Other\\" + pMajor->GetPrefix() + "button_small.bop");//All-Button zeichnen
	if(btnDisplayAllShips)
		g->DrawImage(btnDisplayAllShips,40,750,80,30);

	CString s;
	//AfxMessageBox("m_bDisplayAllShips"); 
	if (m_bDisplayAllShips)
		s=CLoc::GetString("BTN_ALL");
	else
		s=CLoc::GetString("BTN_CURRENTS");
	g->DrawString(CComBSTR(s), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(40,750,80,30), &fontFormat, &fontBrush);


	// "Schiffsdesign" in der Mitte zeichnen
	// Rassenspezifische Schriftart auswählen
	CFontLoader::CreateGDIFont(pMajor, 5, fontName, fontSize);
	// Schriftfarbe wählen
	CFontLoader::GetGDIFontColor(pMajor, 3, normalColor);
	fontBrush.SetColor(normalColor);
	g->DrawString(CComBSTR(CLoc::GetString("SHIPDESIGN")), -1, &Gdiplus::Font(CComBSTR(fontName), fontSize), RectF(188,10,600,50), &fontFormat, &fontBrush);
}
Пример #12
0
void CResearchAI::Calc(CBotEDoc* pDoc)
{
	ASSERT(pDoc);

	// Forschungsdurchschnitt aller Rassen berechnen
	map<CString, CMajor*>* pmMajors = pDoc->GetRaceCtrl()->GetMajors();
	ASSERT(pmMajors);

	// Map mit zum Major zugehörigen Techlevel
	map<CMajor*, double> mTechLevels;
	list<double> lTechLevels;

	for (map<CString, CMajor*>::const_iterator it = pmMajors->begin(); it != pmMajors->end(); ++it)
	{
		CMajor* pMajor = it->second;
		// für menschliche Spieler wird die KI nichts tun
		if (!pMajor || pMajor->AHumanPlays())
			continue;

		double dTechLevel = pMajor->GetEmpire()->GetResearch()->GetBioTech() +
							pMajor->GetEmpire()->GetResearch()->GetEnergyTech() +
							pMajor->GetEmpire()->GetResearch()->GetCompTech() +
							pMajor->GetEmpire()->GetResearch()->GetPropulsionTech() +
							pMajor->GetEmpire()->GetResearch()->GetConstructionTech() +
							pMajor->GetEmpire()->GetResearch()->GetWeaponTech();
		dTechLevel /= 6.0;
		lTechLevels.push_back(dTechLevel);

		// Hat die Rasse überhaupt eine Spezialforschung zur Auswahl? (auf FALSE prüfen!)
		if (!pMajor->GetEmpire()->GetResearch()->GetUniqueReady())
			// Hat die Rasse noch keinen Bereich gewählt?
			if (pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->GetChoiceTaken() == false)
				mTechLevels[pMajor] = dTechLevel;
	}

	// absteigend sortieren
	lTechLevels.sort();
	lTechLevels.reverse();
	// auf die besten zwei begrenzen
	lTechLevels.resize(2);

	// nur die Majors mit dem besten oder zweitbesten Techlevel versuchen eine Spezialforschung
	// zu beginnen. Dies machen sie aber nur, wenn sie mindestens eine Techstufe weiter sind, als
	// sie für die Spezialforschung benötigt haben
	for (list<double>::const_iterator it = lTechLevels.begin(); it != lTechLevels.end(); ++it)
	{
		// Major mit diesem Techlevel suchen
		for (map<CMajor*, double>::const_iterator it2 = mTechLevels.begin(); it2 != mTechLevels.end(); ++it2)
		{
			if (*it == it2->second)
			{
				CMajor* pMajor = it2->first;
				if (pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->GetChoiceTaken())
					break;

				BYTE nUniqueTech = pMajor->GetEmpire()->GetResearch()->GetUniqueTech() + 1;
				// Prüfen ob die Rasse schon ein Level weiter ist, als das was sie für die Spezialforschung braucht
				if (nUniqueTech < pMajor->GetEmpire()->GetResearch()->GetBioTech() &&
					nUniqueTech < pMajor->GetEmpire()->GetResearch()->GetEnergyTech() &&
					nUniqueTech < pMajor->GetEmpire()->GetResearch()->GetCompTech() &&
					nUniqueTech < pMajor->GetEmpire()->GetResearch()->GetConstructionTech() &&
					nUniqueTech < pMajor->GetEmpire()->GetResearch()->GetPropulsionTech() &&
					nUniqueTech < pMajor->GetEmpire()->GetResearch()->GetWeaponTech())
				{
					// zufällig einen Bereich wählen (1 bis 3)
					int nComplex = rand()%3 + 1;
					pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->SetUniqueResearchChoosePossibility(nComplex);
					// 100% zuteilen
					pMajor->GetEmpire()->GetResearch()->SetPercentage(6, 100);
					CString sName = pMajor->GetEmpire()->GetResearch()->GetResearchInfo()->GetCurrentResearchComplex()->GetComplexName();
					MYTRACE("general")(MT::LEVEL_INFO, "CResearchAI::Calc(): %s choose in unique complex '%s' field %d and set level to 100%%\n", pMajor->GetRaceID(), sName, nComplex);
				}
			}
		}
	}
}