1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-19 21:10:12 +02:00

Merge pull request #5383 from IvanSavenko/bugfixing

[1.6.6] Fixes for issues in 1.6.5
This commit is contained in:
Ivan Savenko 2025-02-09 19:27:43 +02:00 committed by GitHub
commit c13edc8af3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 184 additions and 27 deletions

View File

@ -533,7 +533,7 @@ void BattleFieldController::showHighlightedHexes(Canvas & canvas)
BattleHexArray hoveredMoveHexes = getHighlightedHexesForMovementTarget(); BattleHexArray hoveredMoveHexes = getHighlightedHexesForMovementTarget();
BattleHex hoveredHex = getHoveredHex(); BattleHex hoveredHex = getHoveredHex();
BattleHexArray hoveredMouseHex = hoveredHex.isValid() ? BattleHexArray({ hoveredHex }) : BattleHexArray(); BattleHexArray hoveredMouseHex = hoveredHex.isAvailable() ? BattleHexArray({ hoveredHex }) : BattleHexArray();
const CStack * hoveredStack = getHoveredStack(); const CStack * hoveredStack = getHoveredStack();
if(!hoveredStack && hoveredHex == BattleHex::INVALID) if(!hoveredStack && hoveredHex == BattleHex::INVALID)

View File

@ -691,7 +691,7 @@ void StackInfoBasicPanel::initializeData(const CStack * stack)
if (spellBonuses->empty()) if (spellBonuses->empty())
throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey()); throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey());
int duration = spellBonuses->front()->duration; int duration = spellBonuses->front()->turnsRemain;
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed)); icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
if(settings["general"]["enableUiEnhancements"].Bool()) if(settings["general"]["enableUiEnhancements"].Bool())

View File

@ -28,6 +28,7 @@
#include "../widgets/Images.h" #include "../widgets/Images.h"
#include "../widgets/MiscWidgets.h" #include "../widgets/MiscWidgets.h"
#include "../widgets/ObjectLists.h" #include "../widgets/ObjectLists.h"
#include "../widgets/Slider.h"
#include "../widgets/TextControls.h" #include "../widgets/TextControls.h"
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
@ -126,6 +127,15 @@ std::shared_ptr<CIntObject> GlobalLobbyWidget::buildItemList(const JsonNode & co
auto result = std::make_shared<CListBox>(callback, position, itemOffset, visibleAmount, totalAmount, initialPos, sliderMode, Rect(sliderPosition, sliderSize)); auto result = std::make_shared<CListBox>(callback, position, itemOffset, visibleAmount, totalAmount, initialPos, sliderMode, Rect(sliderPosition, sliderSize));
if (result->getSlider())
{
Point scrollBoundsDimensions(sliderPosition.x + result->getSlider()->pos.w, result->getSlider()->pos.h);
Point scrollBoundsOffset = -sliderPosition;
result->getSlider()->setScrollBounds(Rect(scrollBoundsOffset, scrollBoundsDimensions));
result->getSlider()->setPanningStep(itemOffset.length());
}
result->setRedrawParent(true); result->setRedrawParent(true);
return result; return result;
} }

View File

@ -247,7 +247,7 @@ AssetGenerator::CanvasPtr AssetGenerator::createCampaignBackground()
AssetGenerator::CanvasPtr AssetGenerator::createChroniclesCampaignImages(int chronicle) AssetGenerator::CanvasPtr AssetGenerator::createChroniclesCampaignImages(int chronicle)
{ {
auto imgPathBg = ImagePath::builtin("data/chronicles_" + std::to_string(chronicle) + "/GamSelBk"); auto imgPathBg = ImagePath::builtin("chronicles_" + std::to_string(chronicle) + "/GamSelBk");
auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE); auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator); std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);

View File

