1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge branch 'develop' of https://github.com/vcmi/vcmi into test/advMapFading

This commit is contained in:
Fay 2015-02-01 19:12:03 +01:00
commit 4c636c15e9
16 changed files with 268 additions and 95 deletions

View File

@ -12,7 +12,7 @@ before_install:
#new Qt
- sudo add-apt-repository --yes ppa:beineri/opt-qt532
#new FFmpeg
- sudo add-apt-repository --yes ppa:djcj/vlc-stable
- sudo add-apt-repository --yes ppa:jon-severinsson/ffmpeg
#new CMake
- sudo add-apt-repository --yes ppa:andykimpe/cmake

View File

@ -496,9 +496,19 @@ void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
NET_EVENT_HANDLER;
if(sop->what == ObjProperty::OWNER)
{
//we don't want to visit know object twice (do we really?)
if(sop->val == playerID.getNum())
erase_if_present(visitableObjs, myCb->getObj(sop->id));
//TODO restore lost obj
else if (myCb->getPlayerRelations(playerID, (PlayerColor)sop->val) == PlayerRelations::ENEMIES)
{
//we want to visit objects owned by oppponents
auto obj = myCb->getObj(sop->id, false);
if (obj)
{
visitableObjs.insert(obj);
erase_if_present(alreadyVisited, obj);
}
}
}
}

View File

@ -1,4 +1,6 @@
0.97 -> 0.98
ADVENTURE MAP:
* Implemented world veiw
SPELLS:
* implemented CURE spell negative dispell effect
@ -8,6 +10,7 @@ BATTLES:
* Implemented OH3 stack split / upgrade formulas according to AlexSpl
RANDOM MAP GENERATOR:
* Implemented "junction" zone type
* Improved zone placing algorithm
* More balanced distribution of treasure piles
* More obstacles within zones

View File

@ -2317,7 +2317,10 @@ void OptionsTab::nextCastle( PlayerColor player, int dir )
}
if(s.hero >= 0 && !SEL->current->mapHeader->players[s.color.getNum()].hasCustomMainHero()) // remove hero unless it set to fixed one in map editor
{
usedHeroes.erase(s.hero); // restore previously selected hero back to available pool
s.hero = PlayerSettings::RANDOM;
}
if(cur < 0 && s.bonus == PlayerSettings::RESOURCE)
s.bonus = PlayerSettings::RANDOM;
@ -2352,7 +2355,7 @@ void OptionsTab::nextHero( PlayerColor player, int dir )
if(dir > 0)
s.hero = nextAllowedHero(player, s.hero, CGI->heroh->heroes.size(), 1, dir);
else
s.hero = nextAllowedHero(player, 0, s.hero, 1, dir);
s.hero = nextAllowedHero(player, -1, s.hero, 1, dir); // min needs to be -1 -- hero at index 0 would be skipped otherwise
}
if(old != s.hero)
@ -2530,6 +2533,7 @@ void OptionsTab::flagPressed( PlayerColor color )
usedHeroes.erase(old->hero);
old->hero = entries[old->color]->pi.defaultHero();
entries[old->color]->update(); // update previous frame images in case entries were auto-updated
}
SEL->propagateOptions();

View File

@ -261,7 +261,7 @@ bool CVideoPlayer::nextFrame()
if (doLoop && !gotError)
{
// Rewind
if (av_seek_frame(format, stream, 0, 0) < 0)
if (av_seek_frame(format, stream, 0, AVSEEK_FLAG_BYTE) < 0)
break;
gotError = true;
}

View File

@ -30,7 +30,7 @@ public:
class CEmptyVideoPlayer : public IMainVideoPlayer
{
public:
public:
int curFrame() const override {return -1;};
int frameCount() const override {return -1;};
void redraw( int x, int y, SDL_Surface *dst, bool update = true ) override {};
@ -54,6 +54,18 @@ public:
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
// compatibility with different versions od libavutil
#if (LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 42, 0)) || \
(LIBAVUTIL_VERSION_INT == AV_VERSION_INT(51, 73, 101))
#define AV_PIX_FMT_NONE PIX_FMT_NONE
#define AV_PIX_FMT_NV12 PIX_FMT_NV12
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
#define AV_PIX_FMT_UYVY422 PIX_FMT_UYVY422
#define AV_PIX_FMT_YUYV422 PIX_FMT_YUYV422
#endif
}
class CVideoPlayer : public IMainVideoPlayer

