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
fc2a11359e
commit
05b0d82769
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
11
config/cr_to_turret.txt
Normal 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
|
@ -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()
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;};
|
||||
|
@ -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;
|
||||
|
@ -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>();
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user