1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

* second part of sieges

* minor changes
This commit is contained in:
mateuszb 2009-08-26 14:09:55 +00:00
parent af0cfe13a4
commit adcfb3c020
11 changed files with 397 additions and 100 deletions

View File

@ -609,6 +609,15 @@ const CGTownInstance *CCallback::battleGetDefendedTown()
return gs->map->towns[gs->curB->tid];
}
ui8 CCallback::battleGetWallState(int partOfWall)
{
if(!gs->curB || gs->curB->siege == 0)
{
return 0;
}
return gs->curB->si.wallState[partOfWall];
}
void CCallback::swapGarrisonHero( const CGTownInstance *town )
{
if(town->tempOwner != player) return;

View File

@ -175,6 +175,7 @@ public:
virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
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
};
struct HeroMoveDetails
@ -277,6 +278,7 @@ public:
bool battleCanCastSpell(); //returns true, if caller can cast a spell
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
//XXX hmmm _tmain on _GNUC_ wtf?
//friends

View File

@ -95,13 +95,13 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
const CGTownInstance * town = LOCPLINT->cb->battleGetDefendedTown();
if(town)
{
siegeH = new SiegeHelper(town);
siegeH = new SiegeHelper(town, this);
}
//preparing menu background and terrain
if(siegeH)
{
background = BitmapHandler::loadBitmap( siegeH->getBackgroundName() );
background = BitmapHandler::loadBitmap( siegeH->getSiegeName(0) );
}
else
{
@ -476,6 +476,12 @@ void CBattleInterface::show(SDL_Surface * to)
blitAt(images[((animCount+1)/(4/settings.animSpeed))%images.size()].bitmap, x, y, to);
}
//showing siege background
if(siegeH)
{
siegeH->printSiegeBackground(to);
}
//showing hero animations
if(attackingHero)
attackingHero->show(to);
@ -512,94 +518,10 @@ void CBattleInterface::show(SDL_Surface * to)
{
int curStackID = stackAliveByHex[b][v];
if(creAnims.find(curStackID) == creAnims.end()) //eg. for summoned but not yet handled stacks
continue;
const CStack &curStack = stacks[curStackID];
int animType = creAnims[curStackID]->getType();
int affectingSpeed = settings.animSpeed;
if(animType == 1 || animType == 2) //standing stacks should not stand faster :)
affectingSpeed = 2;
bool incrementFrame = (animCount%(4/affectingSpeed)==0) && animType!=5 && animType!=20 && animType!=3 && animType!=2;
if(animType == 2)
{
if(standingFrame.find(curStackID)!=standingFrame.end())
{
incrementFrame = (animCount%(8/affectingSpeed)==0);
if(incrementFrame)
{
++standingFrame[curStackID];
if(standingFrame[curStackID] == creAnims[curStackID]->framesInGroup(2))
{
standingFrame.erase(standingFrame.find(curStackID));
}
}
}
else
{
if((rand()%50) == 0)
{
standingFrame.insert(std::make_pair(curStackID, 0));
}
}
}
creAnims[curStackID]->nextFrame(to, creAnims[curStackID]->pos.x + pos.x, creAnims[curStackID]->pos.y + pos.y, creDir[curStackID], animCount, incrementFrame, curStackID==activeStack, curStackID==mouseHoveredStack); //increment always when moving, never if stack died
//printing amount
if(curStack.amount > 0 //don't print if stack is not alive
&& (!LOCPLINT->curAction
|| (LOCPLINT->curAction->stackNumber != curStackID //don't print if stack is currently taking an action
&& (LOCPLINT->curAction->actionType != 6 || curStack.position != LOCPLINT->curAction->additionalInfo) //nor if it's an object of attack
&& (LOCPLINT->curAction->destinationTile != curStack.position) //nor if it's on destination tile for current action
)
)
&& !curStack.hasFeatureOfType(StackFeature::SIEGE_WEAPON) //and not a war machine...
)
{
int xAdd = curStack.attackerOwned ? 220 : 202;
//blitting amoutn background box
SDL_Surface *amountBG = NULL;
if(curStack.effects.size() == 0)
{
amountBG = amountNormal;
}
else
{
int pos=0; //determining total positiveness of effects
for(int c=0; c<curStack.effects.size(); ++c)
{
pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness;
}
if(pos > 0)
{
amountBG = amountPositive;
}
else if(pos < 0)
{
amountBG = amountNegative;
}
else
{
amountBG = amountEffNeutral;
}
}
SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[curStackID]->pos.x + xAdd + pos.x, creAnims[curStackID]->pos.y + 260 + pos.y));
//blitting amount
CSDL_Ext::printAtMiddleWB(
makeNumberShort(curStack.amount),
creAnims[curStackID]->pos.x + xAdd + 14 + pos.x,
creAnims[curStackID]->pos.y + 260 + 4 + pos.y,
GEOR13,
20,
zwykly,
to
);
}
showAliveStack(stackAliveByHex[b][v], stacks, to);
}
showPieceOfWall(to, b);
}
//units shown
projectileShowHelper(to);//showing projectiles
@ -2269,7 +2191,7 @@ void CBattleInterface::attackingShowHelper()
if (attackingInfo->sh == -1)
attackingInfo->sh = CGI->soundh->playSound(aStack->creature->sounds.attack);
std::map<int, int> dirToType = boost::assign::map_list_of (0, 11)(1, 11)(2, 12)(3, 13)(4, 13)(5, 12);
static std::map<int, int> dirToType = boost::assign::map_list_of (0, 11)(1, 11)(2, 12)(3, 13)(4, 13)(5, 12);
int type; //dependent on attack direction
if(aStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
{
@ -2410,6 +2332,117 @@ void CBattleInterface::attackingShowHelper()
}
}
void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stacks, SDL_Surface * to)
{
if(creAnims.find(ID) == creAnims.end()) //eg. for summoned but not yet handled stacks
return;
const CStack &curStack = stacks.find(ID)->second;
int animType = creAnims[ID]->getType();
int affectingSpeed = settings.animSpeed;
if(animType == 1 || animType == 2) //standing stacks should not stand faster :)
affectingSpeed = 2;
bool incrementFrame = (animCount%(4/affectingSpeed)==0) && animType!=5 && animType!=20 && animType!=3 && animType!=2;
if(animType == 2)
{
if(standingFrame.find(ID)!=standingFrame.end())
{
incrementFrame = (animCount%(8/affectingSpeed)==0);
if(incrementFrame)
{
++standingFrame[ID];
if(standingFrame[ID] == creAnims[ID]->framesInGroup(2))
{
standingFrame.erase(standingFrame.find(ID));
}
}
}
else
{
if((rand()%50) == 0)
{
standingFrame.insert(std::make_pair(ID, 0));
}
}
}
creAnims[ID]->nextFrame(to, creAnims[ID]->pos.x + pos.x, creAnims[ID]->pos.y + pos.y, creDir[ID], animCount, incrementFrame, ID==activeStack, ID==mouseHoveredStack); //increment always when moving, never if stack died
//printing amount
if(curStack.amount > 0 //don't print if stack is not alive
&& (!LOCPLINT->curAction
|| (LOCPLINT->curAction->stackNumber != ID //don't print if stack is currently taking an action
&& (LOCPLINT->curAction->actionType != 6 || curStack.position != LOCPLINT->curAction->additionalInfo) //nor if it's an object of attack
&& (LOCPLINT->curAction->destinationTile != curStack.position) //nor if it's on destination tile for current action
)
)
&& !curStack.hasFeatureOfType(StackFeature::SIEGE_WEAPON) //and not a war machine...
)
{
int xAdd = curStack.attackerOwned ? 220 : 202;
//blitting amoutn background box
SDL_Surface *amountBG = NULL;
if(curStack.effects.size() == 0)
{
amountBG = amountNormal;
}
else
{
int pos=0; //determining total positiveness of effects
for(int c=0; c<curStack.effects.size(); ++c)
{
pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness;
}
if(pos > 0)
{
amountBG = amountPositive;
}
else if(pos < 0)
{
amountBG = amountNegative;
}
else
{
amountBG = amountEffNeutral;
}
}
SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[ID]->pos.x + xAdd + pos.x, creAnims[ID]->pos.y + 260 + pos.y));
//blitting amount
CSDL_Ext::printAtMiddleWB(
makeNumberShort(curStack.amount),
creAnims[ID]->pos.x + xAdd + 14 + pos.x,
creAnims[ID]->pos.y + 260 + 4 + pos.y,
GEOR13,
20,
zwykly,
to
);
}
}
void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex)
{
if(!siegeH)
return;
static std::map<int, int> hexToPart = boost::assign::map_list_of(12, 8)(29, 7)(62, 12)(78, 6)(112, 10)(147, 5)(165, 11)(182, 4);
std::map<int, int>::const_iterator it = hexToPart.find(hex);
if(it != hexToPart.end())
{
siegeH->printPartOfWall(to, it->second);
}
//additionally print lower tower
if(hex == 182)
{
siegeH->printPartOfWall(to, 3);
}
}
void CBattleInterface::redrawBackgroundWithHexes(int activeStack)
{
shadedHexes = LOCPLINT->cb->battleGetAvailableHexes(activeStack, true);
@ -3169,12 +3202,96 @@ void CBattleOptionsWindow::bExitf()
std::string CBattleInterface::SiegeHelper::townTypeInfixes[F_NUMBER] = {"CS", "RM", "TW", "IN", "NC", "DN", "ST", "FR" "EL"};
CBattleInterface::SiegeHelper::SiegeHelper(const CGTownInstance *siegeTown)
: town(siegeTown)
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) );
}
}
std::string CBattleInterface::SiegeHelper::getBackgroundName() const
CBattleInterface::SiegeHelper::~SiegeHelper()
{
return "SG" + townTypeInfixes[town->town->typeID] + "BACK.BMP";
if(backWall)
SDL_FreeSurface(backWall);
for(int g=0; g<ARRAY_COUNT(walls); ++g)
{
SDL_FreeSurface(walls[g]);
}
}
std::string CBattleInterface::SiegeHelper::getSiegeName(ui16 what, ui16 additInfo) const
{
char buf[100];
itoa(additInfo, buf, 10);
std::string addit(buf);
switch(what)
{
case 0: //background
return "SG" + townTypeInfixes[town->town->typeID] + "BACK.BMP";
case 1: //background wall
return "SG" + townTypeInfixes[town->town->typeID] + "TPW1.BMP";
case 2: //keep
return "SG" + townTypeInfixes[town->town->typeID] + "MAN" + addit + ".BMP";
case 3: //bottom tower
return "SG" + townTypeInfixes[town->town->typeID] + "TW1" + addit + ".BMP";
case 4: //bottom wall
return "SG" + townTypeInfixes[town->town->typeID] + "WA1" + addit + ".BMP";
case 5: //below gate
return "SG" + townTypeInfixes[town->town->typeID] + "WA3" + addit + ".BMP";
case 6: //over gate
return "SG" + townTypeInfixes[town->town->typeID] + "WA4" + addit + ".BMP";
case 7: //upper wall
return "SG" + townTypeInfixes[town->town->typeID] + "WA6" + addit + ".BMP";
case 8: //upper tower
return "SG" + townTypeInfixes[town->town->typeID] + "TW2" + addit + ".BMP";
case 9: //gate
return "SG" + townTypeInfixes[town->town->typeID] + "DRW" + addit + ".BMP";
case 10: //gate arch
return "SG" + townTypeInfixes[town->town->typeID] + "ARCH.BMP";
case 11: //bottom static wall
return "SG" + townTypeInfixes[town->town->typeID] + "WA2.BMP";
case 12: //upper static wall
return "SG" + townTypeInfixes[town->town->typeID] + "WA5.BMP";
default:
return "";
}
}
void CBattleInterface::SiegeHelper::printSiegeBackground(SDL_Surface * to)
{
blitAt(backWall, owner->pos.w + owner->pos.x - backWall->w, 50 + owner->pos.y, to);
}
void CBattleInterface::SiegeHelper::printPartOfWall(SDL_Surface * to, int what)
{
Point pos = Point(-1, -1);
switch(what)
{
case 2: //keep
pos = Point(owner->pos.w + owner->pos.x - walls[what-2]->w, 154 + owner->pos.y);
break;
case 3: //bottom tower
case 4: //bottom wall
case 5: //below gate
case 6: //over gate
case 7: //upper wall
case 8: //upper tower
case 9: //gate
case 10: //gate arch
case 11: //bottom static wall
case 12: //upper static wall
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;
};
if(pos.x != -1)
{
blitAt(walls[what-2], pos.x, pos.y, to);
}
}