@ -25,6 +25,11 @@ CanvasImage::CanvasImage(const Point & size, CanvasScalingPolicy scalingPolicy)
{ {
} }
CanvasImage::~CanvasImage()
{
SDL_FreeSurface(surface);
}
void CanvasImage::draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const void CanvasImage::draw(SDL_Surface * where, const Point & pos, const Rect * src, int scalingFactor) const
{ {
if(src) if(src)

View File

@ -16,6 +16,7 @@ class CanvasImage : public IImage
{ {
public: public:
CanvasImage(const Point & size, CanvasScalingPolicy scalingPolicy); CanvasImage(const Point & size, CanvasScalingPolicy scalingPolicy);
~CanvasImage();
Canvas getCanvas(); Canvas getCanvas();

View File

@ -379,7 +379,7 @@ void RenderHandler::addImageListEntries(const EntityService * service)
if (imageName.empty()) if (imageName.empty())
return; return;
auto & layout = getAnimationLayout(AnimationPath::builtin("SPRITES/" + listName), 1, EImageBlitMode::SIMPLE); auto & layout = getAnimationLayout(AnimationPath::builtin("SPRITES/" + listName), 1, EImageBlitMode::COLORKEY);
JsonNode entry; JsonNode entry;
entry["file"].String() = imageName; entry["file"].String() = imageName;
@ -417,8 +417,8 @@ static void detectOverlappingBuildings(RenderHandler * renderHandler, const Fact
if (left->pos.z != right->pos.z) if (left->pos.z != right->pos.z)
continue; // buildings already have different z-index and have well-defined overlap logic continue; // buildings already have different z-index and have well-defined overlap logic
auto leftImage = renderHandler->loadImage(left->defName, 0, 0, EImageBlitMode::SIMPLE); auto leftImage = renderHandler->loadImage(left->defName, 0, 0, EImageBlitMode::COLORKEY);
auto rightImage = renderHandler->loadImage(right->defName, 0, 0, EImageBlitMode::SIMPLE); auto rightImage = renderHandler->loadImage(right->defName, 0, 0, EImageBlitMode::COLORKEY);
Rect leftRect( left->pos.x, left->pos.y, leftImage->width(), leftImage->height()); Rect leftRect( left->pos.x, left->pos.y, leftImage->width(), leftImage->height());
Rect rightRect( right->pos.x, right->pos.y, rightImage->width(), rightImage->height()); Rect rightRect( right->pos.x, right->pos.y, rightImage->width(), rightImage->height());

View File

@ -168,6 +168,11 @@ std::shared_ptr<CIntObject> CListBox::getItem(size_t which)
return std::shared_ptr<CIntObject>(); return std::shared_ptr<CIntObject>();
} }
std::shared_ptr<CSlider> CListBox::getSlider()
{
return slider;
}
size_t CListBox::getIndexOf(std::shared_ptr<CIntObject> item) size_t CListBox::getIndexOf(std::shared_ptr<CIntObject> item)
{ {
size_t i=first; size_t i=first;

View File

@ -91,6 +91,8 @@ public:
//return item with index which or null if not present //return item with index which or null if not present
std::shared_ptr<CIntObject> getItem(size_t which); std::shared_ptr<CIntObject> getItem(size_t which);
std::shared_ptr<CSlider> getSlider();
//return currently active items //return currently active items
const std::list<std::shared_ptr<CIntObject>> & getItems(); const std::list<std::shared_ptr<CIntObject>> & getItems();

View File

@ -238,7 +238,7 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
if (spellBonuses->empty()) if (spellBonuses->empty())
throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey()); throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey());
int duration = spellBonuses->front()->duration; int duration = spellBonuses->front()->turnsRemain;
boost::replace_first(spellText, "%d", std::to_string(duration)); boost::replace_first(spellText, "%d", std::to_string(duration));
spellIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed)); spellIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));

View File