View File

@ -1788,14 +1788,19 @@ void CBattleInterface::getPossibleActionsForStack(const CStack * stack)
void CBattleInterface::printConsoleAttacked( const CStack * defender, int dmg, int killed, const CStack * attacker, bool multiple )
{
boost::format txt;
std::string formattedText;
if (attacker) //ignore if stacks were killed by spell
{
txt = boost::format (CGI->generaltexth->allTexts[attacker->count > 1 ? 377 : 376]) %
boost::format txt = boost::format (CGI->generaltexth->allTexts[attacker->count > 1 ? 377 : 376]) %
(attacker->count > 1 ? attacker->getCreature()->namePl : attacker->getCreature()->nameSing) % dmg;
formattedText.append(boost::to_string(txt));
}
if(killed > 0)
{
if (attacker)
formattedText.append(" ");
boost::format txt;
if(killed > 1)
{
txt = boost::format (CGI->generaltexth->allTexts[379]) % killed % (multiple ? CGI->generaltexth->allTexts[43] : defender->getCreature()->namePl); // creatures perish
@ -1804,9 +1809,12 @@ void CBattleInterface::printConsoleAttacked( const CStack * defender, int dmg, i
{
txt = boost::format (CGI->generaltexth->allTexts[378]) % (multiple ? CGI->generaltexth->allTexts[42] : defender->getCreature()->nameSing); // creature perishes
}
std::string trimmed = boost::to_string(txt);
boost::algorithm::trim(trimmed); // these default h3 texts have unnecessary new lines, so get rid of them before displaying
formattedText.append(trimmed);
}
console->addText(formattedText);
console->addText(boost::to_string (txt));
}

View File

@ -713,11 +713,11 @@ void CMapHandler::CMapWorldViewBlitter::init(const MapDrawingInfo * drawingInfo)
tileSize = (int) floorf(32.0f * info->scale);
halfTileSizeCeil = (int)ceilf(tileSize / 2.0f);
tileCount.x = (int) ceilf((float)info->drawBounds->w / tileSize) + 1;
tileCount.y = (int) ceilf((float)info->drawBounds->h / tileSize) + 1;
tileCount.x = (int) ceilf((float)info->drawBounds->w / tileSize);
tileCount.y = (int) ceilf((float)info->drawBounds->h / tileSize);
initPos.x = parent->offsetX + info->drawBounds->x;
initPos.y = parent->offsetY + info->drawBounds->y;
initPos.x = info->drawBounds->x;
initPos.y = info->drawBounds->y;
realTileRect = Rect(initPos.x, initPos.y, tileSize, tileSize);
defaultTileRect = Rect(0, 0, tileSize, tileSize);
@ -732,8 +732,9 @@ SDL_Rect CMapHandler::CMapWorldViewBlitter::clip(SDL_Surface * targetSurf) const
SDL_FillRect(targetSurf, info->drawBounds, SDL_MapRGB(targetSurf->format, 0, 0, 0));
// makes the clip area smaller if the map is smaller than the screen frame
Rect clipRect(std::max(info->drawBounds->x, -topTile.x * tileSize),
std::max(info->drawBounds->y, -topTile.y * tileSize),
// (actually, it could be made 1 tile bigger so that overlay icons on edge tiles could be drawn partly outside)
Rect clipRect(std::max(info->drawBounds->x, info->drawBounds->x - topTile.x * tileSize),
std::max(info->drawBounds->y, info->drawBounds->y - topTile.y * tileSize),
std::min(info->drawBounds->w, parent->sizes.x * tileSize),
std::min(info->drawBounds->h, parent->sizes.y * tileSize));
SDL_GetClipRect(targetSurf, &prevClip);

View File

@ -12,6 +12,7 @@
#include "../CPlayerInterface.h"
#include "../CPreGame.h"
#include "../Graphics.h"
#include "../CMessage.h"
#include "../gui/CGuiHandler.h"
#include "../gui/SDL_Pixels.h"
@ -1234,6 +1235,11 @@ CAdvMapPanel::CAdvMapPanel(SDL_Surface * bg, Point position)
recActions = 255;
pos.x += position.x;
pos.y += position.y;
if (bg)
{
pos.w = bg->w;
pos.h = bg->h;
}
}
CAdvMapPanel::~CAdvMapPanel()
@ -1270,13 +1276,26 @@ void CAdvMapPanel::addChildToPanel(CIntObject * obj, ui8 actions /* = 0 */)
addChild(obj, false);
}
CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(SDL_Surface * bg, Point position)
: CAdvMapPanel(bg, position)
CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color)
: CAdvMapPanel(bg, position)
{
fillerHeight = bg ? spaceBottom - pos.y - pos.h : 0;
if (fillerHeight > 0)
{
tmpBackgroundFiller = CMessage::drawDialogBox(pos.w, fillerHeight, color);
}
else
tmpBackgroundFiller = nullptr;
}
void CAdvMapWorldViewPanel::recolorIcons(const CDefHandler *def, int indexOffset)
CAdvMapWorldViewPanel::~CAdvMapWorldViewPanel()
{
if (tmpBackgroundFiller)
SDL_FreeSurface(tmpBackgroundFiller);
}
void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor &color, const CDefHandler *def, int indexOffset)
{
for (auto &pic : currentIcons)
{
@ -1292,6 +1311,13 @@ void CAdvMapWorldViewPanel::recolorIcons(const CDefHandler *def, int indexOffset
currentIcons.push_back(pic);
addChildToPanel(pic);
}
if (fillerHeight > 0)
{
if (tmpBackgroundFiller)
SDL_FreeSurface(tmpBackgroundFiller);
tmpBackgroundFiller = CMessage::drawDialogBox(pos.w, fillerHeight, color);
}
}
void CAdvMapWorldViewPanel::addChildIcon(std::pair<int, Point> data, const CDefHandler *def, int indexOffset)
@ -1301,3 +1327,13 @@ void CAdvMapWorldViewPanel::addChildIcon(std::pair<int, Point> data, const CDefH
currentIcons.push_back(pic);
addChildToPanel(pic);
}
void CAdvMapWorldViewPanel::showAll(SDL_Surface * to)
{
if (tmpBackgroundFiller)
{
blitAt(tmpBackgroundFiller, pos.x, pos.y + pos.h, to);
}
CAdvMapPanel::showAll(to);
}

View File

@ -341,13 +341,17 @@ class CAdvMapWorldViewPanel : public CAdvMapPanel
std::vector<std::pair<int, Point>> iconsData;
/// ptrs to child-pictures constructed from iconsData
std::vector<CPicture *> currentIcons;
/// temporary surface drawn below world view panel on higher resolutions (won't be needed when world view panel is configured for extraResolutions mod)
SDL_Surface * tmpBackgroundFiller;
int fillerHeight;
public:
CAdvMapWorldViewPanel(SDL_Surface * bg, Point position);
virtual ~CAdvMapWorldViewPanel(){}
CAdvMapWorldViewPanel(SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color);
virtual ~CAdvMapWorldViewPanel();
void addChildIcon(std::pair<int, Point> data, const CDefHandler *def, int indexOffset);
/// recreates all pictures from given def to recolor them according to current player color
void recolorIcons(const CDefHandler *def, int indexOffset);
void recolorIcons(const PlayerColor &color, const CDefHandler *def, int indexOffset);
void showAll(SDL_Surface * to);
};
class CInGameConsole : public CIntObject

