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

Rewritten handling mouse movement over hex and l-clicking hex into one procedure. That way the tooltip and cursor are always accurate, because they're set by the same routing that selects action. Having that logic duplicated in two methods was unmaintainable. [though the new one is still monstrous...] By the way fixed numerous issues, including:

* #785 and parts of #760
* first aid tent can heal only creatures that suffered damage
* war machines can't be healed by tent
* creatures casting spells won't try to cast them during tactic phase
* console tooltips for first aid tent
* console tooltips for teleport spell
* cursor is reset to pointer when action is requested
* fixed a few other missing or wrong tooltips/cursors

Implemented opening creature window by l-clicking on stack. Master Genie's spell is picked by server, not client.
Minor changes.
This commit is contained in:
Michał W. Urbańczyk 2012-03-30 21:36:07 +00:00
parent e046f06421
commit a9af0da0ab
15 changed files with 585 additions and 633 deletions

File diff suppressed because it is too large Load Diff

View File

@ -130,7 +130,7 @@ private:
bool spellDestSelectMode; //if true, player is choosing destination for his spell
SpellSelectionType spellSelMode;
BattleAction * spellToCast; //spell for which player is choosing destination
ui32 creatureSpellToCast;
si32 creatureSpellToCast;
void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)
void showAliveStack(const CStack *stack, SDL_Surface * to); //helper function for function show
@ -144,7 +144,6 @@ private:
void projectileShowHelper(SDL_Surface * to); //prints projectiles present on the battlefield
void giveCommand(ui8 action, BattleHex tile, ui32 stack, si32 additional=-1);
bool isTileAttackable(const BattleHex & number) const; //returns true if tile 'number' is neighboring any tile from active stack's range or is one of these tiles
bool blockedByObstacle(BattleHex hex) const;
bool isCatapultAttackable(BattleHex hex) const; //returns true if given tile can be attacked by catapult
std::list<BattleEffect> battleEffects; //different animations to display on the screen like spell effects
@ -243,12 +242,15 @@ public:
void castThisSpell(int spellID); //called when player has chosen a spell from spellbook
void displayEffect(ui32 effect, int destTile); //displays effect of a spell on the battlefield; affected: true - attacker. false - defender
void battleTriggerEffect(const BattleTriggerEffect & bte);
void setBattleCursor(const int myNumber); //really complex and messy
void setBattleCursor(const int myNumber); //really complex and messy, sets attackingHex
void endAction(const BattleAction* action);
void hideQueue();
void showQueue();
SpellSelectionType selectionTypeByPositiveness(const CSpell & spell);
void handleHex(BattleHex myNumber, int eventType);
BattleHex fromWhichHexAttack(BattleHex myNumber);
friend class CPlayerInterface;
friend class CAdventureMapButton;

View File

@ -527,9 +527,6 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &stack, bool LClicked, boost
dismiss = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second, dialog, 21, 237, "IVIEWCR2",SDLK_d);
}
ok = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second,
boost::bind(&CCreInfoWindow::close,this), 216, 237, "IOKAY.DEF", SDLK_RETURN);
}
}
@ -612,9 +609,15 @@ void CCreInfoWindow::init(const CCreature *creature, const CBonusSystemNode *sta
luck->set(stackNode);
if(!LClicked)
{
abilityText = new CLabel(17, 231, FONT_SMALL, TOPLEFT, Colors::Cornsilk, creature->abilityText);
}
else
{
abilityText = NULL;
ok = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second,
boost::bind(&CCreInfoWindow::close,this), 216, 237, "IOKAY.DEF", SDLK_RETURN);
}
//if we are displying window fo r stack in battle, there are several more things that we need to display
if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode))
@ -639,10 +642,10 @@ void CCreInfoWindow::clickRight(tribool down, bool previousState)
close();
}
CIntObject * createCreWindow(const CStack *s)
CIntObject * createCreWindow(const CStack *s, bool lclick/* = false*/)
{
if(settings["general"]["classicCreatureWindow"].Bool())
return new CCreInfoWindow(*s);
return new CCreInfoWindow(*s, lclick);
else
return new CCreatureWindow(*s, CCreatureWindow::BATTLE);
}

View File

@ -130,6 +130,6 @@ public:
void show(SDL_Surface * to);
};
CIntObject *createCreWindow(const CStack *s);
CIntObject *createCreWindow(const CStack *s, bool lclick = false);
CIntObject *createCreWindow(int Cid, int Type, int creatureCount);
CIntObject *createCreWindow(const CStackInstance *s, int type, boost::function<void()> Upg = 0, boost::function<void()> Dsm = 0, UpgradeInfo *ui = NULL);

View File