@ -50,7 +50,7 @@
}, },
"chr": "chr":
{ {
"images" : [ {"x": 0, "y": 0, "name":"data/CampaignBackground8"} ], "images" : [ {"x": 0, "y": 0, "name":"CampaignBackground8"} ],
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" }, "exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items": "items":
[ [

View File

@ -2370,5 +2370,120 @@
}, },
"victoryIconIndex" : 11, "victoryIconIndex" : 11,
"victoryString" : "core.vcdesc.0" "victoryString" : "core.vcdesc.0"
},
"data/gelu:1" : { // Cutthroats
"defeatIconIndex" : 1,
"defeatString" : "core.lcdesc.2",
"triggeredEvents" : {
"heroesMustSurvive" : {
"condition" : [
"allOf",
[ "isHuman", { "value" : 1 } ],
[ "noneOf",
[ "control", { "position" : [ 11, 8, 0 ], "type" : "hero" } ] // Gelu
]
],
"effect" : {
"messageToSend" : "core.genrltxt.5",
"type" : "defeat"
},
"message" : "core.genrltxt.253"
},
"specialVictory" : {
"condition" : [ "haveArtifact", { "type" : "artifact.ringOfVitality" } ],
"effect" : {
"messageToSend" : "core.genrltxt.281",
"type" : "victory"
},
"message" : "core.genrltxt.280"
},
"standardDefeat" : {
"condition" : [ "daysWithoutTown", { "value" : 7 } ],
"effect" : {
"messageToSend" : "core.genrltxt.8",
"type" : "defeat"
},
"message" : "core.genrltxt.7"
}
},
"victoryIconIndex" : 0,
"victoryString" : "core.vcdesc.1"
},
"data/gelu:2" : { // Valley of the Dragon Lords
"defeatIconIndex" : 1,
"defeatString" : "core.lcdesc.2",
"triggeredEvents" : {
"heroesMustSurvive" : {
"condition" : [
"allOf",
[ "isHuman", { "value" : 1 } ],
[ "noneOf",
[ "control", { "position" : [ 62, 12, 0 ], "type" : "hero" } ] // Gelu
]
],
"effect" : {
"messageToSend" : "core.genrltxt.5",
"type" : "defeat"
},
"message" : "core.genrltxt.253"
},
"specialVictory" : {
"condition" : [ "haveArtifact", { "type" : "artifact.ringOfLife" } ],
"effect" : {
"messageToSend" : "core.genrltxt.281",
"type" : "victory"
},
"message" : "core.genrltxt.280"
},
"standardDefeat" : {
"condition" : [ "daysWithoutTown", { "value" : 7 } ],
"effect" : {
"messageToSend" : "core.genrltxt.8",
"type" : "defeat"
},
"message" : "core.genrltxt.7"
}
},
"victoryIconIndex" : 0,
"victoryString" : "core.vcdesc.1"
},
"data/gelu:3" : { // A Thief in the Night
"defeatIconIndex" : 1,
"defeatString" : "core.lcdesc.2",
"triggeredEvents" : {
"heroesMustSurvive" : {
"condition" : [
"allOf",
[ "isHuman", { "value" : 1 } ],
[ "noneOf",
[ "control", { "position" : [ 50, 9, 0 ], "type" : "hero" } ] // Gelu
]
],
"effect" : {
"messageToSend" : "core.genrltxt.5",
"type" : "defeat"
},
"message" : "core.genrltxt.253"
},
"specialVictory" : {
"condition" : [ "haveArtifact", { "type" : "artifact.vialOfLifeblood" } ],
"effect" : {
"messageToSend" : "core.genrltxt.281",
"type" : "victory"
},
"message" : "core.genrltxt.280"
},
"standardDefeat" : {
"condition" : [ "daysWithoutTown", { "value" : 7 } ],
"effect" : {
"messageToSend" : "core.genrltxt.8",
"type" : "defeat"
},
"message" : "core.genrltxt.7"
}
},
"victoryIconIndex" : 0,
"victoryString" : "core.vcdesc.1"
} }
} }

View File