View File

@ -239,17 +239,20 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
{
const CGHeroInstance *srcHero = commonInfo->src.AOH->getHero();
artSelected = true;
ArtifactLocation src(srcHero, commonInfo->src.slotID);
ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT);
if (art->canBePutAt(dst, true))
{ //equip clicked stack
if(dst.getArt())
{
//creature can wear only one active artifact
//if we are placing a new one, the old one will be returned to the hero's backpack
LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero)));
if (myStack) // try dropping the artifact only if the slot isn't empty
{
ArtifactLocation src(srcHero, commonInfo->src.slotID);
ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT);
if (art->canBePutAt(dst, true))
{ //equip clicked stack
if(dst.getArt())
{
//creature can wear only one active artifact
//if we are placing a new one, the old one will be returned to the hero's backpack
LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero)));
}
LOCPLINT->cb->swapArtifacts(src, dst);
}
LOCPLINT->cb->swapArtifacts(src, dst);
}
}
}

View File

@ -499,8 +499,11 @@ CAdvMapInt::CAdvMapInt():
nextHero = makeButton(301, std::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h);
endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e);
int panelSpaceBottom = screen->h - resdatabar.pos.h - 4;
panelMain = new CAdvMapPanel(nullptr, Point(0, 0));
panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195)); // TODO correct drawing position
// TODO correct drawing position
panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID);
panelMain->addChildColorableButton(kingOverview);
panelMain->addChildColorableButton(underground);
@ -1072,6 +1075,10 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
if(isActive())
LOCPLINT->showPuzzleMap();
return;
case SDLK_v:
if(isActive())
LOCPLINT->viewWorldMap();
return;
case SDLK_r:
if(isActive() && LOCPLINT->ctrlPressed())
{
@ -1331,7 +1338,7 @@ void CAdvMapInt::setPlayer(PlayerColor Player)
panelMain->setPlayerColor(player);
panelWorldView->setPlayerColor(player);
panelWorldView->recolorIcons(worldViewIconsDef, player.getNum() * 19);
panelWorldView->recolorIcons(player, worldViewIconsDef, player.getNum() * 19);
graphics->blueToPlayersAdv(resdatabar.bg,player);
//heroList.updateHList();
@ -1791,8 +1798,7 @@ void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale /* = 0.4f */)
else if (worldViewScale != newScale) // still in world view mode, but the scale changed
{
worldViewScale = newScale;
terrain.redraw();
minimap.redraw(); // to recalculate radar rect on minimap
redraw();
}
}
@ -1801,7 +1807,7 @@ CAdventureOptions::CAdventureOptions():
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
viewWorld = new CButton(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_x);
viewWorld = new CButton(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_v);
viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT));
exit = new CButton(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN);

