1
0
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:
mateuszb 2009-09-01 13:54:13 +00:00
parent e60c6785a4
commit d25a5a795e
14 changed files with 173 additions and 12 deletions

View File

@ -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)

View File

@ -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?

View File

@ -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
{

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;};

View File

@ -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;

View File

@ -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>();

View File

@ -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;