mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
* next part of sieges
This commit is contained in:
parent
e60c6785a4
commit
d25a5a795e
@ -618,6 +618,15 @@ ui8 CCallback::battleGetWallState(int partOfWall)
|
||||
return gs->curB->si.wallState[partOfWall];
|
||||
}
|
||||
|
||||
int CCallback::battleGetWallUnderHex(int hex)
|
||||
{
|
||||
if(!gs->curB || gs->curB->siege == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return gs->curB->hexToWallPart(hex);
|
||||
}
|
||||
|
||||
std::pair<ui32, ui32> CCallback::battleEstimateDamage(int attackerID, int defenderID)
|
||||
{
|
||||
if(!gs->curB)
|
||||
|
@ -182,6 +182,7 @@ public:
|
||||
virtual bool battleCanFlee()=0; //returns true if caller can flee from the battle
|
||||
virtual const CGTownInstance * battleGetDefendedTown()=0; //returns defended town if current battle is a siege, NULL instead
|
||||
virtual ui8 battleGetWallState(int partOfWall)=0; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||
virtual int battleGetWallUnderHex(int hex)=0; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||
virtual std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID)=0; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||
};
|
||||
|
||||
@ -289,6 +290,7 @@ public:
|
||||
bool battleCanFlee(); //returns true if caller can flee from the battle
|
||||
const CGTownInstance * battleGetDefendedTown(); //returns defended town if current battle is a siege, NULL instead
|
||||
ui8 battleGetWallState(int partOfWall); //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||
int battleGetWallUnderHex(int hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||
std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID); //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||
|
||||
//XXX hmmm _tmain on _GNUC_ wtf?
|
||||
|
@ -40,6 +40,7 @@ struct SetStackEffect;
|
||||
struct HeroBonus;
|
||||
struct PackageApplied;
|
||||
struct SetObjectProperty;
|
||||
struct CatapultAttack;
|
||||
class CLoadFile;
|
||||
class CSaveFile;
|
||||
template <typename Serializer> class CISer;
|
||||
@ -121,6 +122,7 @@ public:
|
||||
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
|
||||
virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
|
||||
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set of obstacles is removed from batlefield; IDs of them are given
|
||||
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
|
||||
};
|
||||
class CAIHandler
|
||||
{
|
||||
|
@ -817,6 +817,12 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
|
||||
console->whoSetAlter = 0;
|
||||
}
|
||||
}
|
||||
else if( sactive->hasFeatureOfType(StackFeature::CATAPULT) && isCatapultAttackable(myNumber) ) //catapulting
|
||||
{
|
||||
CGI->curh->changeGraphic(1,16);
|
||||
console->alterTxt = "";
|
||||
console->whoSetAlter = 0;
|
||||
}
|
||||
else //empty unavailable tile
|
||||
{
|
||||
CGI->curh->changeGraphic(1,0);
|
||||
@ -1579,6 +1585,18 @@ bool CBattleInterface::blockedByObstacle(int hex) const
|
||||
return vstd::contains(coveredHexes, hex);
|
||||
}
|
||||
|
||||
bool CBattleInterface::isCatapultAttackable(int hex) const
|
||||
{
|
||||
if(!siegeH)
|
||||
return false;
|
||||
|
||||
int wallUnder = LOCPLINT->cb->battleGetWallUnderHex(hex);
|
||||
if(wallUnder == -1)
|
||||
return false;
|
||||
|
||||
return LOCPLINT->cb->battleGetWallState(wallUnder) < 3;
|
||||
}
|
||||
|
||||
void CBattleInterface::handleEndOfMove(int stackNumber, int destinationTile)
|
||||
{
|
||||
const CStack * movedStack = LOCPLINT->cb->battleGetStackByID(stackNumber);
|
||||
@ -1652,6 +1670,7 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
const CStack* dest = LOCPLINT->cb->battleGetStackByPos(whichOne); //creature at destination tile; -1 if there is no one
|
||||
if(!dest || !dest->alive()) //no creature at that tile
|
||||
{
|
||||
const CStack * sactive = LOCPLINT->cb->battleGetStackByID(activeStack);
|
||||
if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range
|
||||
{
|
||||
CGI->curh->changeGraphic(1, 6); //cursor should be changed
|
||||
@ -1669,6 +1688,10 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
giveCommand(2,whichOne,activeStack);
|
||||
}
|
||||
}
|
||||
else if(sactive->hasFeatureOfType(StackFeature::CATAPULT) && isCatapultAttackable(whichOne)) //attacking (catapult)
|
||||
{
|
||||
giveCommand(9,whichOne,activeStack);
|
||||
}
|
||||
}
|
||||
else if(dest->owner != attackingHeroInstance->tempOwner
|
||||
&& LOCPLINT->cb->battleCanShoot(activeStack, whichOne) ) //shooting
|
||||
@ -3219,19 +3242,14 @@ std::string CBattleInterface::SiegeHelper::townTypeInfixes[F_NUMBER] = {"CS", "R
|
||||
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface * _owner)
|
||||
: town(siegeTown), owner(_owner)
|
||||
{
|
||||
backWall = BitmapHandler::loadBitmap( getSiegeName(1) );
|
||||
|
||||
for(int g=0; g<ARRAY_COUNT(walls); ++g)
|
||||
{
|
||||
walls[g] = BitmapHandler::loadBitmap( getSiegeName(g + 2) );
|
||||
walls[g] = BitmapHandler::loadBitmap( getSiegeName(g) );
|
||||
}
|
||||
}
|
||||
|
||||
CBattleInterface::SiegeHelper::~SiegeHelper()
|
||||
{
|
||||
if(backWall)
|
||||
SDL_FreeSurface(backWall);
|
||||
|
||||
for(int g=0; g<ARRAY_COUNT(walls); ++g)
|
||||
{
|
||||
SDL_FreeSurface(walls[g]);
|
||||
@ -3240,6 +3258,11 @@ CBattleInterface::SiegeHelper::~SiegeHelper()
|
||||
|
||||
std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, ui16 additInfo) const
|
||||
{
|
||||
if(what == 2 || what == 3 || what == 8)
|
||||
{
|
||||
if(additInfo == 2) additInfo = 1;
|
||||
else if(additInfo == 3) additInfo = 2;
|
||||
}
|
||||
char buf[100];
|
||||
SDL_itoa(additInfo, buf, 10);
|
||||
std::string addit(buf);
|
||||
@ -3292,10 +3315,10 @@ void CBattleInterface::SiegeHelper::printPartOfWall(SDL_Surface * to, int what)
|
||||
switch(what)
|
||||
{
|
||||
case 1: //background wall
|
||||
pos = Point(owner->pos.w + owner->pos.x - backWall->w, 55 + owner->pos.y);
|
||||
pos = Point(owner->pos.w + owner->pos.x - walls[1]->w, 55 + owner->pos.y);
|
||||
break;
|
||||
case 2: //keep
|
||||
pos = Point(owner->pos.w + owner->pos.x - walls[what-2]->w, 154 + owner->pos.y);
|
||||
pos = Point(owner->pos.w + owner->pos.x - walls[2]->w, 154 + owner->pos.y);
|
||||
break;
|
||||
case 3: //bottom tower
|
||||
case 4: //bottom wall
|
||||
@ -3314,6 +3337,6 @@ void CBattleInterface::SiegeHelper::printPartOfWall(SDL_Surface * to, int what)
|
||||
|
||||
if(pos.x != -1)
|
||||
{
|
||||
blitAt(walls[what-2], pos.x, pos.y, to);
|
||||
blitAt(walls[what], pos.x, pos.y, to);
|
||||
}
|
||||
}
|
||||
|
@ -218,6 +218,7 @@ private:
|
||||
void giveCommand(ui8 action, ui16 tile, ui32 stack, si32 additional=-1);
|
||||
bool isTileAttackable(const int & number) const; //returns true if tile 'number' is neighbouring any tile from active stack's range or is one of these tiles
|
||||
bool blockedByObstacle(int hex) const;
|
||||
bool isCatapultAttackable(int hex) const; //returns true if given tile can be attacked by catapult
|
||||
|
||||
void handleEndOfMove(int stackNumber, int destinationTile); //helper function
|
||||
|
||||
@ -233,8 +234,7 @@ private:
|
||||
{
|
||||
private:
|
||||
static std::string townTypeInfixes[F_NUMBER]; //for internal use only - to build filenames
|
||||
SDL_Surface * backWall;
|
||||
SDL_Surface * walls[11];
|
||||
SDL_Surface * walls[13];
|
||||
const CBattleInterface * owner;
|
||||
public:
|
||||
const CGTownInstance * town; //besieged town
|
||||
@ -245,6 +245,8 @@ private:
|
||||
std::string getSiegeName(ui16 what, ui16 additInfo = 1) const; //what: 0 - background, 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall; additInfo: 1 - intact, 2 - damaged, 3 - destroyed
|
||||
|
||||
void printPartOfWall(SDL_Surface * to, int what);//what: 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall
|
||||
|
||||
friend class CPlayerInterface;
|
||||
} * siegeH;
|
||||
public:
|
||||
CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect); //c-tor
|
||||
|
@ -996,6 +996,13 @@ void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObst
|
||||
battleInt->redrawBackgroundWithHexes(battleInt->activeStack);
|
||||
}
|
||||
|
||||
void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca)
|
||||
{
|
||||
SDL_FreeSurface(battleInt->siegeH->walls[ca.attackedPartOfWall + 2]);
|
||||
battleInt->siegeH->walls[ca.attackedPartOfWall + 2] = BitmapHandler::loadBitmap(
|
||||
battleInt->siegeH->getSiegeName(ca.attackedPartOfWall + 2, cb->battleGetWallState(ca.attackedPartOfWall)) );
|
||||
}
|
||||
|
||||
void CPlayerInterface::battleNewRound(int round) //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||
|
@ -181,6 +181,7 @@ public:
|
||||
void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks); //called when stacks are healed / resurrected
|
||||
void battleNewStackAppeared(int stackID); //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
|
||||
void battleObstaclesRemoved(const std::set<si32> & removedObstacles); //called when a certain set of obstacles is removed from batlefield; IDs of them are given
|
||||
void battleCatapultAttacked(const CatapultAttack & ca); //called when catapult makes an attack
|
||||
|
||||
//-------------//
|
||||
void heroKilled(const CGHeroInstance* hero);
|
||||
|
@ -469,6 +469,13 @@ void ObstaclesRemoved::applyCl( CClient *cl )
|
||||
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleObstaclesRemoved, obstacles);
|
||||
}
|
||||
|
||||
void CatapultAttack::applyCl( CClient *cl )
|
||||
{
|
||||
//inform interfaces about catapult attack
|
||||
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1, battleCatapultAttacked, *this);
|
||||
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleCatapultAttacked, *this);
|
||||
}
|
||||
|
||||
CGameState* CPackForClient::GS( CClient *cl )
|
||||
{
|
||||
return cl->gs;
|
||||
|
@ -2473,6 +2473,24 @@ ui32 BattleInfo::getSpellCost(const CSpell * sp, const CGHeroInstance * caster)
|
||||
return ret + manaReduction;
|
||||
}
|
||||
|
||||
int BattleInfo::hexToWallPart(int hex)
|
||||
{
|
||||
if(siege == 0) //there is no battle!
|
||||
return -1;
|
||||
|
||||
static const std::pair<int, int> attackable[] = //potentially attackable parts of wall
|
||||
{std::make_pair(50, 0), std::make_pair(182, 1), std::make_pair(165, 2), std::make_pair(130, 3),
|
||||
std::make_pair(62, 4), std::make_pair(29, 5), std::make_pair(12, 6), std::make_pair(95, 7), std::make_pair(96, 7)};
|
||||
|
||||
for(int g = 0; g < ARRAY_COUNT(attackable); ++g)
|
||||
{
|
||||
if(attackable[g].first == hex)
|
||||
return attackable[g].second;
|
||||
}
|
||||
|
||||
return -1; //not found!
|
||||
}
|
||||
|
||||
CStack * BattleInfo::getNextStack()
|
||||
{
|
||||
CStack *current = getStack(activeStack);
|
||||
|
@ -108,7 +108,7 @@ struct DLL_EXPORT CObstacleInstance
|
||||
//only for use in BattleInfo
|
||||
struct DLL_EXPORT SiegeInfo
|
||||
{
|
||||
ui8 wallState[7]; //[0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; 1 - intact, 2 - damaged, 3 - destroyed
|
||||
ui8 wallState[8]; //[0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; 1 - intact, 2 - damaged, 3 - destroyed
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -155,6 +155,7 @@ struct DLL_EXPORT BattleInfo
|
||||
static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster);
|
||||
CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position); //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||
ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster); //returns cost of given spell
|
||||
int hexToWallPart(int hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||
};
|
||||
|
||||
class DLL_EXPORT CStack
|
||||
|
@ -992,6 +992,22 @@ struct ObstaclesRemoved : public CPackForClient //3014
|
||||
}
|
||||
};
|
||||
|
||||
struct CatapultAttack : public CPackForClient //3015
|
||||
{
|
||||
CatapultAttack(){type = 3015;}
|
||||
|
||||
DLL_EXPORT void applyGs(CGameState *gs);
|
||||
void applyCl(CClient *cl);
|
||||
|
||||
ui8 attackedPartOfWall;//[0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate;
|
||||
ui8 damageDealt;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & attackedPartOfWall & damageDealt;
|
||||
}
|
||||
};
|
||||
|
||||
struct ShowInInfobox : public CPackForClient //107
|
||||
{
|
||||
ShowInInfobox(){type = 107;};
|
||||
|
@ -1068,6 +1068,15 @@ DLL_EXPORT void ObstaclesRemoved::applyGs( CGameState *gs )
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORT void CatapultAttack::applyGs( CGameState *gs )
|
||||
{
|
||||
if(gs->curB && gs->curB->siege != 0) //if there is a battle and it's a siege
|
||||
{
|
||||
gs->curB->si.wallState[attackedPartOfWall] =
|
||||
std::min( gs->curB->si.wallState[attackedPartOfWall] + damageDealt, 3 );
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORT void YourTurn::applyGs( CGameState *gs )
|
||||
{
|
||||
gs->currentPlayer = player;
|
||||
|
@ -106,6 +106,7 @@ void registerTypes2(Serializer &s)
|
||||
s.template registerType<BattleResultsApplied>();
|
||||
s.template registerType<StacksHealedOrResurrected>();
|
||||
s.template registerType<ObstaclesRemoved>();
|
||||
s.template registerType<CatapultAttack>();
|
||||
s.template registerType<ShowInInfobox>();
|
||||
s.template registerType<OpenWindow>();
|
||||
s.template registerType<NewObject>();
|
||||
|
@ -2478,6 +2478,69 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
sendAndApply(&EndAction());
|
||||
break;
|
||||
}
|
||||
case 9: //catapult
|
||||
{
|
||||
const CGHeroInstance * attackingHero = (ba.side) ? gs->getHero(gs->curB->hero2) : gs->getHero(gs->curB->hero1);
|
||||
CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics[attackingHero->getSecSkillLevel(20)]; //artillery
|
||||
|
||||
int attackedPart = gs->curB->hexToWallPart(ba.destinationTile);
|
||||
if(attackedPart == -1)
|
||||
{
|
||||
complain("catapult tried to attack non-catapultable hex!");
|
||||
break;
|
||||
}
|
||||
for(int g=0; g<sbi.shots; ++g)
|
||||
{
|
||||
if(gs->curB->si.wallState[attackedPart] == 3) //it's not destroyed
|
||||
continue;
|
||||
|
||||
CatapultAttack ca; //package for clients
|
||||
ca.attackedPartOfWall = attackedPart;
|
||||
ca.damageDealt = 0;
|
||||
|
||||
int chanceForHit = 0;
|
||||
int dmgChance[3] = {sbi.noDmg, sbi.oneDmg, sbi.twoDmg}; //dmgChance[i] - chance for doing i dmg when hit is successful
|
||||
switch(attackedPart)
|
||||
{
|
||||
case 0: //keep
|
||||
chanceForHit = sbi.keep;
|
||||
break;
|
||||
case 1: //bottom tower
|
||||
case 6: //upper tower
|
||||
chanceForHit = sbi.tower;
|
||||
break;
|
||||
case 2: //bottom wall
|
||||
case 3: //below gate
|
||||
case 4: //over gate
|
||||
case 5: //upper wall
|
||||
chanceForHit = sbi.wall;
|
||||
break;
|
||||
case 7: //gate
|
||||
chanceForHit = sbi.gate;
|
||||
break;
|
||||
}
|
||||
|
||||
if(rand()%100 >= chanceForHit) //hit is successful
|
||||
{
|
||||
int dmgRand = rand()%100;
|
||||
//accumulating dmgChance
|
||||
dmgChance[1] += dmgChance[0];
|
||||
dmgChance[2] += dmgChance[1];
|
||||
//calculating dealt damage
|
||||
for(int v = 0; v < ARRAY_COUNT(dmgChance); ++v)
|
||||
{
|
||||
if(dmgRand <= dmgChance[v])
|
||||
{
|
||||
ca.damageDealt = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendAndApply(&ca);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
battleMadeAction.setn(true);
|
||||
return ok;
|
||||
|
Loading…
Reference in New Issue
Block a user