1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Add santa gremlin missing creature ability, fix shooter init bug

This commit is contained in:
dydzio 2017-01-26 20:53:28 +01:00
parent daec6d933c
commit 3e285c2004
4 changed files with 118 additions and 25 deletions

View File

@ -799,7 +799,7 @@ bool CShootingAnimation::init()
double pi = boost::math::constants::pi<double>();
// only frames below maxFrame are usable: anything higher is either no present or we don't know when it should be used
size_t maxFrame = std::min<size_t>(angles.size(), owner->idToProjectile[spi.creID]->ourImages.size());
size_t maxFrame = std::min<size_t>(angles.size(), owner->idToProjectile.at(spi.creID)->ourImages.size());
assert(maxFrame > 0);

View File

@ -302,29 +302,6 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
if (s->position >= 0) //turrets have position < 0
bfield[s->position]->accessible = false;
//loading projectiles for units
for (const CStack *s : stacks)
{
if (s->getCreature()->isShooting())
{
CDefHandler *&projectile = idToProjectile[s->getCreature()->idNumber];
const CCreature *creature;//creature whose shots should be loaded
if (s->getCreature()->idNumber == CreatureID::ARROW_TOWERS)
creature = CGI->creh->creatures[siegeH->town->town->clientInfo.siegeShooter];
else
creature = s->getCreature();
projectile = CDefHandler::giveDef(creature->animation.projectileImageName);
for (auto & elem : projectile->ourImages) //alpha transforming
{
CSDL_Ext::alphaTransform(elem.bitmap);
}
}
}
//preparing graphic with cell borders
cellBorders = CSDL_Ext::newSurface(background->w, background->h, cellBorder);
//copying palette
@ -1005,6 +982,24 @@ void CBattleInterface::newStack(const CStack *stack)
creAnims[stack->ID]->pos.w = creAnims[stack->ID]->getWidth();
creAnims[stack->ID]->setType(CCreatureAnim::HOLDING);
//loading projectiles for units
if (stack->getCreature()->isShooting())
{
CDefHandler *&projectile = idToProjectile[stack->getCreature()->idNumber];
const CCreature *creature;//creature whose shots should be loaded
if (stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS)
creature = CGI->creh->creatures[siegeH->town->town->clientInfo.siegeShooter];
else
creature = stack->getCreature();
projectile = CDefHandler::giveDef(creature->animation.projectileImageName);
for (auto & elem : projectile->ourImages) //alpha transforming
{
CSDL_Ext::alphaTransform(elem.bitmap);
}
}
}
void CBattleInterface::stackRemoved(int stackID)

View File

@ -212,6 +212,7 @@ public:
BONUS_NAME(REBIRTH) /* val - percent of life restored, subtype = 0 - regular, 1 - at least one unit (sacred Phoenix) */\
BONUS_NAME(SOUL_STEAL) /*val - number of units gained per enemy killed, subtype = 0 - gained units survive after battle, 1 - they do not*/ \
BONUS_NAME(TRANSMUTATION) /*val - chance to trigger in %, subtype = 0 - resurrection based on HP, 1 - based on unit count, additional info - target creature ID (attacker default)*/\
BONUS_NAME(SUMMON_GUARDIANS) /*val - amount in % of stack count, subtype = creature ID*/\
BONUS_NAME(ADDITIONAL_UNITS) /*val of units with id = subtype will be added to hero's army at the beginning of battle */\
BONUS_NAME(SPOILS_OF_WAR) /*val * 10^-6 * gained exp resources of subtype will be given to hero after battle*/\
BONUS_NAME(BLOCK)\

View File

