Переглянути джерело

* mostly working hero flying and water walking; support for artifacts:
- Angel's Wings
- Boots of levitation
and spells
- fly
- water walk

mateuszb 15 роки тому
батько
коміт
71b73bad53

+ 1 - 1
AI/GeniusAI/CGeniusAI.cpp

@@ -1316,7 +1316,7 @@ void CGeniusAI::battleStackMoved(int ID, int dest, int distance, bool end)
 /**
  *
  */
-void CGeniusAI::battleSpellCast(SpellCast *sc)
+void CGeniusAI::battleSpellCast(BattleSpellCast *sc)
 {
 	DbgBox("\t\t\tCGeniusAI::battleSpellCast");
 }

+ 1 - 1
AI/GeniusAI/CGeniusAI.h

@@ -207,7 +207,7 @@ public:
 	virtual void battleEnd(BattleResult *br);
 	virtual void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void battleStackMoved(int ID, int dest, int distance, bool end);
-	virtual void battleSpellCast(SpellCast *sc);
+	virtual void battleSpellCast(BattleSpellCast *sc);
 	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
 	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
 	//

+ 3 - 2
CGameInterface.h

@@ -34,7 +34,7 @@ class IShipyard;
 struct BattleResult;
 struct BattleAttack;
 struct BattleStackAttacked;
-struct SpellCast;
+struct BattleSpellCast;
 struct SetStackEffect;
 struct Bonus;
 struct PackageApplied;
@@ -81,6 +81,7 @@ public:
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
 	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void showPuzzleMap(){};
+	virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell
 	virtual void tileHidden(const std::set<int3> &pos){};
 	virtual void tileRevealed(const std::set<int3> &pos){};
 	virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard
@@ -109,7 +110,7 @@ public:
 	virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
 	virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
-	virtual void battleSpellCast(SpellCast *sc){};
+	virtual void battleSpellCast(BattleSpellCast *sc){};
 	virtual void battleStacksEffectsSet(SetStackEffect & sse){};//called when a specific effect is set to stacks
 	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
 	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning

+ 1 - 1
client/CBattleInterface.cpp

@@ -2621,7 +2621,7 @@ void CBattleInterface::displayBattleFinished()
 	GH.pushInt(resWindow);
 }
 
-void CBattleInterface::spellCast(SpellCast * sc)
+void CBattleInterface::spellCast(BattleSpellCast * sc)
 {
 	CSpell &spell = CGI->spellh->spells[sc->id];
 

+ 2 - 2
client/CBattleInterface.h

@@ -25,7 +25,7 @@ class AdventureMapButton;
 class CHighlightableButton;
 class CHighlightableButtonsGroup;
 struct BattleResult;
-struct SpellCast;
+struct BattleSpellCast;
 template <typename T> struct CondSh;
 struct SetStackEffect;;
 struct BattleAction;
@@ -505,7 +505,7 @@ public:
 	void battleFinished(const BattleResult& br); //called when battle is finished - battleresult window should be printed
 	const BattleResult * bresult; //result of a battle; if non-zero then display when all animations end
 	void displayBattleFinished(); //displays battle result
-	void spellCast(SpellCast * sc); //called when a hero casts a spell
+	void spellCast(BattleSpellCast * sc); //called when a hero casts a spell
 	void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
 	void castThisSpell(int spellID); //called when player has chosen a spell from spellbook
 	void displayEffect(ui32 effect, int destTile); //displays effect of a spell on the battlefield; affected: true - attacker. false - defender

+ 24 - 4
client/CPlayerInterface.cpp

@@ -717,7 +717,7 @@ void CPlayerInterface::battleStackMoved(int ID, int dest, int distance, bool end
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	battleInt->stackMoved(ID, dest, end, distance);
 }
-void CPlayerInterface::battleSpellCast(SpellCast *sc)
+void CPlayerInterface::battleSpellCast(BattleSpellCast *sc)
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -973,6 +973,7 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus
 	{
 		//recalculate paths because hero has lost bonus influencing pathfinding
 		cb->recalculatePaths();
+		eraseCurrentPathOf(hero, false);
 	}
 }
 
@@ -1011,7 +1012,9 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
 		enum TerrainTile::EterrainType newTerrain;
 		int sh = -1;
 
