diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index fb217e52c..0672198ce 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -405,6 +405,9 @@ void CGObjectInstance::setProperty( ui8 what, ui32 val ) case ObjProperty::ID: ID = val; break; + case ObjProperty::SUBID: + subID = val; + break; } setPropertyDer(what, val); } @@ -2606,11 +2609,11 @@ const std::string & CGVisitableOPH::getHoverText() const } hoverName = VLC->generaltexth->names[ID]; if(pom >= 0) - hoverName += (" " + VLC->generaltexth->xtrainfo[pom]); + hoverName += ("\n" + VLC->generaltexth->xtrainfo[pom]); const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); if(h) { - hoverName += ' '; + hoverName += "\n\n"; hoverName += (vstd::contains(visitors,h->id)) ? (VLC->generaltexth->allTexts[352]) //visited : ( VLC->generaltexth->allTexts[353]); //not visited @@ -3061,34 +3064,25 @@ void CGCreature::flee( const CGHeroInstance * h ) const void CGMine::onHeroVisit( const CGHeroInstance * h ) const { - if(subID == 7) //TODO: support for abandoned mine - return; - if(h->tempOwner == tempOwner) //we're visiting our mine { cb->showGarrisonDialog(id,h->id,true,0); return; } + if(subID >= 7) //Abandoned mine + { + BlockingDialog ynd(true,false); + ynd.player = h->tempOwner; + ynd.text << std::pair(MetaString::ADVOB_TXT, 84); + cb->showBlockingDialog(&ynd,boost::bind(&CGMine::fight, this, _1, h)); + return; + } + //TODO: check if mine is guarded - cb->setOwner(id,h->tempOwner); //not ours? flag it! - MetaString ms; - ms << std::pair(9,subID) << " (" << std::pair(6,23+h->tempOwner) << ")"; - cb->setHoverName(id,&ms); + flagMine(h->tempOwner); - int vv=1; //amount of resource per turn - if (subID==0 || subID==2) - vv++; - else if (subID==6) - vv = 1000; - - InfoWindow iw; - iw.soundID = soundBase::FLAGMINE; - iw.text << std::pair(10,subID); - iw.player = h->tempOwner; - iw.components.push_back(Component(2,subID,vv,-1)); - cb->showInfoDialog(&iw); } void CGMine::newTurn() const @@ -3108,13 +3102,95 @@ void CGMine::newTurn() const void CGMine::initObj() { - MetaString ms; - ms << std::pair(9,subID); - if(tempOwner >= PLAYER_LIMIT) - tempOwner = NEUTRAL_PLAYER; + if(subID >= 7) //Abandoned Mine + { + //set guardians + int howManyTroglodytes = 100 + ran()%100; + CStackInstance troglodytes(70, howManyTroglodytes); + addStack(0, troglodytes); + + //after map reading tempOwner placeholds bitmask for allowed resources + std::vector possibleResources; + for (int i = 0; i < 8; i++) + if(tempOwner & 1<generaltexth->mines[7].first + "\n" + VLC->generaltexth->allTexts[202] + " " + troglodytes.getQuantityTXT(false) + " " + troglodytes.type->namePl; + } else - ms << " (" << std::pair(6,23+tempOwner) << ")"; - ms.toString(hoverName); + { + producedResource = subID; + + MetaString ms; + ms << std::pair(9,producedResource); + if(tempOwner >= PLAYER_LIMIT) + tempOwner = NEUTRAL_PLAYER; + else + ms << " (" << std::pair(6,23+tempOwner) << ")"; + ms.toString(hoverName); + } + + producedQuantity = defaultResProduction(); +} + +void CGMine::fight(ui32 agreed, const CGHeroInstance *h) const +{ + cb->startBattleI(h, this, boost::bind(&CGMine::endBattle, this, _1, h->tempOwner)); +} + +void CGMine::endBattle(BattleResult *result, ui8 attackingPlayer) const +{ + if(result->winner == 0) //attacker won + { + if(subID == 7) + { + InfoWindow iw; + iw.player = attackingPlayer; + iw.text.addTxt(MetaString::ADVOB_TXT, 85); + cb->showInfoDialog(&iw); + + } + flagMine(attackingPlayer); + } +} + +void CGMine::flagMine(ui8 player) const +{ + assert(tempOwner != player); + cb->setOwner(id,player); //not ours? flag it! + + MetaString ms; + ms << std::pair(9,subID) << "\n(" << std::pair(6,23+player) << ")"; + if(subID == 7) + { + ms << "(%s)"; + ms.addReplacement(MetaString::RES_NAMES, producedResource); + } + cb->setHoverName(id,&ms); + + InfoWindow iw; + iw.soundID = soundBase::FLAGMINE; + iw.text.addTxt(MetaString::MINE_EVNTS,producedResource); //not use subID, abandoned mines uses default mine texts + iw.player = player; + iw.components.push_back(Component(2,producedResource,producedQuantity,-1)); + cb->showInfoDialog(&iw); +} + +ui32 CGMine::defaultResProduction() +{ + switch(producedResource) + { + case 0: //wood + case 2: //ore + return 2; + case 6: //gold + return 1000; + default: + return 1; + } } void CGResource::initObj() diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index 48090bfaa..dadf07032 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -818,14 +818,24 @@ public: class DLL_EXPORT CGMine : public CArmedInstance { public: + ui8 producedResource; + ui32 producedQuantity; + void offerLeavingGuards(const CGHeroInstance *h) const; + void endBattle(BattleResult *result, ui8 attackingPlayer) const; + void fight(ui32 agreed, const CGHeroInstance *h) const; + void onHeroVisit(const CGHeroInstance * h) const; + + void flagMine(ui8 player) const; void newTurn() const; void initObj(); template void serialize(Handler &h, const int version) { h & static_cast(*this); + h & producedResource & producedQuantity; } + ui32 defaultResProduction(); }; class DLL_EXPORT CGVisitableOPW : public CGObjectInstance //objects visitable OPW diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index fcd8a2c98..b866096c2 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -285,4 +285,9 @@ ui32 CStackInstance::getMinDamage() const ui32 CStackInstance::getMaxDamage() const { return type->damageMax + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 2); +} + +std::string CStackInstance::getQuantityTXT(bool capitalized /*= true*/) const +{ + return VLC->generaltexth->arraytxt[174 + getQuantityID()*3 + 2 - capitalized]; } \ No newline at end of file diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index e90353695..d0485b299 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -40,6 +40,7 @@ public: void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const; //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker int getQuantityID() const; + std::string getQuantityTXT(bool capitalized = true) const; void init(); CStackInstance(); CStackInstance(TCreature id, TQuantity count, const CArmedInstance *ArmyObj = NULL); diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 89d656c01..2f6f79170 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1668,6 +1668,11 @@ int CGameState::battleGetBattlefieldType(int3 tile) else if(tile==int3() && !curB) return -1; + const TerrainTile &t = map->getTile(tile); + //fight in mine -> subterranean + if(const CGMine *mine = dynamic_cast(t.visitableObjects.front())) + return 12; + const std::vector & objs = map->objects; for(int g=0; gterrain[tile.x][tile.y][tile.z].tertype) + switch(t.tertype) { case TerrainTile::dirt: return rand()%3+3; diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index af691dbc3..097733ff2 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -84,13 +84,22 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector, void BonusList::limit(const CBonusSystemNode &node) { +limit_start: for(iterator i = begin(); i != end(); i++) { if(i->limiter && i->limiter->limit(*i, node)) { iterator toErase = i; - i--; - erase(toErase); + if(i != begin()) + { + i--; + erase(toErase); + } + else + { + erase(toErase); + goto limit_start; + } } } } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 5be7f6a70..c72426e55 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -747,7 +747,7 @@ struct InfoWindow : public CPackForClient //103 - displays simple info window namespace ObjProperty { //TODO: move non general properties out to the appropriate objs classes - enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7}; + enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8}; } struct SetObjectProperty : public CPackForClient//1001 diff --git a/lib/map.cpp b/lib/map.cpp index 1684bbd4e..1e4e4ab5d 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -1653,6 +1653,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) break; } case 53: + case 220://mine (?) { nobj = new CGMine(); nobj->setOwner(bufor[i++]); @@ -1672,13 +1673,6 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) nobj = new CGDwelling(); break; } - case 220://mine (?) - { - nobj = new CGObjectInstance(); - nobj->setOwner(bufor[i++]); - i+=3; - break; - } case 88: case 89: case 90: //spell shrine { CGShrine * shr = new CGShrine();