1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

* partial support for arrow turrets

This commit is contained in:
mateuszb 2009-09-04 14:11:42 +00:00
parent 5bfbcfb000
commit a4df8e8831
7 changed files with 199 additions and 73 deletions

View File

@ -71,6 +71,10 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
typedef std::map<int, CStack> map_stacks;
map_stacks allStacks = m_cb->battleGetStacks();
const CStack *currentStack = m_cb->battleGetStackByID(currentCreatureId);
if(currentStack->position < 0) //turret
{
return;
}
/*
// find all creatures belong to the enemy
std::for_each(allStacks.begin(), allStacks.end(),
@ -249,6 +253,11 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
BattleAction CBattleLogic::MakeDecision(int stackID)
{
const CStack *currentStack = m_cb->battleGetStackByID(stackID);
if(currentStack->position < 0) //turret
{
return MakeDefend(stackID);
}
MakeStatistics(stackID);
list<int> creatures;

View File

@ -556,33 +556,14 @@ bool CCallback::battleIsStackMine(int ID)
}
return false;
}
bool CCallback::battleCanShoot(int ID, int dest)
{
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
const CStack *our = battleGetStackByID(ID), *dst = battleGetStackByPos(dest);
if(!our || !dst || !gs->curB) return false;
if(!gs->curB) return false;
int ourHero = our->attackerOwned ? gs->curB->hero1 : gs->curB->hero2;
//for(size_t g=0; g<our->effects.size(); ++g)
//{
// if(61 == our->effects[g].id) //forgetfulness
// return false;
//}
if(our->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness
return false;
if(our->hasFeatureOfType(StackFeature::SHOOTER)//it's shooter
&& our->owner != dst->owner
&& dst->alive()
&& (!gs->curB->isStackBlocked(ID) ||
( gs->getHero(ourHero) && gs->getHero(ourHero)->hasBonusOfType(HeroBonus::FREE_SHOOTING) ) )
&& our->shots
)
return true;
return false;
return gs->battleCanShoot(ID, dest);
}
bool CCallback::battleCanCastSpell()

View File

@ -81,6 +81,14 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
pos = myRect;
strongInterest = true;
givenCommand = new CondSh<BattleAction *>(NULL);
//preparing siege info
const CGTownInstance * town = LOCPLINT->cb->battleGetDefendedTown();
if(town)
{
siegeH = new SiegeHelper(town, this);
}
//initializing armies
this->army1 = army1;
this->army2 = army2;
@ -90,14 +98,6 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
newStack(b->second.ID);
}
//preparing siege info
const CGTownInstance * town = LOCPLINT->cb->battleGetDefendedTown();
if(town)
{
siegeH = new SiegeHelper(town, this);
}
//preparing menu background and terrain
if(siegeH)
{
@ -204,7 +204,8 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
//locking occupied positions on batlefield
for(std::map<int, CStack>::iterator it = stacks.begin(); it!=stacks.end(); ++it) //stacks gained at top of this function
{
bfield[it->second.position].accesible = false;
if(it->second.position >= 0) //turrets have position < 0
bfield[it->second.position].accesible = false;
}
//loading projectiles for units
@ -460,10 +461,6 @@ void CBattleInterface::show(SDL_Surface * to)
SDL_SetClipRect(to, &buf); //restoring previous clip_rect
//showing menu background and console
blitAt(menu, pos.x, 556 + pos.y, to);
console->show(to);
//showing buttons
bOptions->show(to);
bSurrender->show(to);
@ -501,7 +498,7 @@ void CBattleInterface::show(SDL_Surface * to)
//double loop because dead stacks should be printed first
for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j)
{
if(j->second.alive())
if(j->second.alive() && j->second.position >= 0) //don't show turrets here
stackAliveByHex[j->second.position].push_back(j->second.ID);
}
std::vector<int> stackDeadByHex[BFIELD_SIZE];
@ -529,7 +526,7 @@ void CBattleInterface::show(SDL_Surface * to)
showAliveStack(stackAliveByHex[b][v], stacks, to);
}
showPieceOfWall(to, b);
showPieceOfWall(to, b, stacks);
}
//units shown
projectileShowHelper(to);//showing projectiles
@ -608,13 +605,17 @@ void CBattleInterface::show(SDL_Surface * to)
SDL_SetClipRect(to, &buf); //restoring previous clip_rect
//showing menu background and console
blitAt(menu, pos.x, 556 + pos.y, to);
console->show(to);
//showing window with result of battle
if(resWindow)
{
resWindow->show(to);
}
//showing in-gmae console
//showing in-game console
LOCPLINT->cingconsole->show(to);
//printing border around interface
@ -1110,11 +1111,34 @@ void CBattleInterface::newStack(int stackID)
{
const CStack * newStack = LOCPLINT->cb->battleGetStackByID(stackID);
std::pair <int, int> coords = CBattleHex::getXYUnitAnim(newStack->position, newStack->owner == attackingHeroInstance->tempOwner, newStack);
creAnims[stackID] = (new CCreatureAnimation(newStack->creature->animDefName));
std::pair <int, int> coords;
if(newStack->position < 0) //turret
{
static const int townToTurretAnim[] = {2, 18, 34, 44, 64, 76, 88, 100, 127};
switch(newStack->position)
{
case -2: //keep
coords = std::make_pair(505, -66);
break;
case -3: //lower turret
coords = std::make_pair(368, 304);
break;
case -4: //upper turret
coords = std::make_pair(339, -192);
break;
}
creAnims[stackID] = new CCreatureAnimation(CGI->creh->creatures[ townToTurretAnim[siegeH->town->town->typeID] ].animDefName);
}
else
{
coords = CBattleHex::getXYUnitAnim(newStack->position, newStack->owner == attackingHeroInstance->tempOwner, newStack);
creAnims[stackID] = new CCreatureAnimation(newStack->creature->animDefName);
}
creAnims[stackID]->setType(2);
creAnims[stackID]->pos = genRect(creAnims[newStack->ID]->fullHeight, creAnims[newStack->ID]->fullWidth, coords.first, coords.second);
creDir[stackID] = newStack->owner == attackingHeroInstance->tempOwner;
creDir[stackID] = newStack->attackerOwned;
}
void CBattleInterface::stackRemoved(int stackID)
@ -2473,24 +2497,67 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
}
}
void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex)
void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::map<int, CStack> & stacks)
{
if(!siegeH)
return;
static const std::map<int, int> hexToPart = boost::assign::map_list_of(12, 8)(16, 1)(29, 7)(50, 2)(62, 12)(78, 6)(112, 10)(147, 5)(165, 11)(182, 4);
static const std::map<int, int> hexToPart = boost::assign::map_list_of(12, 8)(16, 1)(29, 7)(50, 2)(62, 12)(78, 6)(112, 10)(147, 5)(165, 11)(182, 3)(186, 0);
//additionally print bottom wall
if(hex == 182)
{
siegeH->printPartOfWall(to, 4);
}
std::map<int, int>::const_iterator it = hexToPart.find(hex);
if(it != hexToPart.end())
{
siegeH->printPartOfWall(to, it->second);
//print creature in turret
int posToSeek = -1;
switch(it->second)
{
case 3: //bottom turret
posToSeek = -3;
break;
case 8: //upper turret
posToSeek = -4;
break;
case 2: //keep
posToSeek = -2;
break;
}
if(posToSeek != -1)
{
int ID = -1;
for(std::map<int, CStack>::const_iterator it = stacks.begin(); it != stacks.end(); ++it)
{
if(it->second.position == posToSeek)
{
ID = it->second.ID;
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;
}
}
}
//additionally print lower tower
if(hex == 182)
{
siegeH->printPartOfWall(to, 3);
}
}
void CBattleInterface::redrawBackgroundWithHexes(int activeStack)
@ -3321,6 +3388,12 @@ std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, ui16 additInf
return "SG" + townTypeInfixes[town->town->typeID] + "MOAT.BMP";
case 14: //mlip
return "SG" + townTypeInfixes[town->town->typeID] + "MLIP.BMP";
case 15: //keep creature cover
return "SG" + townTypeInfixes[town->town->typeID] + "MANC.BMP";
case 16: //bottom turret creature cover
return "SG" + townTypeInfixes[town->town->typeID] + "TW1C.BMP";
case 17: //upper turret creature cover
return "SG" + townTypeInfixes[town->town->typeID] + "TW2C.BMP";
default:
return "";
}
@ -3350,6 +3423,17 @@ void CBattleInterface::SiegeHelper::printPartOfWall(SDL_Surface * to, int what)
pos.x = CGI->heroh->wallPositions[town->town->typeID][what - 3].first + owner->pos.x;
pos.y = CGI->heroh->wallPositions[town->town->typeID][what - 3].second + owner->pos.y;
break;
case 15: //keep creature cover
pos = Point(owner->pos.w + owner->pos.x - walls[2]->w, 154 + owner->pos.y);
break;
case 16: //bottom turret creature cover
pos.x = CGI->heroh->wallPositions[town->town->typeID][0].first + owner->pos.x;
pos.y = CGI->heroh->wallPositions[town->town->typeID][0].second + owner->pos.y;
break;
case 17: //upper turret creature cover
pos.x = CGI->heroh->wallPositions[town->town->typeID][5].first + owner->pos.x;
pos.y = CGI->heroh->wallPositions[town->town->typeID][5].second + owner->pos.y;
break;
};
if(pos.x != -1)

View File

@ -198,7 +198,7 @@ private:
} * attackingInfo;
void attackingShowHelper();
void showAliveStack(int ID, const std::map<int, CStack> & stacks, SDL_Surface * to); //helper function for function show
void showPieceOfWall(SDL_Surface * to, int hex); //helper function for show
void showPieceOfWall(SDL_Surface * to, int hex, const std::map<int, CStack> & stacks); //helper function for show
void redrawBackgroundWithHexes(int activeStack);
void printConsoleAttacked(int ID, int dmg, int killed, int IDby);
@ -234,7 +234,7 @@ private:
{
private:
static std::string townTypeInfixes[F_NUMBER]; //for internal use only - to build filenames
SDL_Surface * walls[13];
SDL_Surface * walls[18];
const CBattleInterface * owner;
public:
const CGTownInstance * town; //besieged town
@ -242,9 +242,9 @@ private:
~SiegeHelper(); //d-tor
//filename getters
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, 13 - moat, 14 - mlip; additInfo: 1 - intact, 2 - damaged, 3 - destroyed
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, 13 - moat, 14 - mlip, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover; 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
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, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover
friend class CPlayerInterface;
} * siegeH;

View File

@ -307,7 +307,7 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool atta
for(unsigned int g=0; g<stacks.size(); ++g)
{
if(!stacks[g]->alive() || stacks[g]->ID==stackToOmmit) //we don't want to lock position of this stack
if(!stacks[g]->alive() || stacks[g]->ID==stackToOmmit || stacks[g]->position < 0) //we don't want to lock position of this stack (eg. if it's a turret)
continue;
accessibility[stacks[g]->position] = false;
@ -433,6 +433,10 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c
std::vector<int> ret;
bool ac[BFIELD_SIZE];
const CStack *s = getStack(stackID);
if(s->position < 0) //turrets
return std::vector<int>();
std::set<int> occupyable;
getAccessibilityMap(ac, s->hasFeatureOfType(StackFeature::DOUBLE_WIDE), s->attackerOwned, addOccupiable, occupyable, s->hasFeatureOfType(StackFeature::FLYING), stackID);
@ -713,7 +717,7 @@ si32 CStack::Attack() const
if(hasFeatureOfType(StackFeature::IN_FRENZY)) //frenzy for attacker
{
ret += (VLC->spellh->spells[56].powers[getEffect(56)->level]/100.0) * Defense(false);
ret += si32(VLC->spellh->spells[56].powers[getEffect(56)->level]/100.0) * Defense(false);
}
ret += valOfFeatures(StackFeature::ATTACK_BONUS);
@ -2110,10 +2114,25 @@ bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom,
}
std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge)
{
int attackDefenseBonus,
float attackDefenseBonus,
minDmg = attacker->creature->damageMin * attacker->amount,
maxDmg = attacker->creature->damageMax * attacker->amount;
if(attacker->creature->idNumber == 149) //arrow turret
{
switch(attacker->position)
{
case -2: //keep
minDmg = 15;
maxDmg = 15;
break;
case -3: case -4: //turrets
minDmg = 7.5f;
maxDmg = 7.5f;
break;
}
}
if(attacker->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //any siege weapon, but only ballista can attack
{ //minDmg and maxDmg are multiplied by hero attack + 1
minDmg *= attackerHero->getPrimSkillLevel(0) + 1;
@ -2305,16 +2324,16 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
if(attacker->getEffect(42)) //curse handling (rest)
{
minDmg -= VLC->spellh->spells[42].powers[attacker->getEffect(42)->level];
return std::make_pair(minDmg, minDmg);
return std::make_pair(int(minDmg), int(minDmg));
}
else if(attacker->getEffect(41)) //bless handling
{
maxDmg += VLC->spellh->spells[41].powers[attacker->getEffect(41)->level];
return std::make_pair(maxDmg, maxDmg);
return std::make_pair(int(maxDmg), int(maxDmg));
}
else
{
return std::make_pair(minDmg, maxDmg);
return std::make_pair(int(minDmg), int(maxDmg));
}
tlog1 << "We are too far in calculateDmg...\n";
@ -2570,6 +2589,32 @@ std::pair<const CStack *, int> BattleInfo::getNearestStack(const CStack * closes
return std::make_pair<const CStack * , int>(NULL, -1);
}
bool CGameState::battleCanShoot(int ID, int dest)
{
if(!curB)
return false;
const CStack *our = curB->getStack(ID),
*dst = curB->getStackT(dest);
if(!our || !dst) return false;
int ourHero = our->attackerOwned ? curB->hero1 : curB->hero2;
if(our->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness
return false;
if(our->hasFeatureOfType(StackFeature::SHOOTER)//it's shooter
&& our->owner != dst->owner
&& dst->alive()
&& (!curB->isStackBlocked(ID) ||
( getHero(ourHero) && getHero(ourHero)->hasBonusOfType(HeroBonus::FREE_SHOOTING) ) )
&& our->shots
)
return true;
return false;
}
CStack * BattleInfo::getNextStack()
{
CStack *current = getStack(activeStack);

View File

@ -170,7 +170,7 @@ public:
ui32 firstHPleft; //HP of first creature in stack
ui8 owner, slot; //owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
ui16 position; //position on battlefield
si16 position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
si16 shots; //how many shots left
si8 morale, luck; //base stack luck/morale
@ -331,6 +331,7 @@ public:
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
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);
float getMarketEfficiency(int player, int mode=0);
int canBuildStructure(const CGTownInstance *t, int ID);// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements

View File

@ -1047,6 +1047,24 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
stacks.push_back(stack);
}
//war machines added
switch(curB->siege) //adding towers
{
case 3: //castle
{//lower tower / upper tower
CStack * stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -4);
stacks.push_back(stack);
stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -3);
stacks.push_back(stack);
}
case 2: //citadel
{//main tower
CStack * stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -2);
stacks.push_back(stack);
}
}
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
//seting up siege
@ -2468,19 +2486,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
{
CStack *curStack = gs->curB->getStack(ba.stackNumber),
*destStack= gs->curB->getStackT(ba.destinationTile);
if(!curStack //our stack exists
|| !destStack //there is a stack at destination tile
|| !curStack->shots //stack has shots
|| gs->curB->isStackBlocked(curStack->ID) //we are not blocked
|| !curStack->hasFeatureOfType(StackFeature::SHOOTER) //our stack is shooting unit
)
break;
//for(int g=0; g<curStack->effects.size(); ++g)
//{
// if(61 == curStack->effects[g].id) //forgetfulness
// break;
//}
if(curStack->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness
if( !gs->battleCanShoot(ba.stackNumber, ba.destinationTile) )
break;
sendAndApply(&StartAction(ba)); //start shooting