From f2642cb62c5171df35696a5c00193ebd4a7c51e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Wed, 29 Feb 2012 01:31:48 +0000 Subject: [PATCH] Added VCAI and EmptyAI to the VS solution. Removed from it GeniusAI. Fixed #329, #884, #885. --- AI/EmptyAI/EmptyAI.vcxproj | 177 +++++++++++++++++++++++++++++++++++++ AI/VCAI/VCAI.cpp | 16 ++-- VCMI_VS10.sln | 18 ++-- client/CMT.cpp | 2 +- client/CPreGame.cpp | 12 +-- client/Client.cpp | 2 +- lib/BattleState.cpp | 81 ++++++++++------- lib/BattleState.h | 7 +- lib/NetPacksLib.cpp | 15 ++-- 9 files changed, 262 insertions(+), 68 deletions(-) create mode 100644 AI/EmptyAI/EmptyAI.vcxproj diff --git a/AI/EmptyAI/EmptyAI.vcxproj b/AI/EmptyAI/EmptyAI.vcxproj new file mode 100644 index 000000000..d487c7616 --- /dev/null +++ b/AI/EmptyAI/EmptyAI.vcxproj @@ -0,0 +1,177 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + RD + Win32 + + + RD + x64 + + + + + + + Create + Create + Create + Create + + + + + + + + {C41C4EB6-6F74-4F37-9FB0-9FA6BF377837} + EmptyAI + + + + DynamicLibrary + true + MultiByte + + + DynamicLibrary + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + DynamicLibrary + false + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\AI\ + $(IncludePath) + $(LibraryPath) + + + $(SolutionDir)\AI\ + $(IncludePath) + $(LibraryPath) + + + $(SolutionDir)$(Configuration)\bin\AI\ + $(IncludePath) + $(LibraryPath) + + + $(SolutionDir)$(Configuration)\bin\AI\ + $(IncludePath) + $(LibraryPath) + + + + Level3 + Disabled + %(AdditionalIncludeDirectories) + Use + StdInc.h + VCMI_DLL;%(PreprocessorDefinitions) + + + true + VCMI_lib.lib;%(AdditionalDependencies) + $(OutDir)..;%(AdditionalLibraryDirectories) + $(OutDir)EmptyAI.dll + + + + + Level3 + Disabled + %(AdditionalIncludeDirectories) + Use + StdInc.h + VCMI_DLL;_WINDLL;%(PreprocessorDefinitions) + + + true + VCMI_lib.lib;%(AdditionalDependencies) + $(OutDir)..;%(AdditionalLibraryDirectories) + $(OutDir)EmptyAI.dll + + + + + Level3 + MaxSpeed + true + true + %(AdditionalIncludeDirectories) + Use + StdInc.h + VCMI_DLL;_WINDLL;%(PreprocessorDefinitions) + + + true + true + true + VCMI_lib.lib;%(AdditionalDependencies) + $(OutDir)..;%(AdditionalLibraryDirectories) + $(OutDir)EmptyAI.dll + + + + + Level3 + MaxSpeed + true + true + %(AdditionalIncludeDirectories) + Use + StdInc.h + VCMI_DLL;_WINDLL;%(PreprocessorDefinitions) + + + true + true + true + VCMI_lib.lib;%(AdditionalDependencies) + $(OutDir)..;%(AdditionalLibraryDirectories) + $(OutDir)EmptyAI.dll + + + + + + \ No newline at end of file diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index bc85d8fbf..fa7cc5c59 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -464,13 +464,15 @@ void VCAI::gameOver(ui8 player, bool victory) tlog0 << "VCAI: Player " << (int)player << " lost. It's me. What a disappointment! :(\n"; } - //let's make Impossible difficulty finally standing to its name :> - if(myCb->getStartInfo()->difficulty == 4 && !victory) - { - //play dirty: crash the whole engine to avoid lose - //that way AI is unbeatable! - *(int*)NULL = 666; - } +// //let's make Impossible difficulty finally standing to its name :> +// if(myCb->getStartInfo()->difficulty == 4 && !victory) +// { +// //play dirty: crash the whole engine to avoid lose +// //that way AI is unbeatable! +// *(int*)NULL = 666; +// } + +// TODO - at least write some insults on stdout finish(); } diff --git a/VCMI_VS10.sln b/VCMI_VS10.sln index 144c4e012..7e150ae66 100644 --- a/VCMI_VS10.sln +++ b/VCMI_VS10.sln @@ -7,8 +7,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VCMI_lib", "lib\VCMI_lib.vc EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VCMI_server", "server\VCMI_server.vcxproj", "{8AF697C3-465E-4910-B31B-576A9ECDB309}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genius", "AI\GeniusAI\genius.vcxproj", "{B6A14ED9-E7C1-411B-A596-2FE90B3145B4}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StupidAI", "AI\StupidAI\StupidAI.vcxproj", "{15DABC90-234A-4B6B-9EEB-777C4768B82B}" ProjectSection(ProjectDependencies) = postProject {B952FFC5-3039-4DE1-9F08-90ACDA483D8F} = {B952FFC5-3039-4DE1-9F08-90ACDA483D8F} @@ -19,6 +17,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ERM", "Scripting\ERM\ERM.vc {B952FFC5-3039-4DE1-9F08-90ACDA483D8F} = {B952FFC5-3039-4DE1-9F08-90ACDA483D8F} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VCAI", "AI\VCAI\VCAI.vcxproj", "{276C3DB0-7A6B-4417-8E5C-322B08633AAC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -51,14 +51,6 @@ Global {8AF697C3-465E-4910-B31B-576A9ECDB309}.RD|Win32.Build.0 = RD|Win32 {8AF697C3-465E-4910-B31B-576A9ECDB309}.RD|x64.ActiveCfg = RD|x64 {8AF697C3-465E-4910-B31B-576A9ECDB309}.RD|x64.Build.0 = RD|x64 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.Debug|Win32.ActiveCfg = Debug|Win32 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.Debug|Win32.Build.0 = Debug|Win32 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.Debug|x64.ActiveCfg = Debug|x64 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.Debug|x64.Build.0 = Debug|x64 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.RD|Win32.ActiveCfg = RD|Win32 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.RD|Win32.Build.0 = RD|Win32 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.RD|x64.ActiveCfg = RD|x64 - {B6A14ED9-E7C1-411B-A596-2FE90B3145B4}.RD|x64.Build.0 = RD|x64 {15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|Win32.ActiveCfg = Debug|Win32 {15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|Win32.Build.0 = Debug|Win32 {15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|x64.ActiveCfg = Debug|x64 @@ -75,6 +67,12 @@ Global {8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|Win32.Build.0 = RD|Win32 {8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|x64.ActiveCfg = RD|x64 {8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|x64.Build.0 = RD|x64 + {276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|Win32.Build.0 = Debug|Win32 + {276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|x64.ActiveCfg = Debug|Win32 + {276C3DB0-7A6B-4417-8E5C-322B08633AAC}.RD|Win32.ActiveCfg = RD|Win32 + {276C3DB0-7A6B-4417-8E5C-322B08633AAC}.RD|Win32.Build.0 = RD|Win32 + {276C3DB0-7A6B-4417-8E5C-322B08633AAC}.RD|x64.ActiveCfg = RD|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/client/CMT.cpp b/client/CMT.cpp index 33bf015da..edab30795 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -189,7 +189,7 @@ int main(int argc, char** argv) ("battle,b", po::value(), "runs game in duel mode (battle-only") ("start", po::value(), "starts game from saved StartInfo file") ("onlyAI", "runs without GUI, all players will be default AI") - ("oneGoodAI", "puts one default AI and the rest will be GeniusAI") + ("oneGoodAI", "puts one default AI and the rest will be EmptyAI") ("autoSkip", "automatically skip turns in GUI") ("nointro,i", "skips intro movies"); diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 4691c7ebd..d00001e56 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -2582,11 +2582,9 @@ bool mapSorter::operator()(const CMapInfo *aaa, const CMapInfo *bbb) return (a->victoryCondition.condition < b->victoryCondition.condition); break; case _name: //by name - return (a->namename); - break; + return boost::ilexicographical_compare(a->name, b->name); default: - return (a->namename); - break; + return boost::ilexicographical_compare(a->name, b->name); } } else //if we are sorting campaigns @@ -2598,11 +2596,9 @@ bool mapSorter::operator()(const CMapInfo *aaa, const CMapInfo *bbb) CGI->generaltexth->campaignRegionNames[ bbb->campaignHeader->mapVersion ].size(); break; case _name: //by name - return aaa->campaignHeader->name < bbb->campaignHeader->name; - break; + return boost::ilexicographical_compare(aaa->campaignHeader->name, bbb->campaignHeader->name); default: - return aaa->campaignHeader->name < bbb->campaignHeader->name; - break; + return boost::ilexicographical_compare(aaa->campaignHeader->name, bbb->campaignHeader->name); } } } diff --git a/client/Client.cpp b/client/Client.cpp index c3b0d5d63..e15455e48 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -372,7 +372,7 @@ void CClient::newGame( CConnection *con, StartInfo *si ) { std::string AItoGive = settings["server"]["playerAI"].String(); if(!sensibleAILimit) - AItoGive = "GeniusAI"; + AItoGive = "EmptyAI"; else sensibleAILimit--; playerint[color] = static_cast(CDynLibHandler::getNewAI(AItoGive)); diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index ca37a2617..b47dbbe68 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -933,15 +933,16 @@ int BattleInfo::calculateSpellDuration( const CSpell * spell, const CGHeroInstan } switch(spell->id) { - case 56: //frenzy + case Spells::FRENZY: return 1; default: //other spells - return caster->getPrimSkillLevel(2) + caster->valOfBonuses(Bonus::SPELL_DURATION); + return caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER) + caster->valOfBonuses(Bonus::SPELL_DURATION); } } -CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, BattleHex position) const +CStack * BattleInfo::generateNewStack(const CStackInstance &base, bool attackerOwned, int slot, BattleHex position) const { + int stackID = getIdForNewStack(); int owner = attackerOwned ? sides[0] : sides[1]; assert((owner >= GameConstants::PLAYER_LIMIT) || (base.armyObj && base.armyObj->tempOwner == owner)); @@ -950,8 +951,9 @@ CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, b ret->position = position; return ret; } -CStack * BattleInfo::generateNewStack(const CStackBasicDescriptor &base, int stackID, bool attackerOwned, int slot, BattleHex position) const +CStack * BattleInfo::generateNewStack(const CStackBasicDescriptor &base, bool attackerOwned, int slot, BattleHex position) const { + int stackID = getIdForNewStack(); int owner = attackerOwned ? sides[0] : sides[1]; CStack * ret = new CStack(&base, owner, stackID, attackerOwned, slot); ret->position = position; @@ -1425,25 +1427,28 @@ void BattleInfo::localInit() b->attachTo(this); BOOST_FOREACH(CStack *s, stacks) - { - s->exportBonuses(); - if(s->base) //stack originating from "real" stack in garrison -> attach to it - { - s->attachTo(const_cast(s->base)); - } - else //attach directly to obj to which stack belongs and creature type - { - CArmedInstance *army = belligerents[!s->attackerOwned]; - s->attachTo(army); - assert(s->type); - s->attachTo(const_cast(s->type)); - } - s->postInit(); - } + localInitStack(s); exportBonuses(); } +void BattleInfo::localInitStack(CStack * s) +{ + s->exportBonuses(); + if(s->base) //stack originating from "real" stack in garrison -> attach to it + { + s->attachTo(const_cast(s->base)); + } + else //attach directly to obj to which stack belongs and creature type + { + CArmedInstance *army = belligerents[!s->attackerOwned]; + s->attachTo(army); + assert(s->type); + s->attachTo(const_cast(s->type)); + } + s->postInit(); +} + namespace CGH { using namespace std; @@ -1519,7 +1524,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const else pos = attackerLoose[armies[0]->stacksCount()-1][k]; - CStack * stack = curB->generateNewStack(*i->second, stacks.size(), true, i->first, pos); + CStack * stack = curB->generateNewStack(*i->second, true, i->first, pos); stacks.push_back(stack); } @@ -1534,7 +1539,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const else pos = defenderLoose[armies[1]->stacksCount()-1][k]; - CStack * stack = curB->generateNewStack(*i->second, stacks.size(), false, i->first, pos); + CStack * stack = curB->generateNewStack(*i->second, false, i->first, pos); stacks.push_back(stack); } @@ -1559,17 +1564,17 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const { if(heroes[0]->getArt(13)) //ballista { - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), stacks.size(), true, 255, 52); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), true, 255, 52); stacks.push_back(stack); } if(heroes[0]->getArt(14)) //ammo cart { - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), stacks.size(), true, 255, 18); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), true, 255, 18); stacks.push_back(stack); } if(heroes[0]->getArt(15)) //first aid tent { - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), stacks.size(), true, 255, 154); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), true, 255, 154); stacks.push_back(stack); } } @@ -1578,23 +1583,23 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const //defending hero shouldn't receive ballista (bug #551) if(heroes[1]->getArt(13) && !town) //ballista { - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), stacks.size(), false, 255, 66); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), false, 255, 66); stacks.push_back(stack); } if(heroes[1]->getArt(14)) //ammo cart { - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), stacks.size(), false, 255, 32); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), false, 255, 32); stacks.push_back(stack); } if(heroes[1]->getArt(15)) //first aid tent { - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), stacks.size(), false, 255, 168); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), false, 255, 168); stacks.push_back(stack); } } if(town && heroes[0] && town->hasFort()) //catapult { - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(145, 1), stacks.size(), true, 255, 120); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(145, 1), true, 255, 120); stacks.push_back(stack); } } @@ -1603,15 +1608,15 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const if (curB->siege == 2 || curB->siege == 3) { // keep tower - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -2); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), false, 255, -2); stacks.push_back(stack); if (curB->siege == 3) { // lower tower + upper tower - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -4); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), false, 255, -4); stacks.push_back(stack); - stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -3); + stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), false, 255, -3); stacks.push_back(stack); } } @@ -2302,6 +2307,20 @@ ui8 BattleInfo::whatSide(int player) const return -1; } +int BattleInfo::getIdForNewStack() const +{ + if(stacks.size()) + { + //stacks vector may be sorted not by ID and they may be not contiguous -> find stack with max ID + auto highestIDStack = *std::max_element(stacks.begin(), stacks.end(), + [](const CStack *a, const CStack *b) { return a->ID < b->ID; }); + + return highestIDStack->ID + 1; + } + + return 0; +} + CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S) : base(Base), ID(I), owner(O), slot(S), attackerOwned(AO), counterAttacks(1) diff --git a/lib/BattleState.h b/lib/BattleState.h index e6f76a0f3..d9bfa5c4d 100644 --- a/lib/BattleState.h +++ b/lib/BattleState.h @@ -108,8 +108,9 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode std::set getAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks std::set getAdjacentCreatures (const CStack * stack) const; static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster, int usedSpellPower); - CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield - CStack * generateNewStack(const CStackBasicDescriptor &base, int stackID, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield + CStack * generateNewStack(const CStackInstance &base, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield + CStack * generateNewStack(const CStackBasicDescriptor &base, bool attackerOwned, int slot, BattleHex position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield + int getIdForNewStack() const; //suggest a currently unused ID that'd suitable for generating a new stack ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell int hexToWallPart(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found int lineToWallHex(int line) const; //returns hex with wall in given line @@ -143,6 +144,8 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; NULL if none si8 battleMinSpellLevel() const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned void localInit(); + + void localInitStack(CStack * s); static BattleInfo * setupBattle( int3 tile, int terrain, int terType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town ); bool isInTacticRange( BattleHex dest ) const; int getSurrenderingCost(int player) const; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 46c052d7b..b45d91280 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -1288,15 +1288,14 @@ DLL_LINKAGE void BattleStackAdded::applyGs(CGameState *gs) tlog2 << "No place found for new stack!\n"; return; } - CStackInstance *csi = new CStackInstance(creID, amount); - csi->setArmyObj(gs->curB->belligerents[attacker ? 0 : 1]); - int newStackID = gs->curB->stacks.size() ? gs->curB->stacks.back()->ID+1 : 0; //stacks IDs may not be contiguous, so we need to give after-last ID - CStack * summonedStack = gs->curB->generateNewStack(*csi, newStackID, attacker, 255, pos); //TODO: netpacks? + + CStackBasicDescriptor csbd(creID, amount); + CStack * addedStack = gs->curB->generateNewStack(csbd, attacker, 255, pos); //TODO: netpacks? if (summoned) - summonedStack->state.insert(EBattleStackState::SUMMONED); - summonedStack->attachTo(csi); - summonedStack->postInit(); - gs->curB->stacks.push_back(summonedStack); //the stack is not "SUMMONED", it is permanent + addedStack->state.insert(EBattleStackState::SUMMONED); + + gs->curB->localInitStack(addedStack); + gs->curB->stacks.push_back(addedStack); //the stack is not "SUMMONED", it is permanent } DLL_LINKAGE void BattleSetStackProperty::applyGs(CGameState *gs)