@ -16,6 +16,17 @@ struct SDL_Surface;
*
*/
namespace ECursor
{
enum ECursorTypes { ADVENTURE, COMBAT, DEFAULT, SPELLBOOK };
enum EBattleCursors { COMBAT_BLOCKED, COMBAT_MOVE, COMBAT_FLY, COMBAT_SHOOT,
COMBAT_HERO, COMBAT_QUERY, COMBAT_POINTER,
//various attack frames
COMBAT_SHOOT_PENALTY = 15, COMBAT_SHOOT_CATAPULT, COMBAT_HEAL,
COMBAT_SACRIFICE, COMBAT_TELEPORT};
}
/// handles mouse cursor
class CCursorHandler
{

View File

@ -82,4 +82,9 @@ void BattleHex::checkAndPush(int tile, std::vector<BattleHex> & ret)
if( tile>=0 && tile<GameConstants::BFIELD_SIZE && (tile%GameConstants::BFIELD_WIDTH != (GameConstants::BFIELD_WIDTH - 1))
&& (tile%GameConstants::BFIELD_WIDTH != 0) )
ret.push_back(BattleHex(tile));
}
bool BattleHex::isAvailable() const
{
return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH-1;
}

View File

@ -106,4 +106,5 @@ struct DLL_LINKAGE BattleHex
}
static void checkAndPush(int tile, std::vector<BattleHex> & ret);
bool isAvailable() const; //valid position not in first or last column
};

View File