View File

@ -316,11 +316,18 @@ void CStackWindow::CWindowSection::createActiveSpells()
std::vector<si32> spells = battleStack->activeSpells();
for(si32 effect : spells)
{
const CSpell * sp = CGI->spellh->objects[effect];
std::string spellText;
if (effect < 77) //not all effects have graphics (for eg. Acid Breath)
//not all effects have graphics (for eg. Acid Breath)
//for modded spells iconEffect is added to SpellInt.def
const bool hasGraphics = (effect < SpellID::THUNDERBOLT) || (effect >= SpellID::AFTER_LAST);
if (hasGraphics)
{
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
boost::replace_first (spellText, "%s", CGI->spellh->objects[effect]->name);
boost::replace_first (spellText, "%s", sp->name);
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
boost::replace_first (spellText, "%d", boost::lexical_cast<std::string>(duration));

View File

@ -120,6 +120,11 @@ void CTileInfo::setOccupied(ETileType::ETileType value)
occupied = value;
}
ETileType::ETileType CTileInfo::getTileType() const
{
return occupied;
}
ETerrainType CTileInfo::getTerrainType() const
{
return terrain;
@ -371,6 +376,11 @@ void CRmgTemplateZone::discardDistantTiles (CMapGenerator* gen, float distance)
});
}
void CRmgTemplateZone::clearTiles()
{
tileinfo.clear();
}
void CRmgTemplateZone::initFreeTiles (CMapGenerator* gen)
{
vstd::copy_if (tileinfo, vstd::set_inserter(possibleTiles), [gen](const int3 &tile) -> bool
@ -413,7 +423,7 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
int totalDensity = 0;
for (auto ti : treasureInfo)
totalDensity =+ ti.density;
const float minDistance = totalDensity * 4; //squared
const float minDistance = 10 * 10; //squared
for (auto tile : tileinfo)
{
@ -424,57 +434,62 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
}
assert (clearedTiles.size()); //this should come from zone connections
while (possibleTiles.size())
if (type != ETemplateZoneType::JUNCTION)
{
//link tiles in random order
std::vector<int3> tilesToMakePath(possibleTiles.begin(), possibleTiles.end());
RandomGeneratorUtil::randomShuffle(tilesToMakePath, gen->rand);
for (auto tileToMakePath : tilesToMakePath)
//junction is not fractalized, has only one straight path
//everything else remains blocked
while (possibleTiles.size())
{
//find closest free tile
float currentDistance = 1e10;
int3 closestTile (-1,-1,-1);
//link tiles in random order
std::vector<int3> tilesToMakePath(possibleTiles.begin(), possibleTiles.end());
RandomGeneratorUtil::randomShuffle(tilesToMakePath, gen->rand);
for (auto clearTile : clearedTiles)
for (auto tileToMakePath : tilesToMakePath)
{
float distance = tileToMakePath.dist2dSQ(clearTile);
if (distance < currentDistance)
//find closest free tile
float currentDistance = 1e10;
int3 closestTile(-1, -1, -1);
for (auto clearTile : clearedTiles)
{
currentDistance = distance;
closestTile = clearTile;
float distance = tileToMakePath.dist2dSQ(clearTile);
if (distance < currentDistance)
{
currentDistance = distance;
closestTile = clearTile;
}
if (currentDistance <= minDistance)
{
//this tile is close enough. Forget about it and check next one
tilesToIgnore.insert(tileToMakePath);
break;
}
}
if (currentDistance <= minDistance)
//if tiles is not close enough, make path to it
if (currentDistance > minDistance)
{
//this tile is close enough. Forget about it and check next one
tilesToIgnore.insert (tileToMakePath);
break;
crunchPath(gen, tileToMakePath, closestTile, id, &tilesToClear);
break; //next iteration - use already cleared tiles
}
}
//if tiles is not close enough, make path to it
if (currentDistance > minDistance)
{
crunchPath (gen, tileToMakePath, closestTile, id, &tilesToClear);
break; //next iteration - use already cleared tiles
}
}
for (auto tileToClear : tilesToClear)
{
//move cleared tiles from one set to another
clearedTiles.push_back(tileToClear);
vstd::erase_if_present(possibleTiles, tileToClear);
for (auto tileToClear : tilesToClear)
{
//move cleared tiles from one set to another
clearedTiles.push_back(tileToClear);
vstd::erase_if_present(possibleTiles, tileToClear);
}
for (auto tileToClear : tilesToIgnore)
{
//these tiles are already connected, ignore them
vstd::erase_if_present(possibleTiles, tileToClear);
}
if (tilesToClear.empty()) //nothing else can be done (?)
break;
tilesToClear.clear(); //empty this container
tilesToIgnore.clear();
}
for (auto tileToClear : tilesToIgnore)
{
//these tiles are already connected, ignore them
vstd::erase_if_present(possibleTiles, tileToClear);
}
if (tilesToClear.empty()) //nothing else can be done (?)
break;
tilesToClear.clear(); //empty this container
tilesToIgnore.clear();
}
for (auto tile : clearedTiles)
@ -484,10 +499,13 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
//now block most distant tiles away from passages
float blockDistance = minDistance * 0.6f;
float blockDistance = minDistance * 0.25f;
for (auto tile : possibleTiles)
for (auto tile : tileinfo)
{
if (!gen->isPossible(tile))
continue;
bool closeTileFound = false;
for (auto clearTile : freePaths)
@ -504,7 +522,8 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
gen->setOccupied(tile, ETileType::BLOCKED);
}
if (0) //enable to debug
#define PRINT_FRACTALIZED_MAP false
if (PRINT_FRACTALIZED_MAP) //enable to debug
{
std::ofstream out(boost::to_string(boost::format("zone %d") % id));
int levels = gen->map->twoLevel ? 2 : 1;
@ -516,12 +535,26 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
{
for (int i=0; i<width; i++)
{
out << (int)vstd::contains(freePaths, int3(i,j,k));
char t = '?';
switch (gen->getTile(int3(i, j, k)).getTileType())
{
case ETileType::FREE:
t = ' '; break;
case ETileType::BLOCKED:
t = '#'; break;
case ETileType::POSSIBLE:
t = '-'; break;
case ETileType::USED:
t = 'O'; break;
}
out << t;
}
out << std::endl;
}
out << std::endl;
}
out << std::endl;
}
//logGlobal->infoStream() << boost::format ("Zone %d subdivided fractally") %id;
@ -814,7 +847,9 @@ bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float m
}
if (placeFound.valid())
info.nextTreasurePos = placeFound;
}
else
break; //no more place to add any objects
}
}
if (treasures.size())

