mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-26 22:57:00 +02:00
* Implemented Moat functionality during siege (stops movement and deals dmg)
* Mostly implemented battle spells: - Fire Wall - Force Field - Land Mine - Quicksands
This commit is contained in:
parent
5435101182
commit
d168f3eac2
@ -335,28 +335,31 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
|||||||
backgroundWithHexes = CSDL_Ext::newSurface(background->w, background->h, screen);
|
backgroundWithHexes = CSDL_Ext::newSurface(background->w, background->h, screen);
|
||||||
|
|
||||||
//preparing obstacle defs
|
//preparing obstacle defs
|
||||||
std::vector<CObstacleInstance> obst = curInt->cb->battleGetAllObstacles();
|
auto obst = curInt->cb->battleGetAllObstacles();
|
||||||
for(size_t t = 0; t < obst.size(); ++t)
|
for(size_t t = 0; t < obst.size(); ++t)
|
||||||
{
|
{
|
||||||
int ID = obst[t].ID;
|
const int ID = obst[t]->ID;
|
||||||
std::string gfxName = obst[t].getInfo().defName;
|
if(obst[t]->obstacleType == CObstacleInstance::USUAL)
|
||||||
|
|
||||||
if(obst[t].obstacleType == CObstacleInstance::USUAL)
|
|
||||||
{
|
{
|
||||||
idToObstacle[ID] = CDefHandler::giveDef(gfxName);
|
idToObstacle[ID] = CDefHandler::giveDef(obst[t]->getInfo().defName);
|
||||||
for(size_t n = 0; n < idToObstacle[ID]->ourImages.size(); ++n)
|
for(size_t n = 0; n < idToObstacle[ID]->ourImages.size(); ++n)
|
||||||
{
|
{
|
||||||
SDL_SetColorKey(idToObstacle[ID]->ourImages[n].bitmap, SDL_SRCCOLORKEY, SDL_MapRGB(idToObstacle[ID]->ourImages[n].bitmap->format,0,255,255));
|
SDL_SetColorKey(idToObstacle[ID]->ourImages[n].bitmap, SDL_SRCCOLORKEY, SDL_MapRGB(idToObstacle[ID]->ourImages[n].bitmap->format,0,255,255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if(obst[t]->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
|
||||||
{
|
{
|
||||||
idToAbsoluteObstacle[ID] = BitmapHandler::loadBitmap(gfxName);
|
idToAbsoluteObstacle[ID] = BitmapHandler::loadBitmap(obst[t]->getInfo().defName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quicksand = CDefHandler::giveDef("C17SPE1.DEF");
|
quicksand = CDefHandler::giveDef("C17SPE1.DEF");
|
||||||
landMine = CDefHandler::giveDef("C09SPF1.DEF");
|
landMine = CDefHandler::giveDef("C09SPF1.DEF");
|
||||||
|
fireWall = CDefHandler::giveDef("C07SPF61");
|
||||||
|
bigForceField[0] = CDefHandler::giveDef("C15SPE10.DEF");
|
||||||
|
bigForceField[1] = CDefHandler::giveDef("C15SPE7.DEF");
|
||||||
|
smallForceField[0] = CDefHandler::giveDef("C15SPE1.DEF");
|
||||||
|
smallForceField[1] = CDefHandler::giveDef("C15SPE4.DEF");
|
||||||
|
|
||||||
for (int i = 0; i < bfield.size(); i++)
|
for (int i = 0; i < bfield.size(); i++)
|
||||||
{
|
{
|
||||||
@ -428,6 +431,11 @@ CBattleInterface::~CBattleInterface()
|
|||||||
|
|
||||||
delete quicksand;
|
delete quicksand;
|
||||||
delete landMine;
|
delete landMine;
|
||||||
|
delete fireWall;
|
||||||
|
delete smallForceField[0];
|
||||||
|
delete smallForceField[1];
|
||||||
|
delete bigForceField[0];
|
||||||
|
delete bigForceField[1];
|
||||||
|
|
||||||
delete siegeH;
|
delete siegeH;
|
||||||
|
|
||||||
@ -565,9 +573,9 @@ void CBattleInterface::show(SDL_Surface * to)
|
|||||||
CSDL_Ext::blit8bppAlphaTo24bpp(cellBorders, NULL, to, &pos);
|
CSDL_Ext::blit8bppAlphaTo24bpp(cellBorders, NULL, to, &pos);
|
||||||
}
|
}
|
||||||
//Blit absolute obstacles
|
//Blit absolute obstacles
|
||||||
BOOST_FOREACH(const CObstacleInstance &oi, curInt->cb->battleGetAllObstacles())
|
BOOST_FOREACH(auto &oi, curInt->cb->battleGetAllObstacles())
|
||||||
if(oi.obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
|
if(oi->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
|
||||||
blitAt(imageOfObstacle(oi), pos.x + oi.getInfo().width, pos.y + oi.getInfo().height, to);
|
blitAt(imageOfObstacle(*oi), pos.x + oi->getInfo().width, pos.y + oi->getInfo().height, to);
|
||||||
}
|
}
|
||||||
//printing hovered cell
|
//printing hovered cell
|
||||||
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
|
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
|
||||||
@ -597,14 +605,15 @@ void CBattleInterface::show(SDL_Surface * to)
|
|||||||
if (defendingHeroInstance)
|
if (defendingHeroInstance)
|
||||||
schoolLevel = defendingHeroInstance->getSpellSchoolLevel(&spToCast);
|
schoolLevel = defendingHeroInstance->getSpellSchoolLevel(&spToCast);
|
||||||
}
|
}
|
||||||
|
|
||||||
//obtaining range and printing it
|
//obtaining range and printing it
|
||||||
std::set<ui16> shaded = spToCast.rangeInHexes(b, schoolLevel);
|
auto shaded = spToCast.rangeInHexes(b, schoolLevel, curInt->cb->battleGetMySide());
|
||||||
for(std::set<ui16>::iterator it = shaded.begin(); it != shaded.end(); ++it) //for spells with range greater then one hex
|
BOOST_FOREACH(auto shadedHex, shaded) //for spells with range greater then one hex
|
||||||
{
|
{
|
||||||
if(settings["battle"]["mouseShadow"].Bool() && (*it % GameConstants::BFIELD_WIDTH != 0) && (*it % GameConstants::BFIELD_WIDTH != 16))
|
if(settings["battle"]["mouseShadow"].Bool() && (shadedHex % GameConstants::BFIELD_WIDTH != 0) && (shadedHex % GameConstants::BFIELD_WIDTH != 16))
|
||||||
{
|
{
|
||||||
int x = 14 + ((*it/GameConstants::BFIELD_WIDTH)%2==0 ? 22 : 0) + 44*(*it%GameConstants::BFIELD_WIDTH) + pos.x;
|
int x = 14 + ((shadedHex/GameConstants::BFIELD_WIDTH)%2==0 ? 22 : 0) + 44*(shadedHex%GameConstants::BFIELD_WIDTH) + pos.x;
|
||||||
int y = 86 + 42 * (*it/GameConstants::BFIELD_WIDTH) + pos.y;
|
int y = 86 + 42 * (shadedHex/GameConstants::BFIELD_WIDTH) + pos.y;
|
||||||
SDL_Rect temp_rect = genRect(cellShade->h, cellShade->w, x, y);
|
SDL_Rect temp_rect = genRect(cellShade->h, cellShade->w, x, y);
|
||||||
CSDL_Ext::blit8bppAlphaTo24bpp(cellShade, NULL, to, &temp_rect);
|
CSDL_Ext::blit8bppAlphaTo24bpp(cellShade, NULL, to, &temp_rect);
|
||||||
}
|
}
|
||||||
@ -640,16 +649,16 @@ void CBattleInterface::show(SDL_Surface * to)
|
|||||||
SDL_SetClipRect(to, &pos);
|
SDL_SetClipRect(to, &pos);
|
||||||
|
|
||||||
//preparing obstacles to be shown
|
//preparing obstacles to be shown
|
||||||
std::vector<CObstacleInstance> obstacles = curInt->cb->battleGetAllObstacles();
|
auto obstacles = curInt->cb->battleGetAllObstacles();
|
||||||
std::multimap<BattleHex, int> hexToObstacle;
|
std::multimap<BattleHex, int> hexToObstacle;
|
||||||
|
|
||||||
for(size_t b = 0; b < obstacles.size(); ++b)
|
for(size_t b = 0; b < obstacles.size(); ++b)
|
||||||
{
|
{
|
||||||
const CObstacleInstance &oi = obstacles[b];
|
const auto &oi = obstacles[b];
|
||||||
if(oi.obstacleType != CObstacleInstance::ABSOLUTE_OBSTACLE)
|
if(oi->obstacleType != CObstacleInstance::ABSOLUTE_OBSTACLE && oi->obstacleType != CObstacleInstance::MOAT)
|
||||||
{
|
{
|
||||||
//BattleHex position = CGI->heroh->obstacles.find(obstacles[b].ID)->second.getMaxBlocked(obstacles[b].pos);
|
//BattleHex position = CGI->heroh->obstacles.find(obstacles[b].ID)->second.getMaxBlocked(obstacles[b].pos);
|
||||||
hexToObstacle.insert(std::make_pair(oi.pos, b));
|
hexToObstacle.insert(std::make_pair(oi->pos, b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,13 +715,26 @@ void CBattleInterface::show(SDL_Surface * to)
|
|||||||
if(!active)
|
if(!active)
|
||||||
activate();
|
activate();
|
||||||
|
|
||||||
|
bool changedStack = false;
|
||||||
|
|
||||||
//activation of next stack
|
//activation of next stack
|
||||||
if(pendingAnims.size() == 0 && stackToActivate != NULL)
|
if(pendingAnims.size() == 0 && stackToActivate != NULL)
|
||||||
{
|
{
|
||||||
activateStack();
|
activateStack();
|
||||||
|
changedStack = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
//anims ended
|
//anims ended
|
||||||
animsAreDisplayed.setn(false);
|
animsAreDisplayed.setn(false);
|
||||||
|
|
||||||
|
if(changedStack)
|
||||||
|
{
|
||||||
|
//we may have changed active interface (another side in hot-seat),
|
||||||
|
// so we can't continue drawing with old setting. So we call ourselves again and end.
|
||||||
|
SDL_SetClipRect(to, &buf); //restoring previous clip_rect
|
||||||
|
show(to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b) //showing dead stacks
|
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b) //showing dead stacks
|
||||||
@ -906,14 +928,14 @@ void CBattleInterface::showAliveStacks(std::vector<const CStack *> *aliveStacks,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBattleInterface::showObstacles(std::multimap<BattleHex, int> *hexToObstacle, std::vector<CObstacleInstance> &obstacles, int hex, SDL_Surface *to)
|
void CBattleInterface::showObstacles(std::multimap<BattleHex, int> *hexToObstacle, std::vector<shared_ptr<const CObstacleInstance> > &obstacles, int hex, SDL_Surface *to)
|
||||||
{
|
{
|
||||||
std::pair<std::multimap<BattleHex, int>::const_iterator, std::multimap<BattleHex, int>::const_iterator> obstRange =
|
std::pair<std::multimap<BattleHex, int>::const_iterator, std::multimap<BattleHex, int>::const_iterator> obstRange =
|
||||||
hexToObstacle->equal_range(hex);
|
hexToObstacle->equal_range(hex);
|
||||||
|
|
||||||
for(std::multimap<BattleHex, int>::const_iterator it = obstRange.first; it != obstRange.second; ++it)
|
for(std::multimap<BattleHex, int>::const_iterator it = obstRange.first; it != obstRange.second; ++it)
|
||||||
{
|
{
|
||||||
CObstacleInstance & curOb = obstacles[it->second];
|
const CObstacleInstance & curOb = *obstacles[it->second];
|
||||||
SDL_Surface *toBlit = imageOfObstacle(curOb);
|
SDL_Surface *toBlit = imageOfObstacle(curOb);
|
||||||
Point p = whereToBlitObstacleImage(toBlit, curOb);
|
Point p = whereToBlitObstacleImage(toBlit, curOb);
|
||||||
blitAt(toBlit, p.x, p.y, to);
|
blitAt(toBlit, p.x, p.y, to);
|
||||||
@ -1336,7 +1358,7 @@ void CBattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attacked
|
|||||||
for(size_t h = 0; h < attackedInfos.size(); ++h)
|
for(size_t h = 0; h < attackedInfos.size(); ++h)
|
||||||
{
|
{
|
||||||
++targets;
|
++targets;
|
||||||
killed += attackedInfos[h].killed;
|
killed += attackedInfos[h].amountKilled;
|
||||||
damage += attackedInfos[h].dmg;
|
damage += attackedInfos[h].dmg;
|
||||||
}
|
}
|
||||||
if (attackedInfos.front().cloneKilled) //FIXME: cloned stack is already removed
|
if (attackedInfos.front().cloneKilled) //FIXME: cloned stack is already removed
|
||||||
@ -1855,6 +1877,11 @@ void CBattleInterface::castThisSpell(int spellID)
|
|||||||
spellSelMode = ANY_LOCATION;
|
spellSelMode = ANY_LOCATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(spellID == Spells::FIRE_WALL || spellID == Spells::FORCE_FIELD)
|
||||||
|
{
|
||||||
|
spellSelMode = FREE_LOCATION;
|
||||||
|
}
|
||||||
|
|
||||||
if (spellSelMode == NO_LOCATION) //user does not have to select location
|
if (spellSelMode == NO_LOCATION) //user does not have to select location
|
||||||
{
|
{
|
||||||
spellToCast->destinationTile = -1;
|
spellToCast->destinationTile = -1;
|
||||||
@ -2282,9 +2309,11 @@ void CBattleInterface::redrawBackgroundWithHexes(const CStack * activeStack)
|
|||||||
blitAt(background, 0, 0, backgroundWithHexes);
|
blitAt(background, 0, 0, backgroundWithHexes);
|
||||||
|
|
||||||
//draw absolute obstacles (cliffs and so on)
|
//draw absolute obstacles (cliffs and so on)
|
||||||
BOOST_FOREACH(const CObstacleInstance &oi, curInt->cb->battleGetAllObstacles())
|
BOOST_FOREACH(auto &oi, curInt->cb->battleGetAllObstacles())
|
||||||
if(oi.obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE)
|
{
|
||||||
blitAt(imageOfObstacle(oi), oi.getInfo().width, oi.getInfo().height, backgroundWithHexes);
|
if(oi->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE/* || oi.obstacleType == CObstacleInstance::MOAT*/)
|
||||||
|
blitAt(imageOfObstacle(*oi), oi->getInfo().width, oi->getInfo().height, backgroundWithHexes);
|
||||||
|
}
|
||||||
|
|
||||||
if(settings["battle"]["cellBorders"].Bool())
|
if(settings["battle"]["cellBorders"].Bool())
|
||||||
CSDL_Ext::blit8bppAlphaTo24bpp(cellBorders, NULL, backgroundWithHexes, NULL);
|
CSDL_Ext::blit8bppAlphaTo24bpp(cellBorders, NULL, backgroundWithHexes, NULL);
|
||||||
@ -2307,7 +2336,7 @@ void CBattleInterface::redrawBackgroundWithHexes(const CStack * activeStack)
|
|||||||
|
|
||||||
void CBattleInterface::printConsoleAttacked( const CStack * defender, int dmg, int killed, const CStack * attacker, bool multiple )
|
void CBattleInterface::printConsoleAttacked( const CStack * defender, int dmg, int killed, const CStack * attacker, bool multiple )
|
||||||
{
|
{
|
||||||
char tabh[200];
|
char tabh[200] = {0};
|
||||||
int end = 0;
|
int end = 0;
|
||||||
if (attacker) //ignore if stacks were killed by spell
|
if (attacker) //ignore if stacks were killed by spell
|
||||||
{
|
{
|
||||||
@ -2800,6 +2829,33 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
else
|
else
|
||||||
notLegal = true;
|
notLegal = true;
|
||||||
break;
|
break;
|
||||||
|
case FREE_LOCATION:
|
||||||
|
{
|
||||||
|
ui8 side = curInt->cb->battleGetMySide();
|
||||||
|
auto hero = curInt->cb->battleGetFightingHero(side);
|
||||||
|
assert(!creatureCasting); //we assume hero casts this spell
|
||||||
|
assert(hero);
|
||||||
|
|
||||||
|
legalAction = true;
|
||||||
|
bool hexesOutsideBattlefield = false;
|
||||||
|
auto tilesThatMustBeClear = sp->rangeInHexes(myNumber, hero->getSpellSchoolLevel(sp), side, &hexesOutsideBattlefield);
|
||||||
|
BOOST_FOREACH(BattleHex hex, tilesThatMustBeClear)
|
||||||
|
{
|
||||||
|
if(curInt->cb->battleGetStackByPos(hex) || !!curInt->cb->battleGetObstacleOnPos(hex, false)
|
||||||
|
|| !hex.isAvailable())
|
||||||
|
{
|
||||||
|
legalAction = false;
|
||||||
|
notLegal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hexesOutsideBattlefield)
|
||||||
|
{
|
||||||
|
legalAction = false;
|
||||||
|
notLegal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CATAPULT:
|
case CATAPULT:
|
||||||
if (isCatapultAttackable(myNumber))
|
if (isCatapultAttackable(myNumber))
|
||||||
legalAction = true;
|
legalAction = true;
|
||||||
@ -2930,7 +2986,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
break;
|
break;
|
||||||
case ANY_LOCATION:
|
case ANY_LOCATION:
|
||||||
sp = CGI->spellh->spells[creatureCasting ? creatureSpellToCast : spellToCast->additionalInfo]; //necessary if creature has random Genie spell at same time
|
sp = CGI->spellh->spells[creatureCasting ? creatureSpellToCast : spellToCast->additionalInfo]; //necessary if creature has random Genie spell at same time
|
||||||
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % sp->name); //Cast %s on %s
|
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % sp->name); //Cast %s
|
||||||
isCastingPossible = true;
|
isCastingPossible = true;
|
||||||
break;
|
break;
|
||||||
case RANDOM_GENIE_SPELL: //we assume that teleport / sacrifice will never be avaliable as random spell
|
case RANDOM_GENIE_SPELL: //we assume that teleport / sacrifice will never be avaliable as random spell
|
||||||
@ -2952,6 +3008,11 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
spellToCast->selectedStack = shere->ID; //sacrificed creature is selected
|
spellToCast->selectedStack = shere->ID; //sacrificed creature is selected
|
||||||
isCastingPossible = true;
|
isCastingPossible = true;
|
||||||
break;
|
break;
|
||||||
|
case FREE_LOCATION:
|
||||||
|
//cursorFrame = ECursor::SPELLBOOK;
|
||||||
|
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % sp->name); //Cast %s
|
||||||
|
isCastingPossible = true;
|
||||||
|
break;
|
||||||
case HEAL:
|
case HEAL:
|
||||||
cursorFrame = ECursor::COMBAT_HEAL;
|
cursorFrame = ECursor::COMBAT_HEAL;
|
||||||
consoleMsg = (boost::format(CGI->generaltexth->allTexts[419]) % shere->getName()).str(); //Apply first aid to the %s
|
consoleMsg = (boost::format(CGI->generaltexth->allTexts[419]) % shere->getName()).str(); //Apply first aid to the %s
|
||||||
@ -3006,6 +3067,10 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
case SACRIFICE:
|
case SACRIFICE:
|
||||||
consoleMsg = CGI->generaltexth->allTexts[543]; //choose army to sacrifice
|
consoleMsg = CGI->generaltexth->allTexts[543]; //choose army to sacrifice
|
||||||
break;
|
break;
|
||||||
|
case FREE_LOCATION:
|
||||||
|
cursorFrame = ECursor::COMBAT_BLOCKED;
|
||||||
|
consoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[181]) % sp->name); //No room to place %s here
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
cursorFrame = ECursor::COMBAT_BLOCKED;
|
cursorFrame = ECursor::COMBAT_BLOCKED;
|
||||||
break;
|
break;
|
||||||
@ -3275,6 +3340,20 @@ SDL_Surface * CBattleInterface::imageOfObstacle(const CObstacleInstance &oi) con
|
|||||||
return vstd::circularAt(quicksand->ourImages, frameIndex).bitmap;
|
return vstd::circularAt(quicksand->ourImages, frameIndex).bitmap;
|
||||||
case CObstacleInstance::LAND_MINE:
|
case CObstacleInstance::LAND_MINE:
|
||||||
return vstd::circularAt(landMine->ourImages, frameIndex).bitmap;
|
return vstd::circularAt(landMine->ourImages, frameIndex).bitmap;
|
||||||
|
case CObstacleInstance::FIRE_WALL:
|
||||||
|
return vstd::circularAt(fireWall->ourImages, frameIndex).bitmap;
|
||||||
|
case CObstacleInstance::FORCE_FIELD:
|
||||||
|
{
|
||||||
|
auto &forceField = dynamic_cast<const SpellCreatedObstacle &>(oi);
|
||||||
|
if(forceField.getAffectedTiles().size() > 2)
|
||||||
|
return vstd::circularAt(bigForceField[forceField.casterSide]->ourImages, frameIndex).bitmap;
|
||||||
|
else
|
||||||
|
return vstd::circularAt(smallForceField[forceField.casterSide]->ourImages, frameIndex).bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CObstacleInstance::MOAT:
|
||||||
|
//moat is blitted by SiegeHelper, this shouldn't be called
|
||||||
|
assert(0);
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
@ -3286,16 +3365,47 @@ void CBattleInterface::obstaclePlaced(const CObstacleInstance & oi)
|
|||||||
waitForAnims();
|
waitForAnims();
|
||||||
|
|
||||||
int effectID = -1;
|
int effectID = -1;
|
||||||
|
soundBase::soundID sound = soundBase::invalid;
|
||||||
|
|
||||||
|
std::string defname;
|
||||||
|
|
||||||
switch(oi.obstacleType)
|
switch(oi.obstacleType)
|
||||||
{
|
{
|
||||||
case CObstacleInstance::QUICKSAND:
|
case CObstacleInstance::QUICKSAND:
|
||||||
effectID = 55;
|
effectID = 55;
|
||||||
|
sound = soundBase::QUIKSAND;
|
||||||
break;
|
break;
|
||||||
case CObstacleInstance::LAND_MINE:
|
case CObstacleInstance::LAND_MINE:
|
||||||
effectID = 47;
|
effectID = 47;
|
||||||
|
sound = soundBase::LANDMINE;
|
||||||
|
break;
|
||||||
|
case CObstacleInstance::FORCE_FIELD:
|
||||||
|
{
|
||||||
|
auto &spellObstacle = dynamic_cast<const SpellCreatedObstacle&>(oi);
|
||||||
|
if(spellObstacle.casterSide)
|
||||||
|
{
|
||||||
|
if(oi.getAffectedTiles().size() < 3)
|
||||||
|
defname = "C15SPE0.DEF"; //TODO cannot find def for 2-hex force field \ appearing
|
||||||
|
else
|
||||||
|
defname = "C15SPE6.DEF";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(oi.getAffectedTiles().size() < 3)
|
||||||
|
defname = "C15SPE0.DEF";
|
||||||
|
else
|
||||||
|
defname = "C15SPE9.DEF";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sound = soundBase::FORCEFLD;
|
||||||
|
break;
|
||||||
|
case CObstacleInstance::FIRE_WALL:
|
||||||
|
if(oi.getAffectedTiles().size() < 3)
|
||||||
|
effectID = 43; //small fire wall appearing
|
||||||
|
else
|
||||||
|
effectID = 44; //and the big one
|
||||||
|
sound = soundBase::fireWall;
|
||||||
break;
|
break;
|
||||||
//TODO firewall, force field
|
|
||||||
default:
|
default:
|
||||||
tlog1 << "I don't know how to animate appearing obstacle of type " << (int)oi.obstacleType << std::endl;
|
tlog1 << "I don't know how to animate appearing obstacle of type " << (int)oi.obstacleType << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -3307,12 +3417,17 @@ void CBattleInterface::obstaclePlaced(const CObstacleInstance & oi)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string defname = graphics->battleACToDef[effectID].front();
|
if(defname.empty() && effectID >= 0)
|
||||||
|
defname = graphics->battleACToDef[effectID].front();
|
||||||
|
|
||||||
|
assert(!defname.empty());
|
||||||
//we assume here that effect graphics have the same size as the usual obstacle image
|
//we assume here that effect graphics have the same size as the usual obstacle image
|
||||||
// -> if we know how to blit obstacle, let's blit the effect in the same place
|
// -> if we know how to blit obstacle, let's blit the effect in the same place
|
||||||
Point whereTo = whereToBlitObstacleImage(imageOfObstacle(oi), oi);
|
Point whereTo = whereToBlitObstacleImage(imageOfObstacle(oi), oi);
|
||||||
addNewAnim(new CSpellEffectAnimation(this, defname, whereTo.x, whereTo.y));
|
addNewAnim(new CSpellEffectAnimation(this, defname, whereTo.x, whereTo.y));
|
||||||
|
|
||||||
|
//TODO we need to wait after playing sound till it's finished, otherwise it overlaps and sounds really bad
|
||||||
|
//CCS->soundh->playSound(sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point CBattleInterface::whereToBlitObstacleImage(SDL_Surface *image, const CObstacleInstance &obstacle) const
|
Point CBattleInterface::whereToBlitObstacleImage(SDL_Surface *image, const CObstacleInstance &obstacle) const
|
||||||
|
@ -97,6 +97,7 @@ class CBattleInterface : public CIntObject
|
|||||||
MOVE_TACTICS, CHOOSE_TACTICS_STACK,
|
MOVE_TACTICS, CHOOSE_TACTICS_STACK,
|
||||||
MOVE_STACK, ATTACK, WALK_AND_ATTACK, ATTACK_AND_RETURN, SHOOT, //OPEN_GATE, //we can open castle gate during siege
|
MOVE_STACK, ATTACK, WALK_AND_ATTACK, ATTACK_AND_RETURN, SHOOT, //OPEN_GATE, //we can open castle gate during siege
|
||||||
NO_LOCATION, ANY_LOCATION, FRIENDLY_CREATURE_SPELL, HOSTILE_CREATURE_SPELL, RISING_SPELL, ANY_CREATURE, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL,
|
NO_LOCATION, ANY_LOCATION, FRIENDLY_CREATURE_SPELL, HOSTILE_CREATURE_SPELL, RISING_SPELL, ANY_CREATURE, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL,
|
||||||
|
FREE_LOCATION, //used with Force Field and Fire Wall - all tiles affected by spell must be free
|
||||||
CATAPULT, HEAL, RISE_DEMONS
|
CATAPULT, HEAL, RISE_DEMONS
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
@ -112,8 +113,13 @@ private:
|
|||||||
std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler)
|
std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler)
|
||||||
std::map< int, CDefHandler * > idToObstacle; //obstacles located on the battlefield
|
std::map< int, CDefHandler * > idToObstacle; //obstacles located on the battlefield
|
||||||
std::map< int, SDL_Surface * > idToAbsoluteObstacle; //obstacles located on the battlefield
|
std::map< int, SDL_Surface * > idToAbsoluteObstacle; //obstacles located on the battlefield
|
||||||
|
|
||||||
|
//TODO these should be loaded only when needed (and freed then) but I believe it's rather work for resource manager,
|
||||||
|
//so I didn't implement that (having ongoing RM development)
|
||||||
CDefHandler *landMine;
|
CDefHandler *landMine;
|
||||||
CDefHandler *quicksand;
|
CDefHandler *quicksand;
|
||||||
|
CDefHandler *fireWall;
|
||||||
|
CDefHandler *smallForceField[2], *bigForceField[2]; // [side]
|
||||||
|
|
||||||
std::map< int, bool > creDir; // <creatureID, if false reverse creature's animation>
|
std::map< int, bool > creDir; // <creatureID, if false reverse creature's animation>
|
||||||
ui8 animCount;
|
ui8 animCount;
|
||||||
@ -155,7 +161,7 @@ private:
|
|||||||
void showAliveStack(const CStack *stack, SDL_Surface * to); //helper function for function show
|
void showAliveStack(const CStack *stack, SDL_Surface * to); //helper function for function show
|
||||||
void showAliveStacks(std::vector<const CStack *> *aliveStacks, int hex, std::vector<const CStack *> *flyingStacks, SDL_Surface *to); // loops through all stacks at a given hex position
|
void showAliveStacks(std::vector<const CStack *> *aliveStacks, int hex, std::vector<const CStack *> *flyingStacks, SDL_Surface *to); // loops through all stacks at a given hex position
|
||||||
void showPieceOfWall(SDL_Surface * to, int hex, const std::vector<const CStack*> & stacks); //helper function for show
|
void showPieceOfWall(SDL_Surface * to, int hex, const std::vector<const CStack*> & stacks); //helper function for show
|
||||||
void showObstacles(std::multimap<BattleHex, int> *hexToObstacle, std::vector<CObstacleInstance> &obstacles, int hex, SDL_Surface *to); // show all obstacles at a given hex position
|
void showObstacles(std::multimap<BattleHex, int> *hexToObstacle, std::vector<shared_ptr<const CObstacleInstance> > &obstacles, int hex, SDL_Surface *to); // show all obstacles at a given hex position
|
||||||
SDL_Surface *imageOfObstacle(const CObstacleInstance &oi) const;
|
SDL_Surface *imageOfObstacle(const CObstacleInstance &oi) const;
|
||||||
Point whereToBlitObstacleImage(SDL_Surface *image, const CObstacleInstance &obstacle) const;
|
Point whereToBlitObstacleImage(SDL_Surface *image, const CObstacleInstance &obstacle) const;
|
||||||
void redrawBackgroundWithHexes(const CStack * activeStack);
|
void redrawBackgroundWithHexes(const CStack * activeStack);
|
||||||
|
@ -679,17 +679,17 @@ void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObst
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(std::set<si32>::const_iterator it = removedObstacles.begin(); it != removedObstacles.end(); ++it)
|
// for(std::set<si32>::const_iterator it = removedObstacles.begin(); it != removedObstacles.end(); ++it)
|
||||||
{
|
// {
|
||||||
for(std::map< int, CDefHandler * >::iterator itBat = battleInt->idToObstacle.begin(); itBat != battleInt->idToObstacle.end(); ++itBat)
|
// for(std::map< int, CDefHandler * >::iterator itBat = battleInt->idToObstacle.begin(); itBat != battleInt->idToObstacle.end(); ++itBat)
|
||||||
{
|
// {
|
||||||
if(itBat->first == *it) //remove this obstacle
|
// if(itBat->first == *it) //remove this obstacle
|
||||||
{
|
// {
|
||||||
battleInt->idToObstacle.erase(itBat);
|
// battleInt->idToObstacle.erase(itBat);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
//update accessible hexes
|
//update accessible hexes
|
||||||
battleInt->redrawBackgroundWithHexes(battleInt->activeStack);
|
battleInt->redrawBackgroundWithHexes(battleInt->activeStack);
|
||||||
}
|
}
|
||||||
|
@ -610,7 +610,7 @@ void BattleTriggerEffect::applyCl(CClient * cl)
|
|||||||
|
|
||||||
void BattleObstaclePlaced::applyCl(CClient * cl)
|
void BattleObstaclePlaced::applyCl(CClient * cl)
|
||||||
{
|
{
|
||||||
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleObstaclePlaced, obstacle);
|
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleObstaclePlaced, *obstacle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleResult::applyFirstCl( CClient *cl )
|
void BattleResult::applyFirstCl( CClient *cl )
|
||||||
|
@ -307,6 +307,7 @@
|
|||||||
<ClInclude Include="UIFramework\CIntObjectClasses.h" />
|
<ClInclude Include="UIFramework\CIntObjectClasses.h" />
|
||||||
<ClInclude Include="UIFramework\Geometries.h" />
|
<ClInclude Include="UIFramework\Geometries.h" />
|
||||||
<ClInclude Include="UIFramework\SDL_Extensions.h" />
|
<ClInclude Include="UIFramework\SDL_Extensions.h" />
|
||||||
|
<ClInclude Include="UIFramework\SDL_Pixels.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\ChangeLog" />
|
<None Include="..\ChangeLog" />
|
||||||
|
@ -232,19 +232,10 @@
|
|||||||
<ClInclude Include="UIFramework\SDL_Extensions.h">
|
<ClInclude Include="UIFramework\SDL_Extensions.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\hch\CArtHandler.h">
|
<ClInclude Include="mapHandler.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\hch\CBuildingHandler.h">
|
<ClInclude Include="UIFramework\SDL_Pixels.h">
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\hch\CHeroHandler.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\hch\CObjectHandler.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\hch\CVideoHandler.h">
|
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "BattleHex.h"
|
#include "BattleHex.h"
|
||||||
|
|
||||||
void BattleHex::operator+=(EDir dir)
|
BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
|
||||||
{
|
{
|
||||||
si16 x = getX(),
|
si16 x = getX(),
|
||||||
y = getY();
|
y = getY();
|
||||||
@ -9,27 +9,34 @@ void BattleHex::operator+=(EDir dir)
|
|||||||
switch(dir)
|
switch(dir)
|
||||||
{
|
{
|
||||||
case TOP_LEFT:
|
case TOP_LEFT:
|
||||||
setXY(y%2 ? x-1 : x, y-1);
|
setXY(y%2 ? x-1 : x, y-1, hasToBeValid);
|
||||||
break;
|
break;
|
||||||
case TOP_RIGHT:
|
case TOP_RIGHT:
|
||||||
setXY(y%2 ? x : x+1, y-1);
|
setXY(y%2 ? x : x+1, y-1, hasToBeValid);
|
||||||
break;
|
break;
|
||||||
case RIGHT:
|
case RIGHT:
|
||||||
setXY(x+1, y);
|
setXY(x+1, y, hasToBeValid);
|
||||||
break;
|
break;
|
||||||
case BOTTOM_RIGHT:
|
case BOTTOM_RIGHT:
|
||||||
setXY(y%2 ? x : x+1, y+1);
|
setXY(y%2 ? x : x+1, y+1, hasToBeValid);
|
||||||
break;
|
break;
|
||||||
case BOTTOM_LEFT:
|
case BOTTOM_LEFT:
|
||||||
setXY(y%2 ? x-1 : x, y+1);
|
setXY(y%2 ? x-1 : x, y+1, hasToBeValid);
|
||||||
break;
|
break;
|
||||||
case LEFT:
|
case LEFT:
|
||||||
setXY(x-1, y);
|
setXY(x-1, y, hasToBeValid);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
|
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleHex::operator+=(EDir dir)
|
||||||
|
{
|
||||||
|
moveInDir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
BattleHex BattleHex::operator+(EDir dir) const
|
BattleHex BattleHex::operator+(EDir dir) const
|
||||||
|
@ -58,9 +58,12 @@ struct DLL_LINKAGE BattleHex
|
|||||||
setXY(getX(), y);
|
setXY(getX(), y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setXY(si16 x, si16 y)
|
void setXY(si16 x, si16 y, bool hasToBeValid = true)
|
||||||
|
{
|
||||||
|
if(hasToBeValid)
|
||||||
{
|
{
|
||||||
assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
|
assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
|
||||||
|
}
|
||||||
hex = x + y * GameConstants::BFIELD_WIDTH;
|
hex = x + y * GameConstants::BFIELD_WIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +90,8 @@ struct DLL_LINKAGE BattleHex
|
|||||||
}
|
}
|
||||||
|
|
||||||
//moving to direction
|
//moving to direction
|
||||||
void operator+=(EDir dir);
|
BattleHex& moveInDir(EDir dir, bool hasToBeValid = true);
|
||||||
|
void operator+=(EDir dir); //sugar for above
|
||||||
|
|
||||||
//generates new BattleHex moved by given dir
|
//generates new BattleHex moved by given dir
|
||||||
BattleHex operator+(EDir dir) const;
|
BattleHex operator+(EDir dir) const;
|
||||||
|
@ -151,13 +151,12 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool atta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//obstacles
|
//obstacles
|
||||||
for(ui32 b=0; b<obstacles.size(); ++b)
|
BOOST_FOREACH(const auto &obstacle, obstacles)
|
||||||
{
|
{
|
||||||
std::vector<BattleHex> blocked = obstacles[b].getBlocked();
|
BOOST_FOREACH(BattleHex hex, obstacle->getBlockedTiles())
|
||||||
for(ui32 c=0; c<blocked.size(); ++c)
|
|
||||||
{
|
{
|
||||||
if(blocked[c] >=0 && blocked[c] < GameConstants::BFIELD_SIZE)
|
assert(hex.isValid());
|
||||||
accessibility[blocked[c]] = false;
|
accessibility[hex] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +228,7 @@ bool BattleInfo::isAccessible(BattleHex hex, bool * accessibility, bool twoHex,
|
|||||||
|
|
||||||
void BattleInfo::makeBFS(BattleHex start, bool *accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const //both pointers must point to the at least 187-elements int arrays
|
void BattleInfo::makeBFS(BattleHex start, bool *accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const //both pointers must point to the at least 187-elements int arrays
|
||||||
{
|
{
|
||||||
std::set<BattleHex> quicksands = getQuicksands(!attackerOwned);
|
std::set<BattleHex> quicksands = getStoppers(!attackerOwned);
|
||||||
|
|
||||||
//inits
|
//inits
|
||||||
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
|
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
|
||||||
@ -761,10 +760,11 @@ void BattleInfo::calculateCasualties( std::map<ui32,si32> *casualties ) const
|
|||||||
|
|
||||||
std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, BattleHex destinationTile )
|
std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, BattleHex destinationTile )
|
||||||
{
|
{
|
||||||
std::set<ui16> attackedHexes = s->rangeInHexes(destinationTile, skillLevel);
|
|
||||||
std::set<CStack*> attackedCres; /*std::set to exclude multiple occurrences of two hex creatures*/
|
std::set<CStack*> attackedCres; /*std::set to exclude multiple occurrences of two hex creatures*/
|
||||||
|
|
||||||
bool onlyAlive = s->id != 38 && s->id != 39; //when casting resurrection or animate dead we should be allow to select dead stack
|
const ui8 attackerSide = sides[1] == attackerOwner;
|
||||||
|
const auto attackedHexes = s->rangeInHexes(destinationTile, skillLevel, attackerSide);
|
||||||
|
const bool onlyAlive = s->id != 38 && s->id != 39; //when casting resurrection or animate dead we should be allow to select dead stack
|
||||||
|
|
||||||
if(s->id == Spells::DEATH_RIPPLE || s->id == Spells::DESTROY_UNDEAD || s->id == Spells::ARMAGEDDON)
|
if(s->id == Spells::DEATH_RIPPLE || s->id == Spells::DESTROY_UNDEAD || s->id == Spells::ARMAGEDDON)
|
||||||
{
|
{
|
||||||
@ -782,9 +782,9 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, int skillLe
|
|||||||
}
|
}
|
||||||
else if (s->range[skillLevel].size() > 1) //custom many-hex range
|
else if (s->range[skillLevel].size() > 1) //custom many-hex range
|
||||||
{
|
{
|
||||||
for(std::set<ui16>::iterator it = attackedHexes.begin(); it != attackedHexes.end(); ++it)
|
BOOST_FOREACH(BattleHex hex, attackedHexes)
|
||||||
{
|
{
|
||||||
CStack * st = getStackT(*it, onlyAlive);
|
CStack * st = getStackT(hex, onlyAlive);
|
||||||
if(st)
|
if(st)
|
||||||
{
|
{
|
||||||
if (s->id == 76) //Death Cloud //TODO: fireball and fire immunity
|
if (s->id == 76) //Death Cloud //TODO: fireball and fire immunity
|
||||||
@ -830,9 +830,9 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, int skillLe
|
|||||||
}
|
}
|
||||||
else //custom range from attackedHexes
|
else //custom range from attackedHexes
|
||||||
{
|
{
|
||||||
for(std::set<ui16>::iterator it = attackedHexes.begin(); it != attackedHexes.end(); ++it)
|
BOOST_FOREACH(BattleHex hex, attackedHexes)
|
||||||
{
|
{
|
||||||
CStack * st = getStackT(*it, onlyAlive);
|
CStack * st = getStackT(hex, onlyAlive);
|
||||||
if(st)
|
if(st)
|
||||||
attackedCres.insert(st);
|
attackedCres.insert(st);
|
||||||
}
|
}
|
||||||
@ -1594,7 +1594,7 @@ struct RangeGenerator
|
|||||||
boost::function<int()> myRand;
|
boost::function<int()> myRand;
|
||||||
};
|
};
|
||||||
|
|
||||||
BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town )
|
BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town )
|
||||||
{
|
{
|
||||||
CMP_stack cmpst;
|
CMP_stack cmpst;
|
||||||
BattleInfo *curB = new BattleInfo;
|
BattleInfo *curB = new BattleInfo;
|
||||||
@ -1607,7 +1607,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
std::vector<CStack*> & stacks = (curB->stacks);
|
std::vector<CStack*> & stacks = (curB->stacks);
|
||||||
|
|
||||||
curB->tile = tile;
|
curB->tile = tile;
|
||||||
curB->battlefieldType = terType;
|
curB->battlefieldType = battlefieldType;
|
||||||
curB->belligerents[0] = const_cast<CArmedInstance*>(armies[0]);
|
curB->belligerents[0] = const_cast<CArmedInstance*>(armies[0]);
|
||||||
curB->belligerents[1] = const_cast<CArmedInstance*>(armies[1]);
|
curB->belligerents[1] = const_cast<CArmedInstance*>(armies[1]);
|
||||||
curB->heroes[0] = const_cast<CGHeroInstance*>(heroes[0]);
|
curB->heroes[0] = const_cast<CGHeroInstance*>(heroes[0]);
|
||||||
@ -1620,11 +1620,13 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
{
|
{
|
||||||
curB->town = town;
|
curB->town = town;
|
||||||
curB->siege = town->fortLevel();
|
curB->siege = town->fortLevel();
|
||||||
|
curB->terrainType = VLC->heroh->nativeTerrains[town->town->typeID];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
curB->town = NULL;
|
curB->town = NULL;
|
||||||
curB->siege = 0;
|
curB->siege = 0;
|
||||||
|
curB->terrainType = terrain;
|
||||||
}
|
}
|
||||||
|
|
||||||
//reading battleStartpos
|
//reading battleStartpos
|
||||||
@ -1770,6 +1772,13 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), false, 255, -3);
|
stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), false, 255, -3);
|
||||||
stacks.push_back(stack);
|
stacks.push_back(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//moat
|
||||||
|
auto moat = make_shared<MoatObstacle>();
|
||||||
|
moat->ID = curB->town->subID;
|
||||||
|
moat->obstacleType = CObstacleInstance::MOAT;
|
||||||
|
moat->uniqueID = curB->obstacles.size();
|
||||||
|
curB->obstacles.push_back(moat);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
|
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
|
||||||
@ -1793,17 +1802,17 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
r.srand(tile);
|
r.srand(tile);
|
||||||
r.rand(1,8); //battle sound ID to play... can't do anything with it here
|
r.rand(1,8); //battle sound ID to play... can't do anything with it here
|
||||||
int tilesToBlock = r.rand(5,12);
|
int tilesToBlock = r.rand(5,12);
|
||||||
const int specialBattlefield = battlefieldTypeToBI(terType);
|
const int specialBattlefield = battlefieldTypeToBI(battlefieldType);
|
||||||
|
|
||||||
std::vector<BattleHex> blockedTiles;
|
std::vector<BattleHex> blockedTiles;
|
||||||
|
|
||||||
auto appropriateAbsoluteObstacle = [&](int id)
|
auto appropriateAbsoluteObstacle = [&](int id)
|
||||||
{
|
{
|
||||||
return VLC->heroh->absoluteObstacles[id].isAppropriate(terrain, specialBattlefield);
|
return VLC->heroh->absoluteObstacles[id].isAppropriate(curB->terrainType, specialBattlefield);
|
||||||
};
|
};
|
||||||
auto appropriateUsualObstacle = [&](int id) -> bool
|
auto appropriateUsualObstacle = [&](int id) -> bool
|
||||||
{
|
{
|
||||||
return VLC->heroh->obstacles[id].isAppropriate(terrain, specialBattlefield);
|
return VLC->heroh->obstacles[id].isAppropriate(curB->terrainType, specialBattlefield);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(r.rand(1,100) <= 40) //put cliff-like obstacle
|
if(r.rand(1,100) <= 40) //put cliff-like obstacle
|
||||||
@ -1812,15 +1821,15 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CObstacleInstance coi;
|
auto obstPtr = make_shared<CObstacleInstance>();
|
||||||
coi.obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
|
obstPtr->obstacleType = CObstacleInstance::ABSOLUTE_OBSTACLE;
|
||||||
coi.ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
|
obstPtr->ID = obidgen.getSuchNumber(appropriateAbsoluteObstacle);
|
||||||
coi.uniqueID = curB->obstacles.size();
|
obstPtr->uniqueID = curB->obstacles.size();
|
||||||
curB->obstacles.push_back(coi);
|
curB->obstacles.push_back(obstPtr);
|
||||||
|
|
||||||
BOOST_FOREACH(BattleHex blocked, coi.getBlocked())
|
BOOST_FOREACH(BattleHex blocked, obstPtr->getBlockedTiles())
|
||||||
blockedTiles.push_back(blocked);
|
blockedTiles.push_back(blocked);
|
||||||
tilesToBlock -= VLC->heroh->absoluteObstacles[coi.ID].blockedTiles.size() / 2;
|
tilesToBlock -= VLC->heroh->absoluteObstacles[obstPtr->ID].blockedTiles.size() / 2;
|
||||||
}
|
}
|
||||||
catch(RangeGenerator::ExhaustedPossibilities &)
|
catch(RangeGenerator::ExhaustedPossibilities &)
|
||||||
{
|
{
|
||||||
@ -1861,13 +1870,13 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
|
|
||||||
RangeGenerator posgenerator(18, 168, ourRand);
|
RangeGenerator posgenerator(18, 168, ourRand);
|
||||||
|
|
||||||
CObstacleInstance oi;
|
auto obstPtr = make_shared<CObstacleInstance>();
|
||||||
oi.ID = obid;
|
obstPtr->ID = obid;
|
||||||
oi.pos = posgenerator.getSuchNumber(validPosition);
|
obstPtr->pos = posgenerator.getSuchNumber(validPosition);
|
||||||
oi.uniqueID = curB->obstacles.size();
|
obstPtr->uniqueID = curB->obstacles.size();
|
||||||
curB->obstacles.push_back(oi);
|
curB->obstacles.push_back(obstPtr);
|
||||||
|
|
||||||
BOOST_FOREACH(BattleHex blocked, oi.getBlocked())
|
BOOST_FOREACH(BattleHex blocked, obstPtr->getBlockedTiles())
|
||||||
blockedTiles.push_back(blocked);
|
blockedTiles.push_back(blocked);
|
||||||
tilesToBlock -= obi.blockedTiles.size();
|
tilesToBlock -= obi.blockedTiles.size();
|
||||||
}
|
}
|
||||||
@ -1883,7 +1892,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
|
|
||||||
//giving terrain overalay premies
|
//giving terrain overalay premies
|
||||||
int bonusSubtype = -1;
|
int bonusSubtype = -1;
|
||||||
switch(terType)
|
switch(battlefieldType)
|
||||||
{
|
{
|
||||||
case 9: //magic plains
|
case 9: //magic plains
|
||||||
{
|
{
|
||||||
@ -1941,10 +1950,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
|
|||||||
//overlay premies given
|
//overlay premies given
|
||||||
|
|
||||||
//native terrain bonuses
|
//native terrain bonuses
|
||||||
if(town) //during siege always take premies for native terrain of faction
|
auto nativeTerrain = make_shared<CreatureNativeTerrainLimiter>(curB->terrainType);
|
||||||
terrain = VLC->heroh->nativeTerrains[town->town->typeID];
|
|
||||||
|
|
||||||
auto nativeTerrain = make_shared<CreatureNativeTerrainLimiter>(terrain);
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||||
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||||
@ -2133,8 +2139,16 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleCanCastThisSpellHere( int
|
|||||||
if(moreGeneralProblem != ESpellCastProblem::OK)
|
if(moreGeneralProblem != ESpellCastProblem::OK)
|
||||||
return moreGeneralProblem;
|
return moreGeneralProblem;
|
||||||
|
|
||||||
if(spell->getTargetType() == CSpell::OBSTACLE && !isObstacleOnTile(dest))
|
if(spell->getTargetType() == CSpell::OBSTACLE)
|
||||||
|
{
|
||||||
|
//isObstacleOnTile(dest)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//TODO
|
||||||
|
//assert that it's remove obstacle
|
||||||
|
//rules whether we can remove spell-created obstacle
|
||||||
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//get dead stack if we cast resurrection or animate dead
|
//get dead stack if we cast resurrection or animate dead
|
||||||
@ -2547,16 +2561,13 @@ int BattleInfo::getIdForNewStack() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BattleInfo::isObstacleOnTile(BattleHex tile) const
|
shared_ptr<CObstacleInstance> BattleInfo::getObstacleOnTile(BattleHex tile) const
|
||||||
{
|
{
|
||||||
std::set<BattleHex> coveredHexes;
|
BOOST_FOREACH(auto &obs, obstacles)
|
||||||
BOOST_FOREACH(const CObstacleInstance &obs, obstacles)
|
if(vstd::contains(obs->getAffectedTiles(), tile))
|
||||||
{
|
return obs;
|
||||||
std::vector<BattleHex> blocked = obs.getBlocked();
|
|
||||||
for(size_t w = 0; w < blocked.size(); ++w)
|
return NULL;
|
||||||
coveredHexes.insert(blocked[w]);
|
|
||||||
}
|
|
||||||
return vstd::contains(coveredHexes, tile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CStack * BattleInfo::getStackIf(boost::function<bool(const CStack*)> pred) const
|
const CStack * BattleInfo::getStackIf(boost::function<bool(const CStack*)> pred) const
|
||||||
@ -2582,20 +2593,35 @@ int BattleInfo::battlefieldTypeToBI(int bfieldType)
|
|||||||
return BattlefieldBI::NONE;
|
return BattlefieldBI::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<BattleHex> BattleInfo::getQuicksands(bool whichSidePerspective) const
|
std::set<BattleHex> BattleInfo::getStoppers(bool whichSidePerspective) const
|
||||||
{
|
{
|
||||||
std::set<BattleHex> ret;
|
std::set<BattleHex> ret;
|
||||||
BOOST_FOREACH(const CObstacleInstance &oi, obstacles)
|
BOOST_FOREACH(auto &oi, obstacles)
|
||||||
{
|
{
|
||||||
if(oi.obstacleType == CObstacleInstance::QUICKSAND
|
if(isObstacleVisibleForSide(*oi, whichSidePerspective))
|
||||||
&& oi.visibleForSide(whichSidePerspective)) //quicksands are visible to the caster or if owned unit stepped into that partcular patch
|
|
||||||
{
|
{
|
||||||
range::copy(oi.getAffectedTiles(), std::inserter(ret, ret.begin()));
|
range::copy(oi->getStoppingTile(), std::inserter(ret, ret.begin()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BattleInfo::hasNativeStack(ui8 side) const
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(const CStack *s, stacks)
|
||||||
|
{
|
||||||
|
if(s->attackerOwned == !side && s->getCreature()->isItNativeTerrain(terrainType))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BattleInfo::isObstacleVisibleForSide(const CObstacleInstance & coi, ui8 side) const
|
||||||
|
{
|
||||||
|
return coi.visibleForSide(side, hasNativeStack(side));
|
||||||
|
}
|
||||||
|
|
||||||
CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
|
CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
|
||||||
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
|
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
|
||||||
counterAttacks(1)
|
counterAttacks(1)
|
||||||
|
@ -59,12 +59,14 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
|||||||
CGHeroInstance* heroes[2];
|
CGHeroInstance* heroes[2];
|
||||||
CArmedInstance *belligerents[2]; //may be same as heroes
|
CArmedInstance *belligerents[2]; //may be same as heroes
|
||||||
std::vector<CStack*> stacks;
|
std::vector<CStack*> stacks;
|
||||||
std::vector<CObstacleInstance> obstacles;
|
std::vector<shared_ptr<CObstacleInstance> > obstacles;
|
||||||
ui8 castSpells[2]; //how many spells each side has cast this turn [0] - attacker, [1] - defender
|
ui8 castSpells[2]; //how many spells each side has cast this turn [0] - attacker, [1] - defender
|
||||||
std::vector<const CSpell *> usedSpellsHistory[2]; //each time hero casts spell, it's inserted here -> eagle eye skill
|
std::vector<const CSpell *> usedSpellsHistory[2]; //each time hero casts spell, it's inserted here -> eagle eye skill
|
||||||
si16 enchanterCounter[2]; //tends to pass through 0, so sign is needed
|
si16 enchanterCounter[2]; //tends to pass through 0, so sign is needed
|
||||||
SiegeInfo si;
|
SiegeInfo si;
|
||||||
si32 battlefieldType;
|
|
||||||
|
si32 battlefieldType; //like !!BA:B
|
||||||
|
ui8 terrainType; //used for some stack nativity checks (not the bonus limiters though that have their own copy)
|
||||||
|
|
||||||
ui8 tacticsSide; //which side is requested to play tactics phase
|
ui8 tacticsSide; //which side is requested to play tactics phase
|
||||||
ui8 tacticDistance; //how many hexes we can go forward (1 = only hexes adjacent to margin line)
|
ui8 tacticDistance; //how many hexes we can go forward (1 = only hexes adjacent to margin line)
|
||||||
@ -72,7 +74,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
|||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & sides & round & activeStack & selectedStack & siege & town & tile & stacks & belligerents & obstacles
|
h & sides & round & activeStack & selectedStack & siege & town & tile & stacks & belligerents & obstacles
|
||||||
& castSpells & si & battlefieldType;
|
& castSpells & si & battlefieldType & terrainType;
|
||||||
h & heroes;
|
h & heroes;
|
||||||
h & usedSpellsHistory & enchanterCounter;
|
h & usedSpellsHistory & enchanterCounter;
|
||||||
h & tacticsSide & tacticDistance;
|
h & tacticsSide & tacticDistance;
|
||||||
@ -99,9 +101,9 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
|||||||
std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
|
std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL, bool forPassingBy = false) const; //returns vector of accessible tiles (taking into account the creature range)
|
||||||
|
|
||||||
bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
|
bool isObstacleVisibleForSide(const CObstacleInstance &obstacle, ui8 side) const;
|
||||||
bool isObstacleOnTile(BattleHex tile) const;
|
shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
||||||
bool isStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack
|
bool isStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack
|
||||||
std::set<BattleHex> getQuicksands(bool whichSidePerspective) const;
|
std::set<BattleHex> getStoppers(bool whichSidePerspective) const;
|
||||||
|
|
||||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
|
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||||
TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, TQuantity attackerCount, TQuantity defenderCount, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, TQuantity attackerCount, TQuantity defenderCount, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
||||||
@ -151,9 +153,10 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
|
|||||||
void localInit();
|
void localInit();
|
||||||
|
|
||||||
void localInitStack(CStack * s);
|
void localInitStack(CStack * s);
|
||||||
static BattleInfo * setupBattle( int3 tile, int terrain, int terType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town );
|
static BattleInfo * setupBattle( int3 tile, int terrain, int battlefieldType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town );
|
||||||
bool isInTacticRange( BattleHex dest ) const;
|
bool isInTacticRange( BattleHex dest ) const;
|
||||||
int getSurrenderingCost(int player) const;
|
int getSurrenderingCost(int player) const;
|
||||||
|
bool hasNativeStack(ui8 side) const;
|
||||||
|
|
||||||
int theOtherPlayer(int player) const;
|
int theOtherPlayer(int player) const;
|
||||||
ui8 whatSide(int player) const;
|
ui8 whatSide(int player) const;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
#include "../lib/CGameState.h"
|
#include "../lib/CGameState.h"
|
||||||
#include "../lib/JsonNode.h"
|
#include "../lib/JsonNode.h"
|
||||||
|
#include "CHeroHandler.h"
|
||||||
|
|
||||||
using namespace boost::assign;
|
using namespace boost::assign;
|
||||||
extern CLodHandler * bitmaph;
|
extern CLodHandler * bitmaph;
|
||||||
@ -144,6 +145,15 @@ std::string CCreature::nodeName() const
|
|||||||
return "\"" + namePl + "\"";
|
return "\"" + namePl + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CCreature::isItNativeTerrain(int terrain) const
|
||||||
|
{
|
||||||
|
if(!vstd::iswithin(faction, 0, 9))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//not good handler dependency
|
||||||
|
return VLC->heroh->nativeTerrains[faction] == terrain;
|
||||||
|
}
|
||||||
|
|
||||||
int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
|
int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
|
||||||
{
|
{
|
||||||
befi=i;
|
befi=i;
|
||||||
|
@ -46,6 +46,7 @@ public:
|
|||||||
int troopCountLocationOffset, attackClimaxFrame;
|
int troopCountLocationOffset, attackClimaxFrame;
|
||||||
///end of anim info
|
///end of anim info
|
||||||
|
|
||||||
|
bool isItNativeTerrain(int terrain) const;
|
||||||
bool isDoubleWide() const; //returns true if unit is double wide on battlefield
|
bool isDoubleWide() const; //returns true if unit is double wide on battlefield
|
||||||
bool isFlying() const; //returns true if it is a flying unit
|
bool isFlying() const; //returns true if it is a flying unit
|
||||||
bool isShooting() const; //returns true if unit can shoot
|
bool isShooting() const; //returns true if unit can shoot
|
||||||
|
@ -119,6 +119,7 @@ void CHeroHandler::loadObstacles()
|
|||||||
const JsonNode config(GameConstants::DATA_DIR + "/config/obstacles.json");
|
const JsonNode config(GameConstants::DATA_DIR + "/config/obstacles.json");
|
||||||
loadObstacles(config["obstacles"], false, obstacles);
|
loadObstacles(config["obstacles"], false, obstacles);
|
||||||
loadObstacles(config["absoluteObstacles"], true, absoluteObstacles);
|
loadObstacles(config["absoluteObstacles"], true, absoluteObstacles);
|
||||||
|
//loadObstacles(config["moats"], true, moats);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHeroHandler::loadPuzzleInfo()
|
void CHeroHandler::loadPuzzleInfo()
|
||||||
|
@ -141,6 +141,7 @@ public:
|
|||||||
|
|
||||||
std::map<int, CObstacleInfo> obstacles; //info about obstacles that may be placed on battlefield
|
std::map<int, CObstacleInfo> obstacles; //info about obstacles that may be placed on battlefield
|
||||||
std::map<int, CObstacleInfo> absoluteObstacles; //info about obstacles that may be placed on battlefield
|
std::map<int, CObstacleInfo> absoluteObstacles; //info about obstacles that may be placed on battlefield
|
||||||
|
|
||||||
std::vector<int> nativeTerrains; //info about native terrains of different factions
|
std::vector<int> nativeTerrains; //info about native terrains of different factions
|
||||||
|
|
||||||
void loadObstacles(); //loads info about obstacles
|
void loadObstacles(); //loads info about obstacles
|
||||||
@ -160,7 +161,8 @@ public:
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & heroClasses & heroes & expPerLevel & ballistics & obstacles & absoluteObstacles & nativeTerrains & puzzleInfo;
|
h & heroClasses & heroes & expPerLevel & ballistics & nativeTerrains & puzzleInfo;
|
||||||
|
h & obstacles & absoluteObstacles;
|
||||||
if(!h.saving)
|
if(!h.saving)
|
||||||
{
|
{
|
||||||
//restore class pointers
|
//restore class pointers
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
#include "CObstacleInstance.h"
|
#include "CObstacleInstance.h"
|
||||||
#include "CHeroHandler.h"
|
#include "CHeroHandler.h"
|
||||||
#include "VCMI_Lib.h"
|
#include "VCMI_Lib.h"
|
||||||
|
#include "CSpellHandler.h"
|
||||||
|
|
||||||
CObstacleInstance::CObstacleInstance()
|
CObstacleInstance::CObstacleInstance()
|
||||||
{
|
{
|
||||||
obstacleType = USUAL;
|
obstacleType = USUAL;
|
||||||
casterSide = -1;
|
}
|
||||||
spellLevel = -1;
|
|
||||||
turnsRemaining = -1;
|
CObstacleInstance::~CObstacleInstance()
|
||||||
visibleForAnotherSide = -1;
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CObstacleInfo & CObstacleInstance::getInfo() const
|
const CObstacleInfo & CObstacleInstance::getInfo() const
|
||||||
@ -20,22 +22,25 @@ const CObstacleInfo & CObstacleInstance::getInfo() const
|
|||||||
return VLC->heroh->absoluteObstacles[ID];
|
return VLC->heroh->absoluteObstacles[ID];
|
||||||
case USUAL:
|
case USUAL:
|
||||||
return VLC->heroh->obstacles[ID];
|
return VLC->heroh->obstacles[ID];
|
||||||
|
case MOAT:
|
||||||
|
assert(0);
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BattleHex> CObstacleInstance::getBlocked() const
|
std::vector<BattleHex> CObstacleInstance::getBlockedTiles() const
|
||||||
{
|
{
|
||||||
switch(obstacleType)
|
if(blocksTiles())
|
||||||
{
|
return getAffectedTiles();
|
||||||
case ABSOLUTE_OBSTACLE:
|
return std::vector<BattleHex>();
|
||||||
case USUAL:
|
|
||||||
return getInfo().getBlocked(pos);
|
|
||||||
//TODO Force Field
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<BattleHex> CObstacleInstance::getStoppingTile() const
|
||||||
|
{
|
||||||
|
if(stopsMovement())
|
||||||
|
return getAffectedTiles();
|
||||||
return std::vector<BattleHex>();
|
return std::vector<BattleHex>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,31 +48,91 @@ std::vector<BattleHex> CObstacleInstance::getAffectedTiles() const
|
|||||||
{
|
{
|
||||||
switch(obstacleType)
|
switch(obstacleType)
|
||||||
{
|
{
|
||||||
case QUICKSAND:
|
case ABSOLUTE_OBSTACLE:
|
||||||
case LAND_MINE:
|
case USUAL:
|
||||||
return std::vector<BattleHex>(1, pos);
|
return getInfo().getBlocked(pos);
|
||||||
//TODO Fire Wall
|
default:
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
return std::vector<BattleHex>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CObstacleInstance::spellGenerated() const
|
// bool CObstacleInstance::spellGenerated() const
|
||||||
|
// {
|
||||||
|
// if(obstacleType == USUAL || obstacleType == ABSOLUTE_OBSTACLE)
|
||||||
|
// return false;
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
bool CObstacleInstance::visibleForSide(ui8 side, bool hasNativeStack) const
|
||||||
{
|
{
|
||||||
if(obstacleType == USUAL || obstacleType == ABSOLUTE_OBSTACLE)
|
//by default obstacle is visible for everyone
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CObstacleInstance::visibleForSide(ui8 side) const
|
bool CObstacleInstance::stopsMovement() const
|
||||||
|
{
|
||||||
|
return obstacleType == QUICKSAND || obstacleType == MOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CObstacleInstance::blocksTiles() const
|
||||||
|
{
|
||||||
|
return obstacleType == USUAL || obstacleType == ABSOLUTE_OBSTACLE || obstacleType == FORCE_FIELD;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpellCreatedObstacle::SpellCreatedObstacle()
|
||||||
|
{
|
||||||
|
casterSide = -1;
|
||||||
|
spellLevel = -1;
|
||||||
|
casterSpellPower = -1;
|
||||||
|
turnsRemaining = -1;
|
||||||
|
visibleForAnotherSide = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpellCreatedObstacle::visibleForSide(ui8 side, bool hasNativeStack) const
|
||||||
{
|
{
|
||||||
switch(obstacleType)
|
switch(obstacleType)
|
||||||
{
|
{
|
||||||
case ABSOLUTE_OBSTACLE:
|
case FIRE_WALL:
|
||||||
case USUAL:
|
case FORCE_FIELD:
|
||||||
|
//these are always visible
|
||||||
return true;
|
return true;
|
||||||
default:
|
case QUICKSAND:
|
||||||
|
case LAND_MINE:
|
||||||
//we hide mines and not discovered quicksands
|
//we hide mines and not discovered quicksands
|
||||||
return casterSide == side || visibleForAnotherSide;
|
//quicksands are visible to the caster or if owned unit stepped into that particular patch
|
||||||
|
//additionally if side has a native unit, mines/quicksands will be visible
|
||||||
|
return casterSide == side || visibleForAnotherSide || hasNativeStack;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<BattleHex> SpellCreatedObstacle::getAffectedTiles() const
|
||||||
|
{
|
||||||
|
switch(obstacleType)
|
||||||
|
{
|
||||||
|
case QUICKSAND:
|
||||||
|
case LAND_MINE:
|
||||||
|
case FIRE_WALL:
|
||||||
|
return std::vector<BattleHex>(1, pos);
|
||||||
|
case FORCE_FIELD:
|
||||||
|
return VLC->spellh->spells[Spells::FORCE_FIELD]->rangeInHexes(pos, spellLevel, casterSide);
|
||||||
|
//TODO Fire Wall
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellCreatedObstacle::battleTurnPassed()
|
||||||
|
{
|
||||||
|
if(turnsRemaining > 0)
|
||||||
|
turnsRemaining--;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<BattleHex> MoatObstacle::getAffectedTiles() const
|
||||||
|
{
|
||||||
|
//rrr... need initializer lists
|
||||||
|
static const BattleHex moatHexes[] = {11, 28, 44, 61, 77, 111, 129, 146, 164, 181};
|
||||||
|
return std::vector<BattleHex>(std::begin(moatHexes), std::end(moatHexes));
|
||||||
|
}
|
@ -5,35 +5,68 @@ struct CObstacleInfo;
|
|||||||
|
|
||||||
struct DLL_LINKAGE CObstacleInstance
|
struct DLL_LINKAGE CObstacleInstance
|
||||||
{
|
{
|
||||||
|
BattleHex pos; //position on battlefield, typically left bottom corner
|
||||||
|
ui8 obstacleType; //if true, then position is meaningless
|
||||||
si32 uniqueID;
|
si32 uniqueID;
|
||||||
si32 ID; //ID of obstacle (defines type of it)
|
si32 ID; //ID of obstacle (defines type of it)
|
||||||
BattleHex pos; //position on battlefield
|
|
||||||
|
|
||||||
enum EObstacleType
|
enum EObstacleType
|
||||||
{
|
{
|
||||||
//ABSOLUTE needs an underscore because it's a Win
|
//ABSOLUTE needs an underscore because it's a Win
|
||||||
USUAL, ABSOLUTE_OBSTACLE, QUICKSAND, LAND_MINE, FORCE_FIELD, FIRE_WALL
|
USUAL, ABSOLUTE_OBSTACLE, QUICKSAND, LAND_MINE, FORCE_FIELD, FIRE_WALL, MOAT
|
||||||
};
|
};
|
||||||
|
|
||||||
ui8 obstacleType; //if true, then position is meaningless
|
|
||||||
|
|
||||||
//used only for spell-created obtsacles
|
//used only for spell-created obstacles
|
||||||
si8 turnsRemaining;
|
|
||||||
si8 spellLevel;
|
|
||||||
si8 casterSide; //0 - obstacle created by attacker; 1 - by defender
|
|
||||||
si8 visibleForAnotherSide;
|
|
||||||
|
|
||||||
CObstacleInstance();
|
CObstacleInstance();
|
||||||
bool spellGenerated() const;
|
virtual ~CObstacleInstance();
|
||||||
const CObstacleInfo &getInfo() const; //allowed only when not generated by spell (usual or absolute)
|
|
||||||
std::vector<BattleHex> getBlocked() const;
|
|
||||||
std::vector<BattleHex> getAffectedTiles() const; //to be used with quicksands / fire walls /land mines
|
|
||||||
|
|
||||||
bool visibleForSide(ui8 side) const; //0 attacker
|
//bool spellGenerated() const;
|
||||||
|
const CObstacleInfo &getInfo() const; //allowed only when not generated by spell (usual or absolute)
|
||||||
|
|
||||||
|
std::vector<BattleHex> getBlockedTiles() const;
|
||||||
|
std::vector<BattleHex> getStoppingTile() const; //hexes that will stop stack move
|
||||||
|
|
||||||
|
//The two functions below describe how the obstacle affects affected tiles
|
||||||
|
//additional effects (like hurting stack or disappearing) are hardcoded for appropriate obstacleTypes
|
||||||
|
bool blocksTiles() const;
|
||||||
|
bool stopsMovement() const; //if unit stepping onto obstacle, can't continue movement (in general, doesn't checks for the side)
|
||||||
|
|
||||||
|
virtual std::vector<BattleHex> getAffectedTiles() const;
|
||||||
|
virtual bool visibleForSide(ui8 side, bool hasNativeStack) const; //0 attacker
|
||||||
|
|
||||||
|
virtual void battleTurnPassed(){};
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & ID & pos & obstacleType & uniqueID;
|
h & ID & pos & obstacleType & uniqueID;
|
||||||
h & turnsRemaining & spellLevel & casterSide & visibleForAnotherSide;
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DLL_LINKAGE MoatObstacle : CObstacleInstance
|
||||||
|
{
|
||||||
|
virtual std::vector<BattleHex> getAffectedTiles() const OVERRIDE; //for special effects (not blocking)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
|
||||||
|
{
|
||||||
|
si8 turnsRemaining;
|
||||||
|
si8 casterSpellPower;
|
||||||
|
si8 spellLevel;
|
||||||
|
si8 casterSide; //0 - obstacle created by attacker; 1 - by defender
|
||||||
|
si8 visibleForAnotherSide;
|
||||||
|
|
||||||
|
SpellCreatedObstacle();
|
||||||
|
|
||||||
|
virtual std::vector<BattleHex> getAffectedTiles() const OVERRIDE; //for special effects (not blocking)
|
||||||
|
virtual bool visibleForSide(ui8 side, bool hasNativeStack) const OVERRIDE; //0 attacker
|
||||||
|
|
||||||
|
virtual void battleTurnPassed() OVERRIDE;
|
||||||
|
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{
|
||||||
|
h & static_cast<CObstacleInstance&>(*this);
|
||||||
|
h & turnsRemaining & casterSpellPower & spellLevel & casterSide & visibleForAnotherSide;
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -7,6 +7,7 @@
|
|||||||
#include "../lib/JsonNode.h"
|
#include "../lib/JsonNode.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include "GameConstants.h"
|
#include "GameConstants.h"
|
||||||
|
#include "BattleHex.h"
|
||||||
|
|
||||||
extern CLodHandler *bitmaph;
|
extern CLodHandler *bitmaph;
|
||||||
|
|
||||||
@ -127,9 +128,44 @@ CSpellHandler::CSpellHandler()
|
|||||||
{
|
{
|
||||||
VLC->spellh = this;
|
VLC->spellh = this;
|
||||||
}
|
}
|
||||||
std::set<ui16> CSpell::rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const
|
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
|
||||||
{
|
{
|
||||||
std::set<ui16> ret;
|
std::vector<BattleHex> ret;
|
||||||
|
|
||||||
|
if(id == Spells::FIRE_WALL || id == Spells::FORCE_FIELD)
|
||||||
|
{
|
||||||
|
//Special case - shape of obstacle depends on caster's side
|
||||||
|
//TODO make it possible through spell_info config
|
||||||
|
|
||||||
|
BattleHex::EDir firstStep, secondStep;
|
||||||
|
if(side)
|
||||||
|
{
|
||||||
|
firstStep = BattleHex::TOP_LEFT;
|
||||||
|
secondStep = BattleHex::TOP_RIGHT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
firstStep = BattleHex::TOP_RIGHT;
|
||||||
|
secondStep = BattleHex::TOP_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Adds hex to the ret if it's valid. Otherwise sets output arg flag if given.
|
||||||
|
auto addIfValid = [&](BattleHex hex)
|
||||||
|
{
|
||||||
|
if(hex.isValid())
|
||||||
|
ret.push_back(hex);
|
||||||
|
else if(outDroppedHexes)
|
||||||
|
*outDroppedHexes = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ret.push_back(centralHex);
|
||||||
|
addIfValid(centralHex.moveInDir(firstStep, false));
|
||||||
|
if(schoolLvl >= 2) //advanced versions of fire wall / force field cotnains of 3 hexes
|
||||||
|
addIfValid(centralHex.moveInDir(firstStep, false).moveInDir(secondStep, false));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string rng = range[schoolLvl] + ','; //copy + artificial comma for easier handling
|
std::string rng = range[schoolLvl] + ','; //copy + artificial comma for easier handling
|
||||||
|
|
||||||
@ -174,7 +210,7 @@ std::set<ui16> CSpell::rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) con
|
|||||||
//adding abtained hexes
|
//adding abtained hexes
|
||||||
for(std::set<ui16>::iterator it = curLayer.begin(); it != curLayer.end(); ++it)
|
for(std::set<ui16>::iterator it = curLayer.begin(); it != curLayer.end(); ++it)
|
||||||
{
|
{
|
||||||
ret.insert(*it);
|
ret.push_back(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -187,6 +223,8 @@ std::set<ui16> CSpell::rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//remove duplicates (TODO check if actually needed)
|
||||||
|
range::unique(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct BattleHex;
|
||||||
|
|
||||||
class DLL_LINKAGE CSpell
|
class DLL_LINKAGE CSpell
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -38,7 +40,7 @@ public:
|
|||||||
bool creatureAbility; //if true, only creatures can use this spell
|
bool creatureAbility; //if true, only creatures can use this spell
|
||||||
si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
|
si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
|
||||||
std::vector<std::string> range; //description of spell's range in SRSL by magic school level
|
std::vector<std::string> range; //description of spell's range in SRSL by magic school level
|
||||||
std::set<ui16> rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const; //convert range to specific hexes
|
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = NULL ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret)
|
||||||
si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
|
si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
|
||||||
ETargetType getTargetType() const;
|
ETargetType getTargetType() const;
|
||||||
|
|
||||||
|
@ -1300,7 +1300,7 @@ CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter()
|
|||||||
int CreatureNativeTerrainLimiter::limit(const BonusLimitationContext &context) const
|
int CreatureNativeTerrainLimiter::limit(const BonusLimitationContext &context) const
|
||||||
{
|
{
|
||||||
const CCreature *c = retrieveCreature(&context.node);
|
const CCreature *c = retrieveCreature(&context.node);
|
||||||
return !c || !vstd::iswithin(c->faction, 0, 9) || VLC->heroh->nativeTerrains[c->faction] != terrainType; //drop bonus for non-creatures or non-native residents
|
return !c || !c->isItNativeTerrain(terrainType); //drop bonus for non-creatures or non-native residents
|
||||||
//TODO neutral creatues
|
//TODO neutral creatues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,15 +205,15 @@ int CBattleInfoCallback::battleGetBattlefieldType()
|
|||||||
// return -1;
|
// return -1;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
std::vector<CObstacleInstance> CBattleInfoCallback::battleGetAllObstacles()
|
std::vector<shared_ptr<const CObstacleInstance> > CBattleInfoCallback::battleGetAllObstacles()
|
||||||
{
|
{
|
||||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
std::vector<CObstacleInstance> ret;
|
std::vector<shared_ptr<const CObstacleInstance> > ret;
|
||||||
if(gs->curB)
|
if(gs->curB)
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(const CObstacleInstance &oi, gs->curB->obstacles)
|
BOOST_FOREACH(auto oi, gs->curB->obstacles)
|
||||||
{
|
{
|
||||||
if(player < 0 || oi.visibleForSide(battleGetMySide()))
|
if(player < 0 || gs->curB->isObstacleVisibleForSide(*oi, battleGetMySide()))
|
||||||
ret.push_back(oi);
|
ret.push_back(oi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -409,27 +409,48 @@ const CGHeroInstance * CBattleInfoCallback::battleGetFightingHero(ui8 side) cons
|
|||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
//TODO: this method should not exist... you shouldn't be able to get info about enemy hero
|
||||||
return gs->curB->heroes[side];
|
return gs->curB->heroes[side];
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<CObstacleInstance> CBattleInfoCallback::battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking /*= true*/)
|
shared_ptr<const CObstacleInstance> CBattleInfoCallback::battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking /*= true*/)
|
||||||
{
|
{
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
BOOST_FOREACH(const CObstacleInstance &obs, battleGetAllObstacles())
|
auto ptr = gs->curB->obstacles.front();
|
||||||
|
shared_ptr<const CObstacleInstance> nastala = ptr;
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_FOREACH(auto &obs, battleGetAllObstacles())
|
||||||
{
|
{
|
||||||
if(vstd::contains(obs.getBlocked(), tile)
|
if(vstd::contains(obs->getBlockedTiles(), tile)
|
||||||
|| (!onlyBlocking && vstd::contains(obs.getAffectedTiles(), tile)))
|
|| (!onlyBlocking && vstd::contains(obs->getAffectedTiles(), tile)))
|
||||||
{
|
{
|
||||||
return make_unique<CObstacleInstance>(obs);
|
return obs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CBattleInfoCallback::battleGetMoatDmg()
|
||||||
|
{
|
||||||
|
if(!gs->curB || !gs->curB->town)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//TODO move to config file
|
||||||
|
static const int dmgs[] = {70, 70, -1,
|
||||||
|
90, 70, 90,
|
||||||
|
70, 90, 70};
|
||||||
|
if(gs->curB->town->subID < ARRAY_COUNT(dmgs))
|
||||||
|
return dmgs[gs->curB->town->subID];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
CGameState *const CPrivilagedInfoCallback::gameState ()
|
CGameState *const CPrivilagedInfoCallback::gameState ()
|
||||||
{
|
{
|
||||||
return gs;
|
return gs;
|
||||||
|
@ -96,8 +96,8 @@ public:
|
|||||||
//battle
|
//battle
|
||||||
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||||
//int battleGetObstaclesAtTile(BattleHex tile); //returns bitfield
|
//int battleGetObstaclesAtTile(BattleHex tile); //returns bitfield
|
||||||
unique_ptr<CObstacleInstance> battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking = true);
|
shared_ptr<const CObstacleInstance> battleGetObstacleOnPos(BattleHex tile, bool onlyBlocking = true);
|
||||||
std::vector<CObstacleInstance> battleGetAllObstacles(); //returns all obstacles on the battlefield
|
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(); //returns all obstacles on the battlefield
|
||||||
const CStack * battleGetStackByID(int ID, bool onlyAlive = true); //returns stack info by given ID
|
const CStack * battleGetStackByID(int ID, bool onlyAlive = true); //returns stack info by given ID
|
||||||
const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true); //returns stack info by given pos
|
const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true); //returns stack info by given pos
|
||||||
BattleHex battleGetPos(int stack); //returns position (tile ID) of stack
|
BattleHex battleGetPos(int stack); //returns position (tile ID) of stack
|
||||||
@ -130,6 +130,7 @@ public:
|
|||||||
si8 battleCanTeleportTo(const CStack * stack, BattleHex destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
|
si8 battleCanTeleportTo(const CStack * stack, BattleHex destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
|
||||||
si8 battleGetTacticDist(); //returns tactic distance for calling player or 0 if player is not in tactic phase
|
si8 battleGetTacticDist(); //returns tactic distance for calling player or 0 if player is not in tactic phase
|
||||||
ui8 battleGetMySide(); //return side of player in battle (attacker/defender)
|
ui8 battleGetMySide(); //return side of player in battle (attacker/defender)
|
||||||
|
int battleGetMoatDmg(); //what dmg unit will suffer if ending turn in the moat
|
||||||
|
|
||||||
//convenience methods using the ones above
|
//convenience methods using the ones above
|
||||||
TStacks battleGetAllStacks() //returns all stacks, alive or dead or undead or mechanical :)
|
TStacks battleGetAllStacks() //returns all stacks, alive or dead or undead or mechanical :)
|
||||||
|
@ -1655,7 +1655,7 @@ struct BattleObstaclePlaced : public CPackForClient //3020
|
|||||||
DLL_LINKAGE void applyGs(CGameState *gs); //effect
|
DLL_LINKAGE void applyGs(CGameState *gs); //effect
|
||||||
void applyCl(CClient *cl); //play animations & stuff
|
void applyCl(CClient *cl); //play animations & stuff
|
||||||
|
|
||||||
CObstacleInstance obstacle;
|
shared_ptr<CObstacleInstance> obstacle;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
@ -963,6 +963,9 @@ DLL_LINKAGE void BattleNextRound::applyGs( CGameState *gs )
|
|||||||
// new turn effects
|
// new turn effects
|
||||||
s->battleTurnPassed();
|
s->battleTurnPassed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_FOREACH(auto &obst, gs->curB->obstacles)
|
||||||
|
obst->battleTurnPassed();
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void BattleSetActiveStack::applyGs( CGameState *gs )
|
DLL_LINKAGE void BattleSetActiveStack::applyGs( CGameState *gs )
|
||||||
@ -1061,13 +1064,15 @@ void BattleStackMoved::applyGs( CGameState *gs )
|
|||||||
BattleHex dest = tilesToMove.back();
|
BattleHex dest = tilesToMove.back();
|
||||||
|
|
||||||
//if unit ended movement on quicksands that were created by enemy, that quicksand patch becomes visible for owner
|
//if unit ended movement on quicksands that were created by enemy, that quicksand patch becomes visible for owner
|
||||||
BOOST_FOREACH(CObstacleInstance &oi, gs->curB->obstacles)
|
BOOST_FOREACH(auto &oi, gs->curB->obstacles)
|
||||||
{
|
{
|
||||||
if(oi.obstacleType == CObstacleInstance::QUICKSAND
|
if(oi->obstacleType == CObstacleInstance::QUICKSAND
|
||||||
&& vstd::contains(oi.getAffectedTiles(), tilesToMove.back())
|
&& vstd::contains(oi->getAffectedTiles(), tilesToMove.back()))
|
||||||
&& oi.casterSide != !s->attackerOwned)
|
|
||||||
{
|
{
|
||||||
oi.visibleForAnotherSide = true;
|
SpellCreatedObstacle *sands = dynamic_cast<SpellCreatedObstacle*>(oi.get());
|
||||||
|
assert(sands);
|
||||||
|
if(sands->casterSide != !s->attackerOwned)
|
||||||
|
sands->visibleForAnotherSide = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s->position = dest;
|
s->position = dest;
|
||||||
@ -1365,7 +1370,7 @@ DLL_LINKAGE void ObstaclesRemoved::applyGs( CGameState *gs )
|
|||||||
{
|
{
|
||||||
for(int i=0; i<gs->curB->obstacles.size(); ++i)
|
for(int i=0; i<gs->curB->obstacles.size(); ++i)
|
||||||
{
|
{
|
||||||
if(gs->curB->obstacles[i].uniqueID == *it) //remove this obstacle
|
if(gs->curB->obstacles[i]->uniqueID == *it) //remove this obstacle
|
||||||
{
|
{
|
||||||
gs->curB->obstacles.erase(gs->curB->obstacles.begin() + i);
|
gs->curB->obstacles.erase(gs->curB->obstacles.begin() + i);
|
||||||
break;
|
break;
|
||||||
|
@ -95,6 +95,11 @@ void registerTypes1(Serializer &s)
|
|||||||
s.template registerType<BattleInfo>();
|
s.template registerType<BattleInfo>();
|
||||||
s.template registerType<CArtifactInstance>();
|
s.template registerType<CArtifactInstance>();
|
||||||
s.template registerType<CCombinedArtifactInstance>();
|
s.template registerType<CCombinedArtifactInstance>();
|
||||||
|
|
||||||
|
s.template registerType<CObstacleInstance>();
|
||||||
|
s.template registerType<MoatObstacle>();
|
||||||
|
s.template registerType<SpellCreatedObstacle>();
|
||||||
|
|
||||||
//s.template registerType<CCreatureArtifactInstance>();
|
//s.template registerType<CCreatureArtifactInstance>();
|
||||||
//s.template registerType<ArtSlotInfo>();
|
//s.template registerType<ArtSlotInfo>();
|
||||||
//s.template registerType<ArtifactLocation>();
|
//s.template registerType<ArtifactLocation>();
|
||||||
|
@ -997,7 +997,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
|||||||
{
|
{
|
||||||
// send one package with the creature path information
|
// send one package with the creature path information
|
||||||
|
|
||||||
unique_ptr<CObstacleInstance> obstacle = NULL; //obstacle that interrupted movement
|
shared_ptr<const CObstacleInstance> obstacle = NULL; //obstacle that interrupted movement
|
||||||
std::vector<BattleHex> tiles;
|
std::vector<BattleHex> tiles;
|
||||||
int tilesToMove = std::max((int)(path.first.size() - creSpeed), 0);
|
int tilesToMove = std::max((int)(path.first.size() - creSpeed), 0);
|
||||||
int v = path.first.size()-1;
|
int v = path.first.size()-1;
|
||||||
@ -1008,18 +1008,16 @@ startWalking:
|
|||||||
BattleHex hex = path.first[v];
|
BattleHex hex = path.first[v];
|
||||||
tiles.push_back(hex);
|
tiles.push_back(hex);
|
||||||
|
|
||||||
//if there are quicksands, we stop
|
|
||||||
if(obstacle = battleGetObstacleOnPos(hex, false))
|
if(obstacle = battleGetObstacleOnPos(hex, false))
|
||||||
{
|
{
|
||||||
if(!obstacle->obstacleType == CObstacleInstance::LAND_MINE || obstacle->casterSide != !curStack->attackerOwned) //if it's mine, make boom only if enemy planted it
|
//we walked onto something, so we finalize this portion of stack movement check into obstacle
|
||||||
break;
|
break;
|
||||||
else
|
|
||||||
obstacle = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tiles.size() > 0)
|
if (tiles.size() > 0)
|
||||||
{
|
{
|
||||||
|
//commit movement
|
||||||
BattleStackMoved sm;
|
BattleStackMoved sm;
|
||||||
sm.stack = curStack->ID;
|
sm.stack = curStack->ID;
|
||||||
sm.distance = path.second;
|
sm.distance = path.second;
|
||||||
@ -1028,34 +1026,30 @@ startWalking:
|
|||||||
sendAndApply(&sm);
|
sendAndApply(&sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(obstacle && obstacle->obstacleType == CObstacleInstance::LAND_MINE)
|
//we don't handle obstacle at the destination tile -> it's handled separately in the if at the end
|
||||||
|
if(obstacle && curStack->position != dest)
|
||||||
{
|
{
|
||||||
//TODO make POOF and deal dmg
|
handleDamageFromObstacle(*obstacle, curStack);
|
||||||
|
|
||||||
BattleStackAttacked bsa;
|
|
||||||
bsa.flags |= BattleStackAttacked::EFFECT;
|
|
||||||
bsa.effect = 82;
|
|
||||||
bsa.damageAmount = 50; //TODO TODO TODO
|
|
||||||
bsa.stackAttacked = curStack->ID;
|
|
||||||
bsa.attackerID = -1;
|
|
||||||
curStack->prepareAttacked(bsa);
|
|
||||||
//sendAndApply(&bsa);
|
|
||||||
StacksInjured si;
|
|
||||||
si.stacks.push_back(bsa);
|
|
||||||
sendAndApply(&si);
|
|
||||||
|
|
||||||
ObstaclesRemoved obsRem;
|
|
||||||
obsRem.obstacles.insert(obstacle->uniqueID);
|
|
||||||
sendAndApply(&obsRem);
|
|
||||||
|
|
||||||
//if stack didn't die in explosion, continue movement
|
//if stack didn't die in explosion, continue movement
|
||||||
if(curStack->alive())
|
if(!obstacle->stopsMovement() && curStack->alive())
|
||||||
{
|
{
|
||||||
|
obstacle = NULL;
|
||||||
tiles.clear();
|
tiles.clear();
|
||||||
|
v--;
|
||||||
goto startWalking; //TODO it's so evil
|
goto startWalking; //TODO it's so evil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//handling obstacle on the final field (separate, because it affects both flying and walking stacks)
|
||||||
|
if(curStack->alive())
|
||||||
|
{
|
||||||
|
if(auto theLastObstacle = battleGetObstacleOnPos(curStack->position, false))
|
||||||
|
{
|
||||||
|
handleDamageFromObstacle(*theLastObstacle, curStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3295,6 +3289,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
CStack *curStack = gs->curB->getStack(ba.stackNumber),
|
CStack *curStack = gs->curB->getStack(ba.stackNumber),
|
||||||
*stackAtEnd = gs->curB->getStackT(ba.additionalInfo);
|
*stackAtEnd = gs->curB->getStackT(ba.additionalInfo);
|
||||||
|
|
||||||
|
if(!curStack || !stackAtEnd)
|
||||||
|
{
|
||||||
|
sendAndApply(&end_action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile
|
if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile
|
||||||
&& !(curStack->doubleWide()
|
&& !(curStack->doubleWide()
|
||||||
&& ( curStack->position == ba.destinationTile + (curStack->attackerOwned ? +1 : -1 ) )
|
&& ( curStack->position == ba.destinationTile + (curStack->attackerOwned ? +1 : -1 ) )
|
||||||
@ -3790,6 +3790,55 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
{
|
{
|
||||||
const CSpell *spell = VLC->spellh->spells[spellID];
|
const CSpell *spell = VLC->spellh->spells[spellID];
|
||||||
|
|
||||||
|
|
||||||
|
//Helper local function that creates obstacle on given position. Obstacle type is inferred from spell type.
|
||||||
|
//It creates, sends and applies needed package.
|
||||||
|
auto placeObstacle = [&](BattleHex pos)
|
||||||
|
{
|
||||||
|
static int obstacleIdToGive = gs->curB->obstacles.size()
|
||||||
|
? (gs->curB->obstacles.back()->uniqueID+1)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
auto obstacle = make_shared<SpellCreatedObstacle>();
|
||||||
|
switch(spellID) // :/
|
||||||
|
{
|
||||||
|
case Spells::QUICKSAND:
|
||||||
|
obstacle->obstacleType = CObstacleInstance::QUICKSAND;
|
||||||
|
obstacle->turnsRemaining = -1;
|
||||||
|
obstacle->visibleForAnotherSide = false;
|
||||||
|
break;
|
||||||
|
case Spells::LAND_MINE:
|
||||||
|
obstacle->obstacleType = CObstacleInstance::LAND_MINE;
|
||||||
|
obstacle->turnsRemaining = -1;
|
||||||
|
obstacle->visibleForAnotherSide = false;
|
||||||
|
break;
|
||||||
|
case Spells::FIRE_WALL:
|
||||||
|
obstacle->obstacleType = CObstacleInstance::FIRE_WALL;
|
||||||
|
obstacle->turnsRemaining = 2;
|
||||||
|
obstacle->visibleForAnotherSide = true;
|
||||||
|
break;
|
||||||
|
case Spells::FORCE_FIELD:
|
||||||
|
obstacle->obstacleType = CObstacleInstance::FORCE_FIELD;
|
||||||
|
obstacle->turnsRemaining = 2;
|
||||||
|
obstacle->visibleForAnotherSide = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//this function cannot be used with spells that do not create obstacles
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
obstacle->pos = pos;
|
||||||
|
obstacle->casterSide = casterSide;
|
||||||
|
obstacle->ID = spellID;
|
||||||
|
obstacle->spellLevel = spellLvl;
|
||||||
|
obstacle->casterSpellPower = usedSpellPower;
|
||||||
|
obstacle->uniqueID = obstacleIdToGive++;
|
||||||
|
|
||||||
|
BattleObstaclePlaced bop;
|
||||||
|
bop.obstacle = obstacle;
|
||||||
|
sendAndApply(&bop);
|
||||||
|
};
|
||||||
|
|
||||||
BattleSpellCast sc;
|
BattleSpellCast sc;
|
||||||
sc.side = casterSide;
|
sc.side = casterSide;
|
||||||
sc.id = spellID;
|
sc.id = spellID;
|
||||||
@ -3869,12 +3918,6 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
case Spells::QUICKSAND:
|
case Spells::QUICKSAND:
|
||||||
case Spells::LAND_MINE:
|
case Spells::LAND_MINE:
|
||||||
{
|
{
|
||||||
|
|
||||||
const int baseUniqueID = gs->curB->obstacles.size()
|
|
||||||
? (gs->curB->obstacles.back().uniqueID+1)
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<BattleHex> availableTiles;
|
std::vector<BattleHex> availableTiles;
|
||||||
for(int i = 0; i < GameConstants::BFIELD_SIZE; i += 1)
|
for(int i = 0; i < GameConstants::BFIELD_SIZE; i += 1)
|
||||||
{
|
{
|
||||||
@ -3885,31 +3928,25 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
range::random_shuffle(availableTiles);
|
range::random_shuffle(availableTiles);
|
||||||
|
|
||||||
const int patchesForSkill[] = {4, 4, 6, 8};
|
const int patchesForSkill[] = {4, 4, 6, 8};
|
||||||
int patchesToPut = patchesForSkill[spellLvl];
|
const int patchesToPut = std::min<int>(patchesForSkill[spellLvl], availableTiles.size());
|
||||||
vstd::amin(patchesToPut, availableTiles.size());
|
|
||||||
|
//land mines or quicksand patches are handled as spell created obstacles
|
||||||
for (int i = 0; i < patchesToPut; i++)
|
for (int i = 0; i < patchesToPut; i++)
|
||||||
{
|
placeObstacle(availableTiles[i]);
|
||||||
CObstacleInstance coi;
|
|
||||||
coi.pos = availableTiles[i];
|
|
||||||
coi.casterSide = casterSide;
|
|
||||||
coi.obstacleType = (spellID == Spells::QUICKSAND)
|
|
||||||
? CObstacleInstance::QUICKSAND
|
|
||||||
: CObstacleInstance::LAND_MINE;
|
|
||||||
coi.ID = spellID;
|
|
||||||
coi.spellLevel = spellLvl;
|
|
||||||
coi.turnsRemaining = -1;
|
|
||||||
coi.uniqueID = baseUniqueID + i;
|
|
||||||
coi.visibleForAnotherSide = false;
|
|
||||||
|
|
||||||
BattleObstaclePlaced bop;
|
|
||||||
bop.obstacle = coi;
|
|
||||||
sendAndApply(&bop);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case Spells::FORCE_FIELD:
|
||||||
|
placeObstacle(destination);
|
||||||
|
break;
|
||||||
|
case Spells::FIRE_WALL:
|
||||||
|
{
|
||||||
|
//fire wall is build from multiple obstacles - one fire piece for each affected hex
|
||||||
|
auto affectedHexes = spell->rangeInHexes(destination, spellLvl, casterSide);
|
||||||
|
BOOST_FOREACH(BattleHex hex, affectedHexes)
|
||||||
|
placeObstacle(hex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
//damage spells
|
//damage spells
|
||||||
case Spells::MAGIC_ARROW:
|
case Spells::MAGIC_ARROW:
|
||||||
case Spells::ICE_BOLT:
|
case Spells::ICE_BOLT:
|
||||||
@ -4213,10 +4250,10 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
|||||||
case Spells::REMOVE_OBSTACLE:
|
case Spells::REMOVE_OBSTACLE:
|
||||||
{
|
{
|
||||||
ObstaclesRemoved obr;
|
ObstaclesRemoved obr;
|
||||||
BOOST_FOREACH(const CObstacleInstance &obstacle, battleGetAllObstacles())
|
BOOST_FOREACH(auto &obstacle, battleGetAllObstacles())
|
||||||
{
|
{
|
||||||
if(vstd::contains(obstacle.getBlocked(), destination))
|
if(vstd::contains(obstacle->getBlockedTiles(), destination))
|
||||||
obr.obstacles.insert(obstacle.uniqueID);
|
obr.obstacles.insert(obstacle->uniqueID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!obr.obstacles.empty())
|
if(!obr.obstacles.empty())
|
||||||
@ -4491,6 +4528,65 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, CStack * curStack)
|
||||||
|
{
|
||||||
|
//we want to determine following vars depending on obstacle type
|
||||||
|
int damage = -1;
|
||||||
|
int effect = -1;
|
||||||
|
bool oneTimeObstacle = false;
|
||||||
|
|
||||||
|
//helper info
|
||||||
|
const SpellCreatedObstacle *spellObstacle = dynamic_cast<const SpellCreatedObstacle*>(&obstacle); //not nice but we may need spell params
|
||||||
|
const ui8 side = !curStack->attackerOwned;
|
||||||
|
const CGHeroInstance *hero = gs->curB->heroes[side];
|
||||||
|
|
||||||
|
if(obstacle.obstacleType == CObstacleInstance::MOAT)
|
||||||
|
{
|
||||||
|
damage = battleGetMoatDmg();
|
||||||
|
}
|
||||||
|
else if(obstacle.obstacleType == CObstacleInstance::LAND_MINE)
|
||||||
|
{
|
||||||
|
//You don't get hit by a Mine you can see.
|
||||||
|
if(gs->curB->isObstacleVisibleForSide(obstacle, side))
|
||||||
|
return;
|
||||||
|
|
||||||
|
oneTimeObstacle = true;
|
||||||
|
effect = 82; //makes
|
||||||
|
damage = gs->curB->calculateSpellDmg(VLC->spellh->spells[Spells::LAND_MINE], hero, curStack,
|
||||||
|
spellObstacle->spellLevel, spellObstacle->casterSpellPower);
|
||||||
|
//TODO even if obstacle wasn't created by hero (Tower "moat") it should deal dmg as if casted by hero,
|
||||||
|
//if it is bigger than default dmg. Or is it just irrelevant H3 implementation quirk
|
||||||
|
}
|
||||||
|
else if(obstacle.obstacleType == CObstacleInstance::FIRE_WALL)
|
||||||
|
{
|
||||||
|
damage = gs->curB->calculateSpellDmg(VLC->spellh->spells[Spells::FIRE_WALL], hero, curStack,
|
||||||
|
spellObstacle->spellLevel, spellObstacle->casterSpellPower);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//no other obstacle does damage to stack
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattleStackAttacked bsa;
|
||||||
|
if(effect >= 0)
|
||||||
|
{
|
||||||
|
bsa.flags |= BattleStackAttacked::EFFECT;
|
||||||
|
bsa.effect = effect; //makes POOF
|
||||||
|
}
|
||||||
|
bsa.damageAmount = damage;
|
||||||
|
bsa.stackAttacked = curStack->ID;
|
||||||
|
bsa.attackerID = -1;
|
||||||
|
curStack->prepareAttacked(bsa);
|
||||||
|
|
||||||
|
StacksInjured si;
|
||||||
|
si.stacks.push_back(bsa);
|
||||||
|
sendAndApply(&si);
|
||||||
|
|
||||||
|
if(oneTimeObstacle)
|
||||||
|
removeObstacle(obstacle);
|
||||||
|
}
|
||||||
|
|
||||||
void CGameHandler::handleTimeEvents()
|
void CGameHandler::handleTimeEvents()
|
||||||
{
|
{
|
||||||
gs->map->events.sort(evntCmp);
|
gs->map->events.sort(evntCmp);
|
||||||
@ -5633,6 +5729,14 @@ void CGameHandler::runBattle()
|
|||||||
while(!battleResult.get()) //till the end of the battle ;]
|
while(!battleResult.get()) //till the end of the battle ;]
|
||||||
{
|
{
|
||||||
NEW_ROUND;
|
NEW_ROUND;
|
||||||
|
auto obstacles = gs->curB->obstacles; //we copy container, because we're going to modify it
|
||||||
|
BOOST_FOREACH(auto &obstPtr, obstacles)
|
||||||
|
{
|
||||||
|
if(const SpellCreatedObstacle *sco = dynamic_cast<const SpellCreatedObstacle *>(obstPtr.get()))
|
||||||
|
if(sco->turnsRemaining == 0)
|
||||||
|
removeObstacle(*obstPtr);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<CStack*> & stacks = (gs->curB->stacks);
|
std::vector<CStack*> & stacks = (gs->curB->stacks);
|
||||||
const BattleInfo & curB = *gs->curB;
|
const BattleInfo & curB = *gs->curB;
|
||||||
|
|
||||||
@ -5957,6 +6061,13 @@ bool CGameHandler::isBlockedByQueries(const CPack *pack, int packType, ui8 playe
|
|||||||
return true; //block package
|
return true; //block package
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameHandler::removeObstacle(const CObstacleInstance &obstacle)
|
||||||
|
{
|
||||||
|
ObstaclesRemoved obsRem;
|
||||||
|
obsRem.obstacles.insert(obstacle.uniqueID);
|
||||||
|
sendAndApply(&obsRem);
|
||||||
|
}
|
||||||
|
|
||||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat)
|
CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat)
|
||||||
{
|
{
|
||||||
int color = army->tempOwner;
|
int color = army->tempOwner;
|
||||||
|
@ -199,6 +199,8 @@ public:
|
|||||||
int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack = -1);
|
int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack = -1);
|
||||||
bool makeCustomAction(BattleAction &ba);
|
bool makeCustomAction(BattleAction &ba);
|
||||||
void stackTurnTrigger(const CStack * stack);
|
void stackTurnTrigger(const CStack * stack);
|
||||||
|
void handleDamageFromObstacle(const CObstacleInstance &obstacle, CStack * curStack); //checks if obstacle is land mine and handles possible consequences
|
||||||
|
void removeObstacle(const CObstacleInstance &obstacle);
|
||||||
bool queryReply( ui32 qid, ui32 answer, ui8 player );
|
bool queryReply( ui32 qid, ui32 answer, ui8 player );
|
||||||
bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
|
bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
|
||||||
bool buildBoat( ui32 objid );
|
bool buildBoat( ui32 objid );
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
|
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
|
||||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..</OutDir>
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\</OutDir>
|
||||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)</OutDir>
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)</OutDir>
|
||||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
|
||||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration)\</IntDir>
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration)\</IntDir>
|
||||||
|
Loading…
Reference in New Issue
Block a user