فهرست منبع

Partial support for customizable artifacts and Spell Scroll. Still doesn't work, though.

DjWarmonger 15 سال پیش
والد
کامیت
b75cf89f86
15فایلهای تغییر یافته به همراه194 افزوده شده و 40 حذف شده
  1. 1 1
      client/Client.cpp
  2. 1 0
      client/Client.h
  3. 24 2
      hch/CArtHandler.cpp
  4. 25 10
      hch/CArtHandler.h
  5. 36 17
      hch/CObjectHandler.cpp
  6. 1 0
      hch/CObjectHandler.h
  7. 3 1
      lib/CGameState.h
  8. 2 1
      lib/Connection.cpp
  9. 1 0
      lib/IGameCallback.h
  10. 15 0
      lib/NetPacks.h
  11. 33 6
      lib/NetPacksLib.cpp
  12. 1 0
      lib/RegisterTypes.cpp
  13. 3 2
      lib/map.h
  14. 47 0
      server/CGameHandler.cpp
  15. 1 0
      server/CGameHandler.h

+ 1 - 1
client/Client.cpp

@@ -319,7 +319,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 	CGI->state = new CGameState();
 	tlog0 <<"\tGamestate: "<<tmh.getDif()<<std::endl;
 	serv = con;
-	CConnection &c(*con);
+CConnection &c(*con);
 	////////////////////////////////////////////////////
 	ui8 pom8;
 	c << ui8(2) << ui8(1); //new game; one client

+ 1 - 0
client/Client.h

@@ -113,6 +113,7 @@ public:
 	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 giveCustomArtifact(int artid, int hid, int position, int value){};
 	bool removeArtifact(CArtifact* art, int hid){return false;};
 	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

+ 24 - 2
hch/CArtHandler.cpp

@@ -10,6 +10,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
 #include <boost/random/linear_congruential.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #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<ui32,ui8>::iterator itr;
 	for (int i=0; i<ARTIFACTS_QUANTITY; i++)
 	{
-		CArtifact *art = new CArtifact;
+		CArtifact *art;
+		if ((itr = modableArtifacts.find(i)) != modableArtifacts.end())
+		{
+			switch (itr->second)
+			{
+				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);

+ 25 - 10
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<ui16, CArtifact*> &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
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CArtifact&>(*this);
+		h & ID;
+	}
 };
 
-class DLL_EXPORT CScroll : public CArtifact, public IModableArt // Spell Scroll
+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 <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*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 <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*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 <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CArtifact&>(*this);
+		h & static_cast<IModableArt&>(*this);
 		h & level;
 	}
 };
@@ -107,6 +121,7 @@ public:
 	std::vector<CArtifact *> artifacts;
 	std::vector<CArtifact *> allowedArtifacts;
 	std::set<ui32> bigArtifacts; // Artifacts that cannot be moved to backpack, e.g. war machines.
+	std::map<ui32, ui8> modableArtifacts; //1-scroll, 2-banner, 3-commander art with progressive bonus
 
 	void loadArtifacts(bool onlyTxt);
 	void sortArts();

+ 36 - 17
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<ui8,ui32>(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<ui8,ui32>(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);
 }

+ 1 - 0
hch/CObjectHandler.h

@@ -47,6 +47,7 @@ struct InfoWindow;
 struct Component;
 struct BankConfig;
 struct UpdateHeroSpeciality;
+struct NewArtifact;
 class CGBoat;
 
 class DLL_EXPORT CQuest

+ 3 - 1
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 <typename Handler> 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<CBonusSystemNode&>(*this);
 	}

+ 2 - 1
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;
 }

+ 1 - 0
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<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

+ 15 - 0
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 <typename Handler> 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};

+ 33 - 6
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<ui16,CArtifact*>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
+	for(std::map<ui16,CArtifact*>::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<ui32,ui8>::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<IModableArt*>(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<IModableArt*>(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<ui8, PlayerState>::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;
+		}
 	}
 }
 

+ 1 - 0
lib/RegisterTypes.cpp

@@ -137,6 +137,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<AdvmapSpellCast>();
 	s.template registerType<OpenWindow>();
 	s.template registerType<NewObject>();
+	s.template registerType<NewArtifact>();
 	s.template registerType<SetAvailableArtifacts>();
 
 	s.template registerType<SaveGame>();

+ 3 - 2
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<CGObjectInstance*> objects;
 	std::vector<CGHeroInstance*> heroes;
 	std::vector<CGTownInstance*> towns;
+	std::vector<IModableArt *> artInstances; //stores single scrolls
 	std::map<ui16, CGCreature*> monsters;
 	std::map<ui16, CGHeroInstance*> heroesToBeat;
 
@@ -288,7 +289,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	{
 		h & static_cast<CMapHeader&>(*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)

+ 47 - 0
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<CGTownInstance *>::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; i<art->possibleSlots.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);

+ 1 - 0
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<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero