1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Merge pull request #3435 from IvanSavenko/bugfixing

[1.4.3] Bugfixing
This commit is contained in:
Ivan Savenko 2024-01-06 13:06:07 +02:00 committed by GitHub
commit cf47fbb729
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 52 additions and 31 deletions

View File

@ -634,6 +634,8 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
pos.y = y;
frameTime = 0.0;
auto lastTimePoint = boost::chrono::steady_clock::now();
while(nextFrame())
{
if(stopOnKey)
@ -654,10 +656,17 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
#else
auto packet_duration = frame->duration;
#endif
double frameDurationSec = packet_duration * av_q2d(format->streams[stream]->time_base);
uint32_t timeToSleepMillisec = 1000 * (frameDurationSec);
// Framerate delay
double targetFrameTimeSeconds = packet_duration * av_q2d(format->streams[stream]->time_base);
auto targetFrameTime = boost::chrono::milliseconds(static_cast<int>(1000 * (targetFrameTimeSeconds)));
boost::this_thread::sleep_for(boost::chrono::milliseconds(timeToSleepMillisec));
auto timePointAfterPresent = boost::chrono::steady_clock::now();
auto timeSpentBusy = boost::chrono::duration_cast<boost::chrono::milliseconds>(timePointAfterPresent - lastTimePoint);
if (targetFrameTime > timeSpentBusy)
boost::this_thread::sleep_for(targetFrameTime - timeSpentBusy);
lastTimePoint = boost::chrono::steady_clock::now();
}
return true;

View File

@ -1730,7 +1730,7 @@
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : "creatureLevel1",
"subtype" : "creatureLevel2",
"val" : 5,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
@ -1743,7 +1743,7 @@
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : "creatureLevel2",
"subtype" : "creatureLevel3",
"val" : 4,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
@ -1756,7 +1756,7 @@
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : "creatureLevel3",
"subtype" : "creatureLevel4",
"val" : 3,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
@ -1769,7 +1769,7 @@
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : "creatureLevel4",
"subtype" : "creatureLevel5",
"val" : 2,
"propagator": "VISITED_TOWN_AND_VISITOR"
}
@ -1782,7 +1782,7 @@
"bonuses" : [
{
"type" : "CREATURE_GROWTH",
"subtype" : "creatureLevel5",
"subtype" : "creatureLevel6",
"val" : 1,
"propagator": "VISITED_TOWN_AND_VISITOR"
}

View File

@ -244,7 +244,7 @@ Increased effect of spell affecting creature, ie. Aenain makes Disrupting Ray de
"subtype" : "spell.disruptingRay",
"type" : "SPECIAL_ADD_VALUE_ENCHANT"
}
``````
```
- subtype: affected spell identifier
- additionalInfo: value to add

View File

@ -21,6 +21,7 @@ BattleFieldInfo * BattleFieldHandler::loadFromJson(const std::string & scope, co
auto * info = new BattleFieldInfo(BattleField(index), identifier);
info->modScope = scope;
info->graphics = ImagePath::fromJson(json["graphics"]);
info->icon = json["icon"].String();
info->name = json["name"].String();
@ -66,7 +67,7 @@ int32_t BattleFieldInfo::getIconIndex() const
std::string BattleFieldInfo::getJsonKey() const
{
return identifier;
return modScope + ':' + identifier;
}
std::string BattleFieldInfo::getNameTextID() const

View File

@ -27,6 +27,7 @@ public:
bool isSpecial;
ImagePath graphics;
std::string name;
std::string modScope;
std::string identifier;
std::string icon;
si32 iconIndex;

View File

@ -612,10 +612,20 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
cre->addBonus(node["attack"].Integer(), BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::ATTACK));
cre->addBonus(node["defense"].Integer(), BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::DEFENSE));
cre->addBonus(node["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin);
cre->addBonus(node["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMax);
int minDamage = node["damage"]["min"].Integer();
int maxDamage = node["damage"]["max"].Integer();
assert(node["damage"]["min"].Integer() <= node["damage"]["max"].Integer());
if (minDamage <= maxDamage)
{
cre->addBonus(minDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin);
cre->addBonus(maxDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMax);
}
else
{
logGlobal->error("Mod %s: creature %s has minimal damage (%d) greater than maximal damage (%d)!", scope, identifier, minDamage, maxDamage);
cre->addBonus(maxDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin);
cre->addBonus(minDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMax);
}
if(!node["shots"].isNull())
cre->addBonus(node["shots"].Integer(), BonusType::SHOTS);

View File

@ -320,7 +320,7 @@ void CGDwelling::newTurn(CRandomGenerator & rand) const
creaturesAccumulate = VLC->settings()->getBoolean(EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL);
const CCreature * cre =creatures[i].second[0].toCreature();
TQuantity amount = cre->getGrowth() * (1 + cre->valOfBonuses(BonusType::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(BonusType::CREATURE_GROWTH);
TQuantity amount = cre->getGrowth() * (1 + cre->valOfBonuses(BonusType::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(BonusType::CREATURE_GROWTH, BonusCustomSubtype::creatureLevel(cre->getLevel()));
if (creaturesAccumulate && ID != Obj::REFUGEE_CAMP) //camp should not try to accumulate different kinds of creatures
sac.creatures[i].first += amount;
else

View File

@ -164,7 +164,8 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
}
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
TConstBonusListPtr bonuses = getBonuses(Selector::typeSubtype(BonusType::CREATURE_GROWTH, BonusCustomSubtype::creatureLevel(level)));
// Note: bonus uses 1-based levels (Pikeman is level 1), town list uses 0-based (Pikeman in 0-th creatures entry)
TConstBonusListPtr bonuses = getBonuses(Selector::typeSubtype(BonusType::CREATURE_GROWTH, BonusCustomSubtype::creatureLevel(level+1)));
for(const auto & b : *bonuses)
ret.entries.emplace_back(b->val, b->Description());

View File

@ -2223,17 +2223,10 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
}
{
std::set<SpellID> spellsMask;
std::set<SpellID> spellsMask = VLC->spellh->getDefaultAllowed(); // by default - include spells from mods
reader->readBitmaskSpells(spellsMask, true);
std::copy(spellsMask.begin(), spellsMask.end(), std::back_inserter(object->possibleSpells));
auto defaultAllowed = VLC->spellh->getDefaultAllowed();
//add all spells from mods
for(int i = features.spellsCount; i < defaultAllowed.size(); ++i)
if(defaultAllowed.count(i))
object->possibleSpells.emplace_back(i);
}
if(features.levelHOTA1)

View File

@ -71,7 +71,8 @@ SilentCaster::SilentCaster(PlayerColor owner_, const Caster * hero_):
void SilentCaster::getCasterName(MetaString & text) const
{
logGlobal->error("Unexpected call to SilentCaster::getCasterName");
// NOTE: can be triggered (for example) if creature steps into Tower mines/moat while hero has Recanter's Cloak
logGlobal->debug("Unexpected call to SilentCaster::getCasterName");
}
void SilentCaster::getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const

View File

@ -3292,7 +3292,11 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
for (auto & i : ev.buildings)
{
if (!town->hasBuilt(i))
// Only perform action if:
// 1. Building exists in town (don't attempt to build Lvl 5 guild in Fortress
// 2. Building was not built yet
// othervice, silently ignore / skip it
if (town->town->buildings.count(i) && !town->hasBuilt(i))
{
buildStructure(town->id, i, true);
iw.components.emplace_back(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), i));

View File

@ -1301,6 +1301,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
// send empty event to client
// temporary(?) workaround to force animations to trigger
StacksInjured fakeEvent;
fakeEvent.battleID = battle.getBattle()->getBattleID();
gameHandler->sendAndApply(&fakeEvent);
}

View File

@ -181,6 +181,7 @@ void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle,
// send empty event to client
// temporary(?) workaround to force animations to trigger
StacksInjured fakeEvent;
fakeEvent.battleID = battle.getBattle()->getBattleID();
gameHandler->sendAndApply(&fakeEvent);
}
@ -676,8 +677,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
}
if(st->hasBonusOfType(BonusType::MANA_DRAIN) && !st->drainedMana)
{
const PlayerColor opponent = battle.otherPlayer(battle.battleGetOwner(st));
const CGHeroInstance * opponentHero = battle.battleGetFightingHero(opponent);
const CGHeroInstance * opponentHero = battle.battleGetFightingHero(battle.otherSide(st->unitSide()));
if(opponentHero)
{
ui32 manaDrained = st->valOfBonuses(BonusType::MANA_DRAIN);

View File

@ -498,10 +498,10 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
BattleResultAccepted raccepted;
raccepted.battleID = battle.getBattle()->getBattleID();
raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(0));
raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(1));
raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(0));
raccepted.heroResult[1].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(1));
raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::ATTACKER));
raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::DEFENDER));
raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::ATTACKER));
raccepted.heroResult[1].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::DEFENDER));
raccepted.heroResult[0].exp = battleResult->exp[0];
raccepted.heroResult[1].exp = battleResult->exp[1];
raccepted.winnerSide = finishingBattle->winnerSide;