mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	* new spell: remove obstacle
* minor changes
This commit is contained in:
		| @@ -120,6 +120,7 @@ public: | ||||
| 	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning | ||||
| 	virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp | ||||
| 	virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned | ||||
| 	virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set  of obstacles is removed from batlefield; IDs of them are given | ||||
| }; | ||||
| class CAIHandler | ||||
| { | ||||
|   | ||||
| @@ -848,7 +848,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 			//get dead stack if we cast resurrection or animate dead | ||||
| 			const CStack * stackUnder = LOCPLINT->cb->battleGetStackByPos(myNumber, spellToCast->additionalInfo != 38 && spellToCast->additionalInfo != 39); | ||||
|  | ||||
| 			if(stackUnder && spellToCast->additionalInfo == 39 && !stackUnder->hasFeatureOfType(StackFeature::UNDEAD)) //animate dead can be cast only on living creatures | ||||
| 			if(stackUnder && spellToCast->additionalInfo == 39 && !stackUnder->hasFeatureOfType(StackFeature::UNDEAD)) //animate dead can be cast only on undead creatures | ||||
| 				stackUnder = NULL; | ||||
|  | ||||
| 			bool whichCase; //for cases 1, 2 and 3 | ||||
| @@ -896,6 +896,14 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 				} | ||||
| 				break; | ||||
| 			case 4: //TODO: implement this case | ||||
| 				if( blockedByObstacle(myNumber) ) | ||||
| 				{ | ||||
| 					CGI->curh->changeGraphic(3, 0); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					CGI->curh->changeGraphic(1, 0); | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| @@ -1520,6 +1528,19 @@ bool CBattleInterface::isTileAttackable(const int & number) const | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool CBattleInterface::blockedByObstacle(int hex) const | ||||
| { | ||||
| 	std::vector<CObstacleInstance> obstacles = LOCPLINT->cb->battleGetAllObstacles(); | ||||
| 	std::set<int> coveredHexes; | ||||
| 	for(int b = 0; b < obstacles.size(); ++b) | ||||
| 	{ | ||||
| 		std::vector<int> blocked = CGI->heroh->obstacles[obstacles[b].ID].getBlocked(obstacles[b].pos); | ||||
| 		for(int w = 0; w < blocked.size(); ++w) | ||||
| 			coveredHexes.insert(blocked[w]); | ||||
| 	} | ||||
| 	return vstd::contains(coveredHexes, hex); | ||||
| } | ||||
|  | ||||
| void CBattleInterface::handleEndOfMove(int stackNumber, int destinationTile) | ||||
| { | ||||
| 	const CStack * movedStack = LOCPLINT->cb->battleGetStackByID(stackNumber); | ||||
| @@ -1575,7 +1596,9 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 				if(!LOCPLINT->cb->battleGetStackByPos(whichOne, onlyAlive)) | ||||
| 					allowCasting = false; | ||||
| 				break; | ||||
| 			case 4: //TODO: implement this case | ||||
| 			case 4: | ||||
| 				if(!blockedByObstacle(whichOne)) | ||||
| 					allowCasting = false; | ||||
| 				break; | ||||
| 			} | ||||
| 			//destination checked | ||||
| @@ -1971,6 +1994,10 @@ void CBattleInterface::castThisSpell(int spellID) | ||||
| 			spellSelMode = -1; | ||||
| 		} | ||||
| 	} | ||||
| 	if(CGI->spellh->spells[spellID].attributes.find("OBSTACLE_TARGET") != std::string::npos) //spell to be cast on an obstacle | ||||
| 	{ | ||||
| 		spellSelMode = 4; | ||||
| 	} | ||||
| 	if(spellSelMode == -1) //user does not have to select location | ||||
| 	{ | ||||
| 		spellToCast->destinationTile = -1; | ||||
|   | ||||
| @@ -214,6 +214,7 @@ private: | ||||
| 	void projectileShowHelper(SDL_Surface * to); //prints projectiles present on the battlefield | ||||
| 	void giveCommand(ui8 action, ui16 tile, ui32 stack, si32 additional=-1); | ||||
| 	bool isTileAttackable(const int & number) const; //returns true if tile 'number' is neighbouring any tile from active stack's range or is one of these tiles | ||||
| 	bool blockedByObstacle(int hex) const; | ||||
|  | ||||
| 	void handleEndOfMove(int stackNumber, int destinationTile); //helper function | ||||
|  | ||||
| @@ -237,7 +238,7 @@ public: | ||||
| 	int getAnimSpeed() const; //speed of animation; 1 - slowest, 2 - medium, 4 - fastest | ||||
|  | ||||
| 	CBattleHex bfield[BFIELD_SIZE]; //11 lines, 17 hexes on each | ||||
| 	std::vector< CBattleObstacle * > obstacles; //vector of obstacles on the battlefield | ||||
| 	//std::vector< CBattleObstacle * > obstacles; //vector of obstacles on the battlefield | ||||
| 	SDL_Surface * cellBorder, * cellShade; | ||||
| 	CondSh<BattleAction *> *givenCommand; //data != NULL if we have i.e. moved current unit | ||||
| 	bool myTurn; //if true, interface is active (commands can be ordered | ||||
|   | ||||
| @@ -981,6 +981,23 @@ void CPlayerInterface::battleNewStackAppeared(int stackID) | ||||
| 	battleInt->newStack(stackID); | ||||
| } | ||||
|  | ||||
| void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObstacles) | ||||
| { | ||||
| 	for(std::set<si32>::const_iterator it = removedObstacles.begin(); it != removedObstacles.end(); ++it) | ||||
| 	{ | ||||
| 		for(std::map< int, CDefHandler * >::iterator itBat = battleInt->idToObstacle.begin(); itBat != battleInt->idToObstacle.end(); ++itBat) | ||||
| 		{ | ||||
| 			if(itBat->first == *it) //remove this obstacle | ||||
| 			{ | ||||
| 				battleInt->idToObstacle.erase(itBat); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	//update accessible hexes | ||||
| 	battleInt->redrawBackgroundWithHexes(battleInt->activeStack); | ||||
| } | ||||
|  | ||||
| void CPlayerInterface::battleNewRound(int round) //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn | ||||
| { | ||||
| 	boost::unique_lock<boost::recursive_mutex> un(*pim); | ||||
|   | ||||
| @@ -179,6 +179,7 @@ public: | ||||
| 	void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning | ||||
| 	void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks); //called when stacks are healed / resurrected | ||||
| 	void battleNewStackAppeared(int stackID); //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned | ||||
| 	void battleObstaclesRemoved(const std::set<si32> & removedObstacles); //called when a certain set  of obstacles is removed from batlefield; IDs of them are given | ||||
|  | ||||
| 	//-------------// | ||||
| 	void heroKilled(const CGHeroInstance* hero); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| #define __FONTBASE_H__ | ||||
|  | ||||
| /* | ||||
|  * Graphics.h, part of VCMI engine | ||||
|  * FontBase.h, part of VCMI engine | ||||
|  * | ||||
|  * Authors: listed in file AUTHORS in main folder | ||||
|  * | ||||
|   | ||||
| @@ -462,6 +462,13 @@ void StacksHealedOrResurrected::applyCl( CClient *cl ) | ||||
| 	INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleStacksHealedRes, shiftedHealed); | ||||
| } | ||||
|  | ||||
| void ObstaclesRemoved::applyCl( CClient *cl ) | ||||
| { | ||||
| 	//inform interfaces about removed obstacles | ||||
| 	INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1, battleObstaclesRemoved, obstacles); | ||||
| 	INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleObstaclesRemoved, obstacles); | ||||
| } | ||||
|  | ||||
| CGameState* CPackForClient::GS( CClient *cl ) | ||||
| { | ||||
| 	return cl->gs; | ||||
|   | ||||
| @@ -4035,10 +4035,11 @@ void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const | ||||
|  | ||||
| void CCartographer::onHeroVisit( const CGHeroInstance * h ) const  | ||||
| { | ||||
| 	if (!hasVisited (h->getOwner()) ) | ||||
| 	if (!hasVisited (h->getOwner()) ) //if hero has not visited yet this cartographer | ||||
| 	{ | ||||
| 		if (cb->getResource(h->tempOwner, 6) >= 1000) | ||||
| 		if (cb->getResource(h->tempOwner, 6) >= 1000) //if he can afford a map | ||||
| 		{ | ||||
| 			//ask if he wants to buy one | ||||
| 			int text; | ||||
| 			if (cb->getTile(pos)->tertype == 8) //water | ||||
| 					text = 25; | ||||
| @@ -4055,7 +4056,7 @@ void CCartographer::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 			bd.text.addTxt (MetaString::ADVOB_TXT, text); | ||||
| 			cb->showBlockingDialog (&bd, boost::bind (&CCartographer::buyMap, this, h, _1)); | ||||
| 		} | ||||
| 		else | ||||
| 		else //if he cannot afford | ||||
| 		{ | ||||
| 			InfoWindow iw; | ||||
| 			iw.player = h->getOwner(); | ||||
| @@ -4064,7 +4065,7 @@ void CCartographer::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 			cb->showInfoDialog (&iw); | ||||
| 		} | ||||
| 	}	 | ||||
| 	else | ||||
| 	else //if he already visited carographer | ||||
| 	{ | ||||
| 		InfoWindow iw; | ||||
| 		iw.player = h->getOwner(); | ||||
| @@ -4073,9 +4074,10 @@ void CCartographer::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 		cb->showInfoDialog (&iw); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CCartographer::buyMap (const CGHeroInstance *h, ui32 accept) const | ||||
| { | ||||
| 	if (accept) | ||||
| 	if (accept) //if hero wants to buy map | ||||
| 	{ | ||||
| 		cb->giveResource (h->tempOwner, 6, -1000); | ||||
| 		FoWChange fw; | ||||
| @@ -4090,8 +4092,9 @@ void CCartographer::buyMap (const CGHeroInstance *h, ui32 accept) const | ||||
| 		else | ||||
| 			floor = 2; | ||||
|  | ||||
| 		//reveal apropriate tiles | ||||
| 		cb->getAllTiles (fw.tiles, h->tempOwner, floor, surface); | ||||
| 		cb->sendAndApply (&fw); | ||||
| 		cb->setObjProperty (id, 10, h->tempOwner); | ||||
| 	} | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -96,11 +96,12 @@ public: | ||||
|  | ||||
| struct DLL_EXPORT CObstacleInstance | ||||
| { | ||||
| 	int ID; //ID of obstacle | ||||
| 	int uniqueID; | ||||
| 	int ID; //ID of obstacle (defines type of it) | ||||
| 	int pos; //position on battlefield | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & ID & pos; | ||||
| 		h & ID & pos & uniqueID; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -977,6 +977,21 @@ struct StacksHealedOrResurrected : public CPackForClient //3013 | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct ObstaclesRemoved : public CPackForClient //3014 | ||||
| { | ||||
| 	ObstaclesRemoved(){type = 3014;} | ||||
|  | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
| 	void applyCl(CClient *cl); | ||||
|  | ||||
| 	std::set<si32> obstacles; //uniqueIDs of removed obstacles | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & obstacles; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct ShowInInfobox : public CPackForClient //107 | ||||
| { | ||||
| 	ShowInInfobox(){type = 107;}; | ||||
|   | ||||
| @@ -1013,6 +1013,24 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs ) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| DLL_EXPORT void ObstaclesRemoved::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	if(gs->curB) //if there is a battle | ||||
| 	{ | ||||
| 		for(std::set<si32>::const_iterator it = obstacles.begin(); it != obstacles.end(); ++it) | ||||
| 		{ | ||||
| 			for(int i=0; i<gs->curB->obstacles.size(); ++i) | ||||
| 			{ | ||||
| 				if(gs->curB->obstacles[i].uniqueID == *it) //remove this obstacle | ||||
| 				{ | ||||
| 					gs->curB->obstacles.erase(gs->curB->obstacles.begin() + i); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| DLL_EXPORT void YourTurn::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	gs->currentPlayer = player; | ||||
|   | ||||
| @@ -104,6 +104,7 @@ void registerTypes2(Serializer &s) | ||||
| 	s.template registerType<StacksInjured>(); | ||||
| 	s.template registerType<BattleResultsApplied>(); | ||||
| 	s.template registerType<StacksHealedOrResurrected>(); | ||||
| 	s.template registerType<ObstaclesRemoved>(); | ||||
| 	s.template registerType<ShowInInfobox>(); | ||||
| 	s.template registerType<OpenWindow>(); | ||||
| 	s.template registerType<NewObject>(); | ||||
|   | ||||
| @@ -1014,6 +1014,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 		while(toBlock>0) | ||||
| 		{ | ||||
| 			CObstacleInstance coi; | ||||
| 			coi.uniqueID = curB->obstacles.size(); | ||||
| 			coi.ID = possibleObstacles[rand()%possibleObstacles.size()]; | ||||
| 			coi.pos = rand()%BFIELD_SIZE; | ||||
| 			std::vector<int> block = VLC->heroh->obstacles[coi.ID].getBlocked(coi.pos); | ||||
| @@ -2869,6 +2870,23 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) | ||||
| 						sendAndApply(&shr); | ||||
| 					break; | ||||
| 				} | ||||
| 			case 64: //remove obstacle | ||||
| 				{ | ||||
| 					ObstaclesRemoved obr; | ||||
| 					for(int g=0; g<gs->curB->obstacles.size(); ++g) | ||||
| 					{ | ||||
| 						std::vector<int> blockedHexes = VLC->heroh->obstacles[gs->curB->obstacles[g].ID].getBlocked(gs->curB->obstacles[g].pos); | ||||
|  | ||||
| 						if(vstd::contains(blockedHexes, ba.destinationTile)) //this obstacle covers given hex | ||||
| 						{ | ||||
| 							obr.obstacles.insert(gs->curB->obstacles[g].uniqueID); | ||||
| 						} | ||||
| 					} | ||||
| 					if(!obr.obstacles.empty()) | ||||
| 						sendAndApply(&obr); | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			sendAndApply(&EndAction()); | ||||
| 			return true; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user