mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-29 23:07:48 +02:00
- Renamed /lib subfolders to lowercase
This commit is contained in:
487
lib/mapping/CCampaignHandler.cpp
Normal file
487
lib/mapping/CCampaignHandler.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
#include "StdInc.h"
|
||||
#include "CCampaignHandler.h"
|
||||
|
||||
#include "../filesystem/CResourceLoader.h"
|
||||
#include "../filesystem/CCompressedStream.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../vcmi_endian.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../StartInfo.h"
|
||||
#include "../CArtHandler.h" //for hero crossover
|
||||
#include "../CObjectHandler.h" //for hero crossover
|
||||
#include "../CHeroHandler.h"
|
||||
#include "CMapService.h"
|
||||
#include "CMap.h"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
/*
|
||||
* CCampaignHandler.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
CCampaignHeader CCampaignHandler::getHeader( const std::string & name)
|
||||
{
|
||||
std::vector<ui8> cmpgn = getFile(name, true)[0];
|
||||
|
||||
int it = 0;//iterator for reading
|
||||
CCampaignHeader ret = readHeaderFromMemory(cmpgn.data(), it);
|
||||
ret.filename = name;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name )
|
||||
{
|
||||
auto ret = make_unique<CCampaign>();
|
||||
|
||||
std::vector<std::vector<ui8>> file = getFile(name, false);
|
||||
|
||||
int it = 0; //iterator for reading
|
||||
ret->header = readHeaderFromMemory(file[0].data(), it);
|
||||
ret->header.filename = name;
|
||||
|
||||
int howManyScenarios = VLC->generaltexth->campaignRegionNames[ret->header.mapVersion].size();
|
||||
for(int g=0; g<howManyScenarios; ++g)
|
||||
{
|
||||
CCampaignScenario sc = readScenarioFromMemory(file[0].data(), it, ret->header.version, ret->header.mapVersion);
|
||||
ret->scenarios.push_back(sc);
|
||||
}
|
||||
|
||||
int scenarioID = 0;
|
||||
|
||||
//first entry is campaign header. start loop from 1
|
||||
for (int g=1; g<file.size() && scenarioID<howManyScenarios; ++g)
|
||||
{
|
||||
while(!ret->scenarios[scenarioID].isNotVoid()) //skip void scenarios
|
||||
{
|
||||
scenarioID++;
|
||||
}
|
||||
|
||||
//set map piece appropriately, convert vector to string
|
||||
ret->mapPieces[scenarioID].assign(reinterpret_cast< const char* >(file[g].data()), file[g].size());
|
||||
ret->scenarios[scenarioID].scenarioName = CMapService::loadMapHeader((const ui8*)ret->mapPieces[scenarioID].c_str(), ret->mapPieces[scenarioID].size())->name;
|
||||
scenarioID++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CCampaignHeader CCampaignHandler::readHeaderFromMemory( const ui8 *buffer, int & outIt )
|
||||
{
|
||||
CCampaignHeader ret;
|
||||
ret.version = read_le_u32(buffer + outIt); outIt+=4;
|
||||
ret.mapVersion = buffer[outIt++]; //1 byte only
|
||||
ret.mapVersion -= 1; //change range of it from [1, 20] to [0, 19]
|
||||
ret.name = readString(buffer, outIt);
|
||||
ret.description = readString(buffer, outIt);
|
||||
if (ret.version > CampaignVersion::RoE)
|
||||
ret.difficultyChoosenByPlayer = readChar(buffer, outIt);
|
||||
else
|
||||
ret.difficultyChoosenByPlayer = 0;
|
||||
ret.music = readChar(buffer, outIt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CCampaignScenario CCampaignHandler::readScenarioFromMemory( const ui8 *buffer, int & outIt, int version, int mapVersion )
|
||||
{
|
||||
struct HLP
|
||||
{
|
||||
//reads prolog/epilog info from memory
|
||||
static CCampaignScenario::SScenarioPrologEpilog prologEpilogReader( const ui8 *buffer, int & outIt )
|
||||
{
|
||||
CCampaignScenario::SScenarioPrologEpilog ret;
|
||||
ret.hasPrologEpilog = buffer[outIt++];
|
||||
if(ret.hasPrologEpilog)
|
||||
{
|
||||
ret.prologVideo = buffer[outIt++];
|
||||
ret.prologMusic = buffer[outIt++];
|
||||
ret.prologText = readString(buffer, outIt);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
CCampaignScenario ret;
|
||||
ret.conquered = false;
|
||||
ret.mapName = readString(buffer, outIt);
|
||||
ret.packedMapSize = read_le_u32(buffer + outIt); outIt += 4;
|
||||
if(mapVersion == 18)//unholy alliance
|
||||
{
|
||||
ret.loadPreconditionRegions(read_le_u16(buffer + outIt)); outIt += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.loadPreconditionRegions(buffer[outIt++]);
|
||||
}
|
||||
ret.regionColor = buffer[outIt++];
|
||||
ret.difficulty = buffer[outIt++];
|
||||
ret.regionText = readString(buffer, outIt);
|
||||
ret.prolog = HLP::prologEpilogReader(buffer, outIt);
|
||||
ret.epilog = HLP::prologEpilogReader(buffer, outIt);
|
||||
|
||||
ret.travelOptions = readScenarioTravelFromMemory(buffer, outIt, version);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CCampaignScenario::loadPreconditionRegions(ui32 regions)
|
||||
{
|
||||
for (int i=0; i<32; i++) //for each bit in region. h3c however can only hold up to 16
|
||||
{
|
||||
if ( (1 << i) & regions)
|
||||
preconditionRegions.insert(i);
|
||||
}
|
||||
}
|
||||
|
||||
CScenarioTravel CCampaignHandler::readScenarioTravelFromMemory( const ui8 * buffer, int & outIt , int version )
|
||||
{
|
||||
CScenarioTravel ret;
|
||||
|
||||
ret.whatHeroKeeps = buffer[outIt++];
|
||||
memcpy(ret.monstersKeptByHero, buffer+outIt, ARRAY_COUNT(ret.monstersKeptByHero));
|
||||
outIt += ARRAY_COUNT(ret.monstersKeptByHero);
|
||||
int artifBytes;
|
||||
if (version < CampaignVersion::SoD)
|
||||
{
|
||||
artifBytes = 17;
|
||||
ret.artifsKeptByHero[17] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
artifBytes = 18;
|
||||
}
|
||||
memcpy(ret.artifsKeptByHero, buffer+outIt, artifBytes);
|
||||
outIt += artifBytes;
|
||||
|
||||
ret.startOptions = buffer[outIt++];
|
||||
|
||||
switch(ret.startOptions)
|
||||
{
|
||||
case 0:
|
||||
//no bonuses. Seems to be OK
|
||||
break;
|
||||
case 1: //reading of bonuses player can choose
|
||||
{
|
||||
ret.playerColor = buffer[outIt++];
|
||||
ui8 numOfBonuses = buffer[outIt++];
|
||||
for (int g=0; g<numOfBonuses; ++g)
|
||||
{
|
||||
CScenarioTravel::STravelBonus bonus;
|
||||
bonus.type = static_cast<CScenarioTravel::STravelBonus::EBonusType>(buffer[outIt++]);
|
||||
//hero: FFFD means 'most powerful' and FFFE means 'generated'
|
||||
switch(bonus.type)
|
||||
{
|
||||
case CScenarioTravel::STravelBonus::SPELL:
|
||||
{
|
||||
bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
|
||||
bonus.info2 = buffer[outIt++]; //spell ID
|
||||
break;
|
||||
}
|
||||
case CScenarioTravel::STravelBonus::MONSTER:
|
||||
{
|
||||
bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
|
||||
bonus.info2 = read_le_u16(buffer + outIt); outIt += 2; //monster type
|
||||
bonus.info3 = read_le_u16(buffer + outIt); outIt += 2; //monster count
|
||||
break;
|
||||
}
|
||||
case CScenarioTravel::STravelBonus::BUILDING:
|
||||
{
|
||||
bonus.info1 = buffer[outIt++]; //building ID (0 - town hall, 1 - city hall, 2 - capitol, etc)
|
||||
break;
|
||||
}
|
||||
case CScenarioTravel::STravelBonus::ARTIFACT:
|
||||
{
|
||||
bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
|
||||
bonus.info2 = read_le_u16(buffer + outIt); outIt += 2; //artifact ID
|
||||
break;
|
||||
}
|
||||
case CScenarioTravel::STravelBonus::SPELL_SCROLL:
|
||||
{
|
||||
bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
|
||||
bonus.info2 = buffer[outIt++]; //spell ID
|
||||
break;
|
||||
}
|
||||
case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
|
||||
{
|
||||
bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
|
||||
bonus.info2 = read_le_u32(buffer + outIt); outIt += 4; //bonuses (4 bytes for 4 skills)
|
||||
break;
|
||||
}
|
||||
case CScenarioTravel::STravelBonus::SECONDARY_SKILL:
|
||||
{
|
||||
bonus.info1 = read_le_u16(buffer + outIt); outIt += 2; //hero
|
||||
bonus.info2 = buffer[outIt++]; //skill ID
|
||||
bonus.info3 = buffer[outIt++]; //skill level
|
||||
break;
|
||||
}
|
||||
case CScenarioTravel::STravelBonus::RESOURCE:
|
||||
{
|
||||
bonus.info1 = buffer[outIt++]; //type
|
||||
//FD - wood+ore
|
||||
//FE - mercury+sulfur+crystal+gem
|
||||
bonus.info2 = read_le_u32(buffer + outIt); outIt += 4; //count
|
||||
break;
|
||||
}
|
||||
default:
|
||||
tlog1<<"Corrupted h3c file"<<std::endl;
|
||||
break;
|
||||
}
|
||||
ret.bonusesToChoose.push_back(bonus);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: //reading of players (colors / scenarios ?) player can choose
|
||||
{
|
||||
ui8 numOfBonuses = buffer[outIt++];
|
||||
for (int g=0; g<numOfBonuses; ++g)
|
||||
{
|
||||
CScenarioTravel::STravelBonus bonus;
|
||||
bonus.type = CScenarioTravel::STravelBonus::PLAYER_PREV_SCENARIO;
|
||||
bonus.info1 = buffer[outIt++]; //player color
|
||||
bonus.info2 = buffer[outIt++]; //from what scenario
|
||||
|
||||
ret.bonusesToChoose.push_back(bonus);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: //heroes player can choose between
|
||||
{
|
||||
ui8 numOfBonuses = buffer[outIt++];
|
||||
for (int g=0; g<numOfBonuses; ++g)
|
||||
{
|
||||
CScenarioTravel::STravelBonus bonus;
|
||||
bonus.type = CScenarioTravel::STravelBonus::HERO;
|
||||
bonus.info1 = buffer[outIt++]; //player color
|
||||
bonus.info2 = read_le_u16(buffer + outIt); outIt += 2; //hero, FF FF - random
|
||||
|
||||
ret.bonusesToChoose.push_back(bonus);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
tlog1<<"Corrupted h3c file"<<std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector< std::vector<ui8> > CCampaignHandler::getFile(const std::string & name, bool headerOnly)
|
||||
{
|
||||
CCompressedStream stream(std::move(CResourceHandler::get()->load(ResourceID(name, EResType::CAMPAIGN))), true);
|
||||
|
||||
std::vector< std::vector<ui8> > ret;
|
||||
do
|
||||
{
|
||||
std::vector<ui8> block(stream.getSize());
|
||||
stream.read(block.data(), block.size());
|
||||
ret.push_back(block);
|
||||
}
|
||||
while (!headerOnly && stream.getNextBlock());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CCampaign::conquerable( int whichScenario ) const
|
||||
{
|
||||
//check for void scenraio
|
||||
if (!scenarios[whichScenario].isNotVoid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scenarios[whichScenario].conquered)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//check preconditioned regions
|
||||
for (int g=0; g<scenarios.size(); ++g)
|
||||
{
|
||||
if( vstd::contains(scenarios[whichScenario].preconditionRegions, g) && !scenarios[g].conquered)
|
||||
return false; //prerequisite does not met
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CCampaign::CCampaign()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CCampaignScenario::isNotVoid() const
|
||||
{
|
||||
return mapName.size() > 0;
|
||||
}
|
||||
|
||||
void CCampaignScenario::prepareCrossoverHeroes( std::vector<CGHeroInstance *> heroes )
|
||||
{
|
||||
crossoverHeroes = heroes;
|
||||
|
||||
|
||||
if (!(travelOptions.whatHeroKeeps & 1))
|
||||
{
|
||||
//trimming experience
|
||||
BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
|
||||
{
|
||||
cgh->initExp();
|
||||
}
|
||||
}
|
||||
if (!(travelOptions.whatHeroKeeps & 2))
|
||||
{
|
||||
//trimming prim skills
|
||||
BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
|
||||
{
|
||||
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
||||
{
|
||||
cgh->getBonusLocalFirst(Selector::type(Bonus::PRIMARY_SKILL) &&
|
||||
Selector::subtype(g) && Selector::sourceType(Bonus::HERO_BASE_SKILL) )->val
|
||||
= cgh->type->heroClass->primarySkillInitial[g];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(travelOptions.whatHeroKeeps & 4))
|
||||
{
|
||||
//trimming sec skills
|
||||
BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
|
||||
{
|
||||
cgh->secSkills = cgh->type->secSkillsInit;
|
||||
}
|
||||
}
|
||||
if (!(travelOptions.whatHeroKeeps & 8))
|
||||
{
|
||||
//trimming spells
|
||||
BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
|
||||
{
|
||||
cgh->spells.clear();
|
||||
}
|
||||
}
|
||||
if (!(travelOptions.whatHeroKeeps & 16))
|
||||
{
|
||||
//trimming artifacts
|
||||
BOOST_FOREACH(CGHeroInstance * hero, crossoverHeroes)
|
||||
{
|
||||
size_t totalArts = GameConstants::BACKPACK_START + hero->artifactsInBackpack.size();
|
||||
for (size_t i=0; i<totalArts; i++ )
|
||||
{
|
||||
const ArtSlotInfo *info = hero->getSlot(ArtifactPosition(i));
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
const CArtifactInstance *art = info->artifact;
|
||||
if (!art)//FIXME: check spellbook and catapult behaviour
|
||||
continue;
|
||||
|
||||
int id = art->artType->id;
|
||||
assert( 8*18 > id );//number of arts that fits into h3m format
|
||||
bool takeable = travelOptions.artifsKeptByHero[id / 8] & ( 1 << (id%8) );
|
||||
|
||||
if (!takeable)
|
||||
hero->eraseArtSlot(ArtifactPosition(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//trimming creatures
|
||||
BOOST_FOREACH(CGHeroInstance * cgh, crossoverHeroes)
|
||||
{
|
||||
vstd::erase_if(cgh->stacks, [&](const std::pair<SlotID, CStackInstance *> & j) -> bool
|
||||
{
|
||||
CreatureID::ECreatureID crid = j.second->getCreatureID().toEnum();
|
||||
return !(travelOptions.monstersKeptByHero[crid / 8] & (1 << (crid % 8)) );
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const CGHeroInstance * CCampaignScenario::strongestHero( PlayerColor owner ) const
|
||||
{
|
||||
using boost::adaptors::filtered;
|
||||
std::function<bool(CGHeroInstance*)> isOwned = [=](const CGHeroInstance *h){ return h->tempOwner == owner; };
|
||||
auto ownedHeroes = crossoverHeroes | filtered(isOwned);
|
||||
|
||||
auto i = vstd::maxElementByFun(ownedHeroes,
|
||||
[](const CGHeroInstance * h) {return h->getTotalStrength();});
|
||||
return i == ownedHeroes.end() ? nullptr : *i;
|
||||
}
|
||||
|
||||
bool CScenarioTravel::STravelBonus::isBonusForHero() const
|
||||
{
|
||||
return type == SPELL || type == MONSTER || type == ARTIFACT || type == SPELL_SCROLL || type == PRIMARY_SKILL
|
||||
|| type == SECONDARY_SKILL;
|
||||
}
|
||||
|
||||
// void CCampaignState::initNewCampaign( const StartInfo &si )
|
||||
// {
|
||||
// assert(si.mode == StartInfo::CAMPAIGN);
|
||||
// campaignName = si.mapname;
|
||||
// currentMap = si.campState->currentMap;
|
||||
//
|
||||
// camp = CCampaignHandler::getCampaign(campaignName);
|
||||
// for (ui8 i = 0; i < camp->mapPieces.size(); i++)
|
||||
// mapsRemaining.push_back(i);
|
||||
// }
|
||||
|
||||
void CCampaignState::mapConquered( const std::vector<CGHeroInstance*> & heroes )
|
||||
{
|
||||
camp->scenarios[currentMap].prepareCrossoverHeroes(heroes);
|
||||
mapsConquered.push_back(currentMap);
|
||||
mapsRemaining -= currentMap;
|
||||
camp->scenarios[currentMap].conquered = true;
|
||||
}
|
||||
|
||||
boost::optional<CScenarioTravel::STravelBonus> CCampaignState::getBonusForCurrentMap() const
|
||||
{
|
||||
auto bonuses = getCurrentScenario().travelOptions.bonusesToChoose;
|
||||
assert(chosenCampaignBonuses.count(currentMap) || bonuses.size() == 0);
|
||||
if(bonuses.size())
|
||||
return bonuses[currentBonusID()];
|
||||
else
|
||||
return boost::optional<CScenarioTravel::STravelBonus>();
|
||||
}
|
||||
|
||||
const CCampaignScenario & CCampaignState::getCurrentScenario() const
|
||||
{
|
||||
return camp->scenarios[currentMap];
|
||||
}
|
||||
|
||||
ui8 CCampaignState::currentBonusID() const
|
||||
{
|
||||
return chosenCampaignBonuses[currentMap];
|
||||
}
|
||||
|
||||
CCampaignState::CCampaignState()
|
||||
{}
|
||||
|
||||
CCampaignState::CCampaignState( unique_ptr<CCampaign> _camp ) : camp(std::move(_camp))
|
||||
{
|
||||
for(int i = 0; i < camp->scenarios.size(); i++)
|
||||
{
|
||||
if(vstd::contains(camp->mapPieces, i)) //not all maps must be present in a campaign
|
||||
mapsRemaining.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
std::string CCampaignHandler::prologVideoName(ui8 index)
|
||||
{
|
||||
JsonNode config(ResourceID(std::string("CONFIG/campaignMedia"), EResType::TEXT));
|
||||
auto vids = config["videos"].Vector();
|
||||
if(index < vids.size())
|
||||
return vids[index].String();
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string CCampaignHandler::prologMusicName(ui8 index)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
188
lib/mapping/CCampaignHandler.h
Normal file
188
lib/mapping/CCampaignHandler.h
Normal file
@@ -0,0 +1,188 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../Global.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
/*
|
||||
* CCampaignHandler.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
struct StartInfo;
|
||||
class CGHeroInstance;
|
||||
|
||||
namespace CampaignVersion
|
||||
{
|
||||
enum Version
|
||||
{
|
||||
RoE = 4,
|
||||
AB = 5,
|
||||
SoD = 6,
|
||||
WoG = 6
|
||||
};
|
||||
}
|
||||
|
||||
class DLL_LINKAGE CCampaignHeader
|
||||
{
|
||||
public:
|
||||
si32 version; //4 - RoE, 5 - AB, 6 - SoD and WoG
|
||||
ui8 mapVersion; //CampText.txt's format
|
||||
std::string name, description;
|
||||
ui8 difficultyChoosenByPlayer;
|
||||
ui8 music; //CmpMusic.txt, start from 0
|
||||
|
||||
std::string filename;
|
||||
ui8 loadFromLod; //if true, this campaign must be loaded fro, .lod file
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & version & mapVersion & name & description & difficultyChoosenByPlayer & music & filename & loadFromLod;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CScenarioTravel
|
||||
{
|
||||
public:
|
||||
ui8 whatHeroKeeps; //bitfield [0] - experience, [1] - prim skills, [2] - sec skills, [3] - spells, [4] - artifacts
|
||||
ui8 monstersKeptByHero[19];
|
||||
ui8 artifsKeptByHero[18];
|
||||
|
||||
ui8 startOptions; //1 - start bonus, 2 - traveling hero, 3 - hero options
|
||||
|
||||
ui8 playerColor; //only for startOptions == 1
|
||||
|
||||
struct DLL_LINKAGE STravelBonus
|
||||
{
|
||||
enum EBonusType {SPELL, MONSTER, BUILDING, ARTIFACT, SPELL_SCROLL, PRIMARY_SKILL, SECONDARY_SKILL, RESOURCE,
|
||||
PLAYER_PREV_SCENARIO, HERO};
|
||||
EBonusType type; //uses EBonusType
|
||||
si32 info1, info2, info3; //purpose depends on type
|
||||
|
||||
bool isBonusForHero() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & type & info1 & info2 & info3;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<STravelBonus> bonusesToChoose;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & whatHeroKeeps & monstersKeptByHero & artifsKeptByHero & startOptions & playerColor & bonusesToChoose;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CCampaignScenario
|
||||
{
|
||||
public:
|
||||
std::string mapName; //*.h3m
|
||||
std::string scenarioName; //from header. human-readble
|
||||
ui32 packedMapSize; //generally not used
|
||||
std::set<ui8> preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c)
|
||||
ui8 regionColor;
|
||||
ui8 difficulty;
|
||||
bool conquered;
|
||||
|
||||
std::string regionText;
|
||||
|
||||
struct DLL_LINKAGE SScenarioPrologEpilog
|
||||
{
|
||||
bool hasPrologEpilog;
|
||||
ui8 prologVideo; // from CmpMovie.txt
|
||||
ui8 prologMusic; // from CmpMusic.txt
|
||||
std::string prologText;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & hasPrologEpilog & prologVideo & prologMusic & prologText;
|
||||
}
|
||||
};
|
||||
|
||||
SScenarioPrologEpilog prolog, epilog;
|
||||
|
||||
CScenarioTravel travelOptions;
|
||||
|
||||
std::vector<CGHeroInstance *> crossoverHeroes;
|
||||
|
||||
const CGHeroInstance * strongestHero(PlayerColor owner) const;
|
||||
|
||||
void loadPreconditionRegions(ui32 regions);
|
||||
void prepareCrossoverHeroes(std::vector<CGHeroInstance *> heroes);
|
||||
|
||||
bool isNotVoid() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & mapName & scenarioName & packedMapSize & preconditionRegions & regionColor & difficulty & conquered & regionText &
|
||||
prolog & epilog & travelOptions & crossoverHeroes;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CCampaign
|
||||
{
|
||||
public:
|
||||
CCampaignHeader header;
|
||||
std::vector<CCampaignScenario> scenarios;
|
||||
std::map<int, std::string > mapPieces; //binary h3ms, scenario number -> map data
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & header & scenarios & mapPieces;
|
||||
}
|
||||
|
||||
bool conquerable(int whichScenario) const;
|
||||
|
||||
CCampaign();
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CCampaignState
|
||||
{
|
||||
public:
|
||||
unique_ptr<CCampaign> camp;
|
||||
std::string campaignName;
|
||||
std::vector<ui8> mapsConquered, mapsRemaining;
|
||||
ui8 currentMap;
|
||||
|
||||
bmap<ui8, ui8> chosenCampaignBonuses; //used only for mode CAMPAIGN
|
||||
|
||||
//void initNewCampaign(const StartInfo &si);
|
||||
void mapConquered(const std::vector<CGHeroInstance*> & heroes);
|
||||
boost::optional<CScenarioTravel::STravelBonus> getBonusForCurrentMap() const;
|
||||
const CCampaignScenario &getCurrentScenario() const;
|
||||
ui8 currentBonusID() const;
|
||||
|
||||
CCampaignState();
|
||||
CCampaignState(unique_ptr<CCampaign> _camp);
|
||||
~CCampaignState(){};
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & camp & campaignName & mapsRemaining & mapsConquered & currentMap;
|
||||
h & chosenCampaignBonuses;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CCampaignHandler
|
||||
{
|
||||
static CCampaignHeader readHeaderFromMemory( const ui8 *buffer, int & outIt );
|
||||
static CCampaignScenario readScenarioFromMemory( const ui8 *buffer, int & outIt, int version, int mapVersion );
|
||||
static CScenarioTravel readScenarioTravelFromMemory( const ui8 * buffer, int & outIt , int version);
|
||||
/// returns h3c split in parts. 0 = h3c header, 1-end - maps (binary h3m)
|
||||
/// headerOnly - only header will be decompressed, returned vector wont have any maps
|
||||
static std::vector< std::vector<ui8> > getFile(const std::string & name, bool headerOnly);
|
||||
public:
|
||||
static std::string prologVideoName(ui8 index);
|
||||
static std::string prologMusicName(ui8 index);
|
||||
|
||||
static CCampaignHeader getHeader( const std::string & name); //name - name of appropriate file
|
||||
|
||||
static unique_ptr<CCampaign> getCampaign(const std::string & name); //name - name of appropriate file
|
||||
};
|
||||
309
lib/mapping/CMap.cpp
Normal file
309
lib/mapping/CMap.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "StdInc.h"
|
||||
#include "CMap.h"
|
||||
|
||||
#include "../CArtHandler.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../CTownHandler.h"
|
||||
#include "../CHeroHandler.h"
|
||||
#include "../CDefObjInfoHandler.h"
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
SHeroName::SHeroName() : heroId(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PlayerInfo::PlayerInfo(): canHumanPlay(false), canComputerPlay(false),
|
||||
aiTactic(EAiTactic::RANDOM), isFactionRandom(false), mainHeroPortrait(-1), hasMainTown(false),
|
||||
generateHeroAtMainTown(false), team(255), generateHero(false), p7(0), hasHero(false), customHeroID(-1), powerPlaceholders(-1)
|
||||
{
|
||||
allowedFactions = VLC->townh->getDefaultAllowedFactions();
|
||||
}
|
||||
|
||||
si8 PlayerInfo::defaultCastle() const
|
||||
{
|
||||
if(allowedFactions.size() == 1 || !isFactionRandom)
|
||||
{
|
||||
// faction can't be chosen - set to first that is marked as allowed
|
||||
assert(!allowedFactions.empty());
|
||||
return *allowedFactions.begin();
|
||||
}
|
||||
|
||||
// set to random
|
||||
return -1;
|
||||
}
|
||||
|
||||
si8 PlayerInfo::defaultHero() const
|
||||
{
|
||||
// we will generate hero in front of main town
|
||||
if((generateHeroAtMainTown && hasMainTown) || hasHero)
|
||||
{
|
||||
//random hero
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
LossCondition::LossCondition() : typeOfLossCon(ELossConditionType::LOSSSTANDARD),
|
||||
pos(int3(-1, -1, -1)), timeLimit(-1), obj(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VictoryCondition::VictoryCondition() : condition(EVictoryConditionType::WINSTANDARD),
|
||||
allowNormalVictory(false), appliesToAI(false), pos(int3(-1, -1, -1)), objectId(0),
|
||||
count(0), obj(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DisposedHero::DisposedHero() : heroId(0), portrait(255), players(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CMapEvent::CMapEvent() : players(0), humanAffected(0), computerAffected(0),
|
||||
firstOccurence(0), nextOccurence(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CMapEvent::earlierThan(const CMapEvent & other) const
|
||||
{
|
||||
return firstOccurence < other.firstOccurence;
|
||||
}
|
||||
|
||||
bool CMapEvent::earlierThanOrEqual(const CMapEvent & other) const
|
||||
{
|
||||
return firstOccurence <= other.firstOccurence;
|
||||
}
|
||||
|
||||
CCastleEvent::CCastleEvent() : town(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TerrainTile::TerrainTile() : terType(ETerrainType::BORDER), terView(0), riverType(ERiverType::NO_RIVER),
|
||||
riverDir(0), roadType(ERoadType::NO_ROAD), roadDir(0), extTileFlags(0), visitable(false),
|
||||
blocked(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool TerrainTile::entrableTerrain(const TerrainTile * from /*= NULL*/) const
|
||||
{
|
||||
return entrableTerrain(from ? from->terType != ETerrainType::WATER : true, from ? from->terType == ETerrainType::WATER : true);
|
||||
}
|
||||
|
||||
bool TerrainTile::entrableTerrain(bool allowLand, bool allowSea) const
|
||||
{
|
||||
return terType != ETerrainType::ROCK
|
||||
&& ((allowSea && terType == ETerrainType::WATER) || (allowLand && terType != ETerrainType::WATER));
|
||||
}
|
||||
|
||||
bool TerrainTile::isClear(const TerrainTile *from /*= NULL*/) const
|
||||
{
|
||||
return entrableTerrain(from) && !blocked;
|
||||
}
|
||||
|
||||
int TerrainTile::topVisitableId() const
|
||||
{
|
||||
return visitableObjects.size() ? visitableObjects.back()->ID : -1;
|
||||
}
|
||||
|
||||
bool TerrainTile::isCoastal() const
|
||||
{
|
||||
return extTileFlags & 64;
|
||||
}
|
||||
|
||||
bool TerrainTile::hasFavourableWinds() const
|
||||
{
|
||||
return extTileFlags & 128;
|
||||
}
|
||||
|
||||
bool TerrainTile::isWater() const
|
||||
{
|
||||
return terType == ETerrainType::WATER;
|
||||
}
|
||||
|
||||
CMapHeader::CMapHeader() : version(EMapFormat::SOD), height(72), width(72),
|
||||
twoLevel(true), difficulty(1), levelLimit(0), howManyTeams(0), areAnyPlayers(false)
|
||||
{
|
||||
allowedHeroes = VLC->heroh->getDefaultAllowedHeroes();
|
||||
players.resize(PlayerColor::PLAYER_LIMIT_I);
|
||||
}
|
||||
|
||||
CMapHeader::~CMapHeader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CMap::CMap() : checksum(0), terrain(nullptr), grailRadious(0)
|
||||
{
|
||||
allowedAbilities = VLC->heroh->getDefaultAllowedAbilities();
|
||||
allowedArtifact = VLC->arth->getDefaultAllowedArtifacts();
|
||||
allowedSpell = VLC->spellh->getDefaultAllowedSpells();
|
||||
}
|
||||
|
||||
CMap::~CMap()
|
||||
{
|
||||
if(terrain)
|
||||
{
|
||||
for(int ii=0;ii<width;ii++)
|
||||
{
|
||||
for(int jj=0;jj<height;jj++)
|
||||
delete [] terrain[ii][jj];
|
||||
delete [] terrain[ii];
|
||||
}
|
||||
delete [] terrain;
|
||||
}
|
||||
}
|
||||
|
||||
void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
|
||||
{
|
||||
for(int fx=0; fx<8; ++fx)
|
||||
{
|
||||
for(int fy=0; fy<6; ++fy)
|
||||
{
|
||||
int xVal = obj->pos.x + fx - 7;
|
||||
int yVal = obj->pos.y + fy - 5;
|
||||
int zVal = obj->pos.z;
|
||||
if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
|
||||
{
|
||||
TerrainTile & curt = terrain[xVal][yVal][zVal];
|
||||
if(total || ((obj->defInfo->visitMap[fy] >> (7 - fx)) & 1))
|
||||
{
|
||||
curt.visitableObjects -= obj;
|
||||
curt.visitable = curt.visitableObjects.size();
|
||||
}
|
||||
if(total || !((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1))
|
||||
{
|
||||
curt.blockingObjects -= obj;
|
||||
curt.blocked = curt.blockingObjects.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMap::addBlockVisTiles(CGObjectInstance * obj)
|
||||
{
|
||||
for(int fx=0; fx<8; ++fx)
|
||||
{
|
||||
for(int fy=0; fy<6; ++fy)
|
||||
{
|
||||
int xVal = obj->pos.x + fx - 7;
|
||||
int yVal = obj->pos.y + fy - 5;
|
||||
int zVal = obj->pos.z;
|
||||
if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
|
||||
{
|
||||
TerrainTile & curt = terrain[xVal][yVal][zVal];
|
||||
if(((obj->defInfo->visitMap[fy] >> (7 - fx)) & 1))
|
||||
{
|
||||
curt.visitableObjects.push_back(obj);
|
||||
curt.visitable = true;
|
||||
}
|
||||
if(!((obj->defInfo->blockMap[fy] >> (7 - fx)) & 1))
|
||||
{
|
||||
curt.blockingObjects.push_back(obj);
|
||||
curt.blocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGHeroInstance * CMap::getHero(int heroID)
|
||||
{
|
||||
for(ui32 i=0; i<heroes.size();i++)
|
||||
if(heroes[i]->subID == heroID)
|
||||
return heroes[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CMap::isInTheMap(const int3 &pos) const
|
||||
{
|
||||
if(pos.x < 0 || pos.y < 0 || pos.z < 0 || pos.x >= width || pos.y >= height
|
||||
|| pos.z > (twoLevel ? 1 : 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
TerrainTile & CMap::getTile( const int3 & tile )
|
||||
{
|
||||
return terrain[tile.x][tile.y][tile.z];
|
||||
}
|
||||
|
||||
const TerrainTile & CMap::getTile( const int3 & tile ) const
|
||||
{
|
||||
return terrain[tile.x][tile.y][tile.z];
|
||||
}
|
||||
|
||||
bool CMap::isWaterTile(const int3 &pos) const
|
||||
{
|
||||
return isInTheMap(pos) && getTile(pos).terType == ETerrainType::WATER;
|
||||
}
|
||||
|
||||
const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, bool lookForHero)
|
||||
{
|
||||
const std::vector<CGObjectInstance *> & objs = getTile(pos).visitableObjects;
|
||||
assert(objs.size());
|
||||
if(objs.size() > 1 && lookForHero && objs.front()->ID != Obj::HERO)
|
||||
{
|
||||
assert(objs.back()->ID == Obj::HERO);
|
||||
return objs.back();
|
||||
}
|
||||
else
|
||||
return objs.front();
|
||||
}
|
||||
|
||||
void CMap::checkForObjectives()
|
||||
{
|
||||
if(isInTheMap(victoryCondition.pos))
|
||||
{
|
||||
victoryCondition.obj = getObjectiveObjectFrom(victoryCondition.pos, victoryCondition.condition == EVictoryConditionType::BEATHERO);
|
||||
}
|
||||
|
||||
if(isInTheMap(lossCondition.pos))
|
||||
{
|
||||
lossCondition.obj = getObjectiveObjectFrom(lossCondition.pos, lossCondition.typeOfLossCon == ELossConditionType::LOSSHERO);
|
||||
}
|
||||
}
|
||||
|
||||
void CMap::addNewArtifactInstance(CArtifactInstance * art)
|
||||
{
|
||||
art->id = ArtifactInstanceID(artInstances.size());
|
||||
artInstances.push_back(art);
|
||||
}
|
||||
|
||||
void CMap::eraseArtifactInstance(CArtifactInstance * art)
|
||||
{
|
||||
assert(artInstances[art->id.getNum()] == art);
|
||||
artInstances[art->id.getNum()].dellNull();
|
||||
}
|
||||
|
||||
void CMap::addQuest(CGObjectInstance * quest)
|
||||
{
|
||||
auto q = dynamic_cast<IQuestObject *>(quest);
|
||||
q->quest->qid = quests.size();
|
||||
quests.push_back(q->quest);
|
||||
}
|
||||
|
||||
void CMap::initTerrain()
|
||||
{
|
||||
terrain = new TerrainTile**[width];
|
||||
for(int i = 0; i < width; ++i)
|
||||
{
|
||||
terrain[i] = new TerrainTile*[height];
|
||||
for(int j = 0; j < height; ++j)
|
||||
{
|
||||
terrain[i][j] = new TerrainTile[twoLevel ? 2 : 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
897
lib/mapping/CMap.h
Normal file
897
lib/mapping/CMap.h
Normal file
@@ -0,0 +1,897 @@
|
||||
|
||||
/*
|
||||
* CMap.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../ConstTransitivePtr.h"
|
||||
#include "../CObjectHandler.h"
|
||||
#include "../ResourceSet.h"
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
|
||||
class CArtifactInstance;
|
||||
class CGDefInfo;
|
||||
class CGObjectInstance;
|
||||
class CGHeroInstance;
|
||||
class CCommanderInstance;
|
||||
class CGCreature;
|
||||
class CQuest;
|
||||
class CGTownInstance;
|
||||
class IModableArt;
|
||||
class IQuestObject;
|
||||
class CInputStream;
|
||||
|
||||
/**
|
||||
* The hero name struct consists of the hero id and the hero name.
|
||||
*/
|
||||
struct DLL_LINKAGE SHeroName
|
||||
{
|
||||
/**
|
||||
* Default c-tor.
|
||||
*/
|
||||
SHeroName();
|
||||
|
||||
/** the id of the hero */
|
||||
int heroId;
|
||||
|
||||
/** the name of the hero */
|
||||
std::string heroName;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & heroId & heroName;
|
||||
}
|
||||
};
|
||||
|
||||
namespace EAiTactic
|
||||
{
|
||||
enum EAiTactic
|
||||
{
|
||||
NONE = -1,
|
||||
RANDOM,
|
||||
WARRIOR,
|
||||
BUILDER,
|
||||
EXPLORER
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The player info constains data about which factions are allowed, AI tactical settings,
|
||||
* the main hero name, where to generate the hero, whether the faction should be selected randomly,...
|
||||
*/
|
||||
struct DLL_LINKAGE PlayerInfo
|
||||
{
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
PlayerInfo();
|
||||
|
||||
/**
|
||||
* Gets the default faction id or -1 for a random faction.
|
||||
*
|
||||
* @return the default faction id or -1 for a random faction
|
||||
*/
|
||||
si8 defaultCastle() const;
|
||||
|
||||
/**
|
||||
* Gets -1 for random hero.
|
||||
*
|
||||
* @return -1 for random hero
|
||||
*/
|
||||
si8 defaultHero() const;
|
||||
|
||||
/** True if the player can be played by a human. */
|
||||
bool canHumanPlay;
|
||||
|
||||
/** True if th player can be played by the computer */
|
||||
bool canComputerPlay;
|
||||
|
||||
/** Defines the tactical setting of the AI. The default value is EAiTactic::RANDOM. */
|
||||
EAiTactic::EAiTactic aiTactic;
|
||||
|
||||
/** A list of unique IDs of allowed factions. */
|
||||
std::set<TFaction> allowedFactions;
|
||||
|
||||
/** Unused. True if the faction should be chosen randomly. */
|
||||
bool isFactionRandom;
|
||||
|
||||
/** Specifies the ID of the main hero with chosen portrait. The default value is -1. */
|
||||
si32 mainHeroPortrait;
|
||||
|
||||
/** The name of the main hero. */
|
||||
std::string mainHeroName;
|
||||
|
||||
/** The list of renamed heroes. */
|
||||
std::vector<SHeroName> heroesNames;
|
||||
|
||||
/** True if the player has a main town. The default value is false. */
|
||||
bool hasMainTown;
|
||||
|
||||
/** True if the main hero should be generated at the main town. The default value is false. */
|
||||
bool generateHeroAtMainTown;
|
||||
|
||||
/** The position of the main town. */
|
||||
int3 posOfMainTown;
|
||||
|
||||
/** The team id to which the player belongs to. The default value is 255 representing that the player belongs to no team. */
|
||||
TeamID team;
|
||||
|
||||
/** Unused. True if a hero should be generated. */
|
||||
bool generateHero;
|
||||
|
||||
/** Unknown and unused. */
|
||||
si32 p7;
|
||||
|
||||
/** Player has a (custom?) hero */
|
||||
bool hasHero;
|
||||
|
||||
/** ID of custom hero, -1 if none */
|
||||
si32 customHeroID;
|
||||
|
||||
/**
|
||||
* Unused. Count of hero placeholders containing hero type.
|
||||
* WARNING: powerPlaceholders sometimes gives false 0 (eg. even if there is one placeholder),
|
||||
* maybe different meaning ???
|
||||
*/
|
||||
ui8 powerPlaceholders;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & p7 & hasHero & customHeroID & canHumanPlay & canComputerPlay & aiTactic & allowedFactions & isFactionRandom &
|
||||
mainHeroPortrait & mainHeroName & heroesNames & hasMainTown & generateHeroAtMainTown &
|
||||
posOfMainTown & team & generateHero;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The loss condition describes the condition to lose the game. (e.g. lose all own heroes/castles)
|
||||
*/
|
||||
struct DLL_LINKAGE LossCondition
|
||||
{
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
LossCondition();
|
||||
|
||||
/** specifies the condition type */
|
||||
ELossConditionType::ELossConditionType typeOfLossCon;
|
||||
|
||||
/** the position of an object which mustn't be lost */
|
||||
int3 pos;
|
||||
|
||||
/** time limit in days, -1 if not used */
|
||||
si32 timeLimit;
|
||||
|
||||
/** set during map parsing: hero/town (depending on typeOfLossCon); nullptr if not used */
|
||||
const CGObjectInstance * obj;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & typeOfLossCon & pos & timeLimit & obj;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The victory condition describes the condition to win the game. (e.g. defeat all enemy heroes/castles,
|
||||
* receive a specific artifact, ...)
|
||||
*/
|
||||
struct DLL_LINKAGE VictoryCondition
|
||||
{
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
VictoryCondition();
|
||||
|
||||
/** specifies the condition type */
|
||||
EVictoryConditionType::EVictoryConditionType condition;
|
||||
|
||||
/** true if a normal victory is allowed (defeat all enemy towns, heroes) */
|
||||
bool allowNormalVictory;
|
||||
|
||||
/** true if this victory condition also applies to the AI */
|
||||
bool appliesToAI;
|
||||
|
||||
/** pos of city to upgrade (3); pos of town to build grail, {-1,-1,-1} if not relevant (4); hero pos (5); town pos(6); monster pos (7); destination pos(8) */
|
||||
int3 pos;
|
||||
|
||||
/** artifact ID (0); monster ID (1); resource ID (2); needed fort level in upgraded town (3); artifact ID (8) */
|
||||
si32 objectId;
|
||||
|
||||
/** needed count for creatures (1) / resource (2); upgraded town hall level (3); */
|
||||
si32 count;
|
||||
|
||||
/** object of specific monster / city / hero instance (NULL if not used); set during map parsing */
|
||||
const CGObjectInstance * obj;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & condition & allowNormalVictory & appliesToAI & pos & objectId & count & obj;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The rumor struct consists of a rumor name and text.
|
||||
*/
|
||||
struct DLL_LINKAGE Rumor
|
||||
{
|
||||
/** the name of the rumor */
|
||||
std::string name;
|
||||
|
||||
/** the content of the rumor */
|
||||
std::string text;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & name & text;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The disposed hero struct describes which hero can be hired from which player.
|
||||
*/
|
||||
struct DLL_LINKAGE DisposedHero
|
||||
{
|
||||
/**
|
||||
* Default c-tor.
|
||||
*/
|
||||
DisposedHero();
|
||||
|
||||
/** the id of the hero */
|
||||
ui32 heroId;
|
||||
|
||||
/** the portrait id of the hero, 0xFF is default */
|
||||
ui16 portrait;
|
||||
|
||||
/** the name of the hero */
|
||||
std::string name;
|
||||
|
||||
/** who can hire this hero (bitfield) */
|
||||
ui8 players;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & heroId & portrait & name & players;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The map event is an event which e.g. gives or takes resources of a specific
|
||||
* amount to/from players and can appear regularly or once a time.
|
||||
*/
|
||||
class DLL_LINKAGE CMapEvent
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default c-tor.
|
||||
*/
|
||||
CMapEvent();
|
||||
|
||||
/**
|
||||
* Returns true if this map event occurs earlier than the other map event for the first time.
|
||||
*
|
||||
* @param other the other map event to compare with
|
||||
* @return true if this event occurs earlier than the other map event, false if not
|
||||
*/
|
||||
bool earlierThan(const CMapEvent & other) const;
|
||||
|
||||
/**
|
||||
* Returns true if this map event occurs earlier than or at the same day than the other map event for the first time.
|
||||
*
|
||||
* @param other the other map event to compare with
|
||||
* @return true if this event occurs earlier than or at the same day than the other map event, false if not
|
||||
*/
|
||||
bool earlierThanOrEqual(const CMapEvent & other) const;
|
||||
|
||||
/** the name of the event */
|
||||
std::string name;
|
||||
|
||||
/** the message to display */
|
||||
std::string message;
|
||||
|
||||
/** gained or taken resources */
|
||||
TResources resources;
|
||||
|
||||
/** affected players */
|
||||
ui8 players;
|
||||
|
||||
/** affected humans */
|
||||
ui8 humanAffected;
|
||||
|
||||
/** affacted computer players */
|
||||
ui8 computerAffected;
|
||||
|
||||
/** the day counted continously when the event happens */
|
||||
ui32 firstOccurence;
|
||||
|
||||
/** specifies after how many days the event will occur the next time; 0 if event occurs only one time */
|
||||
ui32 nextOccurence;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & name & message & resources
|
||||
& players & humanAffected & computerAffected & firstOccurence & nextOccurence;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The castle event builds/adds buildings/creatures for a specific town.
|
||||
*/
|
||||
class DLL_LINKAGE CCastleEvent: public CMapEvent
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default c-tor.
|
||||
*/
|
||||
CCastleEvent();
|
||||
|
||||
/** build specific buildings */
|
||||
std::set<BuildingID> buildings;
|
||||
|
||||
/** additional creatures in i-th level dwelling */
|
||||
std::vector<si32> creatures;
|
||||
|
||||
/** owner of this event */
|
||||
CGTownInstance * town;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & static_cast<CMapEvent &>(*this);
|
||||
h & buildings & creatures;
|
||||
}
|
||||
};
|
||||
|
||||
namespace ERiverType
|
||||
{
|
||||
enum ERiverType
|
||||
{
|
||||
NO_RIVER, CLEAR_RIVER, ICY_RIVER, MUDDY_RIVER, LAVA_RIVER
|
||||
};
|
||||
}
|
||||
|
||||
namespace ERoadType
|
||||
{
|
||||
enum ERoadType
|
||||
{
|
||||
NO_ROAD, DIRT_ROAD, GRAVEL_ROAD, COBBLESTONE_ROAD
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The terrain tile describes the terrain type and the visual representation of the terrain.
|
||||
* Furthermore the struct defines whether the tile is visitable or/and blocked and which objects reside in it.
|
||||
*/
|
||||
struct DLL_LINKAGE TerrainTile
|
||||
{
|
||||
/**
|
||||
* Default c-tor.
|
||||
*/
|
||||
TerrainTile();
|
||||
|
||||
/**
|
||||
* Gets true if the terrain is not a rock. If from is water/land, same type is also required.
|
||||
*
|
||||
* @param from
|
||||
* @return
|
||||
*/
|
||||
bool entrableTerrain(const TerrainTile * from = NULL) const;
|
||||
|
||||
/**
|
||||
* Gets true if the terrain is not a rock. If from is water/land, same type is also required.
|
||||
*
|
||||
* @param allowLand
|
||||
* @param allowSea
|
||||
* @return
|
||||
*/
|
||||
bool entrableTerrain(bool allowLand, bool allowSea) const;
|
||||
|
||||
/**
|
||||
* Checks for blocking objects and terraint type (water / land).
|
||||
*
|
||||
* @param from
|
||||
* @return
|
||||
*/
|
||||
bool isClear(const TerrainTile * from = NULL) const;
|
||||
|
||||
/**
|
||||
* Gets the ID of the top visitable object or -1 if there is none.
|
||||
*
|
||||
* @return the ID of the top visitable object or -1 if there is none
|
||||
*/
|
||||
int topVisitableId() const;
|
||||
|
||||
/**
|
||||
* Gets true if the terrain type is water.
|
||||
*
|
||||
* @return true if the terrain type is water
|
||||
*/
|
||||
bool isWater() const;
|
||||
|
||||
/**
|
||||
* Gets true if the terrain tile is coastal.
|
||||
*
|
||||
* @return true if the terrain tile is coastal
|
||||
*/
|
||||
bool isCoastal() const;
|
||||
|
||||
/**
|
||||
* Gets true if the terrain tile has favourable winds.
|
||||
*
|
||||
* @return true if the terrain tile has favourable winds
|
||||
*/
|
||||
bool hasFavourableWinds() const;
|
||||
|
||||
/** the type of terrain */
|
||||
ETerrainType terType;
|
||||
|
||||
/** the visual representation of the terrain */
|
||||
ui8 terView;
|
||||
|
||||
/** the type of the river. 0 if there is no river */
|
||||
ERiverType::ERiverType riverType;
|
||||
|
||||
/** the direction of the river */
|
||||
ui8 riverDir;
|
||||
|
||||
/** the type of the road. 0 if there is no river */
|
||||
ERoadType::ERoadType roadType;
|
||||
|
||||
/** the direction of the road */
|
||||
ui8 roadDir;
|
||||
|
||||
/**
|
||||
* first two bits - how to rotate terrain graphic (next two - river graphic, next two - road);
|
||||
* 7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favourable Winds effect
|
||||
*/
|
||||
ui8 extTileFlags;
|
||||
|
||||
/** true if it is visitable, false if not */
|
||||
bool visitable;
|
||||
|
||||
/** true if it is blocked, false if not */
|
||||
bool blocked;
|
||||
|
||||
/** pointers to objects which the hero can visit while being on this tile */
|
||||
std::vector<CGObjectInstance *> visitableObjects;
|
||||
|
||||
/** pointers to objects that are blocking this tile */
|
||||
std::vector<CGObjectInstance *> blockingObjects;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & terType & terView & riverType & riverDir & roadType &roadDir & extTileFlags & blocked;
|
||||
|
||||
if(!h.saving)
|
||||
{
|
||||
visitable = false;
|
||||
//these flags (and obj vectors) will be restored in map serialization
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace EMapFormat
|
||||
{
|
||||
enum EMapFormat
|
||||
{
|
||||
INVALID, WOG=0x33, AB=0x15, ROE=0x0e, SOD=0x1c
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The map header holds information about loss/victory condition,
|
||||
* map format, version, players, height, width,...
|
||||
*/
|
||||
class DLL_LINKAGE CMapHeader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
CMapHeader();
|
||||
|
||||
/**
|
||||
* D-tor.
|
||||
*/
|
||||
virtual ~CMapHeader();
|
||||
|
||||
/** The version of the map. The default value is EMapFormat::SOD. */
|
||||
EMapFormat::EMapFormat version;
|
||||
|
||||
/** The height of the map. The default value is 72. */
|
||||
si32 height;
|
||||
|
||||
/** The width of the map. The default value is 72. */
|
||||
si32 width;
|
||||
|
||||
/** Specifies if the map has two levels. The default value is true. */
|
||||
bool twoLevel;
|
||||
|
||||
/** The name of the map. */
|
||||
std::string name;
|
||||
|
||||
/** The description of the map. */
|
||||
std::string description;
|
||||
|
||||
/**
|
||||
* Specifies the difficulty of the map ranging from 0 easy to 4 impossible.
|
||||
* The default value is 1 representing a normal map difficulty.
|
||||
*/
|
||||
ui8 difficulty;
|
||||
|
||||
/**
|
||||
* Specifies the maximum level to reach for a hero. A value of 0 states that there is no
|
||||
* maximum level for heroes.
|
||||
*/
|
||||
ui8 levelLimit;
|
||||
|
||||
/** Specifies the loss condition. The default value is lose all your towns and heroes. */
|
||||
LossCondition lossCondition;
|
||||
|
||||
/** Specifies the victory condition. The default value is defeat all enemies. */
|
||||
VictoryCondition victoryCondition;
|
||||
|
||||
/** A list containing information about players. The default size of the vector is PlayerColor::PLAYER_LIMIT. */
|
||||
std::vector<PlayerInfo> players;
|
||||
|
||||
/** The number of teams. */
|
||||
ui8 howManyTeams;
|
||||
|
||||
/**
|
||||
* A list of allowed heroes. The index is the hero id and the value = hero allowed.
|
||||
* The default value is a list of default allowed heroes. See CHeroHandler::getDefaultAllowedHeroes for more info.
|
||||
*/
|
||||
std::vector<bool> allowedHeroes;
|
||||
|
||||
/** A list of placeholded heroes. The index is the id of a hero type. */
|
||||
std::vector<ui16> placeholdedHeroes;
|
||||
|
||||
/** Unused. True if there are any playable players on the map. */
|
||||
bool areAnyPlayers;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int Version)
|
||||
{
|
||||
h & version & name & description & width & height & twoLevel & difficulty & levelLimit & areAnyPlayers;
|
||||
h & players & lossCondition & victoryCondition & howManyTeams & allowedHeroes;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The map contains the map header, the tiles of the terrain, objects,
|
||||
* heroes, towns, rumors...
|
||||
*/
|
||||
class DLL_LINKAGE CMap : public CMapHeader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
CMap();
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~CMap();
|
||||
|
||||
/**
|
||||
* Erases an artifact instance.
|
||||
*
|
||||
* @param art the artifact to erase
|
||||
*/
|
||||
void eraseArtifactInstance(CArtifactInstance * art);
|
||||
|
||||
/**
|
||||
* Gets the topmost object or the lowermost object depending on the flag
|
||||
* lookForHero from the specified position.
|
||||
*
|
||||
* @param pos the position of the tile
|
||||
* @param lookForHero true if you want to get the lowermost object, false if
|
||||
* you want to get the topmost object
|
||||
* @return the object at the given position and level
|
||||
*/
|
||||
const CGObjectInstance * getObjectiveObjectFrom(int3 pos, bool lookForHero);
|
||||
|
||||
/**
|
||||
* Sets the victory/loss condition objectives.
|
||||
*/
|
||||
void checkForObjectives();
|
||||
|
||||
/**
|
||||
* Adds an visitable/blocking object to a terrain tile.
|
||||
*
|
||||
* @param obj the visitable/blocking object to add to a tile
|
||||
*/
|
||||
void addBlockVisTiles(CGObjectInstance * obj);
|
||||
|
||||
/**
|
||||
* Removes an visitable/blocking object from a terrain tile.
|
||||
*
|
||||
* @param obj the visitable/blocking object to remove from a tile
|
||||
* @param total
|
||||
*/
|
||||
void removeBlockVisTiles(CGObjectInstance * obj, bool total = false);
|
||||
|
||||
/**
|
||||
* Gets the terrain tile of the specified position.
|
||||
*
|
||||
* @param tile the position of the tile
|
||||
* @return the terrain tile of the specified position
|
||||
*/
|
||||
TerrainTile & getTile(const int3 & tile);
|
||||
|
||||
/**
|
||||
* Gets the terrain tile as a const of the specified position.
|
||||
*
|
||||
* @param tile the position of the tile
|
||||
* @return the terrain tile as a const of the specified position
|
||||
*/
|
||||
const TerrainTile & getTile(const int3 & tile) const;
|
||||
|
||||
/**
|
||||
* Gets the hero with the given id.
|
||||
* @param heroId the hero id
|
||||
* @return the hero with the given id
|
||||
*/
|
||||
CGHeroInstance * getHero(int heroId);
|
||||
|
||||
/**
|
||||
* Validates if the position is in the bounds of the map.
|
||||
*
|
||||
* @param pos the position to test
|
||||
* @return true if the position is in the bounds of the map
|
||||
*/
|
||||
bool isInTheMap(const int3 & pos) const;
|
||||
|
||||
/**
|
||||
* Validates if the tile at the given position is a water terrain type.
|
||||
*
|
||||
* @param pos the position to test
|
||||
* @return true if the tile at the given position is a water terrain type
|
||||
*/
|
||||
bool isWaterTile(const int3 & pos) const;
|
||||
|
||||
/**
|
||||
* Adds the specified artifact instance to the list of artifacts of this map.
|
||||
*
|
||||
* @param art the artifact which should be added to the list of artifacts
|
||||
*/
|
||||
void addNewArtifactInstance(CArtifactInstance * art);
|
||||
|
||||
/**
|
||||
* Adds the specified quest instance to the list of quests.
|
||||
*
|
||||
* @param quest the quest object which should be added to the list of quests
|
||||
*/
|
||||
void addQuest(CGObjectInstance * quest);
|
||||
|
||||
/**
|
||||
* Initializes the terrain of the map by allocating memory.
|
||||
*/
|
||||
void initTerrain();
|
||||
|
||||
/** the checksum of the map */
|
||||
ui32 checksum;
|
||||
|
||||
/** a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground */
|
||||
TerrainTile*** terrain;
|
||||
|
||||
/** list of rumors */
|
||||
std::vector<Rumor> rumors;
|
||||
|
||||
/** list of disposed heroes */
|
||||
std::vector<DisposedHero> disposedHeroes;
|
||||
|
||||
/** list of predefined heroes */
|
||||
std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;
|
||||
|
||||
/** list of .def files with definitions from .h3m (may be custom) */
|
||||
std::vector<ConstTransitivePtr<CGDefInfo> > customDefs;
|
||||
|
||||
/** list of allowed spells, index is the spell id */
|
||||
std::vector<bool> allowedSpell;
|
||||
|
||||
/** list of allowed artifacts, index is the artifact id */
|
||||
std::vector<bool> allowedArtifact;
|
||||
|
||||
/** list of allowed abilities, index is the ability id */
|
||||
std::vector<bool> allowedAbilities;
|
||||
|
||||
/** list of map events */
|
||||
std::list<CMapEvent> events;
|
||||
|
||||
/** specifies the position of the grail */
|
||||
int3 grailPos;
|
||||
|
||||
/** specifies the radius of the grail */
|
||||
int grailRadious;
|
||||
|
||||
/** list of objects */
|
||||
std::vector< ConstTransitivePtr<CGObjectInstance> > objects;
|
||||
|
||||
/** list of heroes */
|
||||
std::vector< ConstTransitivePtr<CGHeroInstance> > heroes;
|
||||
|
||||
/** list of towns */
|
||||
std::vector< ConstTransitivePtr<CGTownInstance> > towns;
|
||||
|
||||
/** list of artifacts */
|
||||
std::vector< ConstTransitivePtr<CArtifactInstance> > artInstances;
|
||||
|
||||
/** list of quests */
|
||||
std::vector< ConstTransitivePtr<CQuest> > quests;
|
||||
|
||||
/** associative list to identify which hero/creature id belongs to which object id(index for objects) */
|
||||
bmap<si32, ObjectInstanceID> questIdentifierToId;
|
||||
|
||||
/**
|
||||
* Serialize method.
|
||||
*/
|
||||
template <typename Handler>
|
||||
void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & static_cast<CMapHeader&>(*this);
|
||||
h & rumors & allowedSpell & allowedAbilities & allowedArtifact & events & grailPos;
|
||||
h & artInstances & quests;
|
||||
h & questIdentifierToId;
|
||||
|
||||
//TODO: viccondetails
|
||||
if(h.saving)
|
||||
{
|
||||
// Save terrain
|
||||
for(int i = 0; i < width ; ++i)
|
||||
{
|
||||
for(int j = 0; j < height ; ++j)
|
||||
{
|
||||
for(int k = 0; k < (twoLevel ? 2 : 1); ++k)
|
||||
{
|
||||
h & terrain[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load terrain
|
||||
terrain = new TerrainTile**[width];
|
||||
for(int ii = 0; ii < width; ++ii)
|
||||
{
|
||||
terrain[ii] = new TerrainTile*[height];
|
||||
for(int jj = 0; jj < height; ++jj)
|
||||
{
|
||||
terrain[ii][jj] = new TerrainTile[twoLevel ? 2 : 1];
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < width ; ++i)
|
||||
{
|
||||
for(int j = 0; j < height ; ++j)
|
||||
{
|
||||
for(int k = 0; k < (twoLevel ? 2 : 1); ++k)
|
||||
{
|
||||
h & terrain[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h & customDefs & objects;
|
||||
|
||||
// static members
|
||||
h & CGTeleport::objs;
|
||||
h & CGTeleport::gates;
|
||||
h & CGKeys::playerKeyMap;
|
||||
h & CGMagi::eyelist;
|
||||
h & CGObelisk::obeliskCount & CGObelisk::visited;
|
||||
h & CGTownInstance::merchantArtifacts;
|
||||
h & CGTownInstance::universitySkills;
|
||||
|
||||
if(!h.saving)
|
||||
{
|
||||
for(ui32 i = 0; i < objects.size(); ++i)
|
||||
{
|
||||
if(!objects[i]) continue;
|
||||
|
||||
switch (objects[i]->ID)
|
||||
{
|
||||
case Obj::HERO:
|
||||
heroes.push_back (static_cast<CGHeroInstance*>(+objects[i]));
|
||||
break;
|
||||
case Obj::TOWN:
|
||||
towns.push_back (static_cast<CGTownInstance*>(+objects[i]));
|
||||
break;
|
||||
}
|
||||
|
||||
// recreate blockvis map
|
||||
addBlockVisTiles(objects[i]);
|
||||
}
|
||||
|
||||
// if hero is visiting/garrisoned in town set appropriate pointers
|
||||
for(ui32 i = 0; i < heroes.size(); ++i)
|
||||
{
|
||||
int3 vistile = heroes[i]->pos;
|
||||
vistile.x++;
|
||||
for(ui32 j = 0; j < towns.size(); ++j)
|
||||
{
|
||||
// hero stands on the town entrance
|
||||
if(vistile == towns[j]->pos)
|
||||
{
|
||||
if(heroes[i]->inTownGarrison)
|
||||
{
|
||||
towns[j]->garrisonHero = heroes[i];
|
||||
removeBlockVisTiles(heroes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
towns[j]->visitingHero = heroes[i];
|
||||
}
|
||||
|
||||
heroes[i]->visitedTown = towns[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vistile.x -= 2; //manifest pos
|
||||
const TerrainTile & t = getTile(vistile);
|
||||
if(t.terType != ETerrainType::WATER) continue;
|
||||
|
||||
//hero stands on the water - he must be in the boat
|
||||
for(ui32 j = 0; j < t.visitableObjects.size(); ++j)
|
||||
{
|
||||
if(t.visitableObjects[j]->ID == Obj::BOAT)
|
||||
{
|
||||
CGBoat * b = static_cast<CGBoat *>(t.visitableObjects[j]);
|
||||
heroes[i]->boat = b;
|
||||
b->hero = heroes[i];
|
||||
removeBlockVisTiles(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
434
lib/mapping/CMapEditManager.cpp
Normal file
434
lib/mapping/CMapEditManager.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
#include "StdInc.h"
|
||||
#include "CMapEditManager.h"
|
||||
|
||||
#include "../JsonNode.h"
|
||||
#include "../filesystem/CResourceLoader.h"
|
||||
#include "../CDefObjInfoHandler.h"
|
||||
|
||||
const std::string TerrainViewPattern::FLIP_MODE_SAME_IMAGE = "sameImage";
|
||||
const std::string TerrainViewPattern::FLIP_MODE_DIFF_IMAGES = "diffImages";
|
||||
|
||||
const std::string TerrainViewPattern::RULE_DIRT = "D";
|
||||
const std::string TerrainViewPattern::RULE_SAND = "S";
|
||||
const std::string TerrainViewPattern::RULE_TRANSITION = "T";
|
||||
const std::string TerrainViewPattern::RULE_NATIVE = "N";
|
||||
const std::string TerrainViewPattern::RULE_ANY = "?";
|
||||
|
||||
TerrainViewPattern::TerrainViewPattern() : minPoints(0), flipMode(FLIP_MODE_SAME_IMAGE),
|
||||
terGroup(ETerrainGroup::NORMAL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TerrainViewPattern::WeightedRule::WeightedRule() : points(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool TerrainViewPattern::WeightedRule::isStandardRule() const
|
||||
{
|
||||
return TerrainViewPattern::RULE_ANY == name || TerrainViewPattern::RULE_DIRT == name
|
||||
|| TerrainViewPattern::RULE_NATIVE == name || TerrainViewPattern::RULE_SAND == name
|
||||
|| TerrainViewPattern::RULE_TRANSITION == name;
|
||||
}
|
||||
|
||||
CTerrainViewPatternConfig::CTerrainViewPatternConfig()
|
||||
{
|
||||
const JsonNode config(ResourceID("config/terrainViewPatterns.json"));
|
||||
const std::map<std::string, ETerrainGroup::ETerrainGroup> terGroups
|
||||
= boost::assign::map_list_of("normal", ETerrainGroup::NORMAL)("dirt", ETerrainGroup::DIRT)
|
||||
("sand", ETerrainGroup::SAND)("water", ETerrainGroup::WATER)("rock", ETerrainGroup::ROCK);
|
||||
BOOST_FOREACH(auto terMapping, terGroups)
|
||||
{
|
||||
BOOST_FOREACH(const JsonNode & ptrnNode, config[terMapping.first].Vector())
|
||||
{
|
||||
TerrainViewPattern pattern;
|
||||
|
||||
// Read pattern data
|
||||
const JsonVector & data = ptrnNode["data"].Vector();
|
||||
if(data.size() != 9)
|
||||
{
|
||||
throw std::runtime_error("Size of pattern's data vector has to be 9.");
|
||||
}
|
||||
for(int i = 0; i < data.size(); ++i)
|
||||
{
|
||||
std::string cell = data[i].String();
|
||||
boost::algorithm::erase_all(cell, " ");
|
||||
std::vector<std::string> rules;
|
||||
boost::split(rules, cell, boost::is_any_of(","));
|
||||
BOOST_FOREACH(std::string ruleStr, rules)
|
||||
{
|
||||
std::vector<std::string> ruleParts;
|
||||
boost::split(ruleParts, ruleStr, boost::is_any_of("-"));
|
||||
TerrainViewPattern::WeightedRule rule;
|
||||
rule.name = ruleParts[0];
|
||||
if(ruleParts.size() > 1)
|
||||
{
|
||||
rule.points = boost::lexical_cast<int>(ruleParts[1]);
|
||||
}
|
||||
pattern.data[i].push_back(rule);
|
||||
}
|
||||
}
|
||||
|
||||
// Read mapping
|
||||
std::string mappingStr = ptrnNode["mapping"].String();
|
||||
boost::algorithm::erase_all(mappingStr, " ");
|
||||
std::vector<std::string> mappings;
|
||||
boost::split(mappings, mappingStr, boost::is_any_of(","));
|
||||
BOOST_FOREACH(std::string mapping, mappings)
|
||||
{
|
||||
std::vector<std::string> range;
|
||||
boost::split(range, mapping, boost::is_any_of("-"));
|
||||
pattern.mapping.push_back(std::make_pair(boost::lexical_cast<int>(range[0]),
|
||||
boost::lexical_cast<int>(range.size() > 1 ? range[1] : range[0])));
|
||||
}
|
||||
|
||||
// Read optional attributes
|
||||
pattern.id = ptrnNode["id"].String();
|
||||
pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float());
|
||||
pattern.flipMode = ptrnNode["flipMode"].String();
|
||||
if(pattern.flipMode.empty())
|
||||
{
|
||||
pattern.flipMode = TerrainViewPattern::FLIP_MODE_SAME_IMAGE;
|
||||
}
|
||||
|
||||
pattern.terGroup = terMapping.second;
|
||||
patterns[terMapping.second].push_back(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<TerrainViewPattern> & CTerrainViewPatternConfig::getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const
|
||||
{
|
||||
return patterns.find(terGroup)->second;
|
||||
}
|
||||
|
||||
const TerrainViewPattern & CTerrainViewPatternConfig::getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const
|
||||
{
|
||||
const std::vector<TerrainViewPattern> & groupPatterns = getPatternsForGroup(terGroup);
|
||||
BOOST_FOREACH(const TerrainViewPattern & pattern, groupPatterns)
|
||||
{
|
||||
if(id == pattern.id)
|
||||
{
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Pattern with ID not found: " + id);
|
||||
}
|
||||
|
||||
CMapEditManager::CMapEditManager(const CTerrainViewPatternConfig * terViewPatternConfig, CMap * map, int randomSeed /*= std::time(nullptr)*/)
|
||||
: map(map), terViewPatternConfig(terViewPatternConfig)
|
||||
{
|
||||
gen.seed(randomSeed);
|
||||
}
|
||||
|
||||
void CMapEditManager::clearTerrain()
|
||||
{
|
||||
for(int i = 0; i < map->width; ++i)
|
||||
{
|
||||
for(int j = 0; j < map->height; ++j)
|
||||
{
|
||||
map->terrain[i][j][0].terType = ETerrainType::WATER;
|
||||
map->terrain[i][j][0].terView = gen.getInteger(20, 32);
|
||||
|
||||
if(map->twoLevel)
|
||||
{
|
||||
map->terrain[i][j][1].terType = ETerrainType::ROCK;
|
||||
map->terrain[i][j][1].terView = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMapEditManager::drawTerrain(ETerrainType terType, int posx, int posy, int width, int height, bool underground)
|
||||
{
|
||||
bool mapLevel = underground ? 1 : 0;
|
||||
for(int i = posx; i < posx + width; ++i)
|
||||
{
|
||||
for(int j = posy; j < posy + height; ++j)
|
||||
{
|
||||
map->terrain[i][j][mapLevel].terType = terType;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO there are situations where more tiles are affected implicitely
|
||||
//TODO add coastal bit to extTileFlags appropriately
|
||||
|
||||
updateTerrainViews(posx - 1, posy - 1, width + 2, height + 2, mapLevel);
|
||||
}
|
||||
|
||||
void CMapEditManager::updateTerrainViews(int posx, int posy, int width, int height, int mapLevel)
|
||||
{
|
||||
for(int i = posx; i < posx + width; ++i)
|
||||
{
|
||||
for(int j = posy; j < posy + height; ++j)
|
||||
{
|
||||
const std::vector<TerrainViewPattern> & patterns =
|
||||
terViewPatternConfig->getPatternsForGroup(getTerrainGroup(map->terrain[i][j][mapLevel].terType));
|
||||
|
||||
// Detect a pattern which fits best
|
||||
int bestPattern = -1, bestFlip = -1;
|
||||
std::string transitionReplacement;
|
||||
for(int k = 0; k < patterns.size(); ++k)
|
||||
{
|
||||
const TerrainViewPattern & pattern = patterns[k];
|
||||
|
||||
for(int flip = 0; flip < 4; ++flip)
|
||||
{
|
||||
ValidationResult valRslt = validateTerrainView(i, j, mapLevel, flip > 0 ? getFlippedPattern(pattern, flip) : pattern);
|
||||
if(valRslt.result)
|
||||
{
|
||||
tlog5 << "Pattern detected at pos " << i << "x" << j << "x" << mapLevel << ": P-Nr. " << k
|
||||
<< ", Flip " << flip << ", Repl. " << valRslt.transitionReplacement << std::endl;
|
||||
|
||||
bestPattern = k;
|
||||
bestFlip = flip;
|
||||
transitionReplacement = valRslt.transitionReplacement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bestPattern == -1)
|
||||
{
|
||||
// This shouldn't be the case
|
||||
tlog2 << "No pattern detected at pos " << i << "x" << j << "x" << mapLevel << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get mapping
|
||||
const TerrainViewPattern & pattern = patterns[bestPattern];
|
||||
std::pair<int, int> mapping;
|
||||
if(transitionReplacement.empty())
|
||||
{
|
||||
mapping = pattern.mapping[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping = transitionReplacement == TerrainViewPattern::RULE_DIRT ? pattern.mapping[0] : pattern.mapping[1];
|
||||
}
|
||||
|
||||
// Set terrain view
|
||||
if(pattern.flipMode == TerrainViewPattern::FLIP_MODE_SAME_IMAGE)
|
||||
{
|
||||
map->terrain[i][j][mapLevel].terView = gen.getInteger(mapping.first, mapping.second);
|
||||
map->terrain[i][j][mapLevel].extTileFlags = bestFlip;
|
||||
}
|
||||
else
|
||||
{
|
||||
int range = (mapping.second - mapping.first) / 4;
|
||||
map->terrain[i][j][mapLevel].terView = gen.getInteger(mapping.first + bestFlip * range,
|
||||
mapping.first + (bestFlip + 1) * range - 1);
|
||||
map->terrain[i][j][mapLevel].extTileFlags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ETerrainGroup::ETerrainGroup CMapEditManager::getTerrainGroup(ETerrainType terType) const
|
||||
{
|
||||
switch(terType)
|
||||
{
|
||||
case ETerrainType::DIRT:
|
||||
return ETerrainGroup::DIRT;
|
||||
case ETerrainType::SAND:
|
||||
return ETerrainGroup::SAND;
|
||||
case ETerrainType::WATER:
|
||||
return ETerrainGroup::WATER;
|
||||
case ETerrainType::ROCK:
|
||||
return ETerrainGroup::ROCK;
|
||||
default:
|
||||
return ETerrainGroup::NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
CMapEditManager::ValidationResult CMapEditManager::validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern, int recDepth /*= 0*/) const
|
||||
{
|
||||
ETerrainType centerTerType = map->terrain[posx][posy][mapLevel].terType;
|
||||
int totalPoints = 0;
|
||||
std::string transitionReplacement;
|
||||
|
||||
for(int i = 0; i < 9; ++i)
|
||||
{
|
||||
// The center, middle cell can be skipped
|
||||
if(i == 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get terrain group of the current cell
|
||||
int cx = posx + (i % 3) - 1;
|
||||
int cy = posy + (i / 3) - 1;
|
||||
bool isAlien = false;
|
||||
ETerrainType terType;
|
||||
if(cx < 0 || cx >= map->width || cy < 0 || cy >= map->height)
|
||||
{
|
||||
terType = centerTerType;
|
||||
}
|
||||
else
|
||||
{
|
||||
terType = map->terrain[cx][cy][mapLevel].terType;
|
||||
if(terType != centerTerType)
|
||||
{
|
||||
isAlien = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate all rules per cell
|
||||
int topPoints = -1;
|
||||
for(int j = 0; j < pattern.data[i].size(); ++j)
|
||||
{
|
||||
TerrainViewPattern::WeightedRule rule = pattern.data[i][j];
|
||||
if(!rule.isStandardRule())
|
||||
{
|
||||
if(recDepth == 0)
|
||||
{
|
||||
const TerrainViewPattern & patternForRule = terViewPatternConfig->getPatternById(pattern.terGroup, rule.name);
|
||||
ValidationResult rslt = validateTerrainView(cx, cy, mapLevel, patternForRule, 1);
|
||||
if(!rslt.result)
|
||||
{
|
||||
return ValidationResult(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
topPoints = std::max(topPoints, rule.points);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rule.name = TerrainViewPattern::RULE_NATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
bool nativeTestOk = (rule.name == TerrainViewPattern::RULE_NATIVE || rule.name == TerrainViewPattern::RULE_ANY) && !isAlien;
|
||||
auto applyValidationRslt = [&](bool rslt)
|
||||
{
|
||||
if(rslt)
|
||||
{
|
||||
topPoints = std::max(topPoints, rule.points);
|
||||
}
|
||||
};
|
||||
|
||||
// Validate cell with the ruleset of the pattern
|
||||
if(pattern.terGroup == ETerrainGroup::NORMAL)
|
||||
{
|
||||
bool dirtTestOk = (rule.name == TerrainViewPattern::RULE_DIRT
|
||||
|| rule.name == TerrainViewPattern::RULE_TRANSITION || rule.name == TerrainViewPattern::RULE_ANY)
|
||||
&& isAlien && !isSandType(terType);
|
||||
bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION
|
||||
|| rule.name == TerrainViewPattern::RULE_ANY)
|
||||
&& isSandType(terType);
|
||||
|
||||
if(transitionReplacement.empty() && (rule.name == TerrainViewPattern::RULE_TRANSITION
|
||||
|| rule.name == TerrainViewPattern::RULE_ANY) && (dirtTestOk || sandTestOk))
|
||||
{
|
||||
transitionReplacement = dirtTestOk ? TerrainViewPattern::RULE_DIRT : TerrainViewPattern::RULE_SAND;
|
||||
}
|
||||
applyValidationRslt((dirtTestOk && transitionReplacement != TerrainViewPattern::RULE_SAND)
|
||||
|| (sandTestOk && transitionReplacement != TerrainViewPattern::RULE_DIRT)
|
||||
|| nativeTestOk);
|
||||
}
|
||||
else if(pattern.terGroup == ETerrainGroup::DIRT)
|
||||
{
|
||||
bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && isSandType(terType);
|
||||
bool dirtTestOk = rule.name == TerrainViewPattern::RULE_DIRT && !isSandType(terType) && !nativeTestOk;
|
||||
applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || dirtTestOk || nativeTestOk);
|
||||
}
|
||||
else if(pattern.terGroup == ETerrainGroup::SAND)
|
||||
{
|
||||
bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && isAlien;
|
||||
applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk);
|
||||
}
|
||||
else if(pattern.terGroup == ETerrainGroup::WATER)
|
||||
{
|
||||
bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && terType != ETerrainType::DIRT
|
||||
&& terType != ETerrainType::WATER;
|
||||
applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk);
|
||||
}
|
||||
else if(pattern.terGroup == ETerrainGroup::ROCK)
|
||||
{
|
||||
bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && terType != ETerrainType::DIRT
|
||||
&& terType != ETerrainType::ROCK;
|
||||
applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk);
|
||||
}
|
||||
}
|
||||
|
||||
if(topPoints == -1)
|
||||
{
|
||||
return ValidationResult(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
totalPoints += topPoints;
|
||||
}
|
||||
}
|
||||
|
||||
if(pattern.minPoints > totalPoints)
|
||||
{
|
||||
return ValidationResult(false);
|
||||
}
|
||||
|
||||
return ValidationResult(true, transitionReplacement);
|
||||
}
|
||||
|
||||
bool CMapEditManager::isSandType(ETerrainType terType) const
|
||||
{
|
||||
switch(terType)
|
||||
{
|
||||
case ETerrainType::WATER:
|
||||
case ETerrainType::SAND:
|
||||
case ETerrainType::ROCK:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TerrainViewPattern CMapEditManager::getFlippedPattern(const TerrainViewPattern & pattern, int flip) const
|
||||
{
|
||||
if(flip == 0)
|
||||
{
|
||||
return pattern;
|
||||
}
|
||||
|
||||
TerrainViewPattern ret = pattern;
|
||||
if(flip == FLIP_PATTERN_HORIZONTAL || flip == FLIP_PATTERN_BOTH)
|
||||
{
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
int y = i * 3;
|
||||
std::swap(ret.data[y], ret.data[y + 2]);
|
||||
}
|
||||
}
|
||||
if(flip == FLIP_PATTERN_VERTICAL || flip == FLIP_PATTERN_BOTH)
|
||||
{
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
std::swap(ret.data[i], ret.data[6 + i]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CMapEditManager::insertObject(CGObjectInstance * obj, int posx, int posy, bool underground)
|
||||
{
|
||||
obj->pos = int3(posx, posy, underground ? 1 : 0);
|
||||
obj->id = ObjectInstanceID(map->objects.size());
|
||||
map->objects.push_back(obj);
|
||||
if(obj->ID == Obj::TOWN)
|
||||
{
|
||||
map->towns.push_back(static_cast<CGTownInstance *>(obj));
|
||||
}
|
||||
if(obj->ID == Obj::HERO)
|
||||
{
|
||||
map->heroes.push_back(static_cast<CGHeroInstance*>(obj));
|
||||
}
|
||||
map->addBlockVisTiles(obj);
|
||||
}
|
||||
|
||||
CMapEditManager::ValidationResult::ValidationResult(bool result, const std::string & transitionReplacement /*= ""*/)
|
||||
: result(result), transitionReplacement(transitionReplacement)
|
||||
{
|
||||
|
||||
}
|
||||
293
lib/mapping/CMapEditManager.h
Normal file
293
lib/mapping/CMapEditManager.h
Normal file
@@ -0,0 +1,293 @@
|
||||
|
||||
/*
|
||||
* CMapEditManager.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "CMap.h"
|
||||
|
||||
class CGObjectInstance;
|
||||
|
||||
namespace ETerrainGroup
|
||||
{
|
||||
/**
|
||||
* This enumeration lists terrain groups which differ in the terrain view frames alignment.
|
||||
*/
|
||||
enum ETerrainGroup
|
||||
{
|
||||
NORMAL,
|
||||
DIRT,
|
||||
SAND,
|
||||
WATER,
|
||||
ROCK
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The terrain view pattern describes a specific composition of terrain tiles
|
||||
* in a 3x3 matrix and notes which terrain view frame numbers can be used.
|
||||
*/
|
||||
struct TerrainViewPattern
|
||||
{
|
||||
/**
|
||||
* A weighted rule struct is a combination of the rule name and optionally points.
|
||||
*/
|
||||
struct WeightedRule
|
||||
{
|
||||
/** The name of the rule. Can be any value of the RULE_* constants or a ID of a another pattern. */
|
||||
std::string name;
|
||||
|
||||
/** Optional. A rule can have points. Patterns may have a minimum count of points to reach to be successful. */
|
||||
int points;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
WeightedRule();
|
||||
|
||||
/**
|
||||
* Gets true if this rule is a standard rule which means that it has a value of one of the RULE_* constants.
|
||||
*
|
||||
* @return true for a standard rule
|
||||
*/
|
||||
bool isStandardRule() const;
|
||||
};
|
||||
|
||||
/** Constant for the flip mode same image. Pattern will be flipped and the same image will be used(which is given in the mapping). */
|
||||
static const std::string FLIP_MODE_SAME_IMAGE;
|
||||
|
||||
/** Constant for the flip mode different images. Pattern will be flipped and different images will be used(mapping area is divided into 4 parts) */
|
||||
static const std::string FLIP_MODE_DIFF_IMAGES;
|
||||
|
||||
/** Constant for the rule dirt, meaning a dirty border is required. */
|
||||
static const std::string RULE_DIRT;
|
||||
|
||||
/** Constant for the rule sand, meaning a sandy border is required. */
|
||||
static const std::string RULE_SAND;
|
||||
|
||||
/** Constant for the rule transition, meaning a dirty OR sandy border is required. */
|
||||
static const std::string RULE_TRANSITION;
|
||||
|
||||
/** Constant for the rule native, meaning a native type is required. */
|
||||
static const std::string RULE_NATIVE;
|
||||
|
||||
/** Constant for the rule any, meaning a native type, dirty OR sandy border is required. */
|
||||
static const std::string RULE_ANY;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
TerrainViewPattern();
|
||||
|
||||
/**
|
||||
* The pattern data.
|
||||
*
|
||||
* It can be visualized as a 3x3 matrix:
|
||||
* [ ][ ][ ]
|
||||
* [ ][ ][ ]
|
||||
* [ ][ ][ ]
|
||||
*
|
||||
* The box in the center belongs always to the native terrain type and
|
||||
* is the point of origin. Depending on the terrain type different rules
|
||||
* can be used. Their meaning differs also from type to type.
|
||||
*
|
||||
* std::vector -> several rules can be used in one cell
|
||||
*/
|
||||
std::array<std::vector<WeightedRule>, 9> data;
|
||||
|
||||
/** The identifier of the pattern, if it's referenced from a another pattern. */
|
||||
std::string id;
|
||||
|
||||
/**
|
||||
* This describes the mapping between this pattern and the corresponding range of frames
|
||||
* which should be used for the ter view.
|
||||
*
|
||||
* std::vector -> size=1: typical, size=2: if this pattern should map to two different types of borders
|
||||
* std::pair -> 1st value: lower range, 2nd value: upper range
|
||||
*/
|
||||
std::vector<std::pair<int, int> > mapping;
|
||||
|
||||
/** The minimum points to reach to to validate the pattern successfully. */
|
||||
int minPoints;
|
||||
|
||||
/** Describes if flipping is required and which mapping should be used. */
|
||||
std::string flipMode;
|
||||
|
||||
/** The terrain group to which the pattern belongs to. */
|
||||
ETerrainGroup::ETerrainGroup terGroup;
|
||||
};
|
||||
|
||||
/**
|
||||
* The terrain view pattern config loads pattern data from the filesystem.
|
||||
*/
|
||||
class CTerrainViewPatternConfig
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor. Initializes the patterns data.
|
||||
*/
|
||||
CTerrainViewPatternConfig();
|
||||
|
||||
/**
|
||||
* Gets the patterns for a specific group of terrain.
|
||||
*
|
||||
* @param terGroup the terrain group e.g. normal for grass, lava,... OR dirt OR sand,...
|
||||
* @return a vector containing patterns
|
||||
*/
|
||||
const std::vector<TerrainViewPattern> & getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const;
|
||||
|
||||
/**
|
||||
* Gets a pattern by ID. Throws if pattern isn't available(config error).
|
||||
*
|
||||
* @param terGroup the terrain group e.g. normal for grass, lava,... OR dirt OR sand,...
|
||||
* @param id the id of the pattern
|
||||
* @return the pattern which matches the ID
|
||||
*/
|
||||
const TerrainViewPattern & getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const;
|
||||
|
||||
private:
|
||||
/** The patterns data. */
|
||||
std::map<ETerrainGroup::ETerrainGroup, std::vector<TerrainViewPattern> > patterns;
|
||||
};
|
||||
|
||||
/**
|
||||
* The map edit manager provides functionality for drawing terrain and placing
|
||||
* objects on the map.
|
||||
*
|
||||
* TODO add undo / selection functionality for the map editor
|
||||
*/
|
||||
class CMapEditManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor. The map object / terrain data has to be initialized.
|
||||
*
|
||||
* @param terViewPatternConfig the terrain view pattern config
|
||||
* @param map the map object which should be edited
|
||||
* @param randomSeed optional. the seed which is used for generating randomly terrain views
|
||||
*/
|
||||
CMapEditManager(const CTerrainViewPatternConfig * terViewPatternConfig, CMap * map, int randomSeed = std::time(nullptr));
|
||||
|
||||
/**
|
||||
* Clears the terrain. The free level is filled with water and the
|
||||
* underground level with rock.
|
||||
*/
|
||||
void clearTerrain();
|
||||
|
||||
/**
|
||||
* Draws terrain.
|
||||
*
|
||||
* @param terType the type of the terrain to draw
|
||||
* @param posx the x coordinate
|
||||
* @param posy the y coordinate
|
||||
* @param width the height of the terrain to draw
|
||||
* @param height the width of the terrain to draw
|
||||
* @param underground true if you want to draw at the underground, false if open
|
||||
*/
|
||||
void drawTerrain(ETerrainType terType, int posx, int posy, int width, int height, bool underground);
|
||||
|
||||
/**
|
||||
* Inserts an object.
|
||||
*
|
||||
* @param obj the object to insert
|
||||
* @param posx the x coordinate
|
||||
* @param posy the y coordinate
|
||||
* @param underground true if you want to draw at the underground, false if open
|
||||
*/
|
||||
void insertObject(CGObjectInstance * obj, int posx, int posy, bool underground);
|
||||
|
||||
private:
|
||||
/**
|
||||
* The validation result struct represents the result of a pattern validation.
|
||||
*/
|
||||
struct ValidationResult
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param result the result of the validation either true or false
|
||||
* @param transitionReplacement optional. the replacement of a T rule, either D or S
|
||||
*/
|
||||
ValidationResult(bool result, const std::string & transitionReplacement = "");
|
||||
|
||||
/** The result of the validation. */
|
||||
bool result;
|
||||
|
||||
/** The replacement of a T rule, either D or S. */
|
||||
std::string transitionReplacement;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the terrain view ids in the specified area.
|
||||
*
|
||||
* @param posx the x coordinate
|
||||
* @param posy the y coordinate
|
||||
* @param width the height of the terrain to update
|
||||
* @param height the width of the terrain to update
|
||||
* @param mapLevel the map level, 0 for open and 1 for underground
|
||||
*/
|
||||
void updateTerrainViews(int posx, int posy, int width, int height, int mapLevel);
|
||||
|
||||
/**
|
||||
* Gets the terrain group by the terrain type number.
|
||||
*
|
||||
* @param terType the terrain type
|
||||
* @return the terrain group
|
||||
*/
|
||||
ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType terType) const;
|
||||
|
||||
/**
|
||||
* Validates the terrain view of the given position and with the given pattern.
|
||||
*
|
||||
* @param posx the x position
|
||||
* @param posy the y position
|
||||
* @param mapLevel the map level, 0 for open and 1 for underground
|
||||
* @param pattern the pattern to validate the terrain view with
|
||||
* @param recDepth the depth of the recursion, 0 for no recursion - 1 for recursion
|
||||
* @return a validation result struct
|
||||
*/
|
||||
ValidationResult validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern, int recDepth = 0) const;
|
||||
|
||||
/**
|
||||
* Tests whether the given terrain type is a sand type. Sand types are: Water, Sand and Rock
|
||||
*
|
||||
* @param terType the terrain type to test
|
||||
* @return true if the terrain type is a sand type, otherwise false
|
||||
*/
|
||||
bool isSandType(ETerrainType terType) const;
|
||||
|
||||
/**
|
||||
* Gets a flipped pattern.
|
||||
*
|
||||
* @param pattern the original pattern to flip
|
||||
* @param flip the flip mode value, see FLIP_PATTERN_* constants for details
|
||||
* @return the flipped pattern
|
||||
*/
|
||||
TerrainViewPattern getFlippedPattern(const TerrainViewPattern & pattern, int flip) const;
|
||||
|
||||
/** Constant for flipping a pattern horizontally. */
|
||||
static const int FLIP_PATTERN_HORIZONTAL = 1;
|
||||
|
||||
/** Constant for flipping a pattern vertically. */
|
||||
static const int FLIP_PATTERN_VERTICAL = 2;
|
||||
|
||||
/** Constant for flipping a pattern horizontally and vertically. */
|
||||
static const int FLIP_PATTERN_BOTH = 3;
|
||||
|
||||
/** The map object to edit. */
|
||||
CMap * map;
|
||||
|
||||
/** The random number generator. */
|
||||
CRandomGenerator gen;
|
||||
|
||||
/** The terrain view pattern config. */
|
||||
const CTerrainViewPatternConfig * terViewPatternConfig;
|
||||
};
|
||||
49
lib/mapping/CMapInfo.cpp
Normal file
49
lib/mapping/CMapInfo.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "StdInc.h"
|
||||
#include "CMapInfo.h"
|
||||
|
||||
#include "../StartInfo.h"
|
||||
#include "CMap.h"
|
||||
#include "CCampaignHandler.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "CMapService.h"
|
||||
|
||||
void CMapInfo::countPlayers()
|
||||
{
|
||||
actualHumanPlayers = playerAmnt = humanPlayers = 0;
|
||||
for(int i=0; i<PlayerColor::PLAYER_LIMIT_I; i++)
|
||||
{
|
||||
if(mapHeader->players[i].canHumanPlay)
|
||||
{
|
||||
playerAmnt++;
|
||||
humanPlayers++;
|
||||
}
|
||||
else if(mapHeader->players[i].canComputerPlay)
|
||||
{
|
||||
playerAmnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if(scenarioOpts)
|
||||
for (auto i = scenarioOpts->playerInfos.cbegin(); i != scenarioOpts->playerInfos.cend(); i++)
|
||||
if(i->second.playerID != PlayerSettings::PLAYER_AI)
|
||||
actualHumanPlayers++;
|
||||
}
|
||||
|
||||
CMapInfo::CMapInfo() : scenarioOpts(nullptr), playerAmnt(0), humanPlayers(0),
|
||||
actualHumanPlayers(0), isRandomMap(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CMapInfo::mapInit(const std::string & fname)
|
||||
{
|
||||
fileURI = fname;
|
||||
mapHeader = CMapService::loadMapHeader(fname);
|
||||
countPlayers();
|
||||
}
|
||||
|
||||
void CMapInfo::campaignInit()
|
||||
{
|
||||
campaignHeader = std::unique_ptr<CCampaignHeader>(new CCampaignHeader(CCampaignHandler::getHeader(fileURI)));
|
||||
}
|
||||
|
||||
45
lib/mapping/CMapInfo.h
Normal file
45
lib/mapping/CMapInfo.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
// Forward class declarations aren't enough here. The compiler
|
||||
// generated CMapInfo d-tor, generates the unique_ptr d-tor as well here
|
||||
// as a inline method. The unique_ptr d-tor requires a complete type. Defining
|
||||
// the CMapInfo d-tor to let the compiler add the d-tor stuff in the .cpp file
|
||||
// would work with one exception. It prevents the generation of the move
|
||||
// constructor which is needed. (Writing such a c-tor is nasty.) With the
|
||||
// new c++11 keyword "default" for constructors this problem could be solved. But it isn't
|
||||
// available for Visual Studio for now. (Empty d-tor in .cpp would be required anyway)
|
||||
#include "CMap.h"
|
||||
#include "CCampaignHandler.h"
|
||||
|
||||
struct StartInfo;
|
||||
|
||||
/**
|
||||
* A class which stores the count of human players and all players, the filename,
|
||||
* scenario options, the map header information,...
|
||||
*/
|
||||
class DLL_LINKAGE CMapInfo
|
||||
{
|
||||
public:
|
||||
//FIXME: unique_ptr won't work here with gcc-4.5. (can't move into vector at CPregame.cpp, SelectionTab::parseMaps() method)
|
||||
//Needs some workaround or wait till there is no need to support 4.5
|
||||
shared_ptr<CMapHeader> mapHeader; //may be nullptr if campaign
|
||||
shared_ptr<CCampaignHeader> campaignHeader; //may be nullptr if scenario
|
||||
StartInfo * scenarioOpts; //options with which scenario has been started (used only with saved games)
|
||||
std::string fileURI;
|
||||
std::string date;
|
||||
int playerAmnt; //players in map
|
||||
int humanPlayers; //players ALLOWED to be controlled by human
|
||||
int actualHumanPlayers; // >1 if multiplayer game
|
||||
bool isRandomMap; // true if the map will be created randomly, false if not
|
||||
|
||||
CMapInfo();
|
||||
void mapInit(const std::string & fname);
|
||||
void campaignInit();
|
||||
void countPlayers();
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int Version)
|
||||
{
|
||||
h & mapHeader & campaignHeader & scenarioOpts & fileURI & date & playerAmnt & humanPlayers;
|
||||
h & actualHumanPlayers & isRandomMap;
|
||||
}
|
||||
};
|
||||
70
lib/mapping/CMapService.cpp
Normal file
70
lib/mapping/CMapService.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "StdInc.h"
|
||||
#include "CMapService.h"
|
||||
|
||||
#include "../filesystem/CResourceLoader.h"
|
||||
#include "../filesystem/CBinaryReader.h"
|
||||
#include "../filesystem/CCompressedStream.h"
|
||||
#include "../filesystem/CMemoryStream.h"
|
||||
#include "CMap.h"
|
||||
|
||||
#include "MapFormatH3M.h"
|
||||
|
||||
|
||||
std::unique_ptr<CMap> CMapService::loadMap(const std::string & name)
|
||||
{
|
||||
auto stream = getStreamFromFS(name);
|
||||
return getMapLoader(stream)->loadMap();
|
||||
}
|
||||
|
||||
std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const std::string & name)
|
||||
{
|
||||
auto stream = getStreamFromFS(name);
|
||||
return getMapLoader(stream)->loadMapHeader();
|
||||
}
|
||||
|
||||
std::unique_ptr<CMap> CMapService::loadMap(const ui8 * buffer, int size)
|
||||
{
|
||||
auto stream = getStreamFromMem(buffer, size);
|
||||
return getMapLoader(stream)->loadMap();
|
||||
}
|
||||
|
||||
std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const ui8 * buffer, int size)
|
||||
{
|
||||
auto stream = getStreamFromMem(buffer, size);
|
||||
return getMapLoader(stream)->loadMapHeader();
|
||||
}
|
||||
|
||||
std::unique_ptr<CInputStream> CMapService::getStreamFromFS(const std::string & name)
|
||||
{
|
||||
return CResourceHandler::get()->load(ResourceID(name, EResType::MAP));
|
||||
}
|
||||
|
||||
std::unique_ptr<CInputStream> CMapService::getStreamFromMem(const ui8 * buffer, int size)
|
||||
{
|
||||
return std::unique_ptr<CInputStream>(new CMemoryStream(buffer, size));
|
||||
}
|
||||
|
||||
std::unique_ptr<IMapLoader> CMapService::getMapLoader(std::unique_ptr<CInputStream> & stream)
|
||||
{
|
||||
// Read map header
|
||||
CBinaryReader reader(stream.get());
|
||||
ui32 header = reader.readUInt32();
|
||||
reader.getStream()->seek(0);
|
||||
|
||||
// Check which map format is used
|
||||
// gzip header is 3 bytes only in size
|
||||
switch(header & 0xffffff)
|
||||
{
|
||||
// gzip header magic number, reversed for LE
|
||||
case 0x00088B1F:
|
||||
stream = std::unique_ptr<CInputStream>(new CCompressedStream(std::move(stream), true));
|
||||
return std::unique_ptr<IMapLoader>(new CMapLoaderH3M(stream.get()));
|
||||
case EMapFormat::WOG :
|
||||
case EMapFormat::AB :
|
||||
case EMapFormat::ROE :
|
||||
case EMapFormat::SOD :
|
||||
return std::unique_ptr<IMapLoader>(new CMapLoaderH3M(stream.get()));
|
||||
default :
|
||||
throw std::runtime_error("Unknown map format");
|
||||
}
|
||||
}
|
||||
118
lib/mapping/CMapService.h
Normal file
118
lib/mapping/CMapService.h
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
/*
|
||||
* CMapService.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class CMap;
|
||||
class CMapHeader;
|
||||
class CInputStream;
|
||||
|
||||
class IMapLoader;
|
||||
|
||||
/**
|
||||
* The map service provides loading of VCMI/H3 map files. It can
|
||||
* be extended to save maps later as well.
|
||||
*/
|
||||
class DLL_LINKAGE CMapService
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Loads the VCMI/H3 map file specified by the name.
|
||||
*
|
||||
* @param name the name of the map
|
||||
* @return a unique ptr to the loaded map class
|
||||
*/
|
||||
static std::unique_ptr<CMap> loadMap(const std::string & name);
|
||||
|
||||
/**
|
||||
* Loads the VCMI/H3 map header specified by the name.
|
||||
*
|
||||
* @param name the name of the map
|
||||
* @return a unique ptr to the loaded map header class
|
||||
*/
|
||||
static std::unique_ptr<CMapHeader> loadMapHeader(const std::string & name);
|
||||
|
||||
/**
|
||||
* Loads the VCMI/H3 map file from a buffer. This method is temporarily
|
||||
* in use to ease the transition to use the new map service.
|
||||
*
|
||||
* TODO Replace method params with a CampaignMapInfo struct which contains
|
||||
* a campaign loading object + name of map.
|
||||
*
|
||||
* @param buffer a pointer to a buffer containing the map data
|
||||
* @param size the size of the buffer
|
||||
* @return a unique ptr to the loaded map class
|
||||
*/
|
||||
static std::unique_ptr<CMap> loadMap(const ui8 * buffer, int size);
|
||||
|
||||
/**
|
||||
* Loads the VCMI/H3 map header from a buffer. This method is temporarily
|
||||
* in use to ease the transition to use the new map service.
|
||||
*
|
||||
* TODO Replace method params with a CampaignMapInfo struct which contains
|
||||
* a campaign loading object + name of map.
|
||||
*
|
||||
* @param buffer a pointer to a buffer containing the map header data
|
||||
* @param size the size of the buffer
|
||||
* @return a unique ptr to the loaded map class
|
||||
*/
|
||||
static std::unique_ptr<CMapHeader> loadMapHeader(const ui8 * buffer, int size);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Gets a map input stream object specified by a map name.
|
||||
*
|
||||
* @param name the name of the map
|
||||
* @return a unique ptr to the input stream class
|
||||
*/
|
||||
static std::unique_ptr<CInputStream> getStreamFromFS(const std::string & name);
|
||||
|
||||
/**
|
||||
* Gets a map input stream from a buffer.
|
||||
*
|
||||
* @param buffer a pointer to a buffer containing the map data
|
||||
* @param size the size of the buffer
|
||||
* @return a unique ptr to the input stream class
|
||||
*/
|
||||
static std::unique_ptr<CInputStream> getStreamFromMem(const ui8 * buffer, int size);
|
||||
|
||||
/**
|
||||
* Gets a map loader from the given stream. It performs checks to test
|
||||
* in which map format the map is.
|
||||
*
|
||||
* @param stream the input map stream
|
||||
* @return the constructed map loader
|
||||
*/
|
||||
static std::unique_ptr<IMapLoader> getMapLoader(std::unique_ptr<CInputStream> & stream);
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for loading a map.
|
||||
*/
|
||||
class DLL_LINKAGE IMapLoader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Loads the VCMI/H3 map file.
|
||||
*
|
||||
* @return a unique ptr of the loaded map class
|
||||
*/
|
||||
virtual std::unique_ptr<CMap> loadMap() = 0;
|
||||
|
||||
/**
|
||||
* Loads the VCMI/H3 map header.
|
||||
*
|
||||
* @return a unique ptr of the loaded map header class
|
||||
*/
|
||||
virtual std::unique_ptr<CMapHeader> loadMapHeader() = 0;
|
||||
};
|
||||
|
||||
|
||||
2181
lib/mapping/MapFormatH3M.cpp
Normal file
2181
lib/mapping/MapFormatH3M.cpp
Normal file
File diff suppressed because it is too large
Load Diff
265
lib/mapping/MapFormatH3M.h
Normal file
265
lib/mapping/MapFormatH3M.h
Normal file
@@ -0,0 +1,265 @@
|
||||
|
||||
/*
|
||||
* MapFormatH3M.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CMapService.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "../ResourceSet.h"
|
||||
|
||||
#include "../int3.h"
|
||||
|
||||
#include "../filesystem/CBinaryReader.h"
|
||||
|
||||
class CGHeroInstance;
|
||||
class CArtifactInstance;
|
||||
class CGObjectInstance;
|
||||
class CGSeerHut;
|
||||
class IQuestObject;
|
||||
class CGTownInstance;
|
||||
class CCreatureSet;
|
||||
class CInputStream;
|
||||
|
||||
|
||||
class DLL_LINKAGE CMapLoaderH3M : public IMapLoader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @param stream a stream containing the map data
|
||||
*/
|
||||
CMapLoaderH3M(CInputStream * stream);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~CMapLoaderH3M();
|
||||
|
||||
/**
|
||||
* Loads the VCMI/H3 map file.
|
||||
*
|
||||
* @return a unique ptr of the loaded map class
|
||||
*/
|
||||
std::unique_ptr<CMap> loadMap();
|
||||
|
||||
/**
|
||||
* Loads the VCMI/H3 map header.
|
||||
*
|
||||
* @return a unique ptr of the loaded map header class
|
||||
*/
|
||||
std::unique_ptr<CMapHeader> loadMapHeader();
|
||||
|
||||
/** true if you want to enable the map loader profiler to see how long a specific part took; default=false */
|
||||
static const bool IS_PROFILING_ENABLED;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initializes the map object from parsing the input buffer.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Reads the map header.
|
||||
*/
|
||||
void readHeader();
|
||||
|
||||
/**
|
||||
* Reads player information.
|
||||
*/
|
||||
void readPlayerInfo();
|
||||
|
||||
/**
|
||||
* Reads victory/loss conditions.
|
||||
*/
|
||||
void readVictoryLossConditions();
|
||||
|
||||
/**
|
||||
* Reads team information.
|
||||
*/
|
||||
void readTeamInfo();
|
||||
|
||||
/**
|
||||
* Reads the list of allowed heroes.
|
||||
*/
|
||||
void readAllowedHeroes();
|
||||
|
||||
/**
|
||||
* Reads the list of disposed heroes.
|
||||
*/
|
||||
void readDisposedHeroes();
|
||||
|
||||
/**
|
||||
* Reads the list of allowed artifacts.
|
||||
*/
|
||||
void readAllowedArtifacts();
|
||||
|
||||
/**
|
||||
* Reads the list of allowed spells and abilities.
|
||||
*/
|
||||
void readAllowedSpellsAbilities();
|
||||
|
||||
/**
|
||||
* Loads artifacts of a hero.
|
||||
*
|
||||
* @param hero the hero which should hold those artifacts
|
||||
*/
|
||||
void loadArtifactsOfHero(CGHeroInstance * hero);
|
||||
|
||||
/**
|
||||
* Loads an artifact to the given slot of the specified hero.
|
||||
*
|
||||
* @param hero the hero which should hold that artifact
|
||||
* @param slot the artifact slot where to place that artifact
|
||||
* @return true if it loaded an artifact
|
||||
*/
|
||||
bool loadArtifactToSlot(CGHeroInstance * hero, int slot);
|
||||
|
||||
/**
|
||||
* Creates an artifact instance.
|
||||
*
|
||||
* @param aid the id of the artifact
|
||||
* @param spellID optional. the id of a spell if a spell scroll object should be created
|
||||
* @return the created artifact instance
|
||||
*/
|
||||
CArtifactInstance * createArtifact(int aid, int spellID = -1);
|
||||
|
||||
/**
|
||||
* Read rumors.
|
||||
*/
|
||||
void readRumors();
|
||||
|
||||
/**
|
||||
* Reads predefined heroes.
|
||||
*/
|
||||
void readPredefinedHeroes();
|
||||
|
||||
/**
|
||||
* Reads terrain data.
|
||||
*/
|
||||
void readTerrain();
|
||||
|
||||
/**
|
||||
* Reads custom(map) def information.
|
||||
*/
|
||||
void readDefInfo();
|
||||
|
||||
/**
|
||||
* Reads objects(towns, mines,...).
|
||||
*/
|
||||
void readObjects();
|
||||
|
||||
/**
|
||||
* Reads a creature set.
|
||||
*
|
||||
* @param out the loaded creature set
|
||||
* @param number the count of creatures to read
|
||||
*/
|
||||
void readCreatureSet(CCreatureSet * out, int number);
|
||||
|
||||
/**
|
||||
* Reads a hero.
|
||||
*
|
||||
* @param idToBeGiven the object id which should be set for the hero
|
||||
* @return a object instance
|
||||
*/
|
||||
CGObjectInstance * readHero(ObjectInstanceID idToBeGiven);
|
||||
|
||||
/**
|
||||
* Reads a seer hut.
|
||||
*
|
||||
* @return the initialized seer hut object
|
||||
*/
|
||||
CGSeerHut * readSeerHut();
|
||||
|
||||
/**
|
||||
* Reads a quest for the given quest guard.
|
||||
*
|
||||
* @param guard the quest guard where that quest should be applied to
|
||||
*/
|
||||
void readQuest(IQuestObject * guard);
|
||||
|
||||
/**
|
||||
* Reads a town.
|
||||
*
|
||||
* @param castleID the id of the castle type
|
||||
* @return the loaded town object
|
||||
*/
|
||||
CGTownInstance * readTown(int castleID);
|
||||
|
||||
/**
|
||||
* Converts buildings to the specified castle id.
|
||||
*
|
||||
* @param h3m the ids of the buildings
|
||||
* @param castleID the castle id
|
||||
* @param addAuxiliary true if the village hall should be added
|
||||
* @return the converted buildings
|
||||
*/
|
||||
std::set<BuildingID> convertBuildings(const std::set<BuildingID> h3m, int castleID, bool addAuxiliary = true);
|
||||
|
||||
/**
|
||||
* Reads events.
|
||||
*/
|
||||
void readEvents();
|
||||
|
||||
/**
|
||||
* read optional message and optional guards
|
||||
*/
|
||||
void readMessageAndGuards(std::string& message, CCreatureSet * guards);
|
||||
|
||||
void readSpells(std::set<SpellID> & dest);
|
||||
|
||||
void readResourses(TResources& resources);
|
||||
|
||||
template <class Indenifier>
|
||||
void readBitmask(std::set<Indenifier> &dest, const int byteCount, const int limit, bool negate = true);
|
||||
|
||||
/** Reads bitmask to boolean vector
|
||||
* @param dest destination vector, shall be filed with "true" values
|
||||
* @param byteCount size in bytes of bimask
|
||||
* @param limit max count of vector elements to alter
|
||||
* @param negate if true then set bit in mask means clear flag in vertor
|
||||
*/
|
||||
void readBitmask(std::vector<bool> & dest, const int byteCount, const int limit, bool negate = true);
|
||||
|
||||
/**
|
||||
* Reverses the input argument.
|
||||
*
|
||||
* @param arg the input argument
|
||||
* @return the reversed 8-bit integer
|
||||
*/
|
||||
ui8 reverse(ui8 arg);
|
||||
|
||||
/**
|
||||
* Helper to read map position
|
||||
*/
|
||||
inline int3 readInt3()
|
||||
{
|
||||
int3 p;
|
||||
p.x = reader.readUInt8();
|
||||
p.y = reader.readUInt8();
|
||||
p.z = reader.readUInt8();
|
||||
return p;
|
||||
}
|
||||
|
||||
/** ptr to the map object which gets filled by data from the buffer */
|
||||
CMap * map;
|
||||
|
||||
/**
|
||||
* ptr to the map header object which gets filled by data from the buffer.
|
||||
* (when loading a map then the mapHeader ptr points to the same object)
|
||||
*/
|
||||
std::unique_ptr<CMapHeader> mapHeader;
|
||||
|
||||
CBinaryReader reader;
|
||||
CInputStream * inputStream;
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user