diff --git a/client/Client.cpp b/client/Client.cpp index 1c790dd15..a22ce91b7 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -319,7 +319,7 @@ void CClient::newGame( CConnection *con, StartInfo *si ) CGI->state = new CGameState(); tlog0 <<"\tGamestate: "< cb = 0, const CGTownInstance *town = NULL){}; //use hero=NULL for no hero void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used diff --git a/hch/CArtHandler.cpp b/hch/CArtHandler.cpp index 7b1c73133..0577123ce 100644 --- a/hch/CArtHandler.cpp +++ b/hch/CArtHandler.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "../lib/VCMI_Lib.h" extern CLodHandler *bitmaph; using namespace boost::assign; @@ -182,7 +183,8 @@ void CArtifact::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/ void CScroll::Init() { - bonuses.push_back (Bonus (Bonus::PERMANENT, Bonus::SPELL,0, id, spellid, Bonus::INDEPENDENT_MAX)); + bonuses.push_back (Bonus (Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT, 0, id, spellid, Bonus::INDEPENDENT_MAX)); + //boost::algorithm::replace_first(description, "[spell name]", VLC->spellh->spells[spellid].name); } CArtHandler::CArtHandler() @@ -192,6 +194,7 @@ CArtHandler::CArtHandler() // War machines are the default big artifacts. for (ui32 i = 3; i <= 6; i++) bigArtifacts.insert(i); + modableArtifacts = boost::assign::map_list_of(1, 1)(146,3)(147,3)(148,3)(150,3)(151,3)(152,3)(154,3)(156,2); } CArtHandler::~CArtHandler() @@ -217,9 +220,28 @@ void CArtHandler::loadArtifacts(bool onlyTxt) } VLC->generaltexth->artifNames.resize(ARTIFACTS_QUANTITY); VLC->generaltexth->artifDescriptions.resize(ARTIFACTS_QUANTITY); + std::map::iterator itr; for (int i=0; isecond) + { + case 1: + art = new CScroll; + break; + case 2: + art = new CCustomizableArt; + break; + case 3: + art = new CCommanderArt; + break; + }; + } + else + art = new CArtifact; + CArtifact &nart = *art; nart.id=i; loadToIt(VLC->generaltexth->artifNames[i],buf,it,4); diff --git a/hch/CArtHandler.h b/hch/CArtHandler.h index 767ec5fcb..0989eb75f 100644 --- a/hch/CArtHandler.h +++ b/hch/CArtHandler.h @@ -21,6 +21,7 @@ class CArtifact; class DLL_EXPORT CArtifact : public CBonusSystemNode //container for artifacts { +protected: std::string name, description; //set if custom public: enum EartClass {ART_SPECIAL=1, ART_TREASURE=2, ART_MINOR=4, ART_MAJOR=8, ART_RELIC=16}; //artifact classes @@ -32,6 +33,8 @@ public: bool canBeAssembledTo (const std::map &artifWorn, ui32 artifactID) const; void addBonusesTo (BonusList *otherBonuses) const; void removeBonusesFrom (BonusList *otherBonuses) const; + virtual void SetProperty (int mod){}; + virtual void Init(){}; int getArtClassSerial() const; //0 - treasure, 1 - minor, 2 - major, 3 - relic, 4 - spell scroll, 5 - other ui32 price; @@ -54,47 +57,58 @@ public: void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; }; -class DLL_EXPORT IModableArt //artifact which can have different properties, such as scroll or banner -{ +class DLL_EXPORT IModableArt : public CArtifact //artifact which can have different properties, such as scroll or banner +{ //used only for dynamic cast :P public: - virtual void Init() = 0; -}; + si32 ID; //used for smart serialization -class DLL_EXPORT CScroll : public CArtifact, public IModableArt // Spell Scroll -{ -public: - CScroll(spelltype sid){spellid = sid;}; - spelltype spellid; - void Init(); template void serialize(Handler &h, const int version) { h & static_cast(*this); + h & ID; + } +}; + +class DLL_EXPORT CScroll : public IModableArt // Spell Scroll +{ +public: + CScroll(){spellid=0;}; + CScroll(spelltype sid){spellid = sid;}; + spelltype spellid; + void Init(); + void SetProperty (int mod){spellid = mod;}; + template void serialize(Handler &h, const int version) + { + h & static_cast(*this); h & spellid; } }; -class DLL_EXPORT CCustomizableArt : public CArtifact, public IModableArt // Warlord's Banner with multiple options +class DLL_EXPORT CCustomizableArt : public IModableArt // Warlord's Banner with multiple options { public: ui8 mode; + CCustomizableArt(){mode=0;}; void Init(){}; - void SelectMode (int mod){}; + void SetProperty (int mod){}; template void serialize(Handler &h, const int version) { - h & static_cast(*this); + h & static_cast(*this); h & mode; } }; -class DLL_EXPORT CCommanderArt : public CArtifact, public IModableArt // Growing with time +class DLL_EXPORT CCommanderArt : public IModableArt // Growing with time { public: ui32 level; + CCommanderArt(){level = 0;}; void Init(){}; + void SetProperty (int mod){level = mod;}; void Upgrade(){level++;}; template void serialize(Handler &h, const int version) { - h & static_cast(*this); + h & static_cast(*this); h & level; } }; @@ -107,6 +121,7 @@ public: std::vector artifacts; std::vector allowedArtifacts; std::set bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines. + std::map modableArtifacts; //1-scroll, 2-banner, 3-commander art with progressive bonus void loadArtifacts(bool onlyTxt); void sortArts(); diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index c601f7a64..c6ebfd7c6 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -3591,24 +3591,36 @@ void CGArtifact::initObj() blockVisit = true; if(ID == 5) hoverName = VLC->arth->artifacts[subID]->Name(); + if(ID == 93) + subID = 1; } void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const { if(!stacksCount()) { - if(ID == 5) + InfoWindow iw; + iw.soundID = soundBase::treasure; + iw.player = h->tempOwner; + switch(ID) { - InfoWindow iw; - iw.soundID = soundBase::treasure; - iw.player = h->tempOwner; - iw.components.push_back(Component(4,subID,0,0)); - if(message.length()) - iw.text << message; - else - iw.text << std::pair(12,subID); - cb->showInfoDialog(&iw); + case 5: + { + iw.components.push_back(Component(4,subID,0,0)); + if(message.length()) + iw.text << message; + else + iw.text << std::pair(12,subID); + } + break; + case 93: + iw.components.push_back (Component(Component::SPELL, spell,0,0)); + iw.text.addTxt (MetaString::ADVOB_TXT,135); + iw.text.addReplacement(MetaString::SPELL_NAME, spell); + break; + } + cb->showInfoDialog(&iw); pick(h); } else @@ -3629,15 +3641,22 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const void CGArtifact::pick(const CGHeroInstance * h) const { - if(ID == 5) //Artifact - { - if (VLC->arth->artifacts[subID]->isModable()) //TODO: create new instance, initialize it - {} - cb->giveHeroArtifact(subID,h->id,-2); + if (VLC->arth->artifacts[subID]->isModable()) + {//TODO: create new instance, initialize it + if (ID == 93) //scroll + { + NewArtifact na; + na.value = spell; + na.artid = subID; + cb->sendAndApply(&na); + cb->giveNewArtifact(h->id, -2); + } + else + cb->giveNewArtifact(h->id, -2);; //nothing / zero / empty by default } - else if(ID == 93) // Spell scroll + else { - //TODO: support for the spell scroll + cb->giveHeroArtifact(subID,h->id,-2); } cb->removeObject(id); } diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index de980f03b..9f6ec3ceb 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -47,6 +47,7 @@ struct InfoWindow; struct Component; struct BankConfig; struct UpdateHeroSpeciality; +struct NewArtifact; class CGBoat; class DLL_EXPORT CQuest diff --git a/lib/CGameState.h b/lib/CGameState.h index a09d7dc17..50573e180 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -61,6 +61,7 @@ struct TerrainTile; class CHeroClass; class CCampaign; class CCampaignState; +class IModableArt; namespace boost { @@ -142,7 +143,8 @@ public: template void serialize(Handler &h, const int version) { h & color & human & currentSelection & team & resources & status; - h & heroes & towns & availableHeroes & dwellings & bonuses & status & daysWithoutCastle; + h & heroes & towns & availableHeroes & dwellings & bonuses; + h & status & daysWithoutCastle; h & enteredLosingCheatCode & enteredWinningCheatCode; h & static_cast(*this); } diff --git a/lib/Connection.cpp b/lib/Connection.cpp index 72a80673d..33494f36a 100644 --- a/lib/Connection.cpp +++ b/lib/Connection.cpp @@ -385,8 +385,9 @@ CSerializer::CSerializer() void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib) { registerVectoredType(&gs->map->objects, &CGObjectInstance::id); + registerVectoredType(&lib->heroh->heroes, &CHero::ID); registerVectoredType(&lib->creh->creatures, &CCreature::idNumber); registerVectoredType(&lib->arth->artifacts, &CArtifact::id); - registerVectoredType(&lib->heroh->heroes, &CHero::ID); + registerVectoredType(&gs->map->artInstances, &IModableArt::ID); smartVectorMembersSerialization = true; } diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 3591c4386..3d8a7d349 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -93,6 +93,7 @@ public: 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 giveNewArtifact(int hid, int position)=0; virtual bool removeArtifact(CArtifact* art, 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 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 cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 50b5c7824..1c4196c0e 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -694,6 +694,21 @@ struct SetAvailableArtifacts : public CPackForClient //519 } }; +struct NewArtifact : public CPackForClient +{ + NewArtifact(){type = 520;}; + //void applyCl(CClient *cl); + DLL_EXPORT void applyGs(CGameState *gs); + + si32 artid; + si32 value; //initializing parameter + + template void serialize(Handler &h, const int version) + { + h & artid & value; + } +}; + struct NewTurn : public CPackForClient //101 { enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, CUSTOM, NO_ACTION, NONE}; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index d230694c0..a89d02ce1 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -455,9 +455,11 @@ DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs ) if(!vstd::contains(artifWorn,i->first) || artifWorn[i->first] != i->second) unequiped.push_back(i->second); - for(std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) + for(std::map::iterator i = artifWorn.begin(); i != artifWorn.end(); i++) if(!vstd::contains(h->artifWorn,i->first) || h->artifWorn[i->first] != i->second) + { equiped.push_back(i->second); + } //update hero data h->artifacts = artifacts; @@ -584,6 +586,31 @@ DLL_EXPORT void NewObject::applyGs( CGameState *gs ) o->initObj(); assert(o->defInfo); } +DLL_EXPORT void NewArtifact::applyGs( CGameState *gs ) +{ + CArtifact * art; + + std::map::iterator itr = VLC->arth->modableArtifacts.find(artid); + switch (itr->second) + { + case 1: + art = new CScroll; + break; + case 2: + art = new CCustomizableArt; + break; + case 3: + art = new CCommanderArt; + break; + default: + tlog1<<"unhandled customizable artifact!\n"; + }; + *art = *(VLC->arth->artifacts[artid]); //copy properties + static_cast(art)->ID = gs->map->artInstances.size(); + art->SetProperty (value); //init scroll, banner, commander art + art->Init(); //set bonuses for new instance + gs->map->artInstances.push_back(static_cast(art)); +} DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs ) { @@ -630,11 +657,6 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) BOOST_FOREACH(CGHeroInstance *h, gs->map->heroes) h->bonuses.remove_if(Bonus::OneDay); - if(resetBuilded) //reset amount of structures set in this turn in towns - { - BOOST_FOREACH(CGTownInstance* t, gs->map->towns) - t->builded = 0; - } if(gs->getDate(1)) //new week, Monday that is { for( std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) @@ -690,6 +712,11 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) i->second.bonuses.remove_if(Bonus::OneDay); } + if(resetBuilded) //reset amount of structures set in this turn in towns + { + BOOST_FOREACH(CGTownInstance* t, gs->map->towns) + t->builded = 0; + } } } diff --git a/lib/RegisterTypes.cpp b/lib/RegisterTypes.cpp index 2a217360d..9b53e695f 100644 --- a/lib/RegisterTypes.cpp +++ b/lib/RegisterTypes.cpp @@ -137,6 +137,7 @@ void registerTypes2(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/lib/map.h b/lib/map.h index f74081500..c4f5eb9e5 100644 --- a/lib/map.h +++ b/lib/map.h @@ -30,7 +30,7 @@ class CGHeroInstance; class CGCreature; class CQuest; class CGTownInstance; - +class IModableArt; struct DLL_EXPORT TerrainTile @@ -254,6 +254,7 @@ struct DLL_EXPORT Mapa : public CMapHeader std::vector objects; std::vector heroes; std::vector towns; + std::vector artInstances; //stores single scrolls std::map monsters; std::map heroesToBeat; @@ -288,7 +289,7 @@ struct DLL_EXPORT Mapa : public CMapHeader { h & static_cast(*this); h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos; - h & monsters & heroesToBeat; //hoprfully serialization is now automagical? + h & monsters & heroesToBeat & artInstances; //hoprfully serialization is now automagical? //TODO: viccondetails if(h.saving) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index e835f5a76..793289d67 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1211,6 +1211,7 @@ void CGameHandler::newTurn() NewTurn n2; //just to handle creature growths after bonuses are applied n2.specialWeek = NewTurn::NO_ACTION; n2.day = gs->day; + n2.resetBuilded = true; for(std::vector::iterator j = gs->map->towns.begin(); j!=gs->map->towns.end(); j++)//handle towns { @@ -2264,6 +2265,52 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1 sendAndApply(&sha); } +void CGameHandler::giveNewArtifact(int hid, int position) +{ + const CGHeroInstance* h = getHero(hid); + CArtifact * art = gs->map->artInstances.back(); //we use it only to immediatelly equip new artifact + + SetHeroArtifacts sha; + sha.hid = hid; + sha.artifacts = h->artifacts; + sha.artifWorn = h->artifWorn; + + if(position<0) + { + if(position == -2) + { + int i; + for(i=0; ipossibleSlots.size(); i++) //try to put artifact into first available slot + { + if( !vstd::contains(sha.artifWorn, art->possibleSlots[i]) ) + { + //we've found a free suitable slot + VLC->arth->equipArtifact(sha.artifWorn, art->possibleSlots[i], art); + break; + } + } + if(i == art->possibleSlots.size() && !art->isBig()) //if haven't find proper slot, use backpack or discard big artifact + sha.artifacts.push_back(art); + } + else if (!art->isBig()) //should be -1 => put artifact into backpack + { + sha.artifacts.push_back(art); + } + } + else + { + if(!vstd::contains(sha.artifWorn,ui16(position))) + { + VLC->arth->equipArtifact(sha.artifWorn, position, art); + } + else if (!art->isBig()) + { + sha.artifacts.push_back(art); + } + } + + sendAndApply(&sha); +} bool CGameHandler::removeArtifact(CArtifact* art, int hid) { const CGHeroInstance* h = getHero(hid); diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 3ca626756..fb53bb537 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -143,6 +143,7 @@ public: 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 giveNewArtifact(int hid, int position); void moveArtifact(int hid, int oldPosition, int destPos); bool removeArtifact(CArtifact* art, int hid); void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero