1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +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:
Michał W. Urbańczyk 2009-02-12 14:44:58 +00:00
parent efc43e87a8
commit b2924064ee
13 changed files with 152 additions and 88 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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
View File

@ -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
View File

@ -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)

View File

@ -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)