@ -188,6 +188,7 @@ std::shared_ptr<Bonus> CBonusSystemNode::getUpdatedBonus(const std::shared_ptr<B
CBonusSystemNode::CBonusSystemNode(bool isHypotetic): CBonusSystemNode::CBonusSystemNode(bool isHypotetic):
nodeType(UNKNOWN), nodeType(UNKNOWN),
cachedLast(0), cachedLast(0),
nodeChanged(0),
isHypotheticNode(isHypotetic) isHypotheticNode(isHypotetic)
{ {
} }
@ -195,6 +196,7 @@ CBonusSystemNode::CBonusSystemNode(bool isHypotetic):
CBonusSystemNode::CBonusSystemNode(ENodeTypes NodeType): CBonusSystemNode::CBonusSystemNode(ENodeTypes NodeType):
nodeType(NodeType), nodeType(NodeType),
cachedLast(0), cachedLast(0),
nodeChanged(0),
isHypotheticNode(false) isHypotheticNode(false)
{ {
} }

View File

@ -183,14 +183,9 @@ void CResourceHandler::initialize()
knownLoaders["saves"] = new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath()); knownLoaders["saves"] = new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath());
knownLoaders["config"] = new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath()); knownLoaders["config"] = new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath());
knownLoaders["gen_data"] = new CFilesystemLoader("DATA/", VCMIDirs::get().userDataPath() / "Generated" / "Data");
knownLoaders["gen_sprites"] = new CFilesystemLoader("SPRITES/", VCMIDirs::get().userDataPath() / "Generated" / "Sprites");
auto * localFS = new CFilesystemList(); auto * localFS = new CFilesystemList();
localFS->addLoader(knownLoaders["saves"], true); localFS->addLoader(knownLoaders["saves"], true);
localFS->addLoader(knownLoaders["config"], true); localFS->addLoader(knownLoaders["config"], true);
localFS->addLoader(knownLoaders["gen_data"], true);
localFS->addLoader(knownLoaders["gen_sprites"], true);
addFilesystem("root", "initial", createInitial()); addFilesystem("root", "initial", createInitial());
addFilesystem("root", "data", new CFilesystemList()); addFilesystem("root", "data", new CFilesystemList());

View File

@ -117,8 +117,17 @@ void CMapHeader::setupEvents()
defeatMessage.appendTextID("core.lcdesc.0"); defeatMessage.appendTextID("core.lcdesc.0");
} }
CMapHeader::CMapHeader() : version(EMapFormat::VCMI), height(72), width(72), CMapHeader::CMapHeader()
twoLevel(true), difficulty(EMapDifficulty::NORMAL), levelLimit(0), howManyTeams(0), areAnyPlayers(false) : version(EMapFormat::VCMI)
, height(72)
, width(72)
, twoLevel(true)
, difficulty(EMapDifficulty::NORMAL)
, levelLimit(0)
, howManyTeams(0)
, areAnyPlayers(false)
, victoryIconIndex(0)
, defeatIconIndex(0)
{ {
setupEvents(); setupEvents();
allowedHeroes = VLC->heroh->getDefaultAllowed(); allowedHeroes = VLC->heroh->getDefaultAllowed();

View File

@ -216,22 +216,25 @@ InternalConnection::InternalConnection(INetworkConnectionListener & listener, co
void InternalConnection::receivePacket(const std::vector<std::byte> & message) void InternalConnection::receivePacket(const std::vector<std::byte> & message)
{ {
io->post([self = shared_from_this(), message](){ io->post([self = std::static_pointer_cast<InternalConnection>(shared_from_this()), message](){
self->listener.onPacketReceived(self, message); if (self->connectionActive)
self->listener.onPacketReceived(self, message);
}); });
} }
void InternalConnection::disconnect() void InternalConnection::disconnect()
{ {
io->post([self = shared_from_this()](){ io->post([self = std::static_pointer_cast<InternalConnection>(shared_from_this())](){
self->listener.onDisconnected(self, "Internal connection has been terminated"); self->listener.onDisconnected(self, "Internal connection has been terminated");
self->otherSideWeak.reset(); self->otherSideWeak.reset();
self->connectionActive = false;
}); });
} }
void InternalConnection::connectTo(std::shared_ptr<IInternalConnection> connection) void InternalConnection::connectTo(std::shared_ptr<IInternalConnection> connection)
{ {
otherSideWeak = connection; otherSideWeak = connection;
connectionActive = true;
} }
void InternalConnection::sendPacket(const std::vector<std::byte> & message) void InternalConnection::sendPacket(const std::vector<std::byte> & message)
@ -240,8 +243,6 @@ void InternalConnection::sendPacket(const std::vector<std::byte> & message)
if (otherSide) if (otherSide)
otherSide->receivePacket(message); otherSide->receivePacket(message);
else
throw std::runtime_error("Failed to send packet! Connection has been deleted!");
} }
void InternalConnection::setAsyncWritesEnabled(bool on) void InternalConnection::setAsyncWritesEnabled(bool on)
@ -257,6 +258,7 @@ void InternalConnection::close()
otherSide->disconnect(); otherSide->disconnect();
otherSideWeak.reset(); otherSideWeak.reset();
connectionActive = false;
} }
VCMI_LIB_NAMESPACE_END VCMI_LIB_NAMESPACE_END