View File

@ -49,6 +49,7 @@ public:
bool isUsed() const;
void setOccupied(ETileType::ETileType value);
ETerrainType getTerrainType() const;
ETileType::ETileType getTileType() const;
void setTerrainType(ETerrainType value);
private:
@ -148,6 +149,7 @@ public:
void initFreeTiles (CMapGenerator* gen);
std::set<int3> getTileInfo () const;
void discardDistantTiles (CMapGenerator* gen, float distance);
void clearTiles();
void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0);
void addCloseObject(CGObjectInstance * obj, si32 guardStrength = 0);

View File

@ -323,7 +323,7 @@ d = 0.01 * dx^3 - 0.1618 * dx^2 + 1 * dx + ...
void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions)
{
logGlobal->infoStream() << "Starting zone colouring";
logGlobal->infoStream() << "Starting zone colouring";
auto width = mapGenOptions->getWidth();
auto height = mapGenOptions->getHeight();
@ -338,12 +338,62 @@ void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions)
std::vector <Dpair> distances;
distances.reserve(zones.size());
//now place zones correctly and assign tiles to each zone
auto compareByDistance = [](const Dpair & lhs, const Dpair & rhs) -> bool
{
return lhs.second < rhs.second;
};
auto moveZoneToCenterOfMass = [](CRmgTemplateZone * zone) -> void
{
int3 total(0, 0, 0);
auto tiles = zone->getTileInfo();
for (auto tile : tiles)
{
total += tile;
}
int size = tiles.size();
assert(size);
zone->setPos(int3(total.x / size, total.y / size, total.z / size));
};
int levels = gen->map->twoLevel ? 2 : 1;
/*
1. Create Voronoi diagram
2. find current center of mass for each zone. Move zone to that center to balance zones sizes
*/
for (int i = 0; i<width; i++)
{
for (int j = 0; j<height; j++)
{
for (int k = 0; k < levels; k++)
{
distances.clear();
int3 pos(i, j, k);
for (auto zone : zones)
{
if (zone.second->getPos().z == k)
distances.push_back(std::make_pair(zone.second, pos.dist2dSQ(zone.second->getPos())));
else
distances.push_back(std::make_pair(zone.second, std::numeric_limits<float>::max()));
}
boost::sort(distances, compareByDistance);
distances.front().first->addTile(pos); //closest tile belongs to zone
}
}
}
for (auto zone : zones)
moveZoneToCenterOfMass(zone.second);
//assign actual tiles to each zone using nonlinear norm for fine edges
for (auto zone : zones)
zone.second->clearTiles(); //now populate them again
for (int i=0; i<width; i++)
{
for(int j=0; j<height; j++)
@ -364,18 +414,10 @@ void CZonePlacer::assignZones(const CMapGenOptions * mapGenOptions)
}
}
}
//set position to center of mass
//set position (town position) to center of mass of irregular zone
for (auto zone : zones)
{
int3 total(0,0,0);
auto tiles = zone.second->getTileInfo();
for (auto tile : tiles)
{
total += tile;
}
int size = tiles.size();
assert (size);
zone.second->setPos (int3(total.x/size, total.y/size, total.z/size));
moveZoneToCenterOfMass(zone.second);
//TODO: similiar for islands
#define CREATE_FULL_UNDERGROUND true //consider linking this with water amount