1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-04 23:17:41 +02:00

Next part of Seer Hut code, including large number of Components, packs and help functions.

Mapa now contains separate vector of monsters to avoid linear search trough all objects.
This commit is contained in:
DjWarmonger 2010-02-02 17:05:03 +00:00
parent 3dbeaa5ef8
commit ce00ceaf08
15 changed files with 231 additions and 19 deletions

View File

@ -17,6 +17,7 @@
#include "../hch/CGeneralTextHandler.h"
#include "../hch/CObjectHandler.h"
#include "../hch/CTownHandler.h"
#include "../hch/CHeroHandler.h"
#include "../lib/map.h"
#include "../lib/NetPacks.h"
#include <boost/algorithm/string/replace.hpp>

View File

@ -83,10 +83,12 @@ public:
void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb){};
void giveResource(int player, int which, int val){};
void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures) {};
void takeCreatures (int objid, CCreatureSet creatures){};
void showCompInfo(ShowInInfobox * comp){};
void heroVisitCastle(int obj, int heroID){};
void stopHeroVisitCastle(int obj, int heroID){};
void giveHeroArtifact(int artid, int hid, int position){}; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
void removeArtifact(int artid, int hid){};
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL){}; //use hero=NULL for no hero
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle

View File

@ -865,6 +865,9 @@ void SComponent::init(Etype Type, int Subtype, int Val)
subtitle = oss.str();
}
break;
case hero:
subtitle = description = CGI->heroh->heroes[Subtype]->name;
break;
case flag:
subtitle = CGI->generaltexth->capColors[Subtype];
break;
@ -935,6 +938,9 @@ SDL_Surface * SComponent::getImg()
break;
case creature:
return graphics->bigImgs[subtype];
break;
case hero:
return graphics->portraitLarge[subtype];
case flag:
return graphics->flags->ourImages[subtype].bitmap;
}

View File

@ -130,7 +130,7 @@ class SComponent : public virtual CIntObject //common popup window component
public:
enum Etype
{
primskill, secskill, resource, creature, artifact, experience, secskill44, spell, morale, luck, building, flag
primskill, secskill, resource, creature, artifact, experience, secskill44, spell, morale, luck, building, hero, flag
} type; //component type
int subtype; //TODO: comment me
int val; //TODO: comment me

View File

