1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

- fixed crash on start of some campaigns

- allowed on map factions is now set instead of bit field
This commit is contained in:
Ivan Savenko
2012-09-23 14:32:49 +00:00
parent 00c079f7dc
commit 3fcba4fb5c
10 changed files with 66 additions and 69 deletions

View File

@@ -1914,41 +1914,30 @@ void OptionsTab::nextCastle( int player, int dir )
PlayerSettings &s = SEL->sInfo.playerInfos[player];
si32 &cur = s.castle;
ui32 allowed = SEL->current->mapHeader->players[s.color].allowedFactions;
auto & allowed = SEL->current->mapHeader->players[s.color].allowedFactions;
if (cur == -2) //no castle - no change
return;
if (cur == -1) //random => first/last available
{
int pom = (dir>0) ? (0) : (GameConstants::F_NUMBER-1); // last or first
for (;pom >= 0 && pom < GameConstants::F_NUMBER; pom+=dir)
{
if((1 << pom) & allowed)
{
cur=pom;
break;
}
}
if (dir > 0)
cur = *allowed.begin(); //id of first town
else
cur = *allowed.rbegin(); //id of last town
}
else // next/previous available
{
for (;;)
if ( (cur == *allowed.begin() && dir < 0 )
|| (cur == *allowed.rbegin() && dir > 0) )
cur = -1;
else
{
cur+=dir;
if ((1 << cur) & allowed)
break;
if (cur >= GameConstants::F_NUMBER || cur<0)
{
double p1 = log((double)allowed) / log(2.0)+0.000001;
double check = p1 - ((int)p1);
if (check < 0.001)
cur = (int)p1;
else
cur = -1;
break;
}
assert(dir >= -1 && dir <= 1); //othervice std::advance may go out of range
auto iter = allowed.find(cur);
std::advance(iter, dir);
cur = *iter;
}
}

View File

@@ -448,7 +448,7 @@ CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg
if (creature)
{
std::string imgName = owner->smallIcons ? "cprsmall" : "TWCRPORT";
creatureImage = new CAnimImage(imgName, creature->idNumber + 2);
creatureImage = new CAnimImage(imgName, creature->iconIndex);
}
else
creatureImage = nullptr;

View File

@@ -52,23 +52,18 @@ unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name )
ret->scenarios.push_back(sc);
}
int scenarioID = 0;
//first entry is campaign header. start loop from 1
for (int g=1; g<file.size() && g<howManyScenarios; ++g)
for (int g=1; g<file.size() && scenarioID<howManyScenarios; ++g)
{
while(!ret->scenarios[scenarioID].isNotVoid()) //skip void scenarios
{
scenarioID++;
}
//set map piece appropriately
ret->mapPieces[scenarioID].resize(file[g].size());
for(int i = 0; i < file[g].size(); i++)
ret->mapPieces[scenarioID][i] = file[g][i];
//set map piece appropriately, convert vector to string
ret->mapPieces[scenarioID].assign(reinterpret_cast< const char* >(file[g].data()), file[g].size());
scenarioID++;
}

View File

@@ -931,12 +931,11 @@ void CGameState::init(StartInfo * si)
{
if(it->second.castle==-1)
{
int f;
do
{
f = ran()%GameConstants::F_NUMBER;
}while(!(map->players[it->first].allowedFactions & 1<<f));
it->second.castle = f;
int randomID = ran() % map->players[it->first].allowedFactions.size();
auto iter = map->players[it->first].allowedFactions.begin();
std::advance(iter, randomID);
it->second.castle = *iter;
}
}

View File

