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-05 14:10:26 +00:00
parent fc2a11359e
commit 05b0d82769
15 changed files with 185 additions and 33 deletions

View File

@ -41,6 +41,7 @@ struct HeroBonus;
struct PackageApplied;
struct SetObjectProperty;
struct CatapultAttack;
struct BattleStacksRemoved;
class CLoadFile;
class CSaveFile;
template <typename Serializer> class CISer;
@ -123,6 +124,7 @@ public:
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
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){}; //called when certain stack is completely removed from battlefield
};
class CAIHandler
{

View File

@ -109,8 +109,10 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
SDL_Surface * moat = BitmapHandler::loadBitmap( siegeH->getSiegeName(13) ),
* mlip = BitmapHandler::loadBitmap( siegeH->getSiegeName(14) );
blitAt(moat, 410, background->h - moat->h, background);
blitAt(mlip, 410, background->h - mlip->h, background);
if(moat) //eg. tower has no moat
blitAt(moat, 410, background->h - moat->h, background);
if(mlip) //eg. tower has no mlip
blitAt(mlip, 410, background->h - mlip->h, background);
SDL_FreeSurface(moat);
SDL_FreeSurface(mlip);
@ -211,9 +213,10 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
//loading projectiles for units
for(std::map<int, CStack>::iterator g = stacks.begin(); g != stacks.end(); ++g)
{
if(g->second.creature->isShooting() && CGI->creh->idToProjectile[g->second.creature->idNumber] != std::string())
{
idToProjectile[g->second.creature->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile[g->second.creature->idNumber]);
int creID = (g->second.creature->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : g->second.creature->idNumber; //id of creature whose shots should be loaded
if(g->second.creature->isShooting() && CGI->creh->idToProjectile[creID] != std::string())
{
idToProjectile[g->second.creature->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile[creID]);
if(idToProjectile[g->second.creature->idNumber]->ourImages.size() > 2) //add symmetric images
{
@ -1115,21 +1118,23 @@ void CBattleInterface::newStack(int stackID)
if(newStack->position < 0) //turret
{
static const int townToTurretAnim[] = {2, 18, 34, 44, 64, 76, 88, 100, 127};
const CCreature & turretCreature = CGI->creh->creatures[ CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] ];
int xShift = turretCreature.isDoubleWide() ? 44 : 0;
switch(newStack->position)
{
case -2: //keep
coords = std::make_pair(505, -66);
coords = std::make_pair(505 + xShift, -66);
break;
case -3: //lower turret
coords = std::make_pair(368, 304);
coords = std::make_pair(368 + xShift, 304);
break;
case -4: //upper turret
coords = std::make_pair(339, -192);
coords = std::make_pair(339 + xShift, -192);
break;
}
creAnims[stackID] = new CCreatureAnimation(CGI->creh->creatures[ townToTurretAnim[siegeH->town->town->typeID] ].animDefName);
creAnims[stackID] = new CCreatureAnimation(turretCreature.animDefName);
}
else
{
@ -1145,6 +1150,7 @@ void CBattleInterface::stackRemoved(int stackID)
{
delete creAnims[stackID];
creAnims.erase(stackID);
creDir.erase(stackID);
}
void CBattleInterface::stackActivated(int number)
@ -1666,7 +1672,10 @@ void CBattleInterface::handleEndOfMove(int stackNumber, int destinationTile)
void CBattleInterface::hexLclicked(int whichOne)
{
if((whichOne%BFIELD_WIDTH)!=0 && (whichOne%BFIELD_WIDTH)!=(BFIELD_WIDTH-1)) //if player is trying to attack enemey unit or move creature stack
const CStack * actSt = LOCPLINT->cb->battleGetStackByID(activeStack);
if( ((whichOne%BFIELD_WIDTH)!=0 && (whichOne%BFIELD_WIDTH)!=(BFIELD_WIDTH-1)) //if player is trying to attack enemey unit or move creature stack
|| (actSt->hasFeatureOfType(StackFeature::CATAPULT) && !spellDestSelectMode )
)
{
if(!myTurn)
return; //we are not permit to do anything
@ -2541,20 +2550,24 @@ void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::map
break;
}
}
showAliveStack(ID, stacks, to);
//blitting creature cover
switch(posToSeek)
if(ID != -1)
{
case -3: //bottom turret
siegeH->printPartOfWall(to, 16);
break;
case -4: //upper turret
siegeH->printPartOfWall(to, 17);
break;
case -2: //keep
siegeH->printPartOfWall(to, 15);
break;
showAliveStack(ID, stacks, to);
//blitting creature cover
switch(posToSeek)
{
case -3: //bottom turret
siegeH->printPartOfWall(to, 16);
break;
case -4: //upper turret
siegeH->printPartOfWall(to, 17);
break;
case -2: //keep
siegeH->printPartOfWall(to, 15);
break;
}
}
}
}
@ -3340,8 +3353,7 @@ std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, ui16 additInf
{
if(what == 2 || what == 3 || what == 8)
{
if(additInfo == 2) additInfo = 1;
else if(additInfo == 3) additInfo = 2;
if(additInfo == 3) additInfo = 2;
}
char buf[100];
SDL_itoa(additInfo, buf, 10);

View File

@ -1003,6 +1003,14 @@ void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca)
battleInt->siegeH->getSiegeName(ca.attackedPartOfWall + 2, cb->battleGetWallState(ca.attackedPartOfWall)) );
}
void CPlayerInterface::battleStacksRemoved(const BattleStacksRemoved & bsr)
{
for(std::set<ui32>::const_iterator it = bsr.stackIDs.begin(); it != bsr.stackIDs.end(); ++it) //for each removed stack
{
battleInt->stackRemoved(*it);
}
}
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

@ -182,6 +182,7 @@ public:
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 battleStacksRemoved(const BattleStacksRemoved & bsr); //called when certain stack is completely removed from battlefield
//-------------//
void heroKilled(const CGHeroInstance* hero);

View File

@ -476,6 +476,13 @@ void CatapultAttack::applyCl( CClient *cl )
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleCatapultAttacked, *this);
}
void BattleStacksRemoved::applyCl( CClient *cl )
{
//inform interfaces about removed stacks
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1, battleStacksRemoved, *this);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleStacksRemoved, *this);
}
CGameState* CPackForClient::GS( CClient *cl )
{
return cl->gs;

View File

@ -165,6 +165,7 @@
+ 144 FULL_HP_REGENERATION 0 0 0 //troll
+ 147 NOT_ACTIVE 0 0 0 //First Aid Tent //TODO: remove when support is added
+ 148 NOT_ACTIVE 0 0 0 //Ammo Cart
+ 149 SHOOTER 0 0 0 //arrow turret
- 46 FLYING //hell hound doesn't fly
- 47 FLYING //cerberus doesn't fly
- 120 DOUBLE_WIDE //psychic elemental

11
config/cr_to_turret.txt Normal file
View File

@ -0,0 +1,11 @@
//describes_which_creature's_animation_should_be_used_to_dispaly_creature_in_turret_while_siege
//i-th_line_-_i-th_faction
2
18
34
44
64
76
88
100
127

View File

@ -525,6 +525,18 @@ void CCreatureHandler::loadCreatures()
idToProjectileSpin[id] = spin;
}
inp2.close();
//reading factionToTurretCreature
tlog5 << "\t\tReading config/cr_to_turret.txt" << std::endl;
std::ifstream inp3("config" PATHSEPARATOR "cr_to_turret.txt", std::ios::in | std::ios::binary); //this file is not in lod
std::string dump2;
inp3 >> dump2 >> dump2;
for(int g=0; g<F_NUMBER; ++g)
{
inp3 >> factionToTurretCreature[g];
}
inp3.close();
}
void CCreatureHandler::loadAnimationInfo()

