1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-03 13:01:33 +02:00

Merge pull request #425 from vcmi/CatapultRework

Catapult rework
This commit is contained in:
ArseniyShestakov 2018-03-06 01:16:53 +08:00 committed by GitHub
commit 079cd470c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 18 deletions

View File

@ -2905,9 +2905,13 @@ std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, int state) co
switch (state) switch (state)
{ {
case EWallState::INTACT : return 1; case EWallState::INTACT : return 1;
case EWallState::DAMAGED : return 2; case EWallState::DAMAGED :
if(what == 2 || what == 3 || what == 8) // towers don't have separate image here - INTACT and DAMAGED is 1, DESTROYED is 2
return 1;
else
return 2;
case EWallState::DESTROYED : case EWallState::DESTROYED :
if (what == 2 || what == 3 || what == 8) // towers don't have separate image here if (what == 2 || what == 3 || what == 8)
return 2; return 2;
else else
return 3; return 3;

View File

@ -86,6 +86,8 @@ void Catapult::apply(BattleStateProxy * battleState, RNG & rng, const Mechanics
CatapultAttack ca; CatapultAttack ca;
ca.attacker = -1; ca.attacker = -1;
BattleUnitsChanged removeUnits;
for(int i = 0; i < targetsToAttack; i++) for(int i = 0; i < targetsToAttack; i++)
{ {
//Any destructible part can be hit regardless of its HP. Multiple hit on same target is allowed. //Any destructible part can be hit regardless of its HP. Multiple hit on same target is allowed.
@ -120,9 +122,8 @@ void Catapult::apply(BattleStateProxy * battleState, RNG & rng, const Mechanics
break; break;
} }
if(posRemove != BattleHex::INVALID) if(posRemove != BattleHex::INVALID && state - attackInfo.damageDealt <= 0) //HP enum subtraction not intuitive, consider using SiegeInfo::applyDamage
{ {
BattleUnitsChanged removeUnits;
auto all = m->cb->battleGetUnitsIf([=](const battle::Unit * unit) auto all = m->cb->battleGetUnitsIf([=](const battle::Unit * unit)
{ {
return !unit->isGhost(); return !unit->isGhost();
@ -136,12 +137,13 @@ void Catapult::apply(BattleStateProxy * battleState, RNG & rng, const Mechanics
break; break;
} }
} }
if(!removeUnits.changedStacks.empty())
battleState->apply(&removeUnits);
} }
} }
battleState->apply(&ca); battleState->apply(&ca);
if(!removeUnits.changedStacks.empty())
battleState->apply(&removeUnits);
} }
void Catapult::serializeJsonEffect(JsonSerializeFormat & handler) void Catapult::serializeJsonEffect(JsonSerializeFormat & handler)

View File

@ -4279,13 +4279,20 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side); const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
CHeroHandler::SBallisticsLevelInfo sbi; CHeroHandler::SBallisticsLevelInfo stackBallisticsParameters;
if(stack->getCreature()->idNumber == CreatureID::CATAPULT) if(stack->getCreature()->idNumber == CreatureID::CATAPULT)
sbi = VLC->heroh->ballistics.at(attackingHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::BALLISTICS)); stackBallisticsParameters = VLC->heroh->ballistics.at(attackingHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::BALLISTICS));
else //may need to use higher ballistics level for creatures in future for some cases to match original H3 (upgraded cyclops etc) else
{ {
sbi = VLC->heroh->ballistics.at(1); if(stack->hasBonusOfType(Bonus::CATAPULT_EXTRA_SHOTS)) //by design use advanced ballistics parameters with this bonus present, upg. cyclops use advanced ballistics, nonupg. use basic in OH3
sbi.shots += std::max(stack->valOfBonuses(Bonus::CATAPULT_EXTRA_SHOTS), 0); {
stackBallisticsParameters = VLC->heroh->ballistics.at(2);
stackBallisticsParameters.shots = 1; //skip default "2 shots" from adv. ballistics
}
else
stackBallisticsParameters = VLC->heroh->ballistics.at(1);
stackBallisticsParameters.shots += std::max(stack->valOfBonuses(Bonus::CATAPULT_EXTRA_SHOTS), 0); //0 is allowed minimum to let modders force advanced ballistics for "oneshotting creatures"
} }
auto wallPart = gs->curB->battleHexToWallPart(destination); auto wallPart = gs->curB->battleHexToWallPart(destination);
@ -4304,7 +4311,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
break; break;
} }
for (int g=0; g<sbi.shots; ++g) for (int g=0; g<stackBallisticsParameters.shots; ++g)
{ {
bool hitSuccessfull = false; bool hitSuccessfull = false;
auto attackedPart = wallPart; auto attackedPart = wallPart;
@ -4313,7 +4320,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
{ {
if (currentHP.at(attackedPart) != EWallState::DESTROYED && // this part can be hit if (currentHP.at(attackedPart) != EWallState::DESTROYED && // this part can be hit
currentHP.at(attackedPart) != EWallState::NONE && currentHP.at(attackedPart) != EWallState::NONE &&
getRandomGenerator().nextInt(99) < getCatapultHitChance(attackedPart, sbi))//hit is successful getRandomGenerator().nextInt(99) < getCatapultHitChance(attackedPart, stackBallisticsParameters))//hit is successful
{ {
hitSuccessfull = true; hitSuccessfull = true;
} }
@ -4341,8 +4348,9 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
attack.attackedPart = attackedPart; attack.attackedPart = attackedPart;
attack.destinationTile = destination; attack.destinationTile = destination;
attack.damageDealt = 0; attack.damageDealt = 0;
BattleUnitsChanged removeUnits;
int dmgChance[] = { sbi.noDmg, sbi.oneDmg, sbi.twoDmg }; //dmgChance[i] - chance for doing i dmg when hit is successful int dmgChance[] = { stackBallisticsParameters.noDmg, stackBallisticsParameters.oneDmg, stackBallisticsParameters.twoDmg }; //dmgChance[i] - chance for doing i dmg when hit is successful
int dmgRand = getRandomGenerator().nextInt(99); int dmgRand = getRandomGenerator().nextInt(99);
//accumulating dmgChance //accumulating dmgChance
@ -4363,7 +4371,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
logGlobal->trace("Catapult attacks %d dealing %d damage", (int)attack.attackedPart, (int)attack.damageDealt); logGlobal->trace("Catapult attacks %d dealing %d damage", (int)attack.attackedPart, (int)attack.damageDealt);
//removing creatures in turrets / keep if one is destroyed //removing creatures in turrets / keep if one is destroyed
if (attack.damageDealt > 0 && (attackedPart == EWallPart::KEEP || if (currentHP.at(attackedPart) - attack.damageDealt <= 0 && (attackedPart == EWallPart::KEEP || //HP enum subtraction not intuitive, consider using SiegeInfo::applyDamage
attackedPart == EWallPart::BOTTOM_TOWER || attackedPart == EWallPart::UPPER_TOWER)) attackedPart == EWallPart::BOTTOM_TOWER || attackedPart == EWallPart::UPPER_TOWER))
{ {
int posRemove = -1; int posRemove = -1;
@ -4380,7 +4388,6 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
break; break;
} }
BattleUnitsChanged removeUnits;
for(auto & elem : gs->curB->stacks) for(auto & elem : gs->curB->stacks)
{ {
if(elem->initialPosition == posRemove) if(elem->initialPosition == posRemove)
@ -4389,13 +4396,14 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
break; break;
} }
} }
if(!removeUnits.changedStacks.empty())
sendAndApply(&removeUnits);
} }
ca.attacker = ba.stackNumber; ca.attacker = ba.stackNumber;
ca.attackedParts.push_back(attack); ca.attackedParts.push_back(attack);
sendAndApply(&ca); sendAndApply(&ca);
if(!removeUnits.changedStacks.empty())
sendAndApply(&removeUnits);
} }
//finish by scope guard //finish by scope guard
break; break;