diff --git a/client/CAdvmapInterface.cpp b/client/CAdvmapInterface.cpp index c2d7cad91..eb1747b46 100644 --- a/client/CAdvmapInterface.cpp +++ b/client/CAdvmapInterface.cpp @@ -1074,6 +1074,7 @@ townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlis setPlayer(LOCPLINT->playerID); + underground.block(!CGI->mh->map->twoLevel); } CAdvMapInt::~CAdvMapInt() diff --git a/client/CKingdomInterface.cpp b/client/CKingdomInterface.cpp index 238504d7c..f5cef4d44 100644 --- a/client/CKingdomInterface.cpp +++ b/client/CKingdomInterface.cpp @@ -507,7 +507,7 @@ void CKingdomInterface::generateObjectsList(const std::vectorsubID]; if (info.count++ == 0) { - info.hoverText = CGI->creh->creatures[CGI->objh->cregens[object->subID]]->namePl; + info.hoverText = CGI->creh->creatures[CGI->objh->cregens.find(object->subID)->second]->namePl; info.imageID = object->subID; } } diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 33041e231..7d5294575 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -2144,6 +2144,7 @@ void CPlayerInterface::acceptTurn() else adventureInt->select(towns.front()); + adventureInt->updateNextHero(NULL); adventureInt->showAll(screen); if(settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed()) diff --git a/client/mapHandler.cpp b/client/mapHandler.cpp index 56ea14610..c6092fcff 100644 --- a/client/mapHandler.cpp +++ b/client/mapHandler.cpp @@ -498,23 +498,43 @@ void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std:: sr.h=sr.w=32; //blit terrain with river/road - if(tile.terbitmap) { //if custom terrain graphic - use it + if(tile.terbitmap) + { //if custom terrain graphic - use it SDL_Rect temp_rect = genRect(sr.h, sr.w, 0, 0); CSDL_Ext::blitSurface(tile.terbitmap, &temp_rect, extSurf, &sr); - } else //use default terrain graphic + } + else //use default terrain graphic + { blitterWithRotation(terrainGraphics[tinfo.tertype][tinfo.terview],rtile, extSurf, sr, tinfo.siodmyTajemniczyBajt%4); + } if(tinfo.nuine) //print river if present + { blitterWithRotationAndAlpha(staticRiverDefs[tinfo.nuine-1]->ourImages[tinfo.rivDir].bitmap,rtile, extSurf, sr, (tinfo.siodmyTajemniczyBajt>>2)%4); - if(tinfo.malle) //print road if present - blitterWithRotationAndAlpha(roadDefs[tinfo.malle-1]->ourImages[tinfo.roadDir].bitmap,rtile, extSurf, sr, (tinfo.siodmyTajemniczyBajt>>4)%4); + } + + //Roads are shifted by 16 pixels to bottom. We have to draw both parts separately + if (pos.y > 0 && map->terrain[pos.x][pos.y-1][pos.z].malle) + { //part from top tile + const TerrainTile &topTile = map->terrain[pos.x][pos.y-1][pos.z]; + Rect source(0, 16, 32, 16); + Rect dest(sr.x, sr.y, sr.w, sr.h/2); + blitterWithRotationAndAlpha(roadDefs[topTile.malle-1]->ourImages[topTile.roadDir].bitmap, source, extSurf, dest, (topTile.siodmyTajemniczyBajt>>4)%4); + } + + if(tinfo.malle) //print road from this tile + { + Rect source(0, 0, 32, 32); + Rect dest(sr.x, sr.y+16, sr.w, sr.h/2); + blitterWithRotationAndAlpha(roadDefs[tinfo.malle-1]->ourImages[tinfo.roadDir].bitmap, source, extSurf, dest, (tinfo.siodmyTajemniczyBajt>>4)%4); + } //blit objects const std::vector < std::pair > &objects = tile.objects; for(int h=0; h < objects.size(); ++h) { const CGObjectInstance *obj = objects[h].first; - if (!graphics->getDef(obj)) - processDef(obj->defInfo); + if (!graphics->getDef(obj)) + processDef(obj->defInfo); ui8 color = obj->tempOwner; diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 5a4fe10c5..668b149d7 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -591,100 +591,69 @@ std::pair CGameState::pickObject (CGObjectInstance *obj) return std::pair(54, VLC->creh->pickRandomMonster(boost::ref(ran), 6)); case 164: //random monster lvl7 return std::pair(54, VLC->creh->pickRandomMonster(boost::ref(ran), 7)); - case 216: //random dwelling - { - int faction = ran()%GameConstants::F_NUMBER; - CGDwelling * dwl = static_cast(obj); - CCreGen2ObjInfo* info = static_cast(dwl->info); - if (info->asCastle) - { - for(ui32 i=0;iobjects.size();i++) - { - if(map->objects[i]->ID==77 && dynamic_cast(map->objects[i].get())->identifier == info->identifier) - { - randomizeObject(map->objects[i]); //we have to randomize the castle first - faction = map->objects[i]->subID; - break; - } - else if(map->objects[i]->ID==GameConstants::TOWNI_TYPE && dynamic_cast(map->objects[i].get())->identifier == info->identifier) - { - faction = map->objects[i]->subID; - break; - } - } - } - else - { - while((!(info->castles[0]&(1<7) && (info->castles[1]&(1<<(faction-8)))) - break; - faction = ran()%GameConstants::F_NUMBER; - } - } - int level = ((info->maxLevel-info->minLevel) ? (ran()%(info->maxLevel-info->minLevel)+info->minLevel) : (info->minLevel)); - int cid = VLC->townh->towns[faction].basicCreatures[level]; - for(ui32 i=0;iobjh->cregens.size();i++) - if(VLC->objh->cregens[i]==cid) - return std::pair(17,i); - tlog3 << "Cannot find a dwelling for creature "<< cid << std::endl; - return std::pair(17,0); - delete dwl->info; - dwl->info = NULL; - } + case 216: //random dwellings case 217: - { - int faction = ran()%GameConstants::F_NUMBER; - CGDwelling * dwl = static_cast(obj); - CCreGenObjInfo* info = static_cast(dwl->info); - if (info->asCastle) - { - for(ui32 i=0;iobjects.size();i++) - { - if(map->objects[i]->ID==77 && dynamic_cast(map->objects[i].get())->identifier == info->identifier) - { - randomizeObject(map->objects[i]); //we have to randomize the castle first - faction = map->objects[i]->subID; - break; - } - else if(map->objects[i]->ID==GameConstants::TOWNI_TYPE && dynamic_cast(map->objects[i].get())->identifier == info->identifier) - { - faction = map->objects[i]->subID; - break; - } - } - } - else - { - while((!(info->castles[0]&(1<7) && (info->castles[1]&(1<<(faction-8)))) - break; - faction = ran()%GameConstants::F_NUMBER; - } - } - int cid = VLC->townh->towns[faction].basicCreatures[obj->subID]; - for(ui32 i=0;iobjh->cregens.size();i++) - if(VLC->objh->cregens[i]==cid) - return std::pair(17,i); - tlog3 << "Cannot find a dwelling for creature "<(17,0); - delete dwl->info; - dwl->info = NULL; - } case 218: { CGDwelling * dwl = static_cast(obj); - CCreGen3ObjInfo* info = static_cast(dwl->info); - int level = ((info->maxLevel-info->minLevel) ? (ran()%(info->maxLevel-info->minLevel)+info->minLevel) : (info->minLevel)); - int cid = VLC->townh->towns[obj->subID].basicCreatures[level]; - for(ui32 i=0;iobjh->cregens.size();i++) - if(VLC->objh->cregens[i]==cid) - return std::pair(17,i); - tlog3 << "Cannot find a dwelling for creature "<(17,0); + int faction; + + //if castle alignment available + if (auto info = dynamic_cast(dwl->info)) + { + faction = ran()%GameConstants::F_NUMBER; + if (info->asCastle) + { + for(ui32 i=0;iobjects.size();i++) + { + if(map->objects[i]->ID==77 && dynamic_cast(map->objects[i].get())->identifier == info->identifier) + { + randomizeObject(map->objects[i]); //we have to randomize the castle first + faction = map->objects[i]->subID; + break; + } + else if(map->objects[i]->ID==GameConstants::TOWNI_TYPE && dynamic_cast(map->objects[i].get())->identifier == info->identifier) + { + faction = map->objects[i]->subID; + break; + } + } + } + else + { + while((!(info->castles[0]&(1<7) && (info->castles[1]&(1<<(faction-8)))) + break; + faction = ran()%GameConstants::F_NUMBER; + } + } + } + else // castle alignment fixed + faction = obj->subID; + + int level; + + //if level set to range + if (auto info = dynamic_cast(dwl->info)) + level = ((info->maxLevel-info->minLevel) ? (ran()%(info->maxLevel-info->minLevel)+info->minLevel) : (info->minLevel)); + else // fixed level + level = obj->subID; + delete dwl->info; - dwl->info = NULL; + dwl->info = nullptr; + + std::pair result(-1, -1); + int cid = VLC->townh->towns[faction].basicCreatures[level]; + + //NOTE: this will pick last dwelling with this creature (Mantis #900) + //check for block map equality is better but more complex solution + BOOST_FOREACH(auto &iter, VLC->objh->cregens) + if (iter.second == cid) + result = std::pair(17, iter.first); + + tlog3 << "Cannot find a dwelling for creature "<< cid << std::endl; + return result; } } return std::pair(-1,-1); diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index f9b0d3f32..c8367badf 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -155,11 +155,6 @@ static void readBankLevel(const JsonNode &level, BankConfig &bc) void CObjectHandler::loadObjects() { tlog5 << "\t\tReading cregens \n"; - cregens.resize(110); //TODO: hardcoded value - change - for(size_t i=0; i < cregens.size(); ++i) - { - cregens[i]=-1; - } const JsonNode config(GameConstants::DATA_DIR + "/config/dwellings.json"); BOOST_FOREACH(const JsonNode &dwelling, config["dwellings"].Vector()) diff --git a/lib/CObjectHandler.h b/lib/CObjectHandler.h index c5edc00e6..d81962ed1 100644 --- a/lib/CObjectHandler.h +++ b/lib/CObjectHandler.h @@ -412,30 +412,25 @@ class DLL_LINKAGE CSpecObjInfo { public: virtual ~CSpecObjInfo(){}; + ui8 player; //owner }; -class DLL_LINKAGE CCreGenObjInfo : public CSpecObjInfo +class DLL_LINKAGE CCreGenAsCastleInfo : public virtual CSpecObjInfo { public: - ui8 player; //owner bool asCastle; ui32 identifier; ui8 castles[2]; //allowed castles }; -class DLL_LINKAGE CCreGen2ObjInfo : public CSpecObjInfo + +class DLL_LINKAGE CCreGenLeveledInfo : public virtual CSpecObjInfo { public: - ui8 player; //owner - bool asCastle; - ui32 identifier; - ui8 castles[2]; //allowed castles ui8 minLevel, maxLevel; //minimal and maximal level of creature in dwelling: <0, 6> }; -class DLL_LINKAGE CCreGen3ObjInfo : public CSpecObjInfo + +class DLL_LINKAGE CCreGenLeveledCastleInfo : public CCreGenAsCastleInfo, public CCreGenLeveledInfo { -public: - ui8 player; //owner - ui8 minLevel, maxLevel; //minimal and maximal level of creature in dwelling: <0, 6> }; class DLL_LINKAGE CGDwelling : public CArmedInstance @@ -1318,7 +1313,7 @@ struct BankConfig class DLL_LINKAGE CObjectHandler { public: - std::vector cregens; //type 17. dwelling subid -> creature ID + std::map cregens; //type 17. dwelling subid -> creature ID std::map > > banksInfo; //[index][preset] std::map creBanksNames; //[crebank index] -> name of this creature bank std::vector resVals; //default values of resources in gold diff --git a/lib/map.cpp b/lib/map.cpp index fcb64e764..69705f30b 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -1675,64 +1675,49 @@ void Mapa::readObjects( const ui8 * bufor, int &i) grailRadious = read_le_u32(bufor + i); i+=4; continue; } - case 217: + //dwellings + case 216: //same as castle + level range + case 217: //same as castle + case 218: //level range { nobj = new CGDwelling(); - CCreGenObjInfo * spec = new CCreGenObjInfo; - spec->player = read_le_u32(bufor + i); i+=4; - spec->identifier = read_le_u32(bufor + i); i+=4; - if(!spec->identifier) + CSpecObjInfo * spec = nullptr; + switch(defInfo->id) { - spec->asCastle = false; - spec->castles[0] = bufor[i]; ++i; - spec->castles[1] = bufor[i]; ++i; + break; case 216: spec = new CCreGenLeveledCastleInfo; + break; case 217: spec = new CCreGenAsCastleInfo; + break; case 218: spec = new CCreGenLeveledInfo; + } + + spec->player = read_le_u32(bufor + i); i+=4; + //216 and 217 + if (auto castleSpec = dynamic_cast(spec)) + { + castleSpec->identifier = read_le_u32(bufor + i); i+=4; + if(!castleSpec->identifier) + { + castleSpec->asCastle = false; + castleSpec->castles[0] = bufor[i]; ++i; + castleSpec->castles[1] = bufor[i]; ++i; + } + else + { + castleSpec->asCastle = true; + } } else + i+=3; //only for 218 + + //216 and 218 + if (auto lvlSpec = dynamic_cast(spec)) { - spec->asCastle = true; + lvlSpec->minLevel = std::max(bufor[i], ui8(1)); ++i; + lvlSpec->maxLevel = std::min(bufor[i], ui8(7)); ++i; } nobj->setOwner(spec->player); static_cast(nobj)->info = spec; break; } - case 216: - { - nobj = new CGDwelling(); - CCreGen2ObjInfo * spec = new CCreGen2ObjInfo; - spec->player = read_le_u32(bufor + i); i+=4; - spec->identifier = read_le_u32(bufor + i); i+=4; - if(!spec->identifier) - { - spec->asCastle = false; - spec->castles[0] = bufor[i]; ++i; - spec->castles[1] = bufor[i]; ++i; - } - else - { - spec->asCastle = true; - } - spec->minLevel = bufor[i]; ++i; - spec->maxLevel = bufor[i]; ++i; - nobj->setOwner(spec->player); - static_cast(nobj)->info = spec; - break; - } - case 218: - { - nobj = new CGDwelling(); - CCreGen3ObjInfo * spec = new CCreGen3ObjInfo; - spec->player = bufor[i]; ++i; - i+=3; - spec->minLevel = bufor[i]; ++i; - spec->maxLevel = bufor[i]; ++i; - if(spec->maxLevel>7) - spec->maxLevel = 7; - if(spec->minLevel<1) - spec->minLevel = 1; - nobj->setOwner(spec->player); - static_cast(nobj)->info = spec; - break; - } case 215: { CGQuestGuard *guard = new CGQuestGuard();