@ -77,6 +77,7 @@ extern CGameInfo* CGI;
#define HEROI_TYPE (34)
#define TOWNI_TYPE (98)
#define CREI_TYPE (54)
const int F_NUMBER = 9; //factions (town types) quantity
const int PLAYER_LIMIT = 8; //player limit per map
@ -149,6 +150,13 @@ namespace vstd
{
return c.find(i)!=c.end();
}
template <typename V, typename Item, typename Item2>
bool contains2(const std::map<Item,V> & c, const Item2 &i) //returns true if map c leads to item i
{
for (std::map<Item,V>::const_iterator it = c.begin(); it!= c.end(); ++it)
if (it->second == i) return true;
return false;
}
template <typename Container1, typename Container2>
typename Container2::iterator findFirstNot(Container1 &c1, Container2 &c2)//returns first element of c2 not present in c1
{

View File

@ -3125,7 +3125,7 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const
case MISSION_PRIMARY_STAT:
for (int i = 0; i < 4; ++i)
{
if (m2stats[i] < h->primSkills[i])
if (h->primSkills[i] < m2stats[i])
return false;
}
return true;
@ -3136,8 +3136,8 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const
return true;
break;
case MISSION_KILL_CREATURE:
if (h->cb->getObj (m13489val))
return false; //if the pointer is not NULL
if (h->cb->gameState()->map->monsters[m13489val])
return false;
return true;
break;
case MISSION_ART:
@ -3145,7 +3145,7 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const
{
if (vstd::contains(h->artifacts, m5arts[i]))
continue;
if (vstd::contains(h->artifWorn, m5arts[i]))
if (vstd::contains2(h->artifWorn, m5arts[i]))
continue;
return false; //if the artifact was not found
}
@ -3196,9 +3196,14 @@ void CGSeerHut::initObj()
seerName = VLC->generaltexth->seerNames[ran()%VLC->generaltexth->seerNames.size()];
textOption = ran()%3;
progress = 0;
firstVisitText = VLC->generaltexth->quests[missionType][0][textOption];
nextVisitText = VLC->generaltexth->quests[missionType][1][textOption];
completedText = VLC->generaltexth->quests[missionType][2][textOption];
if (missionType)
{
firstVisitText = VLC->generaltexth->quests[missionType-1][0][textOption];
nextVisitText = VLC->generaltexth->quests[missionType-1][1][textOption];
completedText = VLC->generaltexth->quests[missionType-1][2][textOption];
}
else
firstVisitText = VLC->generaltexth->seerEmpty[textOption];
}
const std::string & CGSeerHut::getHoverText() const
@ -3220,27 +3225,163 @@ void CGSeerHut::setPropertyDer (ui8 what, ui32 val)
break;
}
}
void CGSeerHut::newTurn() const
{
if (lastDay >= 0 && lastDay <= cb->getDate(0)) //time is up
{
cb->setObjProperty (id,11,0);
cb->setObjProperty (id,10,0);
}
}
void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
{
InfoWindow iw;
iw.player = h->getOwner();
if (missionType)
{
if (!progress)
if (!progress) //propose quest
{
iw.text << firstVisitText;
cb->setObjProperty (id,10,1);
iw.text << firstVisitText;
switch (missionType)
{
case MISSION_LEVEL:
iw.components.push_back (Component (Component::EXPERIENCE, 1, m13489val, 0));
iw.text.addReplacement(m13489val);
break;
case MISSION_PRIMARY_STAT:
{
MetaString loot;
for (int i = 0; i < 4; ++i)
{
if (m2stats[i])
{
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]);
}
}
iw.text.addReplacement (loot.buildList());
}
break;
case MISSION_KILL_HERO:
case MISSION_HERO:
iw.components.push_back (Component (Component::HERO, 1, m13489val, 0));
iw.text.addReplacement(VLC->heroh->heroes[m13489val]->name);
break;
case MISSION_KILL_CREATURE:
{
const TStack* stack = cb->gameState()->map->monsters[m13489val]->army.getStack(0);
iw.components.push_back (Component (Component::CREATURE, stack->first, stack->second, 0));
if (stack->first == 1)
iw.text.addReplacement (MetaString::CRE_SING_NAMES, stack->first);
else
iw.text.addReplacement (MetaString::CRE_PL_NAMES, stack->first);
}
break;
case MISSION_ART:
{
MetaString loot;
for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
{
iw.components.push_back (Component (Component::ARTIFACT, *it, 0, 0));
loot << "%s";
loot.addReplacement (MetaString::ART_NAMES, *it);
}
iw.text.addReplacement (loot.buildList());
}
break;
case MISSION_ARMY:
{
MetaString loot;
for (TSlots::const_iterator it = m6creatures.begin(); it != m6creatures.end(); ++it)
{
iw.components.push_back (Component (Component::CREATURE, it->second.first, it->second.second, 0));
loot << "%s";
if (it->second.second == 1)
loot.addReplacement (MetaString::CRE_SING_NAMES, it->second.first);
else
loot.addReplacement (MetaString::CRE_PL_NAMES, it->second.first);
}
iw.text.addReplacement (loot.buildList());
}
break;
case MISSION_RESOURCES:
{
MetaString loot;
for (int i = 0; i < 7; ++i)
{
if (m7resources[i])
{
iw.components.push_back (Component (Component::RESOURCE, i, m7resources[i], 0));
loot << "%d %s";
loot.addReplacement (iw.components.back().val);
loot.addReplacement (MetaString::RES_NAMES, iw.components.back().subtype);
}
}
iw.text.addReplacement (loot.buildList());
}
break;
case MISSION_PLAYER:
iw.components.push_back (Component (Component::FLAG, m13489val, 0, 0));
iw.text.addReplacement (VLC->generaltexth->colors[m13489val]);
break;
}
cb->setObjProperty (id,10,1);
}
else
{
if (!checkQuest(h))
iw.text << nextVisitText;
else
{
//iw.text << completedText;
completeQuest (h);
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.soundID = soundBase::QUEST;
bd.text << completedText;
switch (missionType)
{
case CQuest::MISSION_LEVEL:
bd.text.addReplacement(m13489val);
break;
case CQuest::MISSION_PRIMARY_STAT:
if (vstd::contains (completedText,'%')) //there's one case when there's nothing to replace
{
MetaString loot;
for (int i = 0; i < 4; ++i)
{
if (m2stats[i])
{
loot << "%d %s";
loot.addReplacement (m2stats[i]);
loot.addReplacement (VLC->generaltexth->primarySkillNames[i]);
}
}
bd.text.addReplacement (loot.buildList());
}
break;
case CQuest::MISSION_ART:
for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
bd.components.push_back (Component (Component::ARTIFACT, *it, 0, 0));
break;
case CQuest::MISSION_ARMY:
for (TSlots::const_iterator it = m6creatures.begin(); it != m6creatures.end(); ++it)
bd.components.push_back (Component (Component::CREATURE, it->second.first, it->second.second, 0));
break;
case CQuest::MISSION_RESOURCES:
for (int i = 0; i < 7; ++i)
{
if (m7resources[i])
bd.components.push_back (Component (Component::RESOURCE, i, m7resources[i], 0));
}
break;
}
cb->showBlockingDialog (&bd, boost::bind (&CGSeerHut::finishQuest, this, h, _1));
//cb->showBlockingDialog (&bd, boost::bind (&CGBorderGuard::openGate, this, h, _1));
return;
}
}
}
else
{
@ -3249,7 +3390,30 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
}
cb->showInfoDialog(&iw);
}
void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
{
if (accept)
{
switch (missionType)
{
case CQuest::MISSION_ART:
for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
{}
break;
case CQuest::MISSION_ARMY:
//cb->takeCreatures (h->id, m7creatures);
break;
case CQuest::MISSION_RESOURCES:
for (int i = 0; i < 7; ++i)
{
cb->giveResource(h->getOwner(), i, -m7resources[i]);
}
break;
default:
break;
}
}
}
void CGSeerHut::completeQuest (const CGHeroInstance * h) const
{
cb->setObjProperty (id,11,0); //no more mission avaliable
@ -3259,9 +3423,14 @@ void CGQuestGuard::initObj()
{
progress = 0;
textOption = ran()%3 + 3; //3-5
firstVisitText = VLC->generaltexth->quests[missionType][0][textOption];
nextVisitText = VLC->generaltexth->quests[missionType][1][textOption];
completedText = VLC->generaltexth->quests[missionType][2][textOption];
if (missionType)
{
firstVisitText = VLC->generaltexth->quests[missionType-1][0][textOption];
nextVisitText = VLC->generaltexth->quests[missionType-1][1][textOption];
completedText = VLC->generaltexth->quests[missionType-1][2][textOption];
}
else
firstVisitText = VLC->generaltexth->seerEmpty[textOption];
}
const std::string & CGQuestGuard::getHoverText() const
{

View File

@ -618,7 +618,9 @@ public:
void initObj();
const std::string & getHoverText() const;
void setPropertyDer (ui8 what, ui32 val);
void newTurn() const;
void onHeroVisit (const CGHeroInstance * h) const;
void finishQuest (const CGHeroInstance * h, ui32 accept) const; //common for both objects
void completeQuest (const CGHeroInstance * h) const;
template <typename Handler> void serialize(Handler &h, const int version)

8
int3.h
View File

@ -44,6 +44,14 @@ public:
else
return -1;
}
const TStack* getStack (TSlot slot) const
{
std::map<TSlot, TStack>::const_iterator i = slots.find(slot);
if (i != slots.end())
return &(i->second);
else
return NULL;
}
bool setCreature (TSlot slot, TCreature type, TQuantity quantity) //slots 0 to 6
{
slots[slot] = TStack(type, quantity); //brutal force

View File

@ -79,10 +79,12 @@ public:
virtual void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb) =0; //cb will be called when player closes garrison window
virtual void giveResource(int player, int which, int val)=0;
virtual void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures) =0;
virtual void takeCreatures (int objid, CCreatureSet creatures) =0;
virtual void showCompInfo(ShowInInfobox * comp)=0;
virtual void heroVisitCastle(int obj, int heroID)=0;
virtual void stopHeroVisitCastle(int obj, int heroID)=0;
virtual void giveHeroArtifact(int artid, int hid, int position)=0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
virtual void removeArtifact(int artid, int hid) = 0;
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle

