diff --git a/client/BattleInterface/CBattleInterface.cpp b/client/BattleInterface/CBattleInterface.cpp index 385f3cc88..2d1f16e39 100644 --- a/client/BattleInterface/CBattleInterface.cpp +++ b/client/BattleInterface/CBattleInterface.cpp @@ -1946,6 +1946,8 @@ void CBattleInterface::activateStack() if(!pendingAnims.size() && !active) activate(); + + getPossibleActionsForStack (activeStack); } double CBattleInterface::getAnimSpeedMultiplier() const @@ -1986,7 +1988,8 @@ void CBattleInterface::getPossibleActionsForStack(const CStack * stack) { //TODO: poll possible spells const CSpell * spell; - BOOST_FOREACH (Bonus * spellBonus, *stack->getBonuses (Selector::type(Bonus::SPELLCASTER))) + BonusList spellBonuses = *stack->getBonuses (Selector::type(Bonus::SPELLCASTER)); + BOOST_FOREACH (Bonus * spellBonus, spellBonuses) { spell = CGI->spellh->spells[spellBonus->subtype]; if (spell->isRisingSpell()) @@ -2018,12 +2021,15 @@ void CBattleInterface::getPossibleActionsForStack(const CStack * stack) } if (stack->shots && stack->hasBonusOfType (Bonus::SHOOTER)) possibleActions.push_back (SHOOT); - if (stack->hasBonusOfType (Bonus::RETURN_AFTER_STRIKE)); + if (stack->hasBonusOfType (Bonus::RETURN_AFTER_STRIKE)) possibleActions.push_back (ATTACK_AND_RETURN); possibleActions.push_back(ATTACK); //all active stacks can attack possibleActions.push_back(WALK_AND_ATTACK); //not all stacks can always walk, but we will check this elsewhere + if (stack->canMove() && stack->Speed()); //probably no reason to try move war machines or bound stacks + possibleActions.push_back (MOVE_STACK); //all active stacks can attack + if (siegeH && stack->hasBonusOfType (Bonus::CATAPULT)) //TODO: check shots possibleActions.push_back (CATAPULT); if (stack->hasBonusOfType (Bonus::HEALER)) @@ -2664,19 +2670,28 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType) legalAction = true; break; case MOVE_STACK: - if (vstd::contains(occupyableHexes, myNumber) || activeStack->coversPos(myNumber)) - //TODO + { + std::vector acc = curInt->cb->battleGetAvailableHexes (activeStack, false); + int shiftedDest = myNumber + (activeStack->attackerOwned ? 1 : -1); + + if (vstd::contains(acc, myNumber)) legalAction = true; + else if (sactive->doubleWide() && vstd::contains(acc, shiftedDest)) + legalAction = true; + } break; case ATTACK: case WALK_AND_ATTACK: case ATTACK_AND_RETURN: { - std::vector acc = curInt->cb->battleGetAvailableHexes (activeStack, false); + if (shere && shere->alive()) + { + setBattleCursor(myNumber); // temporary - needed for following function :( + BattleHex attackFromHex = fromWhichHexAttack(myNumber); - BattleHex attackFromHex = fromWhichHexAttack(myNumber); - if(shere->alive() && isTileAttackable(myNumber) && attackFromHex >= 0) //we can be in this line when unreachable creature is L - clicked (as of revision 1308) - legalAction = true; + if (isTileAttackable(myNumber) && attackFromHex >= 0) //we can be in this line when unreachable creature is L - clicked (as of revision 1308) + legalAction = true; + } } break; case SHOOT: @@ -2773,7 +2788,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType) consoleMsg = (boost::format(CGI->generaltexth->allTexts[481]) % shere->getName()).str(); //Select %s realizeAction = [=]{ stackActivated(shere); }; break; - case MOVE: + case MOVE_STACK: if(activeStack->hasBonusOfType(Bonus::FLYING)) { cursorFrame = ECursor::COMBAT_FLY; @@ -2807,7 +2822,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType) case ATTACK_AND_RETURN: //TODO: allow to disable return { setBattleCursor(myNumber); //handle direction of cursor and attackable tile - setCursor = false; //don't overwrite settings from the call above + setCursor = false; //don't overwrite settings from the call above //TODO: what does it mean? realizeAction = [=] { BattleHex attackFromHex = fromWhichHexAttack(myNumber); diff --git a/client/CCreatureWindow.cpp b/client/CCreatureWindow.cpp index b5ffbf736..1f015cc0e 100644 --- a/client/CCreatureWindow.cpp +++ b/client/CCreatureWindow.cpp @@ -20,6 +20,7 @@ #include "../lib/BattleState.h" #include "../lib/CSpellHandler.h" #include "../lib/CArtHandler.h" +#include "../lib/NetPacks.h" //ArtifactLocation #include "UIFramework/CGuiHandler.h" #include "UIFramework/CIntObjectClasses.h" @@ -258,15 +259,15 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode * if (GameConstants::STACK_ARTIFACT) { + creatureArtifact = stack->getArt(ArtifactPosition::CREATURE_SLOT); if (type > BATTLE) //artifact buttons inactive in battle { + //TODO: disable buttons if no artifact is equipped leftArtRoll = new CAdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::scrollArt, this, -1), 437, 98, "hsbtns3.def", SDLK_LEFT); rightArtRoll = new CAdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::scrollArt, this, +1), 516, 98, "hsbtns5.def", SDLK_RIGHT); if (heroOwner) - passArtToHero = new CAdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::scrollArt, this, 0), 437, 148, "OVBUTN1.DEF", SDLK_HOME); + passArtToHero = new CAdventureMapButton(std::string(), std::string(), boost::bind (&CCreatureWindow::passArtifactToHero, this), 437, 148, "OVBUTN1.DEF", SDLK_HOME); } - if ((creatureArtifact = stack->getArt(ArtifactPosition::CREATURE_SLOT))) - blitAt(graphics->artDefs->ourImages[creatureArtifact->artType->id].bitmap, 466, 100, *bitmap); } } @@ -379,6 +380,12 @@ void CCreatureWindow::showAll(SDL_Surface * to) BOOST_FOREACH(CBonusItem* b, bonusItems) b->showAll (to); + + if (GameConstants::STACK_ARTIFACT) + { + if (creatureArtifact) + blitAt(graphics->artDefs->ourImages[creatureArtifact->artType->id].bitmap, 466 + pos.x, 100 + pos.y, to); + } } void CCreatureWindow::show(SDL_Surface * to) @@ -402,7 +409,26 @@ void CCreatureWindow::scrollArt(int dir) void CCreatureWindow::passArtifactToHero() { - //creatureArtifact->artType; //FIXME + const CGHeroInstance * h = dynamic_cast(stack->armyObj); + if (h && creatureArtifact) + { + LOCPLINT->cb->swapArtifacts (ArtifactLocation (stack, ArtifactPosition::CREATURE_SLOT), ArtifactLocation(h, creatureArtifact->firstBackpackSlot(h))); + } + else + tlog2 << "Pass artifact to hero should be disabled, no hero or no artifact!\n"; + + //redraw is handled via CArtifactHolder interface +} + +void CCreatureWindow::artifactRemoved (const ArtifactLocation &artLoc) +{ + creatureArtifact = stack->getArt(ArtifactPosition::CREATURE_SLOT); //TODO: select next from the list (for Commanders) + redraw(); +} +void CCreatureWindow::artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc) +{ + creatureArtifact = stack->getArt(ArtifactPosition::CREATURE_SLOT); //TODO: select next from the list (for Commanders) + redraw(); } void CCreatureWindow::clickRight(tribool down, bool previousState) @@ -413,18 +439,6 @@ void CCreatureWindow::clickRight(tribool down, bool previousState) close(); } -//void CCreatureWindow::activate() -//{ -// CIntObject::activate(); -// if(type < 3) -// activateRClick(); -//} - -//void CCreatureWindow::deactivate() -//{ -// -//} - void CCreatureWindow::close() { GH.popIntTotally(this); diff --git a/client/CCreatureWindow.h b/client/CCreatureWindow.h index df679917e..8767dc9e4 100644 --- a/client/CCreatureWindow.h +++ b/client/CCreatureWindow.h @@ -18,6 +18,7 @@ struct Bonus; class CCreature; class CStackInstance; class CStack; +class ArtifactLocation; class CCreatureArtifactInstance; class CAdventureMapButton; class CBonusItem; @@ -35,7 +36,7 @@ class CLabel; class CAnimImage; // New creature window -class CCreatureWindow : public CIntObject +class CCreatureWindow : public CArtifactHolder { public: enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3}; //only last one should open permanently @@ -62,6 +63,11 @@ public: CAdventureMapButton * leftArtRoll, * rightArtRoll; //artifact selection CAdventureMapButton * passArtToHero; + void artifactRemoved (const ArtifactLocation &artLoc); + void artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc); + void artifactDisassembled (const ArtifactLocation &artLoc) {return;}; + void artifactAssembled (const ArtifactLocation &artLoc) {return;}; + boost::function dsm; //dismiss button callback boost::function Upg; //upgrade button callback diff --git a/config/bonusnames.json b/config/bonusnames.json index 7359d48ad..0125a3f40 100644 --- a/config/bonusnames.json +++ b/config/bonusnames.json @@ -23,6 +23,7 @@ { "id": "SPELL_IMMUNITY", "name": "Immune to %s", "description": "" }, { "id": "CHARGE_IMMUNITY", "name": "Immune to Charge", "description": "Immune to Champion charge" }, { "id": "MANA_CHANNELING", "name": "Magic Channel %d%", "description": "Gives mana spent by enemy" }, + { "id": "MANA_DRAIN", "name": "Mana Drain", "description": "Drains %d mana every turn" }, { "id": "CHANGES_SPELL_COST_FOR_ENEMY", "name": "Magic Damper (%d)", "description": "Increase Cost of enemy spells" }, { "id": "MAGIC_MIRROR", "name": "Magic Mirror (%d%)", "description": "Redirects offensive spell to enemy" }, { "id": "MAGIC_RESISTANCE", "name": "Magic Resistance", "description": "%d% chance to resist enemy spell" }, diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index 2d11ee4e7..3d567b0a2 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -583,7 +583,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const case Bonus::DRAGON_NATURE: case Bonus::NON_LIVING: case Bonus::UNDEAD: - case Bonus::FIRE_IMMUNITY: //TODO: what about direct, hostile and total immunity? + case Bonus::FIRE_IMMUNITY: case Bonus::WATER_IMMUNITY: case Bonus::AIR_IMMUNITY: case Bonus::EARTH_IMMUNITY: diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 6aa7ab4be..9a2091415 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -171,7 +171,8 @@ namespace EMarketMode namespace EBattleStackState { - enum EBattleStackState{ALIVE = 180, SUMMONED, CLONED, HAD_MORALE, WAITING, MOVED, DEFENDING, FEAR}; + enum EBattleStackState{ALIVE = 180, SUMMONED, CLONED, HAD_MORALE, WAITING, MOVED, DEFENDING, FEAR, + DRAINED_MANA /*remember to drain mana only once per turn*/}; } namespace ECommander diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index ea573b22f..14f45b047 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -922,6 +922,7 @@ DLL_LINKAGE void BattleNextRound::applyGs( CGameState *gs ) s->state -= EBattleStackState::MOVED; s->state -= EBattleStackState::HAD_MORALE; s->state -= EBattleStackState::FEAR; + s->state -= EBattleStackState::DRAINED_MANA; s->counterAttacks = 1 + s->valOfBonuses(Bonus::ADDITIONAL_RETALIATION); // new turn effects s->battleTurnPassed(); @@ -952,6 +953,7 @@ DLL_LINKAGE void BattleTriggerEffect::applyGs( CGameState *gs ) case Bonus::MANA_DRAIN: { CGHeroInstance * h = gs->getHero(additionalInfo); + st->state.insert (EBattleStackState::DRAINED_MANA); h->mana -= val; vstd::amax(h->mana, 0); break; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 32bf7e750..08cbbcfe7 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -4096,7 +4096,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st) } } } - if(st->hasBonusOfType(Bonus::MANA_DRAIN)) + if (st->hasBonusOfType(Bonus::MANA_DRAIN) && !vstd::contains(st->state, EBattleStackState::DRAINED_MANA)) { const CGHeroInstance * enemy = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner)); if (enemy)