@ -5537,8 +5537,105 @@ void CGameHandler::runBattle()
}
//initial stacks appearance triggers, e.g. built-in bonus spells
for (auto stack : gs->curB->stacks)
auto initialStacks = gs->curB->stacks;
for (CStack * stack : initialStacks)
{
if (stack->hasBonusOfType(Bonus::SUMMON_GUARDIANS))
{
const std::shared_ptr<Bonus> summonInfo = stack->getBonus(Selector::type(Bonus::SUMMON_GUARDIANS));
auto accessibility = getAccesibility();
CreatureID creatureData = CreatureID(summonInfo->subtype);
std::vector<BattleHex> targetHexes;
bool targetIsBig = stack->getCreature()->isDoubleWide(); //target = creature to guard
if (!creatureData.toCreature()->isDoubleWide())
targetHexes = stack->getSurroundingHexes();
else
{
if(stack->attackerOwned) //handle front guardians, TODO: should we handle situation when units start battle near opposite side of the battlefield? Cannot happen in normal H3...
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::RIGHT, false).moveInDir(BattleHex::EDir::RIGHT, false), targetHexes);
else
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::LEFT, false).moveInDir(BattleHex::EDir::LEFT, false), targetHexes);
//guardian spawn locations for four default position cases for attacker and defender, non-default starting location for att and def is handled in first two if's
if (stack->attackerOwned && ( (stack->position.getY() % 2 == 0) || (stack->position.getX() > 1) ))
{
if (targetIsBig && (stack->position.getY() % 2 == 1) && (stack->position.getX() == 2)) //handle exceptional case
{
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::TOP_RIGHT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::BOTTOM_RIGHT, false), targetHexes);
}
else
{ //add back-side guardians for two-hex target, side guardians for one-hex
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(targetIsBig ? BattleHex::EDir::TOP_LEFT : BattleHex::EDir::TOP_RIGHT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(targetIsBig ? BattleHex::EDir::BOTTOM_LEFT : BattleHex::EDir::BOTTOM_RIGHT, false), targetHexes);
if (!targetIsBig && stack->position.getX() > 2) //back guard for one-hex
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::LEFT, false), targetHexes);
else if (targetIsBig)//front-side guardians for two-hex target
{
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::RIGHT, false).moveInDir(BattleHex::EDir::TOP_RIGHT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::RIGHT, false).moveInDir(BattleHex::EDir::BOTTOM_RIGHT, false), targetHexes);
if (stack->position.getX() > 3) //back guard for two-hex
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::LEFT, false).moveInDir(BattleHex::EDir::LEFT, false), targetHexes);
}
}
}
else if (!stack->attackerOwned && ((stack->position.getY() % 2 == 1) || (stack->position.getX() < GameConstants::BFIELD_WIDTH - 2)))
{
if (targetIsBig && (stack->position.getY() % 2 == 0) && (stack->position.getX() == GameConstants::BFIELD_WIDTH - 3 )) //handle exceptional case... equivalent for above for defender side
{
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::TOP_LEFT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::BOTTOM_LEFT, false), targetHexes);
}
else
{
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(targetIsBig ? BattleHex::EDir::TOP_RIGHT : BattleHex::EDir::TOP_LEFT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(targetIsBig ? BattleHex::EDir::BOTTOM_RIGHT : BattleHex::EDir::BOTTOM_LEFT, false), targetHexes);
if (!targetIsBig && stack->position.getX() < GameConstants::BFIELD_WIDTH - 3)
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::RIGHT, false), targetHexes);
else if (targetIsBig)
{
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::LEFT, false).moveInDir(BattleHex::EDir::TOP_LEFT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::LEFT, false).moveInDir(BattleHex::EDir::BOTTOM_LEFT, false), targetHexes);
if (stack->position.getX() < GameConstants::BFIELD_WIDTH - 4)
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::RIGHT, false).moveInDir(BattleHex::EDir::RIGHT, false), targetHexes);
}
}
}
else if (!stack->attackerOwned && stack->position.getY() % 2 == 0)
{
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::LEFT, false).moveInDir(BattleHex::EDir::TOP_LEFT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::LEFT, false).moveInDir(BattleHex::EDir::BOTTOM_LEFT, false), targetHexes);
}
else if (stack->attackerOwned && stack->position.getY() % 2 == 1)
{
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::RIGHT, false).moveInDir(BattleHex::EDir::TOP_RIGHT, false), targetHexes);
BattleHex::checkAndPush(BattleHex(stack->position).moveInDir(BattleHex::EDir::RIGHT, false).moveInDir(BattleHex::EDir::BOTTOM_RIGHT, false), targetHexes);
}
}
for (auto hex : targetHexes)
{
if (accessibility.accessible(hex, creatureData.toCreature()->isDoubleWide(), stack->attackerOwned)) //without this multiple creatures can occupy one hex
{
BattleStackAdded newStack;
newStack.amount = std::max(1, stack->count) * 0.01 * summonInfo->val;
newStack.creID = creatureData.num;
newStack.attacker = stack->attackerOwned;
newStack.summoned = true;
newStack.pos = hex.hex;
sendAndApply(&newStack);
}
}
}
stackAppearTrigger(stack);
}