-		for(int i=path.nodes.size()-1; i>0 && stillMoveHero.data == CONTINUE_MOVE; i--)
+		const TerrainTile * curTile = cb->getTileInfo(CGHeroInstance::convertPosition(h->pos, false));
+
+		for(int i=path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || curTile->blocked); i--)
 		{
 			//stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points)
 			if(path.nodes[i-1].turns)
@@ -1042,6 +1045,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
 			bool guarded = CGI->mh->map->isInTheMap(cb->guardingCreaturePosition(endpos - int3(1, 0, 0)));
 
 			cb->moveHero(h,endpos);
+			curTile = cb->getTileInfo(endpos);
 
 			eventsM.unlock();
 			while(stillMoveHero.data != STOP_MOVE  &&  stillMoveHero.data != CONTINUE_MOVE)
@@ -1791,6 +1795,15 @@ void CPlayerInterface::showPuzzleMap()
 	GH.pushInt(new CPuzzleWindow(grailPos, ratio));
 }
 
+void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellID)
+{
+	if (spellID == Spells::FLY || spellID == Spells::WATER_WALK)
+	{
+		cb->recalculatePaths();
+		eraseCurrentPathOf(caster, false);
+	}
+}
+
 void SystemOptions::setMusicVolume( int newVolume )
 {
 	musicVolume = newVolume;
@@ -1851,9 +1864,16 @@ SystemOptions::SystemOptions()
 	showQueue = true;
 }
 
-void CPlayerInterface::eraseCurrentPathOf( const CGHeroInstance * ho )
+void CPlayerInterface::eraseCurrentPathOf( const CGHeroInstance * ho, bool checkForExistanceOfPath /*= true */ )
 {
-	assert(vstd::contains(paths, ho));
+	if(checkForExistanceOfPath)
+	{
+		assert(vstd::contains(paths, ho));
+	}
+	else if (!vstd::contains(paths, ho))
+	{
+		return;
+	}
 	assert(ho == adventureInt->selection);
 
 	paths.erase(ho);

+ 3 - 2
client/CPlayerInterface.h

@@ -161,6 +161,7 @@ public:
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd);
 	void showArtifactAssemblyDialog(ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList<void()> onYes, CFunctionList<void()> onNo);
 	void showPuzzleMap();
+	void advmapSpellCast(const CGHeroInstance * caster, int spellID); //called when a hero casts a spell
 	void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war
 	void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles
 	void newObject(const CGObjectInstance * obj);
@@ -187,7 +188,7 @@ public:
 	void battleNewRoundFirst(int round); //called at the beginning of each turn before changes are applied; used for HP regen handling
 	void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	void battleStackMoved(int ID, int dest, int distance, bool end);
-	void battleSpellCast(SpellCast *sc);
+	void battleSpellCast(BattleSpellCast *sc);
 	void battleStacksEffectsSet(SetStackEffect & sse); //called when a specific effect is set to stacks
 	void battleStacksAttacked(std::vector<BattleStackAttacked> & bsa);
 	void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
@@ -218,7 +219,7 @@ public:
 	void initMovement(const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp );//initializing objects and performing first step of move
 	void movementPxStep( const TryMoveHero &details, int i, const int3 &hp, const CGHeroInstance * ho );//performing step of movement
 	void finishMovement( const TryMoveHero &details, const int3 &hp, const CGHeroInstance * ho ); //finish movement
-	void eraseCurrentPathOf( const CGHeroInstance * ho );
+	void eraseCurrentPathOf( const CGHeroInstance * ho, bool checkForExistanceOfPath = true );
 	CGPath *getAndVerifyPath( const CGHeroInstance * h );
 	void acceptTurn(); //used during hot seat after your turn message is close
 	void tryDiggging(const CGHeroInstance *h);

+ 8 - 2
client/NetPacksClient.cpp

@@ -530,7 +530,7 @@ void StartAction::applyFirstCl( CClient *cl )
 		cl->playerint[GS(cl)->curB->side2]->actionStarted(&ba);
 }
 
