diff --git a/AI/GeniusAI/CGeniusAI.cpp b/AI/GeniusAI/CGeniusAI.cpp index 9f8f7a877..a97421f6a 100644 --- a/AI/GeniusAI/CGeniusAI.cpp +++ b/AI/GeniusAI/CGeniusAI.cpp @@ -325,8 +325,8 @@ float CGeniusAI::TownObjective::getValue() const newID = ui.newID.back(); int upgrade_serial = ui.newID.size() - 1; - for (std::set< std::pair >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++) - resourceCosts[j->first] = j->second*howMany; +// for (std::set< std::pair >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++) +// resourceCosts[j->first] = j->second*howMany; break; } @@ -762,9 +762,9 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg, HypotheticalGameState& hgs std::set >::iterator j; for (int ii = 0; ii < ui.cost.size(); ii++) // Can afford the upgrade? { - for (j = ui.cost[ii].begin(); j != ui.cost[ii].end(); j++) - if (hgs.resourceAmounts[j->first] < j->second * i->second->count) - canUpgrade = false; +// for (j = ui.cost[ii].begin(); j != ui.cost[ii].end(); j++) +// if (hgs.resourceAmounts[j->first] < j->second * i->second->count) +// canUpgrade = false; } } if (canUpgrade) @@ -889,11 +889,11 @@ void CGeniusAI::addTownObjectives (HypotheticalGameState::TownModel& t, Hypothet bool canAfford = true; int upgrade_serial = ui.newID.size() - 1; - for (std::set< std::pair >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++) - { - if (hgs.resourceAmounts[j->first] < j->second * i->second->count) - canAfford = false; - } +// for (std::set< std::pair >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++) +// { +// if (hgs.resourceAmounts[j->first] < j->second * i->second->count) +// canAfford = false; +// } if (canAfford) { TownObjective to(hgs,AIObjective::upgradeCreatures,&t,i->first,this); diff --git a/AI_Base.h b/AI_Base.h index 4896d8acf..c4986ebc0 100644 --- a/AI_Base.h +++ b/AI_Base.h @@ -3,7 +3,7 @@ #include #include -#include "CGameInterface.h" +#include "lib/CGameInterface.h" /* * AI_Base.h, part of VCMI engine diff --git a/CCallback.cpp b/CCallback.cpp index 9ca25cf43..1e8aa1de0 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -157,14 +157,17 @@ bool CCallback::assembleArtifacts (const CGHeroInstance * hero, ui16 artifactSlo bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID) { - CGTownInstance * t = const_cast(town); + //CGTownInstance * t = const_cast(town); if(town->tempOwner!=player) return false; - const CBuilding *b = CGI->buildh->buildings[t->subID][buildingID]; - for(int i=0;iresources.size();i++) - if(b->resources[i] > gs->players[player].resources[i]) - return false; //lack of resources + + if(!canBuildStructure(town, buildingID)) + return false; +// const CBuilding *b = CGI->buildh->buildings[t->subID][buildingID]; +// for(int i=0;iresources.size();i++) +// if(b->resources[i] > gs->players[player].resources[i]) +// return false; //lack of resources BuildStructure pack(town->id,buildingID); sendRequest(&pack); diff --git a/client/CCreatureWindow.cpp b/client/CCreatureWindow.cpp index d5d8a4423..74aee96c1 100644 --- a/client/CCreatureWindow.cpp +++ b/client/CCreatureWindow.cpp @@ -82,16 +82,14 @@ CCreatureWindow::CCreatureWindow(const CStackInstance &st, int Type, boost::func { if(Upg && ui) { - bool enough = true; - for(std::set >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost + TResources upgradeCost = ui->cost[0] * st.count; + for(TResources::nziterator i(upgradeCost); i.valid(); i++) { BLOCK_CAPTURING; - if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*st.count) - enough = false; - upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*st.count)); + upgResCost.push_back(new SComponent(SComponent::resource, i->resType, i->resVal)); } - if(enough) + if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost)) { CFunctionList fs; fs += Upg; diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index b5adbc274..43fb582c0 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -1,12 +1,13 @@ #ifndef __CPLAYERINTERFACE_H__ #define __CPLAYERINTERFACE_H__ #include "../global.h" -#include "../CGameInterface.h" +#include "../lib/CGameInterface.h" #include "../lib/CondSh.h" #include #include #include #include "GUIBase.h" +#include "FunctionList.h" #ifdef __GNUC__ #define sprintf_s snprintf diff --git a/client/GUIBase.cpp b/client/GUIBase.cpp index 4baedbc12..121e0c7c7 100644 --- a/client/GUIBase.cpp +++ b/client/GUIBase.cpp @@ -820,6 +820,11 @@ void CIntObject::changeUsedEvents(ui16 what, bool enable, bool adjust /*= true*/ } } +void CIntObject::drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color) +{ + CSDL_Ext::drawBorder(sur, r + pos, color); +} + CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free ) { init(); diff --git a/client/GUIBase.h b/client/GUIBase.h index 8436202c7..fa415eaa1 100644 --- a/client/GUIBase.h +++ b/client/GUIBase.h @@ -416,6 +416,7 @@ public: void show(SDL_Surface * to); void showAll(SDL_Surface * to); + void drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color); void printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst); void printToLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst); void printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst); diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index cf8d220cc..cbae78927 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -1741,7 +1741,7 @@ void CRecruitmentWindow::clickLeft(tribool down, bool previousState) { for(int i=0;imotion.x, GH.current->motion.y)) { which = i; @@ -1804,9 +1804,9 @@ void CRecruitmentWindow::showAll( SDL_Surface * to ) for(int j=0;j >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost + TResources upgradeCost = ui->cost[0] * st.count; + for(TResources::nziterator i(upgradeCost); i.valid(); i++) { BLOCK_CAPTURING; - if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*st.count) - enough = false; - upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*st.count)); + upgResCost.push_back(new SComponent(SComponent::resource, i->resType, i->resVal)); } - if(enough) + if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost)) { CFunctionList fs; fs += Upg; fs += boost::bind(&CCreInfoWindow::close,this); CFunctionList cfl; - cfl = boost::bind(&CPlayerInterface::showYesNoDialog, LOCPLINT, CGI->generaltexth->allTexts[207], boost::ref(upgResCost), fs, 0, false); + cfl = boost::bind(&CPlayerInterface::showYesNoDialog, LOCPLINT, CGI->generaltexth->allTexts[207], boost::ref(upgResCost), fs, 0, true); upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,76,237,"IVIEWCR.DEF",SDLK_u); } else @@ -2109,7 +2107,7 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi fs[0] += Dsm; //dismiss fs[0] += boost::bind(&CCreInfoWindow::close,this);//close this window CFunctionList cfl; - cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector(),fs[0],fs[1],false); + cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector(),fs[0],fs[1],true); dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,21,237,"IVIEWCR2.DEF",SDLK_d); } ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),216,237,"IOKAY.DEF",SDLK_RETURN); @@ -6417,12 +6415,10 @@ void CHillFortWindow::updateGarrisons() UpgradeInfo info; LOCPLINT->cb->getUpgradeInfo(hero, i, info); if (info.newID.size())//we have upgrades here - update costs - for(std::set >::iterator it=info.cost[0].begin(); it!=info.cost[0].end(); it++) - { - std::pair pair = std::make_pair(it->first, it->second * hero->getStackCount(i) ); - costs[i].insert(pair); - totalSumm[pair.first] += pair.second; - } + { + costs[i] = info.cost[0] * hero->getStackCount(i); + totalSumm += costs[i]; + } } currState[i] = newState; @@ -6474,10 +6470,13 @@ void CHillFortWindow::showAll (SDL_Surface *to) if ( costs[i].size() )//we have several elements { int curY = 128;//reverse iterator is used to display gold as first element - for( std::map::reverse_iterator rit=costs[i].rbegin(); rit!=costs[i].rend(); rit++) + for(int j = costs[i].size()-1; j >= 0; j--) { - blitAtLoc(resources->ourImages[rit->first].bitmap, 104+76*i, curY, to); - printToLoc(boost::lexical_cast(rit->second), 168+76*i, curY+16, FONT_SMALL, zwykly, to); + int val = costs[i][j]; + if(!val) continue; + + blitAtLoc(resources->ourImages[j].bitmap, 104+76*i, curY, to); + printToLoc(boost::lexical_cast(val), 168+76*i, curY+16, FONT_SMALL, zwykly, to); curY += 20; } } @@ -6515,6 +6514,7 @@ std::string CHillFortWindow::getTextForSlot(int slot) int CHillFortWindow::getState(int slot) { + TResources myRes = LOCPLINT->cb->getResourceAmount(); if ( slot == slotsCount )//"Upgrade all" slot { bool allUpgraded = true;//All creatures are upgraded? @@ -6524,10 +6524,9 @@ int CHillFortWindow::getState(int slot) if (allUpgraded) return 1; - for ( int i=0; icb->getResourceAmount(i) < totalSumm[i]) - return 0; - + if(!totalSumm.canBeAfforded(myRes)) + return 0; + return 2; } @@ -6539,9 +6538,9 @@ int CHillFortWindow::getState(int slot) if (!info.newID.size())//already upgraded return 1; - for(std::set >::iterator it=info.cost[0].begin(); it!=info.cost[0].end(); it++) - if(LOCPLINT->cb->getResourceAmount(it->first) < it->second * hero->getStackCount(slot)) + if(!(info.cost[0] * hero->getStackCount(slot)).canBeAfforded(myRes)) return 0; + return 2;//can upgrade } diff --git a/client/GUIClasses.h b/client/GUIClasses.h index 8be5b93d1..4754c0b41 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -7,6 +7,7 @@ #include #include #include +#include "../lib/ResourceSet.h" #ifdef max #undef max @@ -1246,8 +1247,8 @@ public: const CGObjectInstance * fort; const CGHeroInstance * hero; std::vector currState;//current state of slot - to avoid calls to getState or updating buttons - std::vector > costs;// costs [slot ID] [resource ID] = resource count for upgrade - std::vector totalSumm; // totalSum[resource ID] = value + std::vector costs;// costs [slot ID] [resource ID] = resource count for upgrade + TResources totalSumm; // totalSum[resource ID] = value CHillFortWindow(const CGHeroInstance *visitor, const CGObjectInstance *object); //c-tor ~CHillFortWindow(); //d-tor diff --git a/client/VCMI_client.vcxproj b/client/VCMI_client.vcxproj index d557aee88..d263dac2e 100644 --- a/client/VCMI_client.vcxproj +++ b/client/VCMI_client.vcxproj @@ -183,7 +183,6 @@ - @@ -218,7 +217,6 @@ - diff --git a/global.h b/global.h index f33f77613..d217e4f68 100644 --- a/global.h +++ b/global.h @@ -349,14 +349,6 @@ namespace Buildings }; } -namespace Res -{ - enum ERes - { - WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL - }; -} - namespace Arts { enum EPos diff --git a/lib/CBuildingHandler.cpp b/lib/CBuildingHandler.cpp index 824f5616e..88c8bf0f8 100644 --- a/lib/CBuildingHandler.cpp +++ b/lib/CBuildingHandler.cpp @@ -38,7 +38,6 @@ static unsigned int readNr(std::string &in, int &it) static CBuilding * readBg(std::string &buf, int& it) { CBuilding * nb = new CBuilding(); - nb->resources.resize(RESOURCE_QUANTITY); for(int res=0;res<7;res++) nb->resources[res] = readNr(buf,it); /*nb->refName = */readTo(buf,it,'\n'); diff --git a/lib/CBuildingHandler.h b/lib/CBuildingHandler.h index b97ae0657..80a43148d 100644 --- a/lib/CBuildingHandler.h +++ b/lib/CBuildingHandler.h @@ -6,6 +6,7 @@ #include #include "../lib/ConstTransitivePtr.h" +#include "ResourceSet.h" /* * CBuildingHandler.h, part of VCMI engine @@ -22,7 +23,7 @@ class DLL_EXPORT CBuilding //a typical building encountered in every castle ;] { public: si32 tid, bid; //town ID and structure ID - std::vector resources; + TResources resources; std::string name; std::string description; diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 559f5c0b4..c6ec6d1e6 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -8,6 +8,7 @@ #include "../lib/HeroBonus.h" #include "../lib/ConstTransitivePtr.h" +#include "ResourceSet.h" /* * CCreatureHandler.h, part of VCMI engine @@ -28,7 +29,7 @@ class DLL_EXPORT CCreature : public CBonusSystemNode { public: std::string namePl, nameSing, nameRef; //name in singular and plural form; and reference name - std::vector cost; //cost[res_id] - amount of that resource + TResources cost; //cost[res_id] - amount of that resource std::set upgrades; // IDs of creatures to which this creature can be upgraded ui32 hitPoints, speed, attack, defence; ui32 fightValue, AIValue, growth, hordeGrowth, shots, spells; diff --git a/CGameInterface.cpp b/lib/CGameInterface.cpp similarity index 50% rename from CGameInterface.cpp rename to lib/CGameInterface.cpp index be05484cc..61fcb8305 100644 --- a/CGameInterface.cpp +++ b/lib/CGameInterface.cpp @@ -1,6 +1,6 @@ -#include "stdafx.h" +#define VCMI_DLL #include "CGameInterface.h" -#include "lib/BattleState.h" +#include "BattleState.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing @@ -102,3 +102,91 @@ BattleAction CGlobalAI::activeStack( const CStack * stack ) ba.stackNumber = stack->ID; return ba; } + +CGlobalAI::CGlobalAI() +{ + human = false; +} + +void CAdventureAI::battleNewRound(int round) +{ + battleAI->battleNewRound(round); +} + +void CAdventureAI::battleCatapultAttacked(const CatapultAttack & ca) +{ + battleAI->battleCatapultAttacked(ca); +} + +void CAdventureAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) +{ + assert(!battleAI); + battleAI = CDynLibHandler::getNewBattleAI(battleAIName); + battleAI->battleStart(army1, army2, tile, hero1, hero2, side); +} + +void CAdventureAI::battleStacksAttacked(const std::vector & bsa) +{ + battleAI->battleStacksAttacked(bsa); +} + +void CAdventureAI::actionStarted(const BattleAction *action) +{ + battleAI->actionStarted(action); +} + +void CAdventureAI::battleNewRoundFirst(int round) +{ + battleAI->battleNewRoundFirst(round); +} + +void CAdventureAI::actionFinished(const BattleAction *action) +{ + battleAI->actionFinished(action); +} + +void CAdventureAI::battleStacksEffectsSet(const SetStackEffect & sse) +{ + battleAI->battleStacksEffectsSet(sse); +} + +void CAdventureAI::battleStacksRemoved(const BattleStacksRemoved & bsr) +{ + battleAI->battleStacksRemoved(bsr); +} + +void CAdventureAI::battleObstaclesRemoved(const std::set & removedObstacles) +{ + battleAI->battleObstaclesRemoved(removedObstacles); +} + +void CAdventureAI::battleNewStackAppeared(const CStack * stack) +{ + battleAI->battleNewStackAppeared(stack); +} + +void CAdventureAI::battleStackMoved(const CStack * stack, THex dest, int distance, bool end) +{ + battleAI->battleStackMoved(stack, dest, distance, end); +} + +void CAdventureAI::battleAttack(const BattleAttack *ba) +{ + battleAI->battleAttack(ba); +} + +void CAdventureAI::battleSpellCast(const BattleSpellCast *sc) +{ + battleAI->battleSpellCast(sc); +} + +void CAdventureAI::battleEnd(const BattleResult *br) +{ + battleAI->battleEnd(br); + delNull(battleAI); +} + +void CAdventureAI::battleStacksHealedRes(const std::vector > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) +{ + battleAI->battleStacksHealedRes(healedStacks, lifeDrain, tentHeal, lifeDrainFrom); +} \ No newline at end of file diff --git a/CGameInterface.h b/lib/CGameInterface.h similarity index 65% rename from CGameInterface.h rename to lib/CGameInterface.h index 7dbfb27c0..ef66f2bef 100644 --- a/CGameInterface.h +++ b/lib/CGameInterface.h @@ -1,11 +1,10 @@ #ifndef __CGAMEINTERFACE_H__ #define __CGAMEINTERFACE_H__ -#include "global.h" +#include "../global.h" #include #include -#include "lib/BattleAction.h" -#include "client/FunctionList.h" -#include "lib/IGameEventsReceiver.h" +#include "BattleAction.h" +#include "IGameEventsReceiver.h" /* * CGameInterface.h, part of VCMI engine @@ -83,7 +82,7 @@ public: virtual void serialize(CISer &h, const int version){}; //loading }; -class CDynLibHandler +class DLL_EXPORT CDynLibHandler { public: static CGlobalAI * getNewAI(std::string dllname); @@ -91,10 +90,10 @@ public: static CScriptingModule * getNewScriptingModule(std::string dllname); }; -class CGlobalAI : public CGameInterface // AI class (to derivate) +class DLL_EXPORT CGlobalAI : public CGameInterface // AI class (to derivate) { public: - //CGlobalAI(); + CGlobalAI(); virtual void yourTurn() OVERRIDE{}; virtual void heroKilled(const CGHeroInstance*){}; virtual void heroCreated(const CGHeroInstance*) OVERRIDE{}; @@ -104,4 +103,34 @@ public: virtual BattleAction activeStack(const CStack * stack) OVERRIDE; }; +//class to be inherited by adventure-only AIs, it cedes battle actions to given battle-AI +class DLL_EXPORT CAdventureAI : public CGlobalAI +{ +public: + CAdventureAI() : battleAI(NULL) {}; + CAdventureAI(const std::string &BattleAIName) : battleAIName(BattleAIName), battleAI(NULL) {}; + + std::string battleAIName; + CBattleGameInterface *battleAI; + + //battle interface + virtual void battleNewRound(int round); + virtual void battleCatapultAttacked(const CatapultAttack & ca); + virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side); + virtual void battleStacksAttacked(const std::vector & bsa); + virtual void actionStarted(const BattleAction *action); + virtual void battleNewRoundFirst(int round); + virtual void actionFinished(const BattleAction *action); + virtual void battleStacksEffectsSet(const SetStackEffect & sse); + virtual void battleStacksRemoved(const BattleStacksRemoved & bsr); + virtual void battleObstaclesRemoved(const std::set & removedObstacles); + virtual void battleNewStackAppeared(const CStack * stack); + virtual void battleStackMoved(const CStack * stack, THex dest, int distance, bool end); + virtual void battleAttack(const BattleAttack *ba); + virtual void battleSpellCast(const BattleSpellCast *sc); + virtual void battleEnd(const BattleResult *br); + virtual void battleStacksHealedRes(const std::vector > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom); +}; + + #endif // __CGAMEINTERFACE_H__ diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index fbb17d018..d7871ac43 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1184,7 +1184,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) } /******************RESOURCES****************************************************/ - std::vector startresAI, startresHuman; + TResources startresAI, startresHuman; std::ifstream tis(DATA_DIR "/config/startres.txt"); int k; for (int j=0; jdifficulty * 2; j++) @@ -1195,32 +1195,22 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) } tis >> k; for (int i=0; i> k; - startresHuman.push_back(k); - } + tis >> startresHuman[i]; + tis >> k; for (int i=0; i> k; - startresAI.push_back(k); - } + tis >> startresAI[i]; + tis.close(); tis.clear(); for (std::map::iterator i = players.begin(); i!=players.end(); i++) { - (*i).second.resources.resize(RESOURCE_QUANTITY); - for (int x=0;xsecond.human) - { - (*i).second.resources[x] = startresHuman[x]; - } - else - { - (*i).second.resources[x] = startresAI[x]; - } - } + PlayerState &p = i->second; + + if (p.human) + p.resources = startresHuman; + else + p.resources = startresAI; } //give start resource bonus in case of campaign @@ -1231,7 +1221,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) if(chosenBonus.type == 7) //resource { std::vector people = HLP::getHumanPlayerInfo(scenarioOps); //players we will give resource bonus - for (int b=0; b res; //resources we will give switch (chosenBonus.info1) @@ -1240,10 +1230,10 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) res.push_back(chosenBonus.info1); break; case 0xFD: //wood+ore - res.push_back(0); res.push_back(2); + res.push_back(Res::WOOD); res.push_back(Res::ORE); break; case 0xFE: //rare - res.push_back(1); res.push_back(3); res.push_back(4); res.push_back(5); + res.push_back(Res::MERCURY); res.push_back(Res::SULFUR); res.push_back(Res::CRYSTAL); res.push_back(Res::GEMS); break; default: assert(0); @@ -1252,7 +1242,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) //increasing resource quantity for (int n=0; ncolor].resources[res[n]] += chosenBonus.info2; + players[ps->color].resources[res[n]] += chosenBonus.info2; } } } @@ -1393,15 +1383,15 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) switch(scenarioOps->playerInfos[k->first].bonus) { case PlayerSettings::bgold: - k->second.resources[6] += 500 + (ran()%6)*100; + k->second.resources[Res::GOLD] += 500 + (ran()%6)*100; break; case PlayerSettings::bresource: { int res = VLC->townh->towns[scenarioOps->playerInfos[k->first].castle].primaryRes; if(res == 127) { - k->second.resources[0] += 5 + ran()%6; - k->second.resources[2] += 5 + ran()%6; + k->second.resources[Res::WOOD] += 5 + ran()%6; + k->second.resources[Res::ORE] += 5 + ran()%6; } else { @@ -1682,10 +1672,10 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack) BOOST_FOREACH(const Bonus *it, *lista) { ui16 nid = it->additionalInfo; - if (nid != base->idNumber) //in very specific case the upgrade is avaliable by default (?) + if (nid != base->idNumber) //in very specific case the upgrade is available by default (?) { ret.newID.push_back(nid); - ret.cost.push_back(costDiff(VLC->creh->creatures[nid]->cost, base->cost)); + ret.cost.push_back(VLC->creh->creatures[nid]->cost - base->cost); } } t = h->visitedTown; @@ -1700,7 +1690,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack) if(vstd::contains(base->upgrades, nid)) //possible upgrade { ret.newID.push_back(nid); - ret.cost.push_back(costDiff(VLC->creh->creatures[nid]->cost, base->cost)); + ret.cost.push_back(VLC->creh->creatures[nid]->cost - base->cost); } } } @@ -1715,7 +1705,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack) BOOST_FOREACH(si32 nid, base->upgrades) { ret.newID.push_back(nid); - ret.cost.push_back(costDiff(VLC->creh->creatures[nid]->cost, base->cost, costModifier)); + ret.cost.push_back((VLC->creh->creatures[nid]->cost - base->cost) * costModifier / 100); } } @@ -2619,15 +2609,15 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) } if(level >= 2) //gold { - FILL_FIELD(gold, g->second.resources[6]) + FILL_FIELD(gold, g->second.resources[Res::GOLD]) } if(level >= 2) //wood & ore { - FILL_FIELD(woodOre, g->second.resources[0] + g->second.resources[1]) + FILL_FIELD(woodOre, g->second.resources[Res::WOOD] + g->second.resources[Res::ORE]) } if(level >= 3) //mercury, sulfur, crystal, gems { - FILL_FIELD(mercSulfCrystGems, g->second.resources[2] + g->second.resources[3] + g->second.resources[4] + g->second.resources[5]) + FILL_FIELD(mercSulfCrystGems, g->second.resources[Res::MERCURY] + g->second.resources[Res::SULFUR] + g->second.resources[Res::CRYSTAL] + g->second.resources[Res::GEMS]) } if(level >= 4) //obelisks found { diff --git a/lib/CGameState.h b/lib/CGameState.h index dbe5b9055..0a6124ac5 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -23,6 +23,7 @@ #include "ConstTransitivePtr.h" #include "IGameCallback.h" +#include "ResourceSet.h" /* @@ -161,7 +162,7 @@ public: ui8 human; //true if human controlled player, false for AI ui32 currentSelection; //id of hero/town, 0xffffffff if none ui8 team; - std::vector resources; + TResources resources; std::vector > heroes; std::vector > towns; std::vector > availableHeroes; //heroes available in taverns @@ -209,7 +210,7 @@ struct UpgradeInfo { int oldID; //creature to be upgraded std::vector newID; //possible upgrades - std::vector > > cost; // cost[upgrade_serial] -> set of pairs + std::vector cost; // cost[upgrade_serial] -> set of pairs; cost is for single unit (not entire stack) UpgradeInfo(){oldID = -1;}; }; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index fd23c3c13..926aa8e1c 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -848,11 +848,8 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID ) return Buildings::ERROR; //checking resources - for(int res=0; resresources[res] > getResource(t->tempOwner, res)) - ret = Buildings::NO_RESOURCES; //lack of res - } + if(pom->resources.canBeAfforded(getPlayer(t->tempOwner)->resources)) + ret = Buildings::NO_RESOURCES; //lack of res //checking for requirements std::set reqs = getBuildingRequiments(t, ID);//getting all requirements @@ -1122,10 +1119,10 @@ int CPlayerSpecificInfoCallback::getResourceAmount(int type) const return getResource(player, type); } -std::vector CPlayerSpecificInfoCallback::getResourceAmount() const +TResources CPlayerSpecificInfoCallback::getResourceAmount() const { //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(player == -1, "Applicable only for player callbacks", std::vector()); + ERROR_RET_VAL_IF(player == -1, "Applicable only for player callbacks", TResources()); return gs->players[player].resources; } @@ -1214,7 +1211,7 @@ const CGObjectInstance * IGameCallback::putNewObject(int ID, int subID, int3 pos no.subID= subID; no.pos = pos; commitPackage(&no); - return getObj(no.id); //id field will be filled during applaying on gs + return getObj(no.id); //id field will be filled during applying on gs } const CGCreature * IGameCallback::putNewMonster(int creID, int count, int3 pos) diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 2c70c5346..258a6ad38 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -6,6 +6,7 @@ #include #include "../client/FunctionList.h" #include "CObstacleInstance.h" +#include "ResourceSet.h" /* * IGameCallback.h, part of VCMI engine @@ -213,7 +214,7 @@ public: std::vector getMyObjects() const; //returns all objects flagged by belonging player int getResourceAmount(int type)const; - std::vector getResourceAmount() const; + TResources getResourceAmount() const; const std::vector< std::vector< std::vector > > & getVisibilityMap()const; //returns visibility map const PlayerSettings * getPlayerSettings(int color) const; }; diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 323552539..14fe8987d 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -10,6 +10,7 @@ #include "../StartInfo.h" #include "ConstTransitivePtr.h" #include "../int3.h" +#include "ResourceSet.h" /* * NetPacks.h, part of VCMI engine @@ -238,12 +239,12 @@ struct SetResource : public CPackForClient //102 }; struct SetResources : public CPackForClient //104 { - SetResources(){res.resize(RESOURCE_QUANTITY);type = 104;}; + SetResources(){type = 104;}; void applyCl(CClient *cl); DLL_EXPORT void applyGs(CGameState *gs); ui8 player; - std::vector res; //res[resid] => res amount + TResources res; //res[resid] => res amount template void serialize(Handler &h, const int version) { @@ -965,7 +966,7 @@ struct NewTurn : public CPackForClient //101 std::set heroes; //updates movement and mana points //std::vector res;//resource list - std::map > res; //player ID => resource value[res_id] + std::map res; //player ID => resource value[res_id] std::vector cres;//creatures to be placed in towns ui32 day; bool resetBuilded; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index bf287be3a..bf62969e1 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -45,12 +45,11 @@ DLL_EXPORT void SetResource::applyGs( CGameState *gs ) gs->getPlayer(player)->resources[resid] = val; } - DLL_EXPORT void SetResources::applyGs( CGameState *gs ) - { - assert(player < PLAYER_LIMIT); - for(int i=0;igetPlayer(player)->resources[i] = res[i]; - } +DLL_EXPORT void SetResources::applyGs( CGameState *gs ) +{ + assert(player < PLAYER_LIMIT); + gs->getPlayer(player)->resources = res; +} DLL_EXPORT void SetPrimSkill::applyGs( CGameState *gs ) { @@ -751,12 +750,10 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) hero->mana = h.mana; } - for(std::map >::iterator i = res.begin(); i != res.end(); i++) + for(std::map::iterator i = res.begin(); i != res.end(); i++) { assert(i->first < PLAYER_LIMIT); - std::vector &playerRes = gs->getPlayer(i->first)->resources; - for(int j = 0; j < i->second.size(); j++) - playerRes[j] = i->second[j]; + gs->getPlayer(i->first)->resources = i->second; } BOOST_FOREACH(SetAvailableCreatures h, cres) //set available creatures in towns diff --git a/lib/ResourceSet.cpp b/lib/ResourceSet.cpp new file mode 100644 index 000000000..b5cb6edc5 --- /dev/null +++ b/lib/ResourceSet.cpp @@ -0,0 +1,91 @@ +#define VCMI_DLL +#include "ResourceSet.h" + +Res::ResourceSet::ResourceSet() +{ + resize(RESOURCE_QUANTITY, 0); +} + +bool Res::ResourceSet::nonZero() const +{ + for(int i = 0; i < size(); i++) + if(at(i)) + return true; + + return false; +} + +void Res::ResourceSet::amax(const TResource &val) +{ + for(int i = 0; i < size(); i++) + ::amax(at(i), val); +} + +bool Res::ResourceSet::canBeAfforded(const ResourceSet &res) const +{ + return Res::canAfford(res, *this); +} + +bool Res::ResourceSet::canAfford(const ResourceSet &price) const +{ + return Res::canAfford(*this, price); +} + +bool Res::canAfford(const ResourceSet &res, const ResourceSet &price) +{ + assert(res.size() == price.size() && price.size() == RESOURCE_QUANTITY); + for(int i = 0; i < RESOURCE_QUANTITY; i++) + if(price[i] > res[i]) + return false; + + return true; +} + +bool Res::ResourceSet::nziterator::valid() +{ + return cur.resType < RESOURCE_QUANTITY && cur.resVal; +} + +Res::ResourceSet::nziterator Res::ResourceSet::nziterator::operator++() +{ + advance(); + return *this; +} + +Res::ResourceSet::nziterator Res::ResourceSet::nziterator::operator++(int) +{ + nziterator ret = *this; + advance(); + return ret; +} + +const Res::ResourceSet::nziterator::ResEntry& Res::ResourceSet::nziterator::operator*() const +{ + return cur; +} + +const Res::ResourceSet::nziterator::ResEntry * Res::ResourceSet::nziterator::operator->() const +{ + return &cur; +} + +void Res::ResourceSet::nziterator::advance() +{ + do + { + cur.resType++; + } while(cur.resType < RESOURCE_QUANTITY && !(cur.resVal=rs[cur.resType])); + + if(cur.resType >= RESOURCE_QUANTITY) + cur.resVal = -1; +} + +Res::ResourceSet::nziterator::nziterator(const ResourceSet &RS) + : rs(RS) +{ + cur.resType = 0; + cur.resVal = rs[0]; + + if(!valid()) + advance(); +} \ No newline at end of file diff --git a/lib/ResourceSet.h b/lib/ResourceSet.h new file mode 100644 index 000000000..057769428 --- /dev/null +++ b/lib/ResourceSet.h @@ -0,0 +1,123 @@ +#pragma once + +#include"../global.h" + +typedef si32 TResource; + +namespace Res +{ + class ResourceSet; + bool canAfford(const ResourceSet &res, const ResourceSet &price); //can a be used to pay price b + + enum ERes + { + WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL + }; + + //class to be representing a vector of resource + class ResourceSet : public std::vector + { + public: + DLL_EXPORT ResourceSet(); + + +#define scalarOperator(OPSIGN) \ + DLL_EXPORT ResourceSet operator OPSIGN(const TResource &rhs) const \ + { \ + ResourceSet ret = *this; \ + for(int i = 0; i < size(); i++) \ + ret[i] = at(i) OPSIGN rhs; \ + \ + return ret; \ + } + + + +#define vectorOperator(OPSIGN) \ + DLL_EXPORT ResourceSet operator OPSIGN(const ResourceSet &rhs) const \ + { \ + ResourceSet ret = *this; \ + for(int i = 0; i < size(); i++) \ + ret[i] = at(i) OPSIGN rhs[i]; \ + \ + return ret; \ + } + + +#define opEqOperator(OPSIGN, RHS_TYPE) \ + DLL_EXPORT ResourceSet& operator OPSIGN ## =(const RHS_TYPE &rhs) \ + { \ + return *this = *this OPSIGN rhs; \ + } + + scalarOperator(+) + scalarOperator(-) + scalarOperator(*) + scalarOperator(/) + opEqOperator(+, TResource) + opEqOperator(-, TResource) + opEqOperator(*, TResource) + vectorOperator(+) + vectorOperator(-) + opEqOperator(+, ResourceSet) + opEqOperator(-, ResourceSet) + +#undef scalarOperator +#undef vectorOperator +#undef opEqOperator + + //to be used for calculations of type "how many units of sth can I afford?" + DLL_EXPORT int operator/(const ResourceSet &rhs) + { + int ret = INT_MAX; + for(int i = 0; i < size(); i++) + amin(ret, at(i) / rhs[i]); + + return ret; + } + + // WARNING: comparison operators are used for "can afford" relation: a <= b means that foreach i a[i] <= b[i] + // that doesn't work the other way: a > b doesn't mean that a cannot be afforded with b, it's still b can afford a +// bool operator<(const ResourceSet &rhs) +// { +// for(int i = 0; i < size(); i++) +// if(at(i) >= rhs[i]) +// return false; +// +// return true; +// } + + template void serialize(Handler &h, const int version) + { + h & static_cast&>(*this); + } + + DLL_EXPORT void amax(const TResource &val); //performs amax on each element + DLL_EXPORT bool nonZero() const; //returns true if at least one value is non-zero; + DLL_EXPORT bool canAfford(const ResourceSet &price) const; + DLL_EXPORT bool canBeAfforded(const ResourceSet &res) const; + + //special iterator of iterating over non-zero resources in set + class DLL_EXPORT nziterator + { + struct ResEntry + { + TResource resType, resVal; + } cur; + const ResourceSet &rs; + void advance(); + + public: + nziterator(const ResourceSet &RS); + bool valid(); + nziterator operator++(); + nziterator operator++(int); + const ResEntry& operator*() const; + const ResEntry* operator->() const; + + }; + }; +} + +typedef Res::ResourceSet TResources; + diff --git a/lib/VCMI_lib.vcxproj b/lib/VCMI_lib.vcxproj index 1f79fc243..02e30984f 100644 --- a/lib/VCMI_lib.vcxproj +++ b/lib/VCMI_lib.vcxproj @@ -173,6 +173,7 @@ + @@ -188,6 +189,7 @@ + @@ -203,6 +205,7 @@ + @@ -223,6 +226,7 @@ + diff --git a/lib/map.cpp b/lib/map.cpp index e6a388d16..bf04074c0 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -724,7 +724,6 @@ void Mapa::loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int nce->town = nt; nce->name = readString(bufor,i); nce->message = readString(bufor,i); - nce->resources.resize(RESOURCE_QUANTITY); for(int x=0; x < 7; x++) { nce->resources[x] = readNormalNr(bufor,i); @@ -1885,7 +1884,6 @@ void Mapa::readEvents( const unsigned char * bufor, int &i ) { ne->message +=bufor[i]; ++i; } - ne->resources.resize(RESOURCE_QUANTITY); for(int k=0; k < 7; k++) { ne->resources[k] = readNormalNr(bufor,i); i+=4; diff --git a/lib/map.h b/lib/map.h index a484b4ec4..e730a133f 100644 --- a/lib/map.h +++ b/lib/map.h @@ -15,6 +15,7 @@ #endif #include "ConstTransitivePtr.h" +#include "ResourceSet.h" /* * map.h, part of VCMI engine @@ -211,7 +212,7 @@ class DLL_EXPORT CMapEvent { public: std::string name, message; - std::vector resources; //gained / taken resources + TResources resources; //gained / taken resources ui8 players; //affected players ui8 humanAffected; ui8 computerAffected; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index e029a1d8c..b658a1491 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -924,11 +924,7 @@ void CGameHandler::newTurn() } n.res[i->first] = i->second.resources; -// SetResources r; -// r.player = i->first; -// for(int j=0;jsecond.resources[j]; - + BOOST_FOREACH(CGHeroInstance *h, (*i).second.heroes) { if(h->visitedTown) @@ -955,7 +951,6 @@ void CGameHandler::newTurn() } } } - //n.res.push_back(r); } // townID, creatureID, amount std::map > newCreas;//creatures that needs to be added by town events @@ -987,7 +982,7 @@ void CGameHandler::newTurn() n.res[player][(**j).town->primaryRes] ++;; } } - n.res[player][6] += (**j).dailyIncome(); + n.res[player][Res::GOLD] += (**j).dailyIncome(); } handleTownEvents(*j, n, newCreas); if (vstd::contains((**j).builtBuildings, 26)) @@ -2211,9 +2206,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ ) { SetResources sr; sr.player = t->tempOwner; - sr.res = gs->getPlayer(t->tempOwner)->resources; - for(int i=0;iresources.size();i++) - sr.res[i]-=b->resources[i]; + sr.res = gs->getPlayer(t->tempOwner)->resources - b->resources; sendAndApply(&sr); } @@ -2315,8 +2308,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram, si32 from //recruit SetResources sr; sr.player = dst->tempOwner; - for(int i=0;igetPlayer(dst->tempOwner)->resources[i] - (c->cost[i] * cram); + sr.res = gs->getPlayer(dst->tempOwner)->resources - (c->cost * cram); SetAvailableCreatures sac; sac.tid = objid; @@ -2361,8 +2353,10 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) assert(obj->hasStackAtSlot(pos)); UpgradeInfo ui = gs->getUpgradeInfo(obj->getStack(pos)); int player = obj->tempOwner; + const PlayerState *p = getPlayer(player); int crQuantity = obj->stacks[pos]->count; int newIDpos= vstd::findPos(ui.newID, upgID);//get position of new id in UpgradeInfo + TResources totalCost = ui.cost[newIDpos] * crQuantity; //check if upgrade is possible if( (ui.oldID<0 || newIDpos == -1 ) && complain("That upgrade is not possible!")) @@ -2372,24 +2366,14 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) //check if player has enough resources - for (std::set >::iterator j=ui.cost[newIDpos].begin(); j!=ui.cost[newIDpos].end(); j++) - { - if(gs->getPlayer(player)->resources[j->first] < j->second*crQuantity) - { - complain("Cannot upgrade, not enough resources!"); - return false; - } - } + if(!p->resources.canAfford(totalCost)) + COMPLAIN_RET("Cannot upgrade, not enough resources!"); //take resources - for (std::set >::iterator j=ui.cost[newIDpos].begin(); j!=ui.cost[newIDpos].end(); j++) - { - SetResource sr; - sr.player = player; - sr.resid = j->first; - sr.val = gs->getPlayer(player)->resources[j->first] - j->second*crQuantity; - sendAndApply(&sr); - } + SetResources sr; + sr.player = player; + sr.res = p->resources - totalCost; + sendAndApply(&sr); //upgrade creature changeStackType(StackLocation(obj, pos), VLC->creh->creatures[upgID]); @@ -2854,8 +2838,8 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player) const PlayerState *p = gs->getPlayer(player); const CGTownInstance *t = gs->getTown(obj->id); - //common prconditions - if( p->resources[6]<2500 && complain("Not enough gold for buying hero!") + //common preconditions + if( p->resources[Res::GOLD]<2500 && complain("Not enough gold for buying hero!") || getHeroCount(player, false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!")) return false; @@ -2905,8 +2889,8 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player) SetResource sr; sr.player = player; - sr.resid = 6; - sr.val = p->resources[6] - 2500; + sr.resid = Res::GOLD; + sr.val = p->resources[Res::GOLD] - 2500; sendAndApply(&sr); if(t) @@ -3775,30 +3759,22 @@ void CGameHandler::handleTimeEvents() //give resources SetResources sr; sr.player = player; - sr.res = pinfo->resources; + sr.res = pinfo->resources + ev->resources; //prepare dialog InfoWindow iw; iw.player = player; iw.text << ev->message; + for (int i=0; iresources.size(); i++) { if(ev->resources[i]) //if resource is changed, we add it to the dialog - { - // If removing too much resources, adjust the - // amount so the total doesn't become negative. - if (sr.res[i] + ev->resources[i] < 0) - ev->resources[i] = -sr.res[i]; - - if(ev->resources[i]) //if non-zero res change - { - iw.components.push_back(Component(Component::RESOURCE,i,ev->resources[i],0)); - sr.res[i] += ev->resources[i]; - } - } + iw.components.push_back(Component(Component::RESOURCE,i,ev->resources[i],0)); } + if (iw.components.size()) { + sr.res.amax(0); // If removing too much resources, adjust the amount so the total doesn't become negative. sendAndApply(&sr); //update player resources if changed } @@ -3839,21 +3815,24 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n, std::map< || (ev->humanAffected && pinfo->human) ) ) { + // dialog InfoWindow iw; iw.player = player; iw.text << ev->message; - for (int i=0; iresources.size(); i++) - if(ev->resources[i]) //if resource had changed, we add it to the dialog - { - int was = n.res[player][i]; - n.res[player][i] += ev->resources[i]; - n.res[player][i] = std::max(n.res[player][i], 0); + if(ev->resources.nonZero()) + { + TResources was = n.res[player]; + n.res[player] += ev->resources; + n.res[player].amax(0); + + for (int i=0; iresources.size(); i++) + if(ev->resources[i] && pinfo->resources[i] != n.res[player][i]) //if resource had changed, we add it to the dialog + iw.components.push_back(Component(Component::RESOURCE,i,n.res[player][i]-was[i],0)); + + } - if(pinfo->resources[i] != n.res[player][i]) //if non-zero res change - iw.components.push_back(Component(Component::RESOURCE,i,n.res[player][i]-was,0)); - } for(std::set::iterator i = ev->buildings.begin(); i!=ev->buildings.end();i++) if ( !vstd::contains(town->builtBuildings, *i)) { @@ -4018,8 +3997,8 @@ bool CGameHandler::buildBoat( ui32 objid ) SetResources sr; sr.player = obj->o->tempOwner; sr.res = gs->getPlayer(obj->o->tempOwner)->resources; - sr.res[0] -= 10; - sr.res[6] -= 1000; + sr.res[Res::WOOD] -= 10; + sr.res[Res::GOLD] -= 1000; sendAndApply(&sr); //create boat