From ab20e024c0ee86a860d4f957539e5aea203919f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Fri, 11 Feb 2011 12:27:38 +0000 Subject: [PATCH] Various fixes and improvements around kill hero and kill monster quests. A few minor unrelated fixes. --- client/CBattleInterface.cpp | 6 ++ lib/BattleState.cpp | 2 +- lib/CCreatureHandler.cpp | 1 + lib/CGameState.cpp | 2 +- lib/CObjectHandler.cpp | 167 ++++++++++++++++++++---------------- lib/CObjectHandler.h | 16 +++- lib/IGameCallback.cpp | 6 ++ lib/IGameCallback.h | 1 + lib/NetPacksLib.cpp | 20 ++--- lib/map.cpp | 15 ++-- lib/map.h | 11 +-- server/CGameHandler.cpp | 2 +- 12 files changed, 149 insertions(+), 100 deletions(-) diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index 45bdb51a5..5efaf796a 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -2386,6 +2386,12 @@ void CBattleInterface::hexLclicked(int whichOne) { const CStack * actSt = activeStack; const CStack* dest = curInt->cb->battleGetStackByPos(whichOne); //creature at destination tile; -1 if there is no one + if(!actSt) + { + tlog3 << "Hex l-clicked when no active stack!\n"; + return; + } + if( ((whichOne%BFIELD_WIDTH)!=0 && (whichOne%BFIELD_WIDTH)!=(BFIELD_WIDTH-1)) //if player is trying to attack enemey unit or move creature stack || (actSt->hasBonusOfType(Bonus::CATAPULT) && !spellDestSelectMode || dest ) //enemy's first aid tent can stand there and we want to shoot it ) diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 2959e452a..91dcf3a44 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -850,7 +850,7 @@ ui32 BattleInfo::calculateSpellBonus(ui32 baseDamage, const CSpell * sp, const C else if(sp->earth) ret *= (100.0f + caster->valOfBonuses(Bonus::EARTH_SPELL_DMG_PREMY)) / 100.0f; - if (affectedCreature) //Hero specials like Solmyr, Deemer + if (affectedCreature && affectedCreature->getCreature()->level) //Hero specials like Solmyr, Deemer ret *= (100.f + ((caster->valOfBonuses(Bonus::SPECIAL_SPELL_LEV, sp->id) * caster->level) / affectedCreature->getCreature()->level)) / 100.0f; } return ret; diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 49db1f42d..6c4ab3496 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -486,6 +486,7 @@ void CCreatureHandler::loadCreatures() if(!ifs.good()) break; CCreature *c = creatures[id]; + c->level = lvl; if(isbetw(lvl, 0, ARRAY_COUNT(creaturesOfLevel))) c->attachTo(&creaturesOfLevel[lvl]); else diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 85d2071e2..9befa1366 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -337,7 +337,7 @@ void MetaString::addReplacement(const CStackBasicDescriptor &stack) { assert(stack.count); //valid count assert(stack.type); //valid type - addReplacement(stack.type->idNumber, stack.count); + addCreReplacement(stack.type->idNumber, stack.count); } static CGObjectInstance * createObject(int id, int subid, int3 pos, int owner) diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index 366585cc5..fd49d9989 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -1116,6 +1116,7 @@ void CGHeroInstance::initObj() UpdateSpeciality(); mana = manaLimit(); //after all bonuses are taken into account, make sure this line is the last one + type->name = name; } void CGHeroInstance::UpdateSpeciality() { @@ -3871,12 +3872,10 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const { case MISSION_NONE: return true; - break; case MISSION_LEVEL: if (m13489val <= h->level) return true; return false; - break; case MISSION_PRIMARY_STAT: for (int i = 0; i < 4; ++i) { @@ -3884,17 +3883,11 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const return false; } return true; - break; case MISSION_KILL_HERO: - if (h->cb->gameState()->map->heroesToBeat[m13489val]->tempOwner < PLAYER_LIMIT) - return false; //if the pointer is not NULL - return true; - break; case MISSION_KILL_CREATURE: - if (h->cb->gameState()->map->monsters[m13489val]->pos == int3(-1,-1,-1)) + if (!h->cb->getObjByQuestIdentifier(m13489val)) return true; return false; - break; case MISSION_ART: for (int i = 0; i < m5arts.size(); ++i) { @@ -3903,7 +3896,6 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const return false; //if the artifact was not found } return true; - break; case MISSION_ARMY: { std::vector::const_iterator cre; @@ -3921,7 +3913,6 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const } } return true; - break; case MISSION_RESOURCES: for (int i = 0; i < 7; ++i) //including Mithril ? { //Quest has no direct access to callback @@ -3929,17 +3920,14 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const return false; } return true; - break; case MISSION_HERO: if (m13489val == h->type->ID) return true; return false; - break; case MISSION_PLAYER: if (m13489val == h->getOwner()) return true; return false; - break; default: return false; } @@ -3958,6 +3946,17 @@ void CGSeerHut::initObj() nextVisitText = VLC->generaltexth->quests[missionType-1][1][textOption]; completedText = VLC->generaltexth->quests[missionType-1][2][textOption]; } + + if(missionType == MISSION_KILL_CREATURE) + { + stackToKill = getCreatureToKill(false)->getStack(0); + stackDirection = checkDirection(); + } + else if(missionType == MISSION_KILL_HERO) + { + heroName = getHeroToKill(false)->name; + heroPortrait = getHeroToKill(false)->portrait; + } } else firstVisitText = VLC->generaltexth->seerEmpty[textOption]; @@ -3989,30 +3988,25 @@ const std::string & CGSeerHut::getHoverText() const ms.addReplacement(m13489val); break; case MISSION_PRIMARY_STAT: - { - MetaString loot; - for (int i = 0; i < 4; ++i) { - if (m2stats[i]) + MetaString loot; + for (int i = 0; i < 4; ++i) { - loot << "%d %s"; - loot.addReplacement(m2stats[i]); - loot.addReplacement(VLC->generaltexth->primarySkillNames[i]); - } + if (m2stats[i]) + { + loot << "%d %s"; + loot.addReplacement(m2stats[i]); + loot.addReplacement(VLC->generaltexth->primarySkillNames[i]); + } + } + ms.addReplacement(loot.buildList()); } - ms.addReplacement(loot.buildList()); - } break; case MISSION_KILL_HERO: - ms.addReplacement(cb->gameState()->map->heroesToBeat[m13489val]->name); - break; - case MISSION_HERO: - ms.addReplacement(VLC->heroh->heroes[m13489val]->name); + ms.addReplacement(heroName); break; case MISSION_KILL_CREATURE: - { - ms.addReplacement(cb->gameState()->map->monsters[m13489val]->getStack(0)); - } + ms.addReplacement(stackToKill); break; case MISSION_ART: { @@ -4051,6 +4045,9 @@ const std::string & CGSeerHut::getHoverText() const ms.addReplacement(loot.buildList()); } break; + case MISSION_HERO: + ms.addReplacement(VLC->heroh->heroes[m13489val]->name); + break; case MISSION_PLAYER: ms.addReplacement(VLC->generaltexth->colors[m13489val]); break; @@ -4096,7 +4093,7 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const switch (missionType) { case MISSION_LEVEL: - iw.components.push_back (Component (Component::EXPERIENCE, 1, m13489val, 0)); + iw.components.push_back(Component (Component::EXPERIENCE, 1, m13489val, 0)); if (!isCustom) iw.text.addReplacement(m13489val); break; @@ -4107,7 +4104,7 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const { if (m2stats[i]) { - iw.components.push_back (Component (Component::PRIM_SKILL, i, m2stats[i], 0)); + iw.components.push_back(Component (Component::PRIM_SKILL, i, m2stats[i], 0)); loot << "%d %s"; loot.addReplacement(m2stats[i]); loot.addReplacement(VLC->generaltexth->primarySkillNames[i]); @@ -4118,28 +4115,20 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const } break; case MISSION_KILL_HERO: - iw.components.push_back (Component (Component::HERO, - cb->gameState()->map->heroesToBeat[m13489val]->type->ID, 0, 0)); + iw.components.push_back(Component(Component::HERO, heroPortrait, 0, 0)); if (!isCustom) - iw.text.addReplacement(cb->gameState()->map->heroesToBeat[m13489val]->name); + addReplacements(iw.text, firstVisitText); break; case MISSION_HERO: - iw.components.push_back (Component (Component::HERO, m13489val, 0, 0)); + iw.components.push_back(Component (Component::HERO, m13489val, 0, 0)); if (!isCustom) iw.text.addReplacement(VLC->heroh->heroes[m13489val]->name); break; case MISSION_KILL_CREATURE: { - CStackInstance stack = cb->gameState()->map->monsters[m13489val]->getStack(0); - iw.components.push_back (Component(stack)); + iw.components.push_back(Component(stackToKill)); if (!isCustom) - { - iw.text.addReplacement(stack); - if (std::count(firstVisitText.begin(), firstVisitText.end(), '%') == 2) //say where is placed monster - { - iw.text.addReplacement(VLC->generaltexth->arraytxt[147+checkDirection()]); - } - } + addReplacements(iw.text, firstVisitText); } break; case MISSION_ART: @@ -4147,12 +4136,12 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const MetaString loot; for (std::vector::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it) { - iw.components.push_back (Component (Component::ARTIFACT, *it, 0, 0)); + iw.components.push_back(Component (Component::ARTIFACT, *it, 0, 0)); loot << "%s"; loot.addReplacement(MetaString::ART_NAMES, *it); } if (!isCustom) - iw.text.addReplacement (loot.buildList()); + iw.text.addReplacement(loot.buildList()); } break; case MISSION_ARMY: @@ -4165,7 +4154,7 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const loot.addReplacement(*it); } if (!isCustom) - iw.text.addReplacement (loot.buildList()); + iw.text.addReplacement(loot.buildList()); } break; case MISSION_RESOURCES: @@ -4175,20 +4164,20 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const { if (m7resources[i]) { - iw.components.push_back (Component (Component::RESOURCE, i, m7resources[i], 0)); + iw.components.push_back(Component (Component::RESOURCE, i, m7resources[i], 0)); loot << "%d %s"; loot.addReplacement(m7resources[i]); loot.addReplacement(MetaString::RES_NAMES, i); } } if (!isCustom) - iw.text.addReplacement (loot.buildList()); + iw.text.addReplacement(loot.buildList()); } break; case MISSION_PLAYER: - iw.components.push_back (Component (Component::FLAG, m13489val, 0, 0)); + iw.components.push_back(Component (Component::FLAG, m13489val, 0, 0)); if (!isCustom) - iw.text.addReplacement (VLC->generaltexth->colors[m13489val]); + iw.text.addReplacement(VLC->generaltexth->colors[m13489val]); break; } cb->setObjProperty (id,10,1); @@ -4197,6 +4186,8 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const else if (!checkQuest(h)) { iw.text << nextVisitText; + if(!isCustom) + addReplacements(iw.text, nextVisitText); cb->showInfoDialog(&iw); } if (checkQuest(h)) // propose completion, also on first visit @@ -4269,23 +4260,14 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const } break; case MISSION_KILL_HERO: + case MISSION_KILL_CREATURE: if (!isCustom) - bd.text.addReplacement(cb->gameState()->map->heroesToBeat[m13489val]->name); + addReplacements(bd.text, completedText); break; case MISSION_HERO: if (!isCustom) bd.text.addReplacement(VLC->heroh->heroes[m13489val]->name); break; - case MISSION_KILL_CREATURE: - { - { - bd.text.addReplacement(cb->gameState()->map->monsters[m13489val]->getArmy()[0]); - if (std::count(firstVisitText.begin(), firstVisitText.end(), '%') == 2) //say where is placed monster - { - bd.text.addReplacement(VLC->generaltexth->arraytxt[147+checkDirection()]); - } - } - } case MISSION_PLAYER: if (!isCustom) bd.text.addReplacement(VLC->generaltexth->colors[m13489val]); @@ -4294,25 +4276,25 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const switch (rewardType) { - case 1: bd.components.push_back (Component (Component::EXPERIENCE, 0, rVal*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f, 0)); + case 1: bd.components.push_back(Component (Component::EXPERIENCE, 0, rVal*(100+h->getSecSkillLevel(CGHeroInstance::LEARNING)*5)/100.0f, 0)); break; - case 2: bd.components.push_back (Component (Component::PRIM_SKILL, 5, rVal, 0)); + case 2: bd.components.push_back(Component (Component::PRIM_SKILL, 5, rVal, 0)); break; - case 3: bd.components.push_back (Component (Component::MORALE, 0, rVal, 0)); + case 3: bd.components.push_back(Component (Component::MORALE, 0, rVal, 0)); break; - case 4: bd.components.push_back (Component (Component::LUCK, 0, rVal, 0)); + case 4: bd.components.push_back(Component (Component::LUCK, 0, rVal, 0)); break; - case 5: bd.components.push_back (Component (Component::RESOURCE, rID, rVal, 0)); + case 5: bd.components.push_back(Component (Component::RESOURCE, rID, rVal, 0)); break; - case 6: bd.components.push_back (Component (Component::PRIM_SKILL, rID, rVal, 0)); + case 6: bd.components.push_back(Component (Component::PRIM_SKILL, rID, rVal, 0)); break; - case 7: bd.components.push_back (Component (Component::SEC_SKILL, rID, rVal, 0)); + case 7: bd.components.push_back(Component (Component::SEC_SKILL, rID, rVal, 0)); break; - case 8: bd.components.push_back (Component (Component::ARTIFACT, rID, 0, 0)); + case 8: bd.components.push_back(Component (Component::ARTIFACT, rID, 0, 0)); break; - case 9: bd.components.push_back (Component (Component::SPELL, rID, 0, 0)); + case 9: bd.components.push_back(Component (Component::SPELL, rID, 0, 0)); break; - case 10: bd.components.push_back (Component (Component::CREATURE, rID, rVal, 0)); + case 10: bd.components.push_back(Component (Component::CREATURE, rID, rVal, 0)); break; } @@ -4330,7 +4312,7 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const } int CGSeerHut::checkDirection() const { - int3 cord = cb->gameState()->map->monsters[m13489val]->pos; + int3 cord = getCreatureToKill()->pos; if ((double)cord.x/(double)cb->getMapSize().x < 0.34) //north { if ((double)cord.y/(double)cb->getMapSize().y < 0.34) //northwest @@ -4443,6 +4425,41 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward } } +const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const +{ + const CGObjectInstance *o = cb->getObjByQuestIdentifier(m13489val); + if(allowNull && !o) + return NULL; + assert(o && o->ID == HEROI_TYPE); + return static_cast(o); +} + +const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const +{ + const CGObjectInstance *o = cb->getObjByQuestIdentifier(m13489val); + if(allowNull && !o) + return NULL; + assert(o && o->ID == 54); + return static_cast(o); +} + +void CGSeerHut::addReplacements(MetaString &out, const std::string &base) const +{ + switch(missionType) + { + case MISSION_KILL_CREATURE: + out.addReplacement(stackToKill); + if (std::count(base.begin(), base.end(), '%') == 2) //say where is placed monster + { + out.addReplacement(VLC->generaltexth->arraytxt[147+stackDirection]); + } + break; + case MISSION_KILL_HERO: + out.addReplacement(heroName); + break; + } +} + void CGQuestGuard::initObj() { blockVisit = true; diff --git a/lib/CObjectHandler.h b/lib/CObjectHandler.h index fc265f140..4d0e68bda 100644 --- a/lib/CObjectHandler.h +++ b/lib/CObjectHandler.h @@ -309,7 +309,7 @@ public: ////////////////////////////////////////////////////////////////////////// - const CHero * type; + ConstTransitivePtr type; ui64 exp; //experience points si32 level; //current level of hero std::string name; //may be custom @@ -760,6 +760,14 @@ public: ui8 textOption; //store randomized mission write-ups rather than entire string (?) std::string seerName; + //following field are used only for kill creature/hero missions, the original objects became inaccessible after their removal, so we need to store info needed for messages / hover text + //TODO? organize + CStackBasicDescriptor stackToKill; + ui8 stackDirection; + std::string heroName; //backup of hero name + si32 heroPortrait; + + void initObj(); const std::string & getHoverText() const; void setPropertyDer (ui8 what, ui32 val); @@ -769,10 +777,16 @@ public: void finishQuest (const CGHeroInstance * h, ui32 accept) const; //common for both objects void completeQuest (const CGHeroInstance * h) const; + const CGHeroInstance *getHeroToKill(bool allowNull = false) const; + const CGCreature *getCreatureToKill(bool allowNull = false) const; + + void addReplacements(MetaString &out, const std::string &base) const; + template void serialize(Handler &h, const int version) { h & static_cast(*this) & static_cast(*this); h & rewardType & rID & rVal & textOption & seerName; + h & stackToKill & stackDirection & heroName & heroPortrait; } }; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 6085f6f61..b518991ee 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -266,4 +266,10 @@ const PlayerState * IGameCallback::getPlayerState( int color ) const CTown * IGameCallback::getNativeTown(int color) { return &VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(color).castle]; +} + +const CGObjectInstance * IGameCallback::getObjByQuestIdentifier(int identifier) +{ + assert(vstd::contains(gs->map->questIdentifierToId, identifier)); + return getObj(gs->map->questIdentifierToId[identifier]); } \ No newline at end of file diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index c780b3218..61cbf83df 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -56,6 +56,7 @@ public: virtual const CGHeroInstance* getHero(int objid); virtual const CGTownInstance* getTown(int objid); virtual const CGHeroInstance* getSelectedHero(int player); //NULL if no hero is selected + virtual const CGObjectInstance *getObjByQuestIdentifier(int identifier); //NULL if object has been removed (eg. killed) virtual int getCurrentPlayer()=0; virtual int getSelectedHero()=0; virtual const PlayerSettings * getPlayerSettings(int color); diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 9749cab80..80e24d4e6 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -243,11 +243,8 @@ DLL_EXPORT void RemoveObject::applyGs( CGameState *gs ) if(obj->ID==HEROI_TYPE) { CGHeroInstance *h = static_cast(obj); - std::vector >::iterator nitr = std::find(gs->map->heroes.begin(), gs->map->heroes.end(),h); - gs->map->heroes.erase(nitr); - int player = h->tempOwner; - nitr = std::find(gs->getPlayer(player)->heroes.begin(), gs->getPlayer(player)->heroes.end(), h); - gs->getPlayer(player)->heroes.erase(nitr); + gs->map->heroes -= h; + gs->getPlayer(h->tempOwner)->heroes -= h; h->tempOwner = 255; //no one owns beaten hero if(CGTownInstance *t = const_cast(h->visitedTown)) @@ -264,13 +261,16 @@ DLL_EXPORT void RemoveObject::applyGs( CGameState *gs ) if(!vstd::contains(gs->hpool.pavailable, h->subID)) gs->hpool.pavailable[h->subID] = 0xff; + gs->map->objects[id] = NULL; + + return; } - else if (obj->ID==CREI_TYPE && gs->map->version > CMapHeader::RoE) //only fixed monsters can be a part of quest - { - CGCreature *cre = static_cast(obj); - gs->map->monsters[cre->identifier]->pos = int3 (-1,-1,-1); //use nonexistent monster for quest :> - } +// else if (obj->ID==CREI_TYPE && gs->map->version > CMapHeader::RoE) //only fixed monsters can be a part of quest +// { +// CGCreature *cre = static_cast(obj); +// gs->map->monsters[cre->identifier]->pos = int3 (-1,-1,-1); //use nonexistent monster for quest :> +// } gs->map->objects[id].dellNull(); } diff --git a/lib/map.cpp b/lib/map.cpp index a039e8880..65ec9eb5a 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -779,14 +779,15 @@ void Mapa::loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int nt->garrisonHero = NULL; } -CGObjectInstance * Mapa::loadHero(const unsigned char * bufor, int &i) +CGObjectInstance * Mapa::loadHero(const unsigned char * bufor, int &i, int idToBeGiven) { CGHeroInstance * nhi = new CGHeroInstance(); int identifier = 0; - if(version>RoE) + if(version > RoE) { identifier = readNormalNr(bufor,i, 4); i+=4; + questIdentifierToId[identifier] = idToBeGiven; } ui8 owner = bufor[i++]; @@ -815,7 +816,6 @@ CGObjectInstance * Mapa::loadHero(const unsigned char * bufor, int &i) break; } } - heroesToBeat[identifier] = nhi; if(readChar(bufor,i))//true if hero has nonstandard name nhi->name = readString(bufor,i); if(version>AB) @@ -1224,6 +1224,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) pos.z = bufor[i++]; int defnum = readNormalNr(bufor,i, 4); i+=4; + int idToBeGiven = objects.size(); CGDefInfo * defInfo = defy[defnum]; i+=5; @@ -1306,7 +1307,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) } case 34: case 70: case 62: //34 - hero; 70 - random hero; 62 - prison { - nobj = loadHero(bufor, i); + nobj = loadHero(bufor, i, idToBeGiven); break; } case 4: //Arena @@ -1358,7 +1359,8 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) if(version>RoE) { cre->identifier = readNormalNr(bufor,i); i+=4; - monsters[cre->identifier] = cre; + questIdentifierToId[cre->identifier] = idToBeGiven; + //monsters[cre->identifier] = cre; } CStackInstance *hlp = new CStackInstance(); @@ -1846,10 +1848,11 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) nobj->pos = pos; nobj->ID = defInfo->id; - nobj->id = objects.size(); + nobj->id = idToBeGiven; if(nobj->ID != HEROI_TYPE && nobj->ID != 214 && nobj->ID != 62) nobj->subID = defInfo->subid; nobj->defInfo = defInfo; + assert(idToBeGiven == objects.size()); objects.push_back(nobj); if(nobj->ID==TOWNI_TYPE) towns.push_back(static_cast(nobj)); diff --git a/lib/map.h b/lib/map.h index 47f33b6a8..ec8165ff4 100644 --- a/lib/map.h +++ b/lib/map.h @@ -287,8 +287,10 @@ struct DLL_EXPORT Mapa : public CMapHeader std::vector< ConstTransitivePtr > heroes; std::vector< ConstTransitivePtr > towns; std::vector< ConstTransitivePtr > artInstances; //stores all artifacts - bmap > monsters; - bmap > heroesToBeat; + //bmap > monsters; + //bmap > heroesToBeat; + + bmap questIdentifierToId; void initFromBytes( const unsigned char * bufor); //creates map from decompressed .h3m data @@ -300,7 +302,7 @@ struct DLL_EXPORT Mapa : public CMapHeader void readPredefinedHeroes( const unsigned char * bufor, int &i); void readHeader( const unsigned char * bufor, int &i); void readRumors( const unsigned char * bufor, int &i); - CGObjectInstance *loadHero(const unsigned char * bufor, int &i); + CGObjectInstance *loadHero(const unsigned char * bufor, int &i, int idToBeGiven); void loadArtifactsOfHero(const unsigned char * bufor, int & i, CGHeroInstance * nhi); bool loadArtifactToSlot(CGHeroInstance *h, int slot, const unsigned char * bufor, int &i); void loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int &i, int subid); @@ -326,9 +328,8 @@ struct DLL_EXPORT Mapa : public CMapHeader { h & static_cast(*this); h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos; - h & monsters; - h & heroesToBeat; h & artInstances; //hopefully serialization is now automagical? + h & questIdentifierToId; //TODO: viccondetails if(h.saving) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index b65d42958..9808dd387 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1529,7 +1529,7 @@ void CGameHandler::giveCreatures(const CArmedInstance *obj, const CGHeroInstance COMPLAIN_RET_IF(creatures.stacksCount() > ARMY_SIZE, "Too many stacks to give!"); //first we move creatures to give to make them army of object-source - for(int i = 0; creatures.stacksCount(); i++) + for(int i = 0; i != creatures.stacksCount(); i++) { TSlots::const_iterator stack = creatures.Slots().begin(); addToSlot(StackLocation(obj, i), stack->second->type, stack->second->count);