1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-09-16 09:26:28 +02:00

Small refactoring of adventure map spell casting:

- Removed duplicated checks for DD possibility
- Moved most of spell-specific code from AdventureMapInterface to library
code
- AdventureSpellMechanics class now provides methods to check whether
spellcast is possible, similarly to battle spells
- If it is not possible to cast adventure map spell (e.g. no mana or no
move points) game will show infowindow immediately on clicking spellbook
instead of on cast attempt
- If hero does not have movement points for a DD, game will show correct
error message
- Added game settings 'dimensionDoorFailureSpendsPoints' due to
discovered H3 logic
This commit is contained in:
Ivan Savenko
2024-04-10 18:19:48 +03:00
parent bcd4a8c961
commit 8353bca34f
15 changed files with 285 additions and 289 deletions

View File

@@ -45,6 +45,8 @@
#include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/mapping/CMapDefines.h"
#include "../../lib/pathfinder/CGPathNode.h"
#include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/spells/Problem.h"
std::shared_ptr<AdventureMapInterface> adventureInt;
@@ -506,11 +508,6 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
if(!shortcuts->optionMapViewActive())
return;
if(!LOCPLINT->cb->isVisible(targetPosition))
{
if(!spellBeingCasted || spellBeingCasted->id != SpellID::DIMENSION_DOOR)
return;
}
if(!LOCPLINT->makingTurn)
return;
@@ -519,23 +516,16 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
if(spellBeingCasted)
{
assert(shortcuts->optionSpellcasting());
assert(spellBeingCasted->id == SpellID::SCUTTLE_BOAT || spellBeingCasted->id == SpellID::DIMENSION_DOOR);
switch(spellBeingCasted->id)
{
case SpellID::SCUTTLE_BOAT:
if(isValidAdventureSpellTarget(targetPosition, topBlocking, SpellID::SCUTTLE_BOAT))
performSpellcasting(targetPosition);
break;
case SpellID::DIMENSION_DOOR:
if(isValidAdventureSpellTarget(targetPosition, topBlocking, SpellID::DIMENSION_DOOR))
performSpellcasting(targetPosition);
break;
default:
break;
}
if(isValidAdventureSpellTarget(targetPosition))
performSpellcasting(targetPosition);
return;
}
if(!LOCPLINT->cb->isVisible(targetPosition))
return;
//check if we can select this object
bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID;
canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner) != PlayerRelations::ENEMIES;
@@ -610,21 +600,45 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
return;
bool isTargetPositionVisible = LOCPLINT->cb->isVisible(targetPosition);
const CGObjectInstance *objAtTile = isTargetPositionVisible ? getActiveObject(targetPosition) : nullptr;
if(spellBeingCasted)
{
switch(spellBeingCasted->id)
{
case SpellID::SCUTTLE_BOAT:
if(isValidAdventureSpellTarget(targetPosition))
CCS->curh->set(Cursor::Map::SCUTTLE_BOAT);
else
CCS->curh->set(Cursor::Map::POINTER);
return;
case SpellID::DIMENSION_DOOR:
if(isValidAdventureSpellTarget(targetPosition))
{
if(VLC->settings()->getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS) && LOCPLINT->cb->isTileGuardedUnchecked(targetPosition))
CCS->curh->set(Cursor::Map::T1_ATTACK);
else
CCS->curh->set(Cursor::Map::TELEPORT);
return;
}
else
CCS->curh->set(Cursor::Map::POINTER);
return;
default:
CCS->curh->set(Cursor::Map::POINTER);
return;
}
}
if(!isTargetPositionVisible)
{
GH.statusbar()->clear();
if(!spellBeingCasted || spellBeingCasted->id != SpellID::DIMENSION_DOOR)
{
CCS->curh->set(Cursor::Map::POINTER);
return;
}
CCS->curh->set(Cursor::Map::POINTER);
return;
}
auto objRelations = PlayerRelations::ALLIES;
const CGObjectInstance *objAtTile = isTargetPositionVisible ? getActiveObject(targetPosition) : nullptr;
if(objAtTile)
{
objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner);
@@ -638,40 +652,6 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
GH.statusbar()->write(tileTooltipText);
}
if(spellBeingCasted)
{
switch(spellBeingCasted->id)
{
case SpellID::SCUTTLE_BOAT:
if(isValidAdventureSpellTarget(targetPosition, objAtTile, SpellID::SCUTTLE_BOAT))
CCS->curh->set(Cursor::Map::SCUTTLE_BOAT);
else
CCS->curh->set(Cursor::Map::POINTER);
return;
case SpellID::DIMENSION_DOOR:
if(isValidAdventureSpellTarget(targetPosition, objAtTile, SpellID::DIMENSION_DOOR))
{
if(VLC->settings()->getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS))
{
auto isGuarded = LOCPLINT->cb->isTileGuardedAfterDimensionDoorUse(targetPosition, LOCPLINT->localState->getCurrentHero());
if(isGuarded)
{
CCS->curh->set(Cursor::Map::T1_ATTACK);
return;
}
}
CCS->curh->set(Cursor::Map::TELEPORT);
}
else
CCS->curh->set(Cursor::Map::POINTER);
return;
default:
CCS->curh->set(Cursor::Map::POINTER);
return;
}
}
if(LOCPLINT->localState->getCurrentArmy()->ID == Obj::TOWN || GH.isKeyboardCtrlDown())
{
if(objAtTile)
@@ -945,34 +925,9 @@ void AdventureMapInterface::onScreenResize()
activate();
}
bool AdventureMapInterface::isValidAdventureSpellTarget(int3 targetPosition, const CGObjectInstance * topObjectAtTarget, SpellID spellId)
bool AdventureMapInterface::isValidAdventureSpellTarget(int3 targetPosition)
{
int3 heroPosition = LOCPLINT->localState->getCurrentArmy()->getSightCenter();
if (!isInScreenRange(heroPosition, targetPosition))
{
return false;
}
spells::detail::ProblemImpl problem;
switch(spellId)
{
case SpellID::SCUTTLE_BOAT:
{
if(topObjectAtTarget && topObjectAtTarget->ID == Obj::BOAT)
return true;
else
return false;
}
case SpellID::DIMENSION_DOOR:
{
const TerrainTile * t = LOCPLINT->cb->getTileForDimensionDoor(targetPosition, LOCPLINT->localState->getCurrentHero());
if(t && t->isClear(LOCPLINT->cb->getTile(heroPosition)))
return true;
else
return false;
}
default:
logGlobal->warn("Called AdventureMapInterface::isValidAdventureSpellTarget with unknown Spell ID!");
return false;
}
return spellBeingCasted->getAdventureMechanics().canBeCastAt(problem, LOCPLINT->cb.get(), LOCPLINT->localState->getCurrentHero(), targetPosition);
}