diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 6eb0a6725..950a8b113 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -1586,7 +1586,14 @@ int SelectionTab::getLine() Point clickPos(GH.current->button.x, GH.current->button.y); clickPos = clickPos - pos.topLeft(); - if (clickPos.y > 115 && clickPos.y < 564 && clickPos.x > 22 && clickPos.x < 371) + // Ignore clicks on save name area + int maxPosY; + if(tabType == CMenuScreen::saveGame) + maxPosY = 516; + else + maxPosY = 564; + + if(clickPos.y > 115 && clickPos.y < maxPosY && clickPos.x > 22 && clickPos.x < 371) { line = (clickPos.y-115) / 25; //which line } @@ -2164,6 +2171,10 @@ void InfoCard::changeSelection( const CMapInfo *to ) else mapDescription->setText(to->mapHeader->description); + mapDescription->label->scrollTextTo(0); + if (mapDescription->slider) + mapDescription->slider->moveToMin(); + if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) { //difficulty->block(true); difficulty->setSelected(SEL->sInfo.difficulty); diff --git a/client/widgets/Buttons.cpp b/client/widgets/Buttons.cpp index 6a2956cf0..200d1801d 100644 --- a/client/widgets/Buttons.cpp +++ b/client/widgets/Buttons.cpp @@ -744,6 +744,11 @@ void CSlider::keyPressed(const SDL_KeyboardEvent & key) moveTo(moveDest); } +void CSlider::moveToMin() +{ + moveTo(0); +} + void CSlider::moveToMax() { moveTo(amount); diff --git a/client/widgets/Buttons.h b/client/widgets/Buttons.h index 7fcd4336f..fb41e8a02 100644 --- a/client/widgets/Buttons.h +++ b/client/widgets/Buttons.h @@ -230,6 +230,7 @@ public: void moveRight(); void moveTo(int value); void moveBy(int amount); + void moveToMin(); void moveToMax(); /// Amount modifier diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index e229e23e4..be98c9535 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -280,15 +280,20 @@ void CTextBox::resize(Point newSize) void CTextBox::setText(const std::string &text) { + label->pos.w = pos.w; // reset to default before textSize.y check label->setText(text); - if (label->textSize.y <= label->pos.h && slider) + if(label->textSize.y <= label->pos.h && slider) { // slider is no longer needed vstd::clear_pointer(slider); - label->pos.w = pos.w; + } + else if(slider) + { + // decrease width again if slider still used + label->pos.w = pos.w - 32; label->setText(text); } - else if (label->textSize.y > label->pos.h && !slider) + else if(label->textSize.y > label->pos.h) { // create slider and update widget label->pos.w = pos.w - 32; diff --git a/client/windows/CCreatureWindow.cpp b/client/windows/CCreatureWindow.cpp index e6992bc88..e30f2d16e 100644 --- a/client/windows/CCreatureWindow.cpp +++ b/client/windows/CCreatureWindow.cpp @@ -651,7 +651,7 @@ void CStackWindow::CWindowSection::createBonusItem(size_t index, Point position) BonusInfo & bi = parent->activeBonuses[index]; new CPicture(bi.imagePath, position.x, position.y); new CLabel(position.x + 60, position.y + 2, FONT_SMALL, TOPLEFT, Colors::WHITE, bi.name); - new CLabel(position.x + 60, position.y + 25, FONT_SMALL, TOPLEFT, Colors::WHITE, bi.description); + new CMultiLineLabel(Rect(position.x + 60, position.y + 17, 137,30), FONT_SMALL, TOPLEFT, Colors::WHITE, bi.description); } } diff --git a/config/bonuses_texts.json b/config/bonuses_texts.json index ffd8ae1e3..b63f23a34 100644 --- a/config/bonuses_texts.json +++ b/config/bonuses_texts.json @@ -75,7 +75,7 @@ "DEATH_STARE": { "name": "Death Stare (${val}%)", - "description": "Chance to kill single creature" + "description": "${val}% chance to kill single creature" }, "DEFENSIVE_STANCE": @@ -110,14 +110,14 @@ "ENCHANTER": { - "name": "Enchanter (${subtype.spell})", - "description": "Casts mass spell every turn" + "name": "Enchanter", + "description": "Can cast mass ${subtype.spell} every turn" }, "ENCHANTED": { - "name": "Enchanted (${subtype.spell})", - "description": "Affected by permanent spell" + "name": "Enchanted", + "description": "Affected by permanent ${subtype.spell}" }, "ENEMY_DEFENCE_REDUCTION": @@ -198,14 +198,17 @@ "KING1": { + "name": "King1" }, "KING2": { + "name": "King2" }, "KING3": { + "name": "King3" }, "LEVEL_SPELL_IMMUNITY": @@ -263,6 +266,7 @@ "NO_MORALE": { + }, @@ -320,8 +324,8 @@ }, "SPELLCASTER": { - "name": "Spellcaster (${subtype.spell})", - "description": "Can cast spells" + "name": "Spellcaster", + "description": "Can cast ${subtype.spell}" }, "SPELL_AFTER_ATTACK": diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 775e0ad36..9f283a87f 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -2224,7 +2224,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co for(const CSpell *spell : VLC->spellh->objects) { - if (spell->isPositive()) //only positive + if (spell->isPositive() && !spell->isRisingSpell()) //only positive and not rising { if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spell->id) || battleCanCastThisSpellHere(subject->owner, spell, ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK) @@ -2295,6 +2295,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co continue; } break; + case SpellID::TELEPORT: //issue 1928 case SpellID::CLONE: //not allowed continue; break; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 4da5c5d13..96d25aa13 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -1197,6 +1197,7 @@ void BattleResult::applyGs( CGameState *gs ) void BattleStackMoved::applyGs( CGameState *gs ) { CStack *s = gs->curB->getStack(stack); + assert(s); BattleHex dest = tilesToMove.back(); //if unit ended movement on quicksands that were created by enemy, that quicksand patch becomes visible for owner diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 2006acbe8..6249c1d3e 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -1445,7 +1445,8 @@ void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const void CCartographer::onHeroVisit( const CGHeroInstance * h ) const { - if (!wasVisited (h->getOwner()) ) //if hero has not visited yet this cartographer + //if player has not bought map of this subtype yet and underground exist for stalagmite cartographer + if (!wasVisited(h->getOwner()) && (subID != 2 || cb->gameState()->map->twoLevel)) { if (cb->getResource(h->tempOwner, Res::GOLD) >= 1000) //if he can afford a map { diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 366252811..3136e25c3 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -74,7 +74,7 @@ void CMapGenerator::initPrisonsRemaining() if (isAllowed) prisonsRemaining++; } - prisonsRemaining = std::max (0, prisonsRemaining - 16 * map->players.size()); //so at least 16 heroes will be available for every player + prisonsRemaining = std::max (0, prisonsRemaining - 16 * mapGenOptions->getPlayerCount()); //so at least 16 heroes will be available for every player } std::unique_ptr CMapGenerator::generate(CMapGenOptions * mapGenOptions, int randomSeed /*= std::time(nullptr)*/) diff --git a/vcmibuilder b/vcmibuilder index 59ac71e06..36de6039a 100755 --- a/vcmibuilder +++ b/vcmibuilder @@ -209,17 +209,13 @@ fi if [[ -n "$data_dir" ]] then - cp -r "$data_dir"/Data "$dest_dir" - cp -r "$data_dir"/Maps "$dest_dir" - # this folder is named differently from time to time - # vcmi can handle any case but script can't - if [ -d "$data_dir"/MP3 ] - then - cp -r "$data_dir"/MP3 "$dest_dir" - else - cp -r "$data_dir"/Mp3 "$dest_dir" - fi + # bash also has `shopt -s nocaseglob` but we don't want this to + # accidentally influence other parts of this script + # since the directory names are short, we use this pattern matching + cp -r "$data_dir"/[Dd][Aa][Tt][Aa] "$dest_dir" + cp -r "$data_dir"/[Mm][Aa][Pp][Ss] "$dest_dir" + cp -r "$data_dir"/[Mm][Pp]3 "$dest_dir" fi if [[ -n "$download" ]]