From 42773e67f24e699eaac7c4630b076e9248a3deb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Sat, 28 Mar 2009 00:38:48 +0000 Subject: [PATCH] * amounts of units taking actions / being an object of actions won't be shown until action ends * provisional support for "Save" button in System Options Window * forbidden buildings will be shown as forbidden, even if there are no res / other conditions are not fulfilled * improved damage calculation formula * several minor improvements --- CBattleInterface.cpp | 42 +++++++++++++-------- CCallback.cpp | 5 +++ CCallback.h | 2 + CGameInterface.h | 2 +- CGameState.cpp | 79 +++++++++++++++++++++++----------------- CMessage.cpp | 2 +- CPlayerInterface.cpp | 31 ++++++++++++++-- CPlayerInterface.h | 9 +++-- CPreGame.cpp | 4 +- hch/CCreatureHandler.cpp | 10 ++++- hch/CObjectHandler.cpp | 2 +- lib/NetPacks.h | 2 +- server/CGameHandler.cpp | 1 + 13 files changed, 128 insertions(+), 63 deletions(-) diff --git a/CBattleInterface.cpp b/CBattleInterface.cpp index 6bf5deef7..b2ca315be 100644 --- a/CBattleInterface.cpp +++ b/CBattleInterface.cpp @@ -485,19 +485,22 @@ void CBattleInterface::show(SDL_Surface * to) { for(size_t v=0; vgetType(); + int curStackID = stackAliveByHex[b][v]; + const CStack &curStack = stacks[curStackID]; + int animType = creAnims[curStackID]->getType(); bool incrementFrame = (animCount%(4/animSpeed)==0) && animType!=5 && animType!=20 && animType!=3 && animType!=2; + if(animType == 2) { - if(standingFrame.find(stackAliveByHex[b][v])!=standingFrame.end()) + if(standingFrame.find(curStackID)!=standingFrame.end()) { incrementFrame = (animCount%(8/animSpeed)==0); if(incrementFrame) { - ++standingFrame[stackAliveByHex[b][v]]; - if(standingFrame[stackAliveByHex[b][v]] == creAnims[stackAliveByHex[b][v]]->framesInGroup(2)) + ++standingFrame[curStackID]; + if(standingFrame[curStackID] == creAnims[curStackID]->framesInGroup(2)) { - standingFrame.erase(standingFrame.find(stackAliveByHex[b][v])); + standingFrame.erase(standingFrame.find(curStackID)); } } } @@ -505,29 +508,36 @@ void CBattleInterface::show(SDL_Surface * to) { if((rand()%50) == 0) { - standingFrame.insert(std::make_pair(stackAliveByHex[b][v], 0)); + standingFrame.insert(std::make_pair(curStackID, 0)); } } } - creAnims[stackAliveByHex[b][v]]->nextFrame(to, creAnims[stackAliveByHex[b][v]]->pos.x + pos.x, creAnims[stackAliveByHex[b][v]]->pos.y + pos.y, creDir[stackAliveByHex[b][v]], animCount, incrementFrame, stackAliveByHex[b][v]==activeStack, stackAliveByHex[b][v]==mouseHoveredStack); //increment always when moving, never if stack died + 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(stacks[stackAliveByHex[b][v]].amount > 0) //don't print if stack is not alive + 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 + ) + ) { - int xAdd = stacks[stackAliveByHex[b][v]].attackerOwned ? 220 : 202; + int xAdd = curStack.attackerOwned ? 220 : 202; //blitting amoutn background box SDL_Surface *amountBG = NULL; - if(stacks[stackAliveByHex[b][v]].effects.size() == 0) + if(curStack.effects.size() == 0) { amountBG = amountNormal; } else { int pos=0; //determining total positiveness of effects - for(int c=0; cspellh->spells[ stacks[stackAliveByHex[b][v]].effects[c].id ].positiveness; + pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness; } if(pos > 0) { @@ -542,14 +552,14 @@ void CBattleInterface::show(SDL_Surface * to) amountBG = amountEffNeutral; } } - SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[stackAliveByHex[b][v]]->pos.x + xAdd + pos.x, creAnims[stackAliveByHex[b][v]]->pos.y + 260 + pos.y)); + 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 std::stringstream ss; - ss<pos.x + xAdd + 14 + pos.x, - creAnims[stackAliveByHex[b][v]]->pos.y + 260 + 4 + pos.y, + creAnims[curStackID]->pos.x + xAdd + 14 + pos.x, + creAnims[curStackID]->pos.y + 260 + 4 + pos.y, GEOR13, 20, zwykly, diff --git a/CCallback.cpp b/CCallback.cpp index 3b11c3495..b21773775 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -698,4 +698,9 @@ CPath * CCallback::getPath( int3 src, int3 dest, const CGHeroInstance * hero ) { boost::shared_lock lock(*gs->mx); return gs->getPath(src,dest,hero); +} + +void CCallback::save( const std::string &fname ) +{ + cl->save(fname); } \ No newline at end of file diff --git a/CCallback.h b/CCallback.h index 67a35bbda..6240b2b1f 100644 --- a/CCallback.h +++ b/CCallback.h @@ -47,6 +47,7 @@ public: virtual void setFormation(const CGHeroInstance * hero, bool tight)=0; virtual void setSelection(const CArmedInstance * obj)=0; virtual void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)=0; + virtual void save(const std::string &fname) = 0; //get info virtual bool verifyPath(CPath * path, bool blockSea)const =0; @@ -136,6 +137,7 @@ public: void setFormation(const CGHeroInstance * hero, bool tight); void setSelection(const CArmedInstance * obj); void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero); + void save(const std::string &fname); //get info bool verifyPath(CPath * path, bool blockSea) const; diff --git a/CGameInterface.h b/CGameInterface.h index 8082479ed..006f855c6 100644 --- a/CGameInterface.h +++ b/CGameInterface.h @@ -62,7 +62,7 @@ public: virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){}; virtual void init(ICallback * CB){}; virtual void receivedResource(int type, int val){}; - virtual void showInfoDialog(std::string &text, const std::vector &components){}; + virtual void showInfoDialog(const std::string &text, const std::vector &components){}; virtual void showSelDialog(std::string &text, const std::vector &components, ui32 askID){}; virtual void showYesNoDialog(std::string &text, const std::vector &components, ui32 askID){}; virtual void tileHidden(const std::set &pos){}; diff --git a/CGameState.cpp b/CGameState.cpp index d05142b51..3667461f8 100644 --- a/CGameState.cpp +++ b/CGameState.cpp @@ -1455,12 +1455,6 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID ) { int ret = 7; //allowed by default - //can we build it? - if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end()) - ret = 2; //forbidden - else if(t->builded >= MAX_BUILDING_PER_TURN) - ret = 5; //building limit - //checking resources CBuilding * pom = VLC->buildh->buildings[t->subID][ID]; for(int res=0;res<7;res++) //TODO: support custom amount of resources @@ -1478,6 +1472,12 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID ) ret = 8; //lack of requirements - cannot build } + //can we build it? + if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end()) + ret = 2; //forbidden + else if(t->builded >= MAX_BUILDING_PER_TURN) + ret = 5; //building limit + if(ID == 13) //capitol { for(int in = 0; in < map->towns.size(); in++) @@ -1672,17 +1672,22 @@ bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting) { - int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0); + int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0), + defenderDefenseBonus = defender->creature->defence + (defendingHero ? defendingHero->getPrimSkillLevel(1) : 0), + attackDefenseBonus = 0, + minDmg = attacker->creature->damageMin * attacker->amount, + maxDmg = attacker->creature->damageMax * attacker->amount; + + //calculating total attack/defense skills modifier if(attacker->getEffect(56)) //frenzy for attacker { attackerAttackBonus += (VLC->spellh->spells[attacker->getEffect(56)->id].powers[attacker->getEffect(56)->level]/100.0) *(attacker->creature->defence + (attackerHero ? attackerHero->getPrimSkillLevel(1) : 0)); } - int defenderDefenseBonus = defender->creature->defence + (defendingHero ? defendingHero->getPrimSkillLevel(1) : 0); if(defender->getEffect(56)) //frenzy for defender { defenderDefenseBonus = 0; } - int attackDefenseBonus = attackerAttackBonus - defenderDefenseBonus; + attackDefenseBonus = attackerAttackBonus - defenderDefenseBonus; if(defender->getEffect(48)) //defender's prayer handling { attackDefenseBonus -= VLC->spellh->spells[defender->getEffect(48)->id].powers[defender->getEffect(48)->level]; @@ -1703,27 +1708,10 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con { attackDefenseBonus += VLC->spellh->spells[attacker->getEffect(43)->id].powers[attacker->getEffect(43)->level]; } - int damageBase = 0; - if(attacker->getEffect(42)) //curse handling (partial, the rest is below) - { - damageBase = attacker->creature->damageMin; - damageBase -= VLC->spellh->spells[attacker->getEffect(42)->id].powers[attacker->getEffect(42)->level]; - } - else if(attacker->getEffect(41)) //bless handling - { - damageBase = attacker->creature->damageMax; - damageBase += VLC->spellh->spells[attacker->getEffect(41)->id].powers[attacker->getEffect(41)->level]; - } - else if(attacker->creature->damageMax == attacker->creature->damageMin) //constant damage - { - damageBase = attacker->creature->damageMin; - } - else - { - damageBase = rand()%(attacker->creature->damageMax - attacker->creature->damageMin) + attacker->creature->damageMin + 1; - } float dmgBonusMultiplier = 1.0f; + + //bonus from attack/defense skills if(attackDefenseBonus < 0) //decreasing dmg { if(0.02f * (-attackDefenseBonus) > 0.3f) @@ -1746,6 +1734,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con dmgBonusMultiplier += 0.05f * attackDefenseBonus; } } + //handling secondary abilities if(attackerHero) { @@ -1766,7 +1755,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con } else { - switch(attackerHero->getSecSkillLevel(22)) //offence + switch(attackerHero->getSecSkillLevel(22)) //offense { case 1: //basic dmgBonusMultiplier *= 1.1f; @@ -1782,7 +1771,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con } if(defendingHero) { - switch(defendingHero->getSecSkillLevel(23)) //armourer + switch(defendingHero->getSecSkillLevel(23)) //armorer { case 1: //basic dmgBonusMultiplier *= 0.95f; @@ -1803,20 +1792,44 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con else //adv or expert dmgBonusMultiplier *= 0.7f; } - if(shooting && defender->getEffect(28)) //air shield + else if(shooting && defender->getEffect(28)) //air shield { if(defender->getEffect(28)->level<=1) //none or basic dmgBonusMultiplier *= 0.75f; else //adv or expert dmgBonusMultiplier *= 0.5f; } - if(attacker->getEffect(42)) //curse, second part of handling + if(attacker->getEffect(42)) //curse handling (partial, the rest is below) { if(attacker->getEffect(42)->level>=2) //adv or expert dmgBonusMultiplier *= 0.8f; } - return int( (float)damageBase * (float)attacker->amount * dmgBonusMultiplier ); + + + minDmg *= dmgBonusMultiplier; + maxDmg *= dmgBonusMultiplier; + + if(attacker->getEffect(42)) //curse handling (rest) + { + minDmg -= VLC->spellh->spells[attacker->getEffect(42)->id].powers[attacker->getEffect(42)->level]; + return minDmg; + } + else if(attacker->getEffect(41)) //bless handling + { + maxDmg += VLC->spellh->spells[attacker->getEffect(41)->id].powers[attacker->getEffect(41)->level]; + return maxDmg; + } + else + { + if(minDmg != maxDmg) + return minDmg + rand() % (maxDmg - minDmg + 1); + else + return minDmg; + } + + tlog1 << "We are too far in calculateDmg...\n"; + return -1; } void BattleInfo::calculateCasualties( std::set > *casualties ) diff --git a/CMessage.cpp b/CMessage.cpp index 253fef28d..e23ebede2 100644 --- a/CMessage.cpp +++ b/CMessage.cpp @@ -279,7 +279,7 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_ curh += imgToBmp; blitAt(bitmap,(ret->w/2)-(bitmap->w/2),curh,ret); curh += bitmap->h + 5; - CSDL_Ext::printAtMiddle(sub,ret->w/2,curh+( ((*txtg)[0][0]->h) / 2 ),GEOR13,zwykly,ret); + CSDL_Ext::printAtMiddle(sub,ret->w/2,curh+10,GEOR13,zwykly,ret); delete tekst; delete txtg; return ret; diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index 1957588f4..e3ea58a1b 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1081,6 +1082,7 @@ void TimeInterested::deactivate() CPlayerInterface::CPlayerInterface(int Player, int serial) { LOCPLINT = this; + curAction = NULL; curint = NULL; playerID=Player; serialID=serial; @@ -2374,7 +2376,7 @@ void CPlayerInterface::showComp(SComponent comp) adventureInt->infoBar.showComp(&comp,4000); } -void CPlayerInterface::showInfoDialog(std::string &text, const std::vector &components) +void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector &components) { std::vector intComps; for(int i=0;i & components) +void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector & components, bool deactivateCur) { boost::unique_lock un(*pim); @@ -2392,9 +2394,12 @@ void CPlayerInterface::showInfoDialog(std::string &text, const std::vectorbuttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint); showingDialog->set(true); - curint->deactivate(); //dezaktywacja starego interfejsu + if(deactivateCur) + { + temp->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint); + curint->deactivate(); //dezaktywacja starego interfejsu + } temp->activate(); LOCPLINT->objsToBlit.push_back(temp); } @@ -4249,6 +4254,8 @@ CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface CSDL_Ext::printAt(CGI->generaltexth->allTexts[577], 283, 217, GEOR16, zwykly, background); //spell book animation //setting up buttons + save = new AdventureMapButton (CGI->generaltexth->zelp[321].first, CGI->generaltexth->zelp[321].second, boost::bind(&CSystemOptionsWindow::bsavef, this), 516, 354, "SOSAVE.DEF", SDLK_s); + std::swap(save->imgs[0][0], save->imgs[0][1]); quitGame = new AdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second, boost::bind(&CSystemOptionsWindow::bquitf, this), 405, 471, "soquit.def", SDLK_q); std::swap(quitGame->imgs[0][0], quitGame->imgs[0][1]); backToMap = new AdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second, boost::bind(&CSystemOptionsWindow::breturnf, this), 516, 471, "soretrn.def", SDLK_RETURN); @@ -4274,6 +4281,7 @@ CSystemOptionsWindow::~CSystemOptionsWindow() { SDL_FreeSurface(background); + delete save; delete quitGame; delete backToMap; delete heroMoveSpeed; @@ -4303,8 +4311,21 @@ void CSystemOptionsWindow::breturnf() LOCPLINT->curint->activate(); } + +void CSystemOptionsWindow::bsavef() +{ + using namespace boost::posix_time; + std::ostringstream fnameStream; + fnameStream << second_clock::local_time(); + std::string fname = fnameStream.str(); + boost::algorithm::replace_all(fname,":",""); + boost::algorithm::replace_all(fname," ","-"); + LOCPLINT->showYesNoDialog("Do you want to save current game as " + fname, std::vector(), boost::bind(&CCallback::save, LOCPLINT->cb, fname), boost::bind(&CSystemOptionsWindow::activate, this), false, false); +} + void CSystemOptionsWindow::activate() { + save->activate(); quitGame->activate(); backToMap->activate(); heroMoveSpeed->activate(); @@ -4313,6 +4334,7 @@ void CSystemOptionsWindow::activate() void CSystemOptionsWindow::deactivate() { + save->deactivate(); quitGame->deactivate(); backToMap->deactivate(); heroMoveSpeed->deactivate(); @@ -4327,6 +4349,7 @@ void CSystemOptionsWindow::show(SDL_Surface *to) SDL_BlitSurface(background, NULL, to, &pos); + save->show(to); quitGame->show(to); backToMap->show(to); heroMoveSpeed->show(to); diff --git a/CPlayerInterface.h b/CPlayerInterface.h index 8f2f214aa..d7885ed2f 100644 --- a/CPlayerInterface.h +++ b/CPlayerInterface.h @@ -538,7 +538,7 @@ public: void heroMovePointsChanged(const CGHeroInstance * hero); void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town); void receivedResource(int type, int val); - void showInfoDialog(std::string &text, const std::vector &components); + void showInfoDialog(const std::string &text, const std::vector &components); void showSelDialog(std::string &text, const std::vector &components, ui32 askID); void showYesNoDialog(std::string &text, const std::vector &components, ui32 askID); void tileHidden(const std::set &pos); @@ -577,7 +577,7 @@ public: void init(ICallback * CB); int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on void removeObjToBlit(IShowable* obj); - void showInfoDialog(std::string &text, const std::vector & components); + void showInfoDialog(const std::string &text, const std::vector & components, bool deactivateCur=true); void showYesNoDialog(std::string &text, const std::vector & components, CFunctionList onYes, CFunctionList onNo, bool deactivateCur, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close bool moveHero(const CGHeroInstance *h, CPath * path); @@ -838,14 +838,15 @@ class CSystemOptionsWindow : public IShowActivable, public CIntObject { private: SDL_Surface * background; //background of window - AdventureMapButton * quitGame, * backToMap; + AdventureMapButton *load, *save, *restart, *mainMenu, * quitGame, * backToMap; //load, restart and main menu are not used yet CHighlightableButtonsGroup * heroMoveSpeed; CHighlightableButtonsGroup * mapScrollSpeed; public: CSystemOptionsWindow(const SDL_Rect & pos, CPlayerInterface * owner); //c-tor ~CSystemOptionsWindow(); //d-tor - //functions for butons + //functions bound to buttons + void bsavef(); //save game void bquitf(); //quit game void breturnf(); //return to game diff --git a/CPreGame.cpp b/CPreGame.cpp index 1fa34333a..f4d6bf50c 100644 --- a/CPreGame.cpp +++ b/CPreGame.cpp @@ -973,7 +973,8 @@ void MapSel::printMaps(int from, int to, int at, bool abs) } else { - CSDL_Ext::printAtMiddle(curVector()[(i-at)+from]->filename,192,13,GEOR13,nasz,scenin, 2); + std::string &name = curVector()[(i-at)+from]->filename; + CSDL_Ext::printAtMiddle(name.substr(6,name.size()-12),192,13,GEOR13,nasz,scenin, 2); } if (curVector()[(i-at)+from]->victoryCondition.condition == winStandard) temp=11; @@ -1064,6 +1065,7 @@ void MapSel::show() //print scenario list printMaps(0,18); + slid->whereAreWe = 0; slid->activate(); //SDL_Flip(screen); diff --git a/hch/CCreatureHandler.cpp b/hch/CCreatureHandler.cpp index 72d8e8c1b..44ddaca9d 100644 --- a/hch/CCreatureHandler.cpp +++ b/hch/CCreatureHandler.cpp @@ -458,7 +458,15 @@ void CCreatureHandler::loadCreatures() creatures[140].abilities.insert(DOUBLE_WIDE);//boar should be treated as double-wide creatures[142].abilities.insert(DOUBLE_WIDE);//nomads should be treated as double-wide - creatures[46].abilities -= FLYING; + creatures[46].abilities -= FLYING; //hell hound + creatures[47].abilities -= FLYING; //cerberus + creatures[52].abilities += FLYING; //Efreeti + creatures[53].abilities += FLYING; //Efreet Sultan + + creatures[47].abilities += MULTI_HEAD_ATTACK; //cerberus + + + creatures[88].abilities += TWICE_ATTACK; //wolf raider } void CCreatureHandler::loadAnimationInfo() diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index 7f0e97805..0a938f8f1 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -709,7 +709,7 @@ std::vector > CGHeroInstance::getCurrentMoraleModifie { char buf[100]; sprintf(buf,VLC->generaltexth->arraytxt[117].c_str(),VLC->creh->creatures[13].namePl.c_str()); - ret.push_back(std::pair(-1,buf)); //%s in group +1 + ret.push_back(std::pair(1,buf)); //%s in group +1 } } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index a952947ab..46943e47c 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -824,7 +824,7 @@ struct EndTurn : public CPackForServer struct DismissHero : public CPackForServer { DismissHero(){}; - DismissHero(si32 HID) : hid(hid) {}; + DismissHero(si32 HID) : hid(HID) {}; si32 hid; void applyGh(CGameHandler *gh); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 3d4de9213..492d8abf0 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -481,6 +481,7 @@ void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, CStack *def) void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def) { + bat.bsa.clear(); bat.stackAttacking = att->ID; std::set::iterator i = bat.bsa.insert(BattleStackAttacked()).first; BattleStackAttacked *bsa = (BattleStackAttacked *) &*i;