-void SpellCast::applyCl( CClient *cl )
+void BattleSpellCast::applyCl( CClient *cl )
 {
 	if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
 		cl->playerint[GS(cl)->curB->side1]->battleSpellCast(this);
@@ -548,7 +548,7 @@ void SpellCast::applyCl( CClient *cl )
 
 void SetStackEffect::applyCl( CClient *cl )
 {
-	SpellCast sc;
+	BattleSpellCast sc;
 	sc.id = effect.id;
 	sc.side = 3; //doesn't matter
 	sc.skill = effect.level;
@@ -681,6 +681,12 @@ void ShowInInfobox::applyCl(CClient *cl)
 	}
 }
 
+
+void AdvmapSpellCast::applyCl(CClient *cl)
+{
+	cl->playerint[caster->getOwner()]->advmapSpellCast(caster, spellID);
+}
+
 void OpenWindow::applyCl(CClient *cl)
 {
 	switch(window)

+ 6 - 0
lib/CGameState.cpp

@@ -1771,6 +1771,12 @@ void CGameState::getNeighbours( const TerrainTile &srct, int3 tile, std::vector<
 
 		const TerrainTile &hlpt = map->getTile(hlp);
 
+		//we cannot visit things from blocked tiles
+		if(srct.blocked && hlpt.visitable)
+		{
+			continue;
+		}
+
 		if((indeterminate(onLand)  ||  onLand == (hlpt.tertype!=TerrainTile::water) ) 
 			&& hlpt.tertype != TerrainTile::rock) 
 		{

+ 15 - 2
lib/NetPacks.h

@@ -1041,9 +1041,9 @@ struct EndAction : public CPackForClient//3008
 	}
 };
 
-struct SpellCast : public CPackForClient//3009
+struct BattleSpellCast : public CPackForClient//3009
 {
-	SpellCast(){type = 3009;};
+	BattleSpellCast(){type = 3009;};
 	DLL_EXPORT void applyGs(CGameState *gs);
 	void applyCl(CClient *cl);
 
@@ -1164,6 +1164,19 @@ struct ShowInInfobox : public CPackForClient //107
 	}
 };
 
+struct AdvmapSpellCast : public CPackForClient //108
+{
+	AdvmapSpellCast(){type = 108;}
+	const CGHeroInstance * caster;
+	si32 spellID;
+
+	void applyCl(CClient *cl);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & caster & spellID;
+	}
+};
+
 
 /***********************************************************************************************************/
 

+ 1 - 1
lib/NetPacksLib.cpp

@@ -808,7 +808,7 @@ DLL_EXPORT void StartAction::applyGs( CGameState *gs )
 		st->state -= WAITING; //if stack was waiting it has made move, so it won't be "waiting" anymore (if the action was WAIT, then we have returned)
 }
 
-DLL_EXPORT void SpellCast::applyGs( CGameState *gs )
+DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
 {
 	assert(gs->curB);
 	CGHeroInstance *h = (side) ? gs->curB->heroes[1] : gs->curB->heroes[0];

+ 2 - 1
lib/RegisterTypes.cpp

@@ -111,7 +111,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<BattleAttack>();
 	s.template registerType<StartAction>();
 	s.template registerType<EndAction>();
-	s.template registerType<SpellCast>();
+	s.template registerType<BattleSpellCast>();
 	s.template registerType<SetStackEffect>();
 	s.template registerType<StacksInjured>();
 	s.template registerType<BattleResultsApplied>();
@@ -120,6 +120,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<CatapultAttack>();
 	s.template registerType<BattleStacksRemoved>();
 	s.template registerType<ShowInInfobox>();
+	s.template registerType<AdvmapSpellCast>();
 	s.template registerType<OpenWindow>();
 	s.template registerType<NewObject>();
 

+ 6 - 1
server/CGameHandler.cpp

@@ -3620,7 +3620,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
 {
 	CSpell *spell = &VLC->spellh->spells[spellID];
 
-	SpellCast sc;
+	BattleSpellCast sc;
 	sc.side = casterSide;
 	sc.id = spellID;
 	sc.skill = spellLvl;
@@ -4324,6 +4324,11 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
 	if(s->combatSpell)
 		COMPLAIN_RET("This function can be used only for adventure map spells!");
 
+	AdvmapSpellCast asc;
+	asc.caster = h;
+	asc.spellID = spellID;
+	sendAndApply(&asc);
+
 	using namespace Spells;
 	switch(spellID)
 	{