@ -1948,6 +1948,31 @@ ESpellCastProblem::ESpellCastProblem BattleInfo::battleCanCastThisSpellHere( int
if(moreGeneralProblem != ESpellCastProblem::OK)
return moreGeneralProblem;
if(spell->getTargetType() == CSpell::OBSTACLE && !isObstacleOnTile(dest))
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
//get dead stack if we cast resurrection or animate dead
const CStack * stackUnder = getStackT(dest, false);
if(spell->isRisingSpell())
{
if(!stackUnder || stackUnder->alive())
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
if(spell->id == Spells::ANIMATE_DEAD && !stackUnder->hasBonusOfType(Bonus::UNDEAD))
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
}
if(spell->getTargetType() == CSpell::CREATURE)
{
if(!stackUnder)
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
if(spell->isNegative() && stackUnder->owner == player)
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
if(spell->isPositive() && stackUnder->owner != player)
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
}
if (mode != ECastingMode::CREATURE_ACTIVE_CASTING && mode != ECastingMode::ENCHANTER_CASTING)
return battleIsImmune(getHero(player), spell, mode, dest);
else
@ -2333,6 +2358,18 @@ int BattleInfo::getIdForNewStack() const
return 0;
}
bool BattleInfo::isObstacleOnTile(BattleHex tile) const
{
std::set<BattleHex> coveredHexes;
BOOST_FOREACH(const CObstacleInstance &obs, obstacles)
{
std::vector<BattleHex> blocked = VLC->heroh->obstacles.find(obs.ID)->second.getBlocked(obs.pos);
for(size_t w = 0; w < blocked.size(); ++w)
coveredHexes.insert(blocked[w]);
}
return vstd::contains(coveredHexes, tile);
}
CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
counterAttacks(1)
@ -2861,6 +2898,13 @@ bool CStack::isValidTarget(bool allowDead/* = false*/) const /*alive non-turret
return (alive() || allowDead) && position.isValid();
}
bool CStack::canBeHealed() const
{
return firstHPleft != MaxHealth()
&& alive()
&& !hasBonusOfType(Bonus::SIEGE_WEAPON);
}
bool CMP_stack::operator()( const CStack* a, const CStack* b )
{
switch(phase)

View File

@ -96,6 +96,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode
std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
std::vector<BattleHex> getAccessibility(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL) const; //returns vector of accessible tiles (taking into account the creature range)
bool isObstacleOnTile(BattleHex tile) const;
bool isStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
@ -188,6 +189,7 @@ public:
bool ableToRetaliate() const; //if stack can retaliate after attacked
bool moved(int turn = 0) const; //if stack was already moved this turn
bool canMove(int turn = 0) const; //if stack can move
bool canBeHealed() const; //for first aid tent - only harmed stacks that are not war machines
ui32 Speed(int turn = 0, bool useBind = false) const; //get speed of creature with all modificators
si32 magicResistance() const; //include aura of resistance
static void stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse);

View File

@ -215,6 +215,11 @@ bool CSpell::isNegative() const
return positiveness == NEGATIVE;
}
bool CSpell::isRisingSpell() const
{
return vstd::contains(VLC->spellh->risingSpells, id);
}
static bool startsWithX(const std::string &s)
{
return s.size() && s[0] == 'x';

View File

@ -44,6 +44,7 @@ public:
bool isPositive() const;
bool isNegative() const;
bool isRisingSpell() const;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -133,7 +133,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCreatureCastT
return gs->curB->battleCanCastThisSpellHere(player, spell, ECastingMode::CREATURE_ACTIVE_CASTING, destination);
}
TSpell CBattleInfoCallback::battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode)
si32 CBattleInfoCallback::battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode)
{
switch (mode)
{
@ -199,11 +199,11 @@ int CBattleInfoCallback::battleGetBattlefieldType()
return gs->curB->battlefieldType;
}
int CBattleInfoCallback::battleGetObstaclesAtTile(BattleHex tile) //returns bitfield
{
//TODO - write
return -1;
}
// int CBattleInfoCallback::battleGetObstaclesAtTile(BattleHex tile) //returns bitfield
// {
// //TODO - write
// return -1;
// }
std::vector<CObstacleInstance> CBattleInfoCallback::battleGetAllObstacles()
{
@ -405,6 +405,13 @@ const CGHeroInstance * CBattleInfoCallback::battleGetFightingHero(ui8 side) cons
return gs->curB->heroes[side];
}
bool CBattleInfoCallback::battleIsBlockedByObstacle(BattleHex tile)
{
if(!gs->curB)
return 0;
return gs->curB->isObstacleOnTile(tile);
}
CGameState *const CPrivilagedInfoCallback::gameState ()

View File

@ -94,7 +94,8 @@ public:
//battle
int battleGetBattlefieldType(); // 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
int battleGetObstaclesAtTile(BattleHex tile); //returns bitfield
//int battleGetObstaclesAtTile(BattleHex tile); //returns bitfield
bool battleIsBlockedByObstacle(BattleHex tile);
std::vector<CObstacleInstance> battleGetAllObstacles(); //returns all obstacles on the battlefield
const CStack * battleGetStackByID(int ID, bool onlyAlive = true); //returns stack info by given ID
const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true); //returns stack info by given pos
@ -110,7 +111,7 @@ public:
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell); //determines if given spell can be casted (and returns problem description)
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell, BattleHex destination); //if hero can cast spell here
ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination); //determines if creature can cast a spell here
ui32 battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode);
si32 battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode);
bool battleCanFlee(); //returns true if caller can flee from the battle
int battleGetSurrenderCost(); //returns cost of surrendering battle, -1 if surrendering is not possible
const CGTownInstance * battleGetDefendedTown(); //returns defended town if current battle is a siege, NULL instead
@ -121,6 +122,10 @@ public:
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding to given side (0 - attacker, 1 - defender)
si8 battleHasDistancePenalty(const CStack * stack, BattleHex destHex); //checks if given stack has distance penalty
si8 battleHasWallPenalty(const CStack * stack, BattleHex destHex); //checks if given stack has wall penalty
si8 battleHasShootingPenalty(const CStack * stack, BattleHex destHex)
{
return battleHasDistancePenalty(stack, destHex) || battleHasWallPenalty(stack, destHex);
}
si8 battleCanTeleportTo(const CStack * stack, BattleHex destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
si8 battleGetTacticDist(); //returns tactic distance for calling player or 0 if player is not in tactic phase
ui8 battleGetMySide(); //return side of player in battle (attacker/defender)

View File

@ -3367,19 +3367,29 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
int spellID = ba.additionalInfo;
BattleHex destination(ba.destinationTile);
int spellLvl = 0;
Bonus * bonus = stack->getBonus(Selector::typeSubtype(Bonus::SPELLCASTER, spellID));
if (bonus)
vstd::amax(spellLvl, bonus->val);
bonus = stack->getBonus(Selector::type(Bonus::RANDOM_SPELLCASTER));
if (bonus)
vstd::amax(spellLvl, bonus->val);
vstd::amin (spellLvl, 3);
const Bonus *randSpellcaster = stack->getBonus(Selector::type(Bonus::RANDOM_SPELLCASTER));
const Bonus * spellcaster = stack->getBonus(Selector::typeSubtype(Bonus::SPELLCASTER, spellID));
int casterSide = gs->curB->whatSide(stack->owner);
const CGHeroInstance * secHero = gs->curB->getHero(gs->curB->theOtherPlayer(stack->owner));
//TODO special bonus for genies ability
if(randSpellcaster && battleGetRandomStackSpell(stack, CBattleInfoCallback::RANDOM_AIMED) < 0)
spellID = battleGetRandomStackSpell(stack, CBattleInfoCallback::RANDOM_GENIE);
handleSpellCasting(spellID, spellLvl, destination, casterSide, stack->owner, NULL, secHero, 0, ECastingMode::CREATURE_ACTIVE_CASTING, stack);
if(spellID < 0)
complain("That stack can't cast spells!");
else
{
int spellLvl = 0;
if (spellcaster)
vstd::amax(spellLvl, spellcaster->val);
if (randSpellcaster)
vstd::amax(spellLvl, randSpellcaster->val);
vstd::amin (spellLvl, 3);
int casterSide = gs->curB->whatSide(stack->owner);
const CGHeroInstance * secHero = gs->curB->getHero(gs->curB->theOtherPlayer(stack->owner));
handleSpellCasting(spellID, spellLvl, destination, casterSide, stack->owner, NULL, secHero, 0, ECastingMode::CREATURE_ACTIVE_CASTING, stack);
}
sendAndApply(&end_action);
break;

View File

@ -80,7 +80,7 @@ struct CasualtiesAfterBattle
void takeFromArmy(CGameHandler *gh);
};
class CGameHandler : public IGameCallback
class CGameHandler : public IGameCallback, CBattleInfoCallback
{
private:
void makeStackDoNothing(const CStack * next);