mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	* new movement cost calculation.
* fixed crashes on loading maps with flag all mines/dwelling victory condition * minor changes
This commit is contained in:
		| @@ -1067,7 +1067,7 @@ void CBattleLogic::PrintBattleAction(const BattleAction &action) // for debug pu | ||||
| 	std::cout << color; | ||||
| #endif | ||||
|  | ||||
| 	std::cout << message.c_str() << std::flush; | ||||
| 	std::cout << message.c_str() << std::endl; | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| 	SetConsoleTextAttribute(hConsole, csbi.wAttributes); | ||||
|   | ||||
| @@ -940,7 +940,7 @@ int CGameState::pickHero(int owner) | ||||
| } | ||||
| CGHeroInstance *CGameState::getHero(int objid) | ||||
| { | ||||
| 	if(objid<0 || objid>=map->objects.size()) | ||||
| 	if(objid<0 || objid>=map->objects.size() || map->objects[objid]->ID!=34) | ||||
| 		return NULL; | ||||
| 	return static_cast<CGHeroInstance *>(map->objects[objid]); | ||||
| } | ||||
| @@ -1706,6 +1706,98 @@ void CGameState::setObjProperty( SetObjectProperty * p ) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGameState::getNeighbours(int3 tile, std::vector<int3> &vec, bool onLand) | ||||
| { | ||||
| 	vec.clear(); | ||||
| 	int3 hlp; | ||||
| 	bool weAreOnLand = (map->getTile(tile).tertype != 8); | ||||
| 	if(tile.x > 0) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x-1,tile.y,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| 	if(tile.y > 0) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x,tile.y-1,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| 	if(tile.x > 0   &&   tile.y > 0) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x-1,tile.y-1,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| 	if(tile.x > 0   &&   tile.y < map->height-1) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x-1,tile.y+1,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| 	if(tile.y < map->height-1) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x,tile.y+1,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| 	if(tile.x < map->width-1) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x+1,tile.y,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| 	if(tile.x < map->width-1   &&   tile.y > 0) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x+1,tile.y-1,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| 	if(tile.x < map->width-1   &&   tile.y < map->height-1) | ||||
| 	{ | ||||
| 		hlp = int3(tile.x+1,tile.y+1,tile.z); | ||||
| 		if((weAreOnLand == map->getTile(hlp).tertype!=8) && map->getTile(hlp).tertype!=9)  | ||||
| 			vec.push_back(hlp); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int CGameState::getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, int remainingMovePoints, bool checkLast) | ||||
| { | ||||
| 	TerrainTile &s = map->terrain[src.x][src.y][src.z], | ||||
| 		&d = map->terrain[dest.x][dest.y][dest.z]; | ||||
|  | ||||
| 	//get basic cost | ||||
| 	int ret = h->getTileCost(d,s); | ||||
|  | ||||
| 	if(src.x!=dest.x && src.y!=dest.y) //diagonal move costs too much but normal move is possible | ||||
| 	{ | ||||
| 		int old = ret; | ||||
| 		ret *= 1.414; | ||||
| 		if(ret > remainingMovePoints  &&  remainingMovePoints > old) | ||||
| 		{ | ||||
| 			return remainingMovePoints; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	int left = remainingMovePoints-ret; | ||||
| 	if(checkLast  &&  left > 0  &&  remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points | ||||
| 	{ | ||||
| 		std::vector<int3> vec; | ||||
| 		getNeighbours(dest,vec,true); | ||||
| 		for(size_t i=0; i < vec.size(); i++) | ||||
| 		{ | ||||
| 			int fcost = getMovementCost(h,dest,vec[i],left,false); | ||||
| 			if(fcost <= left) | ||||
| 			{ | ||||
| 				return ret; | ||||
| 			} | ||||
| 		} | ||||
| 		ret = remainingMovePoints; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting) | ||||
| { | ||||
| 	int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0); | ||||
|   | ||||
| @@ -231,10 +231,8 @@ private: | ||||
| 	void randomizeObject(CGObjectInstance *cur); | ||||
| 	std::pair<int,int> pickObject(CGObjectInstance *obj); | ||||
| 	int pickHero(int owner); | ||||
|  | ||||
| 	CGHeroInstance *getHero(int objid); | ||||
| 	CGTownInstance *getTown(int objid); | ||||
|  | ||||
| 	bool battleMoveCreatureStack(int ID, int dest); | ||||
| 	bool battleAttackCreatureStack(int ID, int dest); | ||||
| 	bool battleShootCreatureStack(int ID, int dest); | ||||
| @@ -246,6 +244,8 @@ private: | ||||
| public: | ||||
| 	CGameState(); | ||||
| 	~CGameState(); | ||||
| 	void getNeighbours(int3 tile, std::vector<int3> &vec, bool onLand); | ||||
| 	int getMovementCost(const CGHeroInstance *h, int3 src, int3 dest, int remainingMovePoints=-1, bool checkLast=true); | ||||
| 	int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -178,11 +178,9 @@ void CPathfinder::convertPath(CPath * path, unsigned int mode) //mode=0 -> from | ||||
| } | ||||
|  | ||||
| void CPathfinder::processNode(CPathNode & dp, const CGHeroInstance * hero, std::queue<CPathNode> & mq, const CPathNode & cp, const int3 & src, bool diagonal) | ||||
| { | ||||
| {	 | ||||
| 	const TerrainTile * tinfo = CGI->mh->ttiles[dp.coord.x][dp.coord.y][src.z].tileInfo; | ||||
| 	int cost = hero->getTileCost(tinfo->tertype, tinfo->malle, tinfo->nuine, hero->movement - cp.dist); | ||||
| 	if(diagonal && (hero->movement - cp.dist) > 145) //second condition - workaround for strange behaviour manifested by Heroes III | ||||
| 		cost *= std::sqrt(2.0); | ||||
| 	int cost = CGI->state->getMovementCost(hero,cp.coord,dp.coord,hero->movement - cp.dist); | ||||
| 	if((dp.dist==-1 || (dp.dist > cp.dist + cost)) && dp.accesible && checkForVisitableDir(cp.coord, dp.coord) && checkForVisitableDir(dp.coord, cp.coord)) | ||||
| 	{ | ||||
| 		dp.dist = cp.dist + cost; | ||||
|   | ||||
| @@ -1106,7 +1106,7 @@ void MapSel::processGames(const std::vector<std::string> &pliczkiTemp) | ||||
| 		lf >> sign >> hlp; | ||||
| 		if(hlp != version) | ||||
| 		{ | ||||
| 			tlog3 << "\t" << pliczkiTemp[i] << " seems to be too " << ((hlp>version) ? "new" : "old") << " and will be ommited.\n"; | ||||
| 			tlog3 << "\t\t" << pliczkiTemp[i] << " seems to be too " << ((hlp>version) ? "new" : "old") << " and will be ommited.\n"; | ||||
| 			ourGames[i] = NULL; | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -1239,8 +1239,12 @@ void MapSel::init() | ||||
| 	processGames(pliczkiTemp); | ||||
| 	for (int i = 0; i < ourGames.size(); i++) | ||||
| 	{ | ||||
| 		ourGames[i]->date = datestemp[i]; | ||||
| 		if(ourGames[i]) | ||||
| 			ourGames[i]->date = datestemp[i]; | ||||
| 	} | ||||
| 	maps = std::remove_if(ourGames.begin(),ourGames.end(),isNull); | ||||
| 	ourGames.erase(maps,ourGames.end()); | ||||
| 	std::sort(ourGames.begin(),ourGames.end(),mapSorter(_name)); | ||||
| } | ||||
| void MapSel::moveByOne(bool up) | ||||
| { | ||||
|   | ||||
| @@ -19,7 +19,7 @@ ADVENTURE INTERFACE: | ||||
| * campfire, borderguard, bordergate, questguard will be accessible from the top  | ||||
|  | ||||
| BATTLES: | ||||
| * partial support for battle obstackles | ||||
| * partial support for battle obstacles | ||||
| * spells not known by hero can't be casted  | ||||
| * spell books won't be placed in War Machine slots after battle | ||||
| * attack is now possible when hex under cursor is not displayed  | ||||
|   | ||||
							
								
								
									
										2
									
								
								global.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								global.h
									
									
									
									
									
								
							| @@ -19,7 +19,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte) | ||||
| #define THC | ||||
| #endif | ||||
|  | ||||
| #define NAME_VER ("VCMI 0.7b") | ||||
| #define NAME_VER ("VCMI 0.7c") | ||||
| #define CONSOLE_LOGGING_LEVEL 5 | ||||
| #define FILE_LOGGING_LEVEL 6 | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| #include "../CGameState.h" | ||||
| #include "../lib/NetPacks.h" | ||||
| #include "../StartInfo.h" | ||||
| #include "../Map.h" | ||||
|  | ||||
| std::map<int,std::map<int, std::vector<int> > > CGTeleport::objs; | ||||
| IGameCallback * IObjectInterface::cb = NULL; | ||||
| @@ -196,72 +197,37 @@ int lowestSpeed(const CGHeroInstance * chi) | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| unsigned int CGHeroInstance::getTileCost(const EterrainType & ttype, const Eroad & rdtype, const Eriver & rvtype, const int & remaingMP) const | ||||
| unsigned int CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &from) const | ||||
| { | ||||
| 	if(remaingMP <= 100) return 100; //workaround for strange behaviour manifested by Heroes III | ||||
| 	unsigned int ret = type->heroClass->terrCosts[ttype]; | ||||
| 	//applying pathfinding skill | ||||
| 	switch(getSecSkillLevel(0)) | ||||
| 	{ | ||||
| 	case 1: //basic | ||||
| 		switch(ttype) | ||||
| 		{ | ||||
| 		case rough: | ||||
| 			ret = 100; | ||||
| 			break; | ||||
| 		case sand: case snow: | ||||
| 			if(ret>125) | ||||
| 				ret = 125; | ||||
| 			break; | ||||
| 		case swamp: | ||||
| 			if(ret>150) | ||||
| 				ret = 150; | ||||
| 			break; | ||||
|         default: | ||||
|             //TODO do something nasty here throw maybe? or some def value asing | ||||
|             break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case 2: //advanced | ||||
| 		switch(ttype) | ||||
| 		{ | ||||
| 		case rough:  | ||||
|                 case sand: | ||||
|                 case snow: | ||||
| 			ret = 100; | ||||
| 			break; | ||||
| 		case swamp: | ||||
| 			if(ret>125) | ||||
| 				ret = 125; | ||||
| 			break; | ||||
|         default: | ||||
|             //TODO look up | ||||
|             break; | ||||
| 		} | ||||
| 		break; | ||||
| 	case 3: //expert | ||||
| 		ret = 100; | ||||
| 		break; | ||||
|     default: | ||||
|         //TODO look up | ||||
|         break; | ||||
| 	} | ||||
| 	//TODO: check if all creatures are on its native terrain and change cost appropriately | ||||
|  | ||||
| 	//calculating road influence | ||||
| 	switch(rdtype) | ||||
| 	//base move cost | ||||
| 	unsigned ret = 100; | ||||
| 	 | ||||
| 	//if there is road both on dest and src tiles - use road movement cost | ||||
| 	if(dest.malle && from.malle)  | ||||
| 	{ | ||||
| 	case dirtRoad: | ||||
| 		ret*=0.75; | ||||
| 		break; | ||||
| 	case grazvelRoad: | ||||
| 		ret*=0.667; | ||||
| 		break; | ||||
| 	case cobblestoneRoad: | ||||
| 		ret*=0.5; | ||||
| 		break; | ||||
|     default: | ||||
|         //TODO killllll me | ||||
|         break; | ||||
| 		int road = std::min(dest.malle,from.malle); //used road ID | ||||
| 		switch(road) | ||||
| 		{ | ||||
| 		case dirtRoad: | ||||
| 			ret = 75; | ||||
| 			break; | ||||
| 		case grazvelRoad: | ||||
| 			ret = 65; | ||||
| 			break; | ||||
| 		case cobblestoneRoad: | ||||
| 			ret = 50; | ||||
| 			break; | ||||
| 		default: | ||||
| 			tlog1 << "Unknown road type: " << road << "... Something wrong!\n"; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	else  | ||||
| 	{ | ||||
| 		ret = std::max(type->heroClass->terrCosts[dest.tertype],type->heroClass->terrCosts[from.tertype]); //take cost of worse of two tiles | ||||
| 		ret = std::max(ret - 25*unsigned(getSecSkillLevel(0)), 100u); //reduce 25% of terrain penalty for each pathfinding level | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|   | ||||
| @@ -30,6 +30,7 @@ class CGTownInstance; | ||||
| class CArtifact; | ||||
| class CGDefInfo; | ||||
| class CSpecObjInfo; | ||||
| struct TerrainTile; | ||||
|  | ||||
| class DLL_EXPORT CCastleEvent | ||||
| { | ||||
| @@ -207,7 +208,7 @@ public: | ||||
| 	const HeroBonus *getBonus(int from, int id) const; | ||||
| 	const std::string &getBiography() const; | ||||
| 	bool needsLastStack()const; | ||||
| 	unsigned int getTileCost(const EterrainType & ttype, const Eroad & rdtype, const Eriver & rvtype, const int & remaingMP) const; | ||||
| 	unsigned int getTileCost(const TerrainTile &dest, const TerrainTile &from) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling | ||||
| 	unsigned int getLowestCreatureSpeed() const; | ||||
| 	unsigned int getAdditiveMoveBonus() const; | ||||
| 	float getMultiplicativeMoveBonus() const; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ | ||||
| #include <boost/mpl/identity.hpp> | ||||
|  | ||||
| #include <boost/type_traits/is_array.hpp> | ||||
| const ui32 version = 63; | ||||
| const ui32 version = 703; | ||||
| class CConnection; | ||||
|  | ||||
| namespace mpl = boost::mpl; | ||||
|   | ||||
							
								
								
									
										16
									
								
								map.cpp
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								map.cpp
									
									
									
									
									
								
							| @@ -359,7 +359,7 @@ void CMapHeader::loadViCLossConditions( unsigned char * bufor, int &i) | ||||
| 			{ | ||||
| 				victoryCondition.ID = bufor[i+2]; | ||||
| 				victoryCondition.count = readNormalNr(bufor, i+3); | ||||
| 				nr=5; | ||||
| 				nr = 5; | ||||
| 				break; | ||||
| 			} | ||||
| 		case buildCity: | ||||
| @@ -369,7 +369,7 @@ void CMapHeader::loadViCLossConditions( unsigned char * bufor, int &i) | ||||
| 				victoryCondition.pos.z = bufor[i+4]; | ||||
| 				victoryCondition.count = bufor[i+5]; | ||||
| 				victoryCondition.ID = bufor[i+6]; | ||||
| 				nr=5; | ||||
| 				nr = 5; | ||||
| 				break; | ||||
| 			} | ||||
| 		case buildGrail: | ||||
| @@ -382,7 +382,7 @@ void CMapHeader::loadViCLossConditions( unsigned char * bufor, int &i) | ||||
| 					victoryCondition.pos.y = bufor[i+3]; | ||||
| 					victoryCondition.pos.z = bufor[i+4]; | ||||
| 				} | ||||
| 				nr=3; | ||||
| 				nr = 3; | ||||
| 				break; | ||||
| 			} | ||||
| 		case beatHero: | ||||
| @@ -392,13 +392,13 @@ void CMapHeader::loadViCLossConditions( unsigned char * bufor, int &i) | ||||
| 				victoryCondition.pos.x = bufor[i+2]; | ||||
| 				victoryCondition.pos.y = bufor[i+3]; | ||||
| 				victoryCondition.pos.z = bufor[i+4]; | ||||
| 				nr=3; | ||||
| 				nr = 3; | ||||
| 				break; | ||||
| 			} | ||||
| 		case takeDwellings: | ||||
| 		case takeMines: | ||||
| 			{ | ||||
| 				nr=3; | ||||
| 				nr = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 		case transportItem: | ||||
| @@ -407,7 +407,7 @@ void CMapHeader::loadViCLossConditions( unsigned char * bufor, int &i) | ||||
| 				victoryCondition.pos.x = bufor[i+3]; | ||||
| 				victoryCondition.pos.y = bufor[i+4]; | ||||
| 				victoryCondition.pos.z = bufor[i+5]; | ||||
| 				nr=4; | ||||
| 				nr = 4; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| @@ -1954,6 +1954,10 @@ void Mapa::loadQuest(CQuest * guard, unsigned char * bufor, int & i) | ||||
| 	guard->completedText = readString(bufor,i); | ||||
| } | ||||
|  | ||||
| TerrainTile & Mapa::getTile( int3 tile ) | ||||
| { | ||||
| 	return terrain[tile.x][tile.y][tile.z]; | ||||
| } | ||||
| void CMapInfo::countPlayers() | ||||
| { | ||||
| 	playerAmnt=humenPlayers=0; | ||||
|   | ||||
							
								
								
									
										1
									
								
								map.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								map.h
									
									
									
									
									
								
							| @@ -326,6 +326,7 @@ struct DLL_EXPORT Mapa : public CMapHeader | ||||
| 	Mapa(std::string filename); //creates map structure from .h3m file | ||||
| 	Mapa(); | ||||
| 	~Mapa(); | ||||
| 	TerrainTile &getTile(int3 tile); | ||||
| 	CGHeroInstance * getHero(int ID, int mode=0); | ||||
| 	bool isInTheMap(int3 pos); | ||||
| 	template <typename TObject, typename Handler> void serializeObj(Handler &h, const int version, TObject ** obj) | ||||
|   | ||||
| @@ -495,9 +495,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c) | ||||
| 					int3 hmpos = end + int3(-1,0,0); | ||||
| 					TerrainTile t = gs->map->terrain[hmpos.x][hmpos.y][hmpos.z]; | ||||
| 					CGHeroInstance *h = static_cast<CGHeroInstance *>(gs->map->objects[id]); | ||||
| 					double dist = distance(start,end); | ||||
| 					if(h->movement <= 145) dist = 1.0f; //workaround for strange behaviour manifested by Heroes III | ||||
| 					int cost = (int)((double)h->getTileCost(t.tertype,t.malle,t.nuine, h->movement) * dist); | ||||
| 					int cost = gs->getMovementCost(h,start,end,h->movement); | ||||
|  | ||||
| 					TryMoveHero tmh; | ||||
| 					tmh.id = id; | ||||
| @@ -508,7 +506,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c) | ||||
|  | ||||
| 					if((h->getOwner() != gs->currentPlayer) //not turn of that hero | ||||
| 						|| (distance(start,end)>=1.5) //tiles are not neighouring | ||||
| 						|| (h->movement < cost) //lack of movement points | ||||
| 						|| (h->movement < cost  &&  h->movement < 100) //lack of movement points | ||||
| 						|| (t.tertype == rock)  //rock | ||||
| 						|| (!h->canWalkOnSea() && t.tertype == water) | ||||
| 						|| (t.blocked && !t.visitable) //tile is blocked andnot visitable | ||||
| @@ -518,7 +516,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c) | ||||
| 					 | ||||
| 					//check if there is blocking visitable object | ||||
| 					blockvis = false; | ||||
| 					tmh.movePoints = h->movement = (h->movement-cost); //take move points | ||||
| 					tmh.movePoints = h->movement = std::max(si32(0),h->movement-cost); //take move points | ||||
| 					BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects) | ||||
| 					{ | ||||
| 						if(obj->blockVisit) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user