mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +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:
parent
efc43e87a8
commit
b2924064ee
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user