View File

@ -102,7 +102,8 @@ public:
std::map<std::string,int> nameToID;
std::map<int,std::string> idToProjectile;
std::map<int,bool> idToProjectileSpin; //if true, appropriate projectile is spinning during flight
std::vector<bool> factionAlignments; //1 for good, 0 for neutral and -1 for evil with faction ID as index
std::vector<si8> factionAlignments; //1 for good, 0 for neutral and -1 for evil with faction ID as index
int factionToTurretCreature[F_NUMBER]; //which creature's animation should be used to dispaly creature in turret while siege
void loadCreatures();
void loadAnimationInfo();
@ -117,7 +118,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
//TODO: should be optimized, not all these informations needs to be serialized (same for ccreature)
h & notUsedMonsters & creatures & nameToID & idToProjectile & idToProjectileSpin;
h & notUsedMonsters & creatures & nameToID & idToProjectile & idToProjectileSpin & factionToTurretCreature;
if(!h.saving)
{

View File

@ -1564,6 +1564,16 @@ int CGameState::battleGetBattlefieldType(int3 tile)
}
}
const CGHeroInstance * CGameState::battleGetOwner(int stackID)
{
if(!curB)
return NULL;
si32 ourHero = curB->getStack(stackID)->attackerOwned ? curB->hero1 : curB->hero2;
return getHero(ourHero);
}
UpgradeInfo CGameState::getUpgradeInfo(CArmedInstance *obj, int stackPos)
{
UpgradeInfo ret;
@ -2133,7 +2143,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
}
}
if(attacker->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //any siege weapon, but only ballista can attack
if(attacker->hasFeatureOfType(StackFeature::SIEGE_WEAPON) && attacker->creature->idNumber != 149) //any siege weapon, but only ballista can attack (second condition - not arrow turret)
{ //minDmg and maxDmg are multiplied by hero attack + 1
minDmg *= attackerHero->getPrimSkillLevel(0) + 1;
maxDmg *= attackerHero->getPrimSkillLevel(0) + 1;
@ -2599,7 +2609,7 @@ bool CGameState::battleCanShoot(int ID, int dest)
if(!our || !dst) return false;
int ourHero = our->attackerOwned ? curB->hero1 : curB->hero2;
const CGHeroInstance * ourHero = battleGetOwner(our->ID);
if(our->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness
return false;
@ -2608,7 +2618,7 @@ bool CGameState::battleCanShoot(int ID, int dest)
&& our->owner != dst->owner
&& dst->alive()
&& (!curB->isStackBlocked(ID) ||
( getHero(ourHero) && getHero(ourHero)->hasBonusOfType(HeroBonus::FREE_SHOOTING) ) )
( ourHero && ourHero->hasBonusOfType(HeroBonus::FREE_SHOOTING) ) )
&& our->shots
)
return true;

View File

@ -330,6 +330,7 @@ public:
bool battleCanFlee(int player); //returns true if player can flee from the battle
int battleGetStack(int pos, bool onlyAlive); //returns ID of stack at given tile
int battleGetBattlefieldType(int3 tile = int3());// 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
const CGHeroInstance * battleGetOwner(int stackID); //returns hero that owns given stack; NULL if none
si8 battleMaxSpellLevel(); //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, SPELL_LEVELS is returned
bool battleCanShoot(int ID, int dest); //determines if stack with given ID shoot at the selected destination
UpgradeInfo getUpgradeInfo(CArmedInstance *obj, int stackPos);

View File

@ -1008,6 +1008,21 @@ struct CatapultAttack : public CPackForClient //3015
}
};
struct BattleStacksRemoved : public CPackForClient //3016
{
BattleStacksRemoved(){type = 3016;}
DLL_EXPORT void applyGs(CGameState *gs);
void applyCl(CClient *cl);
std::set<ui32> stackIDs; //IDs of removed stacks
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stackIDs;
}
};
struct ShowInInfobox : public CPackForClient //107
{
ShowInInfobox(){type = 107;};

View File

@ -1080,6 +1080,24 @@ DLL_EXPORT void CatapultAttack::applyGs( CGameState *gs )
}
}
DLL_EXPORT void BattleStacksRemoved::applyGs( CGameState *gs )
{
if(!gs->curB)
return;
for(std::set<ui32>::const_iterator it = stackIDs.begin(); it != stackIDs.end(); ++it) //for each removed stack
{
for(int b=0; b<gs->curB->stacks.size(); ++b) //find it in vector of stacks
{
if(gs->curB->stacks[b]->ID == *it) //if found
{
gs->curB->stacks.erase(gs->curB->stacks.begin() + b); //remove
break;
}
}
}
}
DLL_EXPORT void YourTurn::applyGs( CGameState *gs )
{
gs->currentPlayer = player;

View File

@ -107,6 +107,7 @@ void registerTypes2(Serializer &s)
s.template registerType<StacksHealedOrResurrected>();
s.template registerType<ObstaclesRemoved>();
s.template registerType<CatapultAttack>();
s.template registerType<BattleStacksRemoved>();
s.template registerType<ShowInInfobox>();
s.template registerType<OpenWindow>();
s.template registerType<NewObject>();

View File

@ -396,6 +396,30 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
continue;
}
const CGHeroInstance * curOwner = gs->battleGetOwner(next->ID);
if(next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //arrow turret, hero has no ballistics
{
BattleAction attack;
attack.actionType = 7;
attack.side = !next->attackerOwned;
attack.stackNumber = next->ID;
for(int g=0; g<gs->curB->stacks.size(); ++g)
{
if(gs->curB->stacks[g]->attackerOwned)
{
attack.destinationTile = gs->curB->stacks[g]->position;
break;
}
}
makeBattleAction(attack);
checkForBattleEnd(stacks);
continue;
}
askInterfaceForMove:
//ask interface and wait for answer
if(!battleResult.get())
@ -536,8 +560,8 @@ void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def, in
BattleStackAttacked *bsa = &*i;
#endif
bsa->stackAttacked = def->ID;
bsa->damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), bat.shot(), distance);//counting dealt damage
bsa->stackAttacked = def->ID;
bsa->damageAmount = BattleInfo::calculateDmg(att, def, gs->battleGetOwner(att->ID), gs->battleGetOwner(def->ID), bat.shot(), distance);//counting dealt damage
if(att->Luck() > 0 && rand()%24 < att->Luck())
{
bsa->damageAmount *= 2;
@ -2552,7 +2576,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
break;
}
if(rand()%100 >= chanceForHit) //hit is successful
if(rand()%100 <= chanceForHit) //hit is successful
{
int dmgRand = rand()%100;
//accumulating dmgChance
@ -2567,6 +2591,34 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
break;
}
}
if(ca.damageDealt > 0 && (attackedPart == 0 || attackedPart == 1 || attackedPart == 6))
{
int posRemove = -1;
switch(attackedPart)
{
case 0: //keep
posRemove = -2;
break;
case 1: //bottom tower
posRemove = -3;
break;
case 6: //upper tower
posRemove = -4;
break;
}
BattleStacksRemoved bsr;
for(int g=0; g<gs->curB->stacks.size(); ++g)
{
if(gs->curB->stacks[g]->position == posRemove)
{
bsr.stackIDs.insert( gs->curB->stacks[g]->ID );
break;
}
}
sendAndApply(&bsr);
}
}
sendAndApply(&ca);