@@ -81,6 +81,8 @@ void CModHandler::loadConfigFromFile (std::string name)
tlog3 << "\t\tFound mod file: " << entry.getResourceName() << "\n";
const JsonNode config ((char*)textData.get(), stream->getSize());
VLC->townh->loadFactions(config["factions"]);
const JsonNode *value = &config["creatures"];
BOOST_FOREACH (auto creature, value->Vector())
{

View File

@@ -5,6 +5,7 @@
#include "VCMI_Lib.h"
#include "CCreatureHandler.h"
#include "CArtHandler.h"
#include "CTownHandler.h"
/*
* CModHandler.h, part of VCMI engine

View File

@@ -189,10 +189,6 @@ class DLL_LINKAGE CTownHandler
void loadPuzzle(CFaction & faction, const JsonNode & source);
/// main loading function, accepts merged JSON source and add all entries from it into game
/// all entries in JSON should be checked for validness before using this function
void loadFactions(const JsonNode & source);
/// load all available data from h3 txt(s) into json structure using format similar to vcmi configs
/// returns 2d array [townID] [buildID] of buildings
void loadLegacyData(JsonNode & dest);
@@ -203,7 +199,11 @@ public:
CTownHandler(); //c-tor, set pointer in VLC to this
/// "entry point" for towns loading.
/// main loading function for mods, accepts merged JSON source and add all entries from it into game
/// all entries in JSON should be checked for validness before using this function
void loadFactions(const JsonNode & source);
/// "entry point" for loading of OH3 town.
/// reads legacy txt's from H3 + vcmi json, merges them
/// and loads resulting structure to game using loadTowns method
/// in future may require loaded Creature Handler

View File

@@ -543,31 +543,38 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
{
ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", -1);
int ret = EBuildingState::ALLOWED;
if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN)
ret = EBuildingState::CANT_BUILD_TODAY; //building limit
CBuilding * pom = t->town->buildings[ID];
if(!pom)
return EBuildingState::BUILDING_ERROR;
//checking resources
if(!pom->resources.canBeAfforded(getPlayer(t->tempOwner)->resources))
ret = EBuildingState::NO_RESOURCES; //lack of res
if(t->hasBuilt(ID)) //already built
return EBuildingState::ALREADY_PRESENT;
//can we build it?
if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end())
return EBuildingState::FORBIDDEN; //forbidden
//checking for requirements
std::set<int> reqs = getBuildingRequiments(t, ID);//getting all requirements
bool notAllBuilt = false;
for( std::set<int>::iterator ri = reqs.begin(); ri != reqs.end(); ri++ )
{
if(!t->hasBuilt(*ri))
ret = EBuildingState::PREREQUIRES; //lack of requirements - cannot build
if(!t->hasBuilt(*ri)) //lack of requirements - cannot build
{
if(vstd::contains(t->forbiddenBuildings, *ri)) // not built requirement forbidden - same goes to this build
return EBuildingState::FORBIDDEN;
else
notAllBuilt = true; // no return here - we need to check if any required builds are forbidden
}
}
//can we build it?
if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end())
ret = EBuildingState::FORBIDDEN; //forbidden
if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN)
return EBuildingState::CANT_BUILD_TODAY; //building limit
if (notAllBuilt)
return EBuildingState::PREREQUIRES;
if(ID == 13) //capitol
{
@@ -578,8 +585,7 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
{
if(t->hasBuilt(EBuilding::CAPITOL))
{
ret = EBuildingState::HAVE_CAPITAL; //no more than one capitol
break;
return EBuildingState::HAVE_CAPITAL; //no more than one capitol
}
}
}
@@ -589,12 +595,14 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
const TerrainTile *tile = getTile(t->bestLocation(), false);
if(!tile || tile->tertype != TerrainTile::water )
ret = EBuildingState::NO_WATER; //lack of water
return EBuildingState::NO_WATER; //lack of water
}
if(t->hasBuilt(ID)) //already built
ret = EBuildingState::ALREADY_PRESENT;
return ret;
//checking resources
if(!pom->resources.canBeAfforded(getPlayer(t->tempOwner)->resources))
return EBuildingState::NO_RESOURCES; //lack of res
return EBuildingState::ALLOWED;
}
std::set<int> CGameInfoCallback::getBuildingRequiments( const CGTownInstance *t, int ID )

View File

@@ -228,10 +228,13 @@ void CMapHeader::loadPlayerInfo( int &pom, const ui8 * bufor, int &i )
players[pom].p7= -1;
//factions this player can choose
players[pom].allowedFactions = 0;
players[pom].allowedFactions += bufor[i++];
ui16 allowedFactions = bufor[i++];
if(version != RoE)
players[pom].allowedFactions += (bufor[i++])*256;
allowedFactions += (bufor[i++])*256;
for (size_t fact=0; fact<16; fact++)
if (allowedFactions & (1 << fact))
players[pom].allowedFactions.insert(fact);
players[pom].isFactionRandom = bufor[i++];
players[pom].hasMainTown = bufor[i++];

View File

@@ -96,7 +96,7 @@ struct DLL_LINKAGE PlayerInfo
ui8 canHumanPlay;
ui8 canComputerPlay;
ui32 AITactic; //(00 - random, 01 - warrior, 02 - builder, 03 - explorer)
ui32 allowedFactions; //(01 - castle; 02 - rampart; 04 - tower; 08 - inferno; 16 - necropolis; 32 - dungeon; 64 - stronghold; 128 - fortress; 256 - conflux);
std::set<ui32> allowedFactions; //set with factions player can play with
ui8 isFactionRandom;
ui32 mainHeroPortrait; //it's ID of hero with chosen portrait; 255 if standard
std::string mainHeroName;
@@ -108,7 +108,7 @@ struct DLL_LINKAGE PlayerInfo
ui8 generateHero;
PlayerInfo(): p7(0), p8(0), p9(0), canHumanPlay(0), canComputerPlay(0),
AITactic(0), allowedFactions(0), isFactionRandom(0),
AITactic(0), isFactionRandom(0),
mainHeroPortrait(0), hasMainTown(0), generateHeroAtMainTown(0),
team(255), generateHero(0) {};
@@ -117,7 +117,7 @@ struct DLL_LINKAGE PlayerInfo
si8 ret = -2;
for (int j = 0; j < GameConstants::F_NUMBER && ret != -1; j++) //we start with none and find matching faction. if more than one, then set to random
{
if((1 << j) & allowedFactions)
if(vstd::contains(allowedFactions, j))
{
if (ret >= 0) //we've already assigned a castle and another one is possible -> set random and let player choose
ret = -1; //breaks