View File

@ -51,6 +51,7 @@ class InternalConnection final : public IInternalConnection, public std::enable_
std::weak_ptr<IInternalConnection> otherSideWeak; std::weak_ptr<IInternalConnection> otherSideWeak;
std::shared_ptr<NetworkContext> io; std::shared_ptr<NetworkContext> io;
INetworkConnectionListener & listener; INetworkConnectionListener & listener;
bool connectionActive = false;
public: public:
InternalConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkContext> & context); InternalConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkContext> & context);

View File

@ -40,15 +40,23 @@ namespace PathfinderUtil
} }
else else
{ {
bool hasBlockedVisitable = false;
bool hasVisitable = false;
for(const CGObjectInstance * obj : tinfo.visitableObjects) for(const CGObjectInstance * obj : tinfo.visitableObjects)
{ {
if(obj->isBlockedVisitable()) if(obj->isBlockedVisitable())
return EPathAccessibility::BLOCKVIS; hasBlockedVisitable = true;
else if(obj->passableFor(player)) else if(!obj->passableFor(player) && obj->ID != Obj::EVENT)
return EPathAccessibility::ACCESSIBLE; hasVisitable = true;
else if(obj->ID != Obj::EVENT)
return EPathAccessibility::VISITABLE;
} }
if(hasBlockedVisitable)
return EPathAccessibility::BLOCKVIS;
if(hasVisitable)
return EPathAccessibility::VISITABLE;
return EPathAccessibility::ACCESSIBLE;
} }
} }
else if(tinfo.blocked()) else if(tinfo.blocked())

View File

@ -102,7 +102,8 @@ std::unique_ptr<CPack> CConnection::retrievePack(const std::vector<std::byte> &
if (packReader->position != data.size()) if (packReader->position != data.size())
throw std::runtime_error("Failed to retrieve pack! Not all data has been read!"); throw std::runtime_error("Failed to retrieve pack! Not all data has been read!");
logNetwork->trace("Received CPack of type %s", typeid(result.get()).name()); auto packRawPtr = result.get();
logNetwork->trace("Received CPack of type %s", typeid(*packRawPtr).name());
deserializer->loadedPointers.clear(); deserializer->loadedPointers.clear();
deserializer->loadedSharedPointers.clear(); deserializer->loadedSharedPointers.clear();
return result; return result;

View File

@ -249,6 +249,8 @@ void TurnOrderProcessor::doStartNewDay()
assert(awaitingPlayers.empty()); assert(awaitingPlayers.empty());
assert(actingPlayers.empty()); assert(actingPlayers.empty());
gameHandler->onNewTurn();
bool activePlayer = false; bool activePlayer = false;
for (auto player : actedPlayers) for (auto player : actedPlayers)
{ {
@ -264,7 +266,6 @@ void TurnOrderProcessor::doStartNewDay()
std::swap(actedPlayers, awaitingPlayers); std::swap(actedPlayers, awaitingPlayers);
gameHandler->onNewTurn();
updateAndNotifyContactStatus(); updateAndNotifyContactStatus();
tryStartTurnsForPlayers(); tryStartTurnsForPlayers();
} }