View File

@ -197,6 +197,8 @@ private:
int sh; // temporary sound handler
} * 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 redrawBackgroundWithHexes(int activeStack);
void printConsoleAttacked(int ID, int dmg, int killed, int IDby);
@ -231,12 +233,19 @@ private:
{
private:
static std::string townTypeInfixes[F_NUMBER]; //for internal use only - to build filenames
SDL_Surface * backWall;
SDL_Surface * walls[11];
const CBattleInterface * owner;
public:
const CGTownInstance * town; //besieged town
SiegeHelper(const CGTownInstance * siegeTown); //c-tor
SiegeHelper(const CGTownInstance * siegeTown, const CBattleInterface * _owner); //c-tor
~SiegeHelper(); //d-tor
//filename getters
std::string getBackgroundName() const;
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 printSiegeBackground(SDL_Surface * to);
void printPartOfWall(SDL_Surface * to, int what);//what: 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
} * siegeH;
public:
CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect); //c-tor

100
config/wall_pos.txt Normal file
View File

@ -0,0 +1,100 @@
//this file is a description of positions of wall parts' positions, following lines contain positions of: bottom tower, bottom wall, wall below gate, wall over gate, upper wall, upper tower, gate, gate arch, bottom static wall and upper static wall (x, y)
//castle
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//rampart
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//tower
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//inferno
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//necropolis
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//dungeon
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//stronghold
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//fortress
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54
//conflux
602 494
557 469
474 300
491 188
544 57
567 16
391 260
471 164
518 305
500 54

