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

* fixed crash on saving when some objects havebeen removed

* support for multi-target attacks/spells in the protocol
* version bumped to 0.7d
This commit is contained in:
Michał W. Urbańczyk 2009-03-21 12:49:58 +00:00
parent 0cf1b2588d
commit b2c4f3e0fd
11 changed files with 86 additions and 53 deletions

View File

@ -97,9 +97,9 @@ void CGeniusAI::battleAttack(BattleAttack *ba)
/**
* called when stack receives damage (after battleAttack())
*/
void CGeniusAI::battleStackAttacked(BattleStackAttacked * bsa)
void CGeniusAI::battleStacksAttacked(std::set<BattleStackAttacked> & bsa)
{
MsgBox("\t\t\tCGeniusAI::battleStackAttacked");
MsgBox("\t\t\tCGeniusAI::battleStacksAttacked");
}
/**
* called by engine when battle starts; side=0 - left, side=1 - right

View File

@ -197,7 +197,7 @@ public:
virtual void actionFinished(const BattleAction *action);//occurs AFTER every action taken by any stack or by the hero
virtual void actionStarted(const BattleAction *action);//occurs BEFORE every action taken by any stack or by the hero
virtual void battleAttack(BattleAttack *ba); //called when stack is performing attack
virtual void battleStackAttacked(BattleStackAttacked * bsa); //called when stack receives damage (after battleAttack())
virtual void battleStacksAttacked(std::set<BattleStackAttacked> & bsa); //called when stack receives damage (after battleAttack())
virtual void battleEnd(BattleResult *br);
virtual void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
virtual void battleStackMoved(int ID, int dest);

View File

@ -75,7 +75,7 @@ public:
virtual void actionStarted(const BattleAction *action){};//occurs BEFORE every action taken by any stack or by the hero
virtual BattleAction activeStack(int stackID)=0; //called when it's turn of that stack
virtual void battleAttack(BattleAttack *ba){}; //called when stack is performing attack
virtual void battleStackAttacked(BattleStackAttacked * bsa){}; //called when stack receives damage (after battleAttack())
virtual void battleStacksAttacked(std::set<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
virtual void battleEnd(BattleResult *br){};
virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
virtual void battleStackMoved(int ID, int dest, int distance){};

View File

@ -2288,18 +2288,24 @@ void CPlayerInterface::battleSpellCasted(SpellCasted *sc)
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->spellCasted(sc);
}
void CPlayerInterface::battleStackAttacked(BattleStackAttacked * bsa)
void CPlayerInterface::battleStacksAttacked(std::set<BattleStackAttacked> & bsa)
{
tlog5 << "CPlayerInterface::battleStackAttacked - locking...";
boost::unique_lock<boost::recursive_mutex> un(*pim);
tlog5 << "done!\n";
if(bsa->isEffect())
{
battleInt->displayEffect(bsa->effect, cb->battleGetStackByID(bsa->stackAttacked)->position);
}
std::vector<CBattleInterface::SStackAttackedInfo> arg;
CBattleInterface::SStackAttackedInfo to_put = {bsa->stackAttacked, bsa->damageAmount, bsa->killedAmount, LOCPLINT->curAction->stackNumber, LOCPLINT->curAction->actionType==7, bsa->killed()};
arg.push_back(to_put);
for(std::set<BattleStackAttacked>::iterator i = bsa.begin(); i != bsa.end(); i++)
{
if(i->isEffect())
{
battleInt->displayEffect(i->effect, cb->battleGetStackByID(i->stackAttacked)->position);
}
CBattleInterface::SStackAttackedInfo to_put = {i->stackAttacked, i->damageAmount, i->killedAmount, LOCPLINT->curAction->stackNumber, LOCPLINT->curAction->actionType==7, i->killed()};
arg.push_back(to_put);
}
battleInt->stacksAreAttacked(arg);
}
void CPlayerInterface::battleAttack(BattleAttack *ba)
@ -2307,7 +2313,7 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
tlog5 << "CPlayerInterface::battleAttack - locking...";
boost::unique_lock<boost::recursive_mutex> un(*pim);
tlog5 << "done!\n";
if(ba->bsa.lucky()) //lucky hit
if(ba->lucky()) //lucky hit
{
CStack *stack = cb->battleGetStackByID(ba->stackAttacking);
std::string hlp = CGI->generaltexth->allTexts[45];
@ -2315,8 +2321,13 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
battleInt->console->addText(hlp);
battleInt->displayEffect(18,stack->position);
}
//TODO: bad luck?
if(ba->shot())
battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked));
{
for(std::set<BattleStackAttacked>::iterator i = ba->bsa.begin(); i != ba->bsa.end(); i++)
battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(i->stackAttacked));
}
else
{
CStack * attacker = cb->battleGetStackByID(ba->stackAttacking);

View File

@ -495,7 +495,7 @@ public:
void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
void battleStackMoved(int ID, int dest, int distance);
void battleSpellCasted(SpellCasted *sc);
void battleStackAttacked(BattleStackAttacked * bsa);
void battleStacksAttacked(std::set<BattleStackAttacked> & bsa);
void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning

View File

@ -335,11 +335,11 @@ void BattleStackMoved::applyFirstCl( CClient *cl )
void BattleStackAttacked::applyCl( CClient *cl )
{
std::set<BattleStackAttacked> bsa;
bsa.insert(*this);
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side1]->battleStackAttacked(this);
if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side2]->battleStackAttacked(this);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1,battleStacksAttacked,bsa);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2,battleStacksAttacked,bsa);
}
void BattleAttack::applyFirstCl( CClient *cl )
@ -352,10 +352,8 @@ void BattleAttack::applyFirstCl( CClient *cl )
void BattleAttack::applyCl( CClient *cl )
{
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side1]->battleStackAttacked(&bsa);
if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side2]->battleStackAttacked(&bsa);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1,battleStacksAttacked,bsa);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2,battleStacksAttacked,bsa);
}
void StartAction::applyFirstCl( CClient *cl )
@ -381,11 +379,14 @@ void SetStackEffect::applyCl( CClient *cl )
sc.id = effect.id;
sc.side = 3; //doesn't matter
sc.skill = effect.level;
sc.tile = GS(cl)->curB->getStack(stack)->position;
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side1]->battleSpellCasted(&sc);
if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side2]->battleSpellCasted(&sc);
BOOST_FOREACH(ui32 stack, stacks)
{
sc.tile = GS(cl)->curB->getStack(stack)->position;
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side1]->battleSpellCasted(&sc);
if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side2]->battleSpellCasted(&sc);
}
}
CGameState* CPackForClient::GS( CClient *cl )

View File

@ -19,7 +19,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
#define THC
#endif
#define NAME_VER ("VCMI 0.7c")
#define NAME_VER ("VCMI 0.7d")
#define CONSOLE_LOGGING_LEVEL 5
#define FILE_LOGGING_LEVEL 6

View File

@ -665,7 +665,7 @@ struct BattleStackAttacked : public CPackForClient//3005
ui32 stackAttacked;
ui32 newAmount, newHP, killedAmount, damageAmount;
ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown; 4 - lucky hit
ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown;
ui32 effect; //set only if flag 2 is present
bool killed() //if target stack was killed
@ -676,14 +676,14 @@ struct BattleStackAttacked : public CPackForClient//3005
{
return flags & 2;
}
bool lucky()
{
return flags & 4;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stackAttacked & newAmount & newHP & flags & killedAmount & damageAmount & effect;
}
bool operator<(const BattleStackAttacked &b) const
{
return stackAttacked < b.stackAttacked;
}
};
struct BattleAttack : public CPackForClient//3006
@ -693,7 +693,7 @@ struct BattleAttack : public CPackForClient//3006
DLL_EXPORT void applyGs(CGameState *gs);
void applyCl(CClient *cl);
BattleStackAttacked bsa;
std::set<BattleStackAttacked> bsa;
ui32 stackAttacking;
ui8 flags;
@ -705,10 +705,19 @@ struct BattleAttack : public CPackForClient//3006
{
return flags & 2;
}
bool killed() //if target stack was killed
bool lucky()
{
return bsa.killed();
return flags & 4;
}
bool unlucky()
{
//TODO: support?
return flags & 8;
}
//bool killed() //if target stack was killed
//{
// return bsa.killed();
//}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & bsa & stackAttacking & flags;
@ -761,11 +770,11 @@ struct SetStackEffect : public CPackForClient //3010
DLL_EXPORT void applyGs(CGameState *gs);
void applyCl(CClient *cl);
ui32 stack;
std::set<ui32> stacks;
CStack::StackEffect effect;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stack & effect;
h & stacks & effect;
}
};

View File

@ -428,7 +428,8 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
attacker->counterAttacks--;
if(shot())
attacker->shots--;
bsa.applyGs(gs);
BOOST_FOREACH(BattleStackAttacked &stackAttacked, bsa)
stackAttacked.applyGs(gs);
}
DLL_EXPORT void StartAction::applyGs( CGameState *gs )
@ -464,8 +465,14 @@ DLL_EXPORT void SpellCasted::applyGs( CGameState *gs )
DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
{
CStack *s = gs->curB->getStack(stack);
s->effects.push_back(effect);
BOOST_FOREACH(ui32 id, stacks)
{
CStack *s = gs->curB->getStack(id);
if(s)
s->effects.push_back(effect);
else
tlog1 << "Cannot find stack " << id << std::endl;
}
}
DLL_EXPORT void YourTurn::applyGs( CGameState *gs )

13
map.h
View File

@ -389,11 +389,14 @@ struct DLL_EXPORT Mapa : public CMapHeader
CGObjectInstance *&obj = objects[i];
h & obj;
si32 shlp;
//definfo
h & (h.saving ? (shlp=obj->defInfo->serial) : shlp); //read / write pos of definfo in defs vector
if(!h.saving)
obj->defInfo = defy[shlp];
if (obj)
{
si32 shlp;
//definfo
h & (h.saving ? (shlp=obj->defInfo->serial) : shlp); //read / write pos of definfo in defs vector
if(!h.saving)
obj->defInfo = defy[shlp];
}
}
if(!h.saving)

View File

@ -485,14 +485,16 @@ void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, CStack *def)
void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
{
bat.stackAttacking = att->ID;
bat.bsa.stackAttacked = def->ID;
bat.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());//counting dealt damage
std::set<BattleStackAttacked>::iterator bsa = bat.bsa.insert(BattleStackAttacked()).first;
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());//counting dealt damage
if(att->Luck() > 0 && rand()%24 < att->Luck())
{
bat.bsa.damageAmount *= 2;
bat.bsa.flags |= 4;
bsa->damageAmount *= 2;
bsa->flags |= 4;
}
prepareAttacked(bat.bsa,def);
prepareAttacked(*bsa,def);
}
void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
{
@ -2226,7 +2228,7 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
#define SPELL_CAST_TEMPLATE_1(NUMBER, DURATION) SetStackEffect sse; \
if(getSchoolLevel(h,s) < 3) /*not expert */ \
{ \
sse.stack = gs->curB->getStackT(ba.destinationTile)->ID; \
sse.stacks.insert(gs->curB->getStackT(ba.destinationTile)->ID); \
sse.effect.id = (NUMBER); \
sse.effect.level = getSchoolLevel(h,s); \
sse.effect.turnsRemain = (DURATION); /*! - any duration */ \
@ -2241,7 +2243,7 @@ if(getSchoolLevel(h,s) < 3) /*not expert */ \
||(VLC->spellh->spells[ba.additionalInfo].positiveness <= 0 && gs->curB->stacks[it]->owner != h->tempOwner ) \
) \
{ \
sse.stack = gs->curB->stacks[it]->ID; \
sse.stacks.insert(gs->curB->stacks[it]->ID); \
sse.effect.id = (NUMBER); \
sse.effect.level = getSchoolLevel(h,s); \
sse.effect.turnsRemain = (DURATION); \