View File

@ -631,7 +631,7 @@ struct NewTurn : public CPackForClient //101
struct Component : public CPack //2002 helper for object scrips informations
{
enum {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE=8, LUCK, HERO, FLAG};
enum {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE=8, LUCK, BUILDING, HERO, FLAG};
ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels)
si32 val; // + give; - take
si16 when; // 0 - now; +x - within x days; -x - per x days

View File

@ -249,6 +249,11 @@ DLL_EXPORT void RemoveObject::applyGs( CGameState *gs )
//TODO: add to the pool?
}
else if (obj->ID==CREI_TYPE) //only fixed monsters can be a part of quest
{
CGCreature *cre = static_cast<CGCreature*>(obj);
gs->map->monsters[cre->identifier] = NULL;
}
gs->map->objects[id] = NULL;
//unblock tiles

View File

@ -1540,6 +1540,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
if(version>RoE)
{
cre->identifier = readNormalNr(bufor,i); i+=4;
monsters[cre->identifier] = cre;
}
cre->army.slots[0].second = readNormalNr(bufor,i, 2); i+=2;
cre->character = bufor[i]; ++i;

View File

@ -27,6 +27,7 @@
class CGDefInfo;
class CGObjectInstance;
class CGHeroInstance;
class CGCreature;
class CQuest;
class CGTownInstance;
enum ESortBy{_playerAm, _size, _format, _name, _viccon, _loscon};
@ -324,6 +325,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
std::vector<CGObjectInstance*> objects;
std::vector<CGHeroInstance*> heroes;
std::vector<CGTownInstance*> towns;
std::map<ui16, CGCreature*> monsters;
void initFromBytes( const unsigned char * bufor); //creates map from decompressed .h3m data
@ -355,6 +357,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
{
h & static_cast<CMapHeader&>(*this);
h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos;
h & monsters; //hoprfully serialization is now automagical?
//TODO: viccondetails
if(h.saving)

View File

@ -1702,6 +1702,8 @@ void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, CCreature
return;
}
}
void CGameHandler::takeCreatures (int objid, CCreatureSet creatures)
{}
void CGameHandler::showCompInfo(ShowInInfobox * comp)
{
sendToAllClients(comp);
@ -1781,6 +1783,8 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
sendAndApply(&sha);
}
void CGameHandler::removeArtifact(int artid, int hid)
{}
void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town) //use hero=NULL for no hero
{

View File

@ -128,13 +128,14 @@ public:
void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb);
void giveResource(int player, int which, int val);
void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures);
void takeCreatures (int objid, CCreatureSet creatures);
void showCompInfo(ShowInInfobox * comp);
void heroVisitCastle(int obj, int heroID);
void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);
void stopHeroVisitCastle(int obj, int heroID);
void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack; pos==-2 - default if available or backpack
void moveArtifact(int hid, int oldPosition, int destPos);
void removeArtifact(int hid, int pos);
void removeArtifact(int artid, int hid);
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army