View File

@ -43,7 +43,7 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
{
std::vector<ui16> slots;
slots += 17, 16, 15,14,13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0;
std::map<char, CArtifact::EartClass> classes =
static std::map<char, CArtifact::EartClass> classes =
map_list_of('S',CArtifact::ART_SPECIAL)('T',CArtifact::ART_TREASURE)('N',CArtifact::ART_MINOR)('J',CArtifact::ART_MAJOR)('R',CArtifact::ART_RELIC);
std::string buf = bitmaph->getTextFile("ARTRAITS.TXT"), dump, pom;
int it=0;

View File

@ -123,6 +123,36 @@ CHeroHandler::~CHeroHandler()
CHeroHandler::CHeroHandler()
{}
void CHeroHandler::loadWallPositions()
{
std::ifstream inp;
inp.open("config" PATHSEPARATOR "wall_pos.txt", std::ios_base::in|std::ios_base::binary);
if(!inp.is_open())
{
tlog1<<"missing file: config/wall_pos.txt"<<std::endl;
}
else
{
const int MAX_BUF = 2000;
char buf[MAX_BUF+1];
inp.getline(buf, MAX_BUF);
std::string dump;
for(int g=0; g<ARRAY_COUNT(wallPositions); ++g)
{
inp >> dump;
for(int b=0; b<10; ++b)
{
std::pair<int, int> pt;
inp >> pt.first;
inp >> pt.second;
wallPositions[g].push_back(pt);
}
}
}
inp.close();
}
void CHeroHandler::loadObstacles()
{
std::ifstream inp;

View File

@ -108,6 +108,9 @@ public:
};
std::vector<SBallisticsLevelInfo> ballistics; //info about ballistics ability per level; [0] - none; [1] - basic; [2] - adv; [3] - expert
std::vector<std::pair<int, int>> wallPositions[F_NUMBER]; //positions of different pieces of wall <x, y>
void loadWallPositions();
std::map<int, CObstacleInfo> obstacles; //info about obstacles that may be placed on battlefield
std::vector<int> nativeTerrains; //info about native terrains of different factions
@ -126,7 +129,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & heroClasses & heroes & expPerLevel & ballistics & obstacles & nativeTerrains;
h & heroClasses & heroes & expPerLevel & ballistics & wallPositions & obstacles & nativeTerrains;
if(!h.saving)
{
//restore class pointers

View File

@ -105,6 +105,17 @@ 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
template <typename Handler> void serialize(Handler &h, const int version)
{
h & wallState;
}
};
struct DLL_EXPORT BattleInfo
{
ui8 side1, side2; //side1 - attacker, side2 - defender
@ -117,11 +128,12 @@ struct DLL_EXPORT BattleInfo
std::vector<CStack*> stacks;
std::vector<CObstacleInstance> obstacles;
ui8 castSpells[2]; //[0] - attacker, [1] - defender
SiegeInfo si;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & army1 & army2 & hero1 & hero2 & obstacles
& castSpells;
& castSpells & si;
}
CStack * getNextStack(); //which stack will have turn after current one
std::vector<CStack> getStackQueue(); //returns stack in order of their movement action

View File

@ -174,6 +174,7 @@ void LibClasses::init()
heroh = new CHeroHandler;
heroh->loadHeroes();
heroh->loadObstacles();
heroh->loadWallPositions();
tlog0 <<"\tHero handler: "<<pomtime.getDif()<<std::endl;
arth = new CArtHandler;

View File

@ -997,9 +997,23 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
stacks.push_back(stack);
}
}
if(town && hero1) //catapult
{
CStack * stack = BattleInfo::generateNewStack(hero1, 145, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120);
stacks.push_back(stack);
}
//war machines added
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
//seting up siege
if(town)
{
for(int b=0; b<ARRAY_COUNT(curB->si.wallState); ++b)
{
curB->si.wallState[b] = 1;
}
}
//randomize obstacles
bool obAv[BFIELD_SIZE]; //availability of hexes for obstacles;
std::vector<int> possibleObstacles;
@ -2569,7 +2583,7 @@ static ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster,
//15 - magic arrows, 16 - ice bolt, 17 - lightning bolt, 18 - implosion, 20 - frost ring, 21 - fireball, 22 - inferno, 23 - meteor shower,
//24 - death ripple, 25 - destroy undead, 26 - armageddon
std::map <int, int> dmgMultipliers = boost::assign::map_list_of(15, 10)(16, 20)(17, 25)(18, 75)(20, 10)(21, 10)(22, 10)(23, 10)(24, 5)(25, 10)(26, 50);
static std::map <int, int> dmgMultipliers = boost::assign::map_list_of(15, 10)(16, 20)(17, 25)(18, 75)(20, 10)(21, 10)(22, 10)(23, 10)(24, 5)(25, 10)(26, 50);
ret = caster->getPrimSkillLevel(2) * dmgMultipliers[sp->id] + sp->powers[caster->getSpellSchoolLevel(sp)];