2015-02-02 10:40:06 +02:00
/*
* AdventureSpellMechanics . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
# include "StdInc.h"
# include "AdventureSpellMechanics.h"
2015-02-02 11:22:19 +02:00
2017-07-20 06:08:49 +02:00
# include "CSpellHandler.h"
2015-02-02 11:22:19 +02:00
# include "../CRandomGenerator.h"
# include "../mapObjects/CGHeroInstance.h"
# include "../NetPacks.h"
# include "../CGameInfoCallback.h"
2015-12-02 21:05:10 +02:00
# include "../mapping/CMap.h"
2015-12-02 21:39:53 +02:00
# include "../CPlayerState.h"
2015-02-02 11:22:19 +02:00
2016-09-04 07:19:28 +02:00
///AdventureSpellMechanics
2017-06-06 06:53:51 +02:00
AdventureSpellMechanics : : AdventureSpellMechanics ( const CSpell * s ) :
IAdventureSpellMechanics ( s )
{
}
2017-07-03 20:09:27 +02:00
bool AdventureSpellMechanics : : adventureCast ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
2016-09-04 07:19:28 +02:00
{
if ( ! owner - > isAdventureSpell ( ) )
{
env - > complain ( " Attempt to cast non adventure spell in adventure mode " ) ;
return false ;
}
const CGHeroInstance * caster = parameters . caster ;
if ( caster - > inTownGarrison )
{
env - > complain ( " Attempt to cast an adventure spell in town garrison " ) ;
return false ;
}
const int cost = caster - > getSpellCost ( owner ) ;
if ( ! caster - > canCastThisSpell ( owner ) )
{
env - > complain ( " Hero cannot cast this spell! " ) ;
return false ;
}
if ( caster - > mana < cost )
{
env - > complain ( " Hero doesn't have enough spell points to cast this spell! " ) ;
return false ;
}
2017-07-03 20:09:27 +02:00
ESpellCastResult result = beginCast ( env , parameters ) ;
2016-09-04 07:19:28 +02:00
2017-07-03 20:09:27 +02:00
if ( result = = ESpellCastResult : : OK )
performCast ( env , parameters ) ;
return result ! = ESpellCastResult : : ERROR ;
2016-09-04 07:19:28 +02:00
}
2017-06-06 06:53:51 +02:00
ESpellCastResult AdventureSpellMechanics : : applyAdventureEffects ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
2016-09-04 07:19:28 +02:00
{
if ( owner - > hasEffects ( ) )
{
2016-11-02 19:11:01 +02:00
//todo: cumulative effects support
2016-09-04 07:19:28 +02:00
const int schoolLevel = parameters . caster - > getSpellSchoolLevel ( owner ) ;
std : : vector < Bonus > bonuses ;
2016-11-02 19:11:01 +02:00
owner - > getEffects ( bonuses , schoolLevel , false , parameters . caster - > getEnchantPower ( owner ) ) ;
2016-09-04 07:19:28 +02:00
for ( Bonus b : bonuses )
{
GiveBonus gb ;
gb . id = parameters . caster - > id . getNum ( ) ;
gb . bonus = b ;
env - > sendAndApply ( & gb ) ;
}
return ESpellCastResult : : OK ;
}
else
{
//There is no generic algorithm of adventure cast
env - > complain ( " Unimplemented adventure spell " ) ;
return ESpellCastResult : : ERROR ;
}
}
2017-07-03 20:09:27 +02:00
ESpellCastResult AdventureSpellMechanics : : beginCast ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
{
return ESpellCastResult : : OK ;
}
void AdventureSpellMechanics : : performCast ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
{
AdvmapSpellCast asc ;
2018-03-10 21:19:55 +02:00
asc . casterID = parameters . caster - > id ;
2017-07-03 20:09:27 +02:00
asc . spellID = owner - > id ;
env - > sendAndApply ( & asc ) ;
ESpellCastResult result = applyAdventureEffects ( env , parameters ) ;
endCast ( env , parameters , result ) ;
}
void AdventureSpellMechanics : : endCast ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters , const ESpellCastResult result ) const
{
const int cost = parameters . caster - > getSpellCost ( owner ) ;
switch ( result )
{
case ESpellCastResult : : OK :
{
SetMana sm ;
sm . hid = parameters . caster - > id ;
sm . absolute = false ;
sm . val = - cost ;
env - > sendAndApply ( & sm ) ;
}
break ;
default :
break ;
}
}
2015-02-02 11:22:19 +02:00
///SummonBoatMechanics
2017-06-06 06:53:51 +02:00
SummonBoatMechanics : : SummonBoatMechanics ( const CSpell * s ) :
AdventureSpellMechanics ( s )
2015-02-02 11:22:19 +02:00
{
2017-06-06 06:53:51 +02:00
}
ESpellCastResult SummonBoatMechanics : : applyAdventureEffects ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
{
2017-07-22 22:47:29 +02:00
if ( parameters . caster - > boat )
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 333 ) ; //%s is already in boat
iw . text . addReplacement ( parameters . caster - > name ) ;
env - > sendAndApply ( & iw ) ;
return ESpellCastResult : : CANCEL ;
}
2017-06-06 06:53:51 +02:00
int3 summonPos = parameters . caster - > bestLocation ( ) ;
if ( summonPos . x < 0 )
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 334 ) ; //There is no place to put the boat.
env - > sendAndApply ( & iw ) ;
return ESpellCastResult : : CANCEL ;
}
2015-02-26 19:59:18 +02:00
const int schoolLevel = parameters . caster - > getSpellSchoolLevel ( owner ) ;
2017-06-06 06:53:51 +02:00
2015-02-02 11:22:19 +02:00
//check if spell works at all
if ( env - > getRandomGenerator ( ) . nextInt ( 99 ) > = owner - > getPower ( schoolLevel ) ) //power is % chance of success
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 336 ) ; //%s tried to summon a boat, but failed.
iw . text . addReplacement ( parameters . caster - > name ) ;
env - > sendAndApply ( & iw ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : OK ;
2015-02-02 11:22:19 +02:00
}
//try to find unoccupied boat to summon
const CGBoat * nearest = nullptr ;
double dist = 0 ;
for ( const CGObjectInstance * obj : env - > getMap ( ) - > objects )
{
if ( obj & & obj - > ID = = Obj : : BOAT )
{
const CGBoat * b = static_cast < const CGBoat * > ( obj ) ;
2015-02-26 19:59:18 +02:00
if ( b - > hero )
2015-02-02 11:22:19 +02:00
continue ; //we're looking for unoccupied boat
double nDist = b - > pos . dist2d ( parameters . caster - > getPosition ( ) ) ;
if ( ! nearest | | nDist < dist ) //it's first boat or closer than previous
{
nearest = b ;
dist = nDist ;
}
2015-02-26 19:59:18 +02:00
}
2015-02-02 11:22:19 +02:00
}
if ( nullptr ! = nearest ) //we found boat to summon
{
ChangeObjPos cop ;
cop . objid = nearest - > id ;
2017-06-06 06:53:51 +02:00
cop . nPos = summonPos + int3 ( 1 , 0 , 0 ) ;
2015-02-02 11:22:19 +02:00
cop . flags = 1 ;
env - > sendAndApply ( & cop ) ;
}
else if ( schoolLevel < 2 ) //none or basic level -> cannot create boat :(
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 335 ) ; //There are no boats to summon.
env - > sendAndApply ( & iw ) ;
}
else //create boat
{
NewObject no ;
no . ID = Obj : : BOAT ;
no . subID = parameters . caster - > getBoatType ( ) ;
2017-06-06 06:53:51 +02:00
no . pos = summonPos + int3 ( 1 , 0 , 0 ) ;
2015-02-02 11:22:19 +02:00
env - > sendAndApply ( & no ) ;
2015-02-26 19:59:18 +02:00
}
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : OK ;
2015-02-02 11:22:19 +02:00
}
///ScuttleBoatMechanics
2017-06-06 06:53:51 +02:00
ScuttleBoatMechanics : : ScuttleBoatMechanics ( const CSpell * s ) :
AdventureSpellMechanics ( s )
{
}
ESpellCastResult ScuttleBoatMechanics : : applyAdventureEffects ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
2015-02-02 11:22:19 +02:00
{
const int schoolLevel = parameters . caster - > getSpellSchoolLevel ( owner ) ;
//check if spell works at all
if ( env - > getRandomGenerator ( ) . nextInt ( 99 ) > = owner - > getPower ( schoolLevel ) ) //power is % chance of success
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 337 ) ; //%s tried to scuttle the boat, but failed
iw . text . addReplacement ( parameters . caster - > name ) ;
env - > sendAndApply ( & iw ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : OK ;
2015-02-02 11:22:19 +02:00
}
2015-02-26 19:59:18 +02:00
2015-02-02 11:22:19 +02:00
if ( ! env - > getMap ( ) - > isInTheMap ( parameters . pos ) )
{
env - > complain ( " Invalid dst tile for scuttle! " ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : ERROR ;
2015-02-02 11:22:19 +02:00
}
//TODO: test range, visibility
const TerrainTile * t = & env - > getMap ( ) - > getTile ( parameters . pos ) ;
if ( ! t - > visitableObjects . size ( ) | | t - > visitableObjects . back ( ) - > ID ! = Obj : : BOAT )
{
env - > complain ( " There is no boat to scuttle! " ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : ERROR ;
2015-02-02 11:22:19 +02:00
}
RemoveObject ro ;
ro . id = t - > visitableObjects . back ( ) - > id ;
env - > sendAndApply ( & ro ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : OK ;
2015-02-02 11:22:19 +02:00
}
///DimensionDoorMechanics
2017-06-06 06:53:51 +02:00
DimensionDoorMechanics : : DimensionDoorMechanics ( const CSpell * s ) :
AdventureSpellMechanics ( s )
{
}
ESpellCastResult DimensionDoorMechanics : : applyAdventureEffects ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
2015-02-02 11:22:19 +02:00
{
if ( ! env - > getMap ( ) - > isInTheMap ( parameters . pos ) )
{
env - > complain ( " Destination is out of map! " ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : ERROR ;
2015-02-26 19:59:18 +02:00
}
2015-02-02 11:22:19 +02:00
const TerrainTile * dest = env - > getCb ( ) - > getTile ( parameters . pos ) ;
const TerrainTile * curr = env - > getCb ( ) - > getTile ( parameters . caster - > getSightCenter ( ) ) ;
if ( nullptr = = dest )
{
env - > complain ( " Destination tile doesn't exist! " ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : ERROR ;
2015-02-02 11:22:19 +02:00
}
2015-02-26 19:59:18 +02:00
2015-02-02 11:22:19 +02:00
if ( nullptr = = curr )
{
env - > complain ( " Source tile doesn't exist! " ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : ERROR ;
2015-02-26 19:59:18 +02:00
}
2015-12-21 17:44:21 +02:00
if ( parameters . caster - > movement < = 0 ) //unlike town portal non-zero MP is enough
2015-02-02 11:22:19 +02:00
{
env - > complain ( " Hero needs movement points to cast Dimension Door! " ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : ERROR ;
2015-02-02 11:22:19 +02:00
}
2015-02-26 19:59:18 +02:00
2015-02-02 11:22:19 +02:00
const int schoolLevel = parameters . caster - > getSpellSchoolLevel ( owner ) ;
2015-12-21 17:44:21 +02:00
const int movementCost = GameConstants : : BASE_MOVEMENT_COST * ( ( schoolLevel > = 3 ) ? 2 : 3 ) ;
2015-02-26 19:59:18 +02:00
2016-10-01 05:51:12 +02:00
std : : stringstream cachingStr ;
cachingStr < < " source_ " < < Bonus : : SPELL_EFFECT < < " id_ " < < owner - > id . num ;
if ( parameters . caster - > getBonuses ( Selector : : source ( Bonus : : SPELL_EFFECT , owner - > id ) , Selector : : all , cachingStr . str ( ) ) - > size ( ) > = owner - > getPower ( schoolLevel ) ) //limit casts per turn
2015-02-02 11:22:19 +02:00
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 338 ) ; //%s is not skilled enough to cast this spell again today.
iw . text . addReplacement ( parameters . caster - > name ) ;
env - > sendAndApply ( & iw ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : CANCEL ;
2015-02-02 11:22:19 +02:00
}
GiveBonus gb ;
gb . id = parameters . caster - > id . getNum ( ) ;
gb . bonus = Bonus ( Bonus : : ONE_DAY , Bonus : : NONE , Bonus : : SPELL_EFFECT , 0 , owner - > id ) ;
env - > sendAndApply ( & gb ) ;
if ( ! dest - > isClear ( curr ) ) //wrong dest tile
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 70 ) ; //Dimension Door failed!
2015-02-26 19:59:18 +02:00
env - > sendAndApply ( & iw ) ;
2015-02-02 11:22:19 +02:00
}
else if ( env - > moveHero ( parameters . caster - > id , parameters . pos + parameters . caster - > getVisitableOffset ( ) , true ) )
{
SetMovePoints smp ;
smp . hid = parameters . caster - > id ;
2017-08-18 21:33:15 +02:00
if ( movementCost < parameters . caster - > movement )
smp . val = parameters . caster - > movement - movementCost ;
else
smp . val = 0 ;
2015-02-02 11:22:19 +02:00
env - > sendAndApply ( & smp ) ;
}
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : OK ;
2015-02-02 11:22:19 +02:00
}
///TownPortalMechanics
2017-06-06 06:53:51 +02:00
TownPortalMechanics : : TownPortalMechanics ( const CSpell * s ) :
AdventureSpellMechanics ( s )
2015-02-02 11:22:19 +02:00
{
2017-06-06 06:53:51 +02:00
}
2015-02-02 11:22:19 +02:00
2017-06-06 06:53:51 +02:00
ESpellCastResult TownPortalMechanics : : applyAdventureEffects ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
{
const CGTownInstance * destination = nullptr ;
2017-07-03 20:09:27 +02:00
const int moveCost = movementCost ( parameters ) ;
2016-02-15 12:34:37 +02:00
2017-06-06 06:53:51 +02:00
if ( parameters . caster - > getSpellSchoolLevel ( owner ) < 2 )
{
std : : vector < const CGTownInstance * > pool = getPossibleTowns ( env , parameters ) ;
destination = findNearestTown ( env , parameters , pool ) ;
2016-02-15 12:34:37 +02:00
2017-06-06 06:53:51 +02:00
if ( nullptr = = destination )
2017-07-03 20:09:27 +02:00
return ESpellCastResult : : ERROR ;
2015-02-26 19:59:18 +02:00
2017-07-03 20:09:27 +02:00
if ( parameters . caster - > movement < moveCost )
return ESpellCastResult : : ERROR ;
2015-02-26 19:59:18 +02:00
2017-07-03 20:09:27 +02:00
if ( destination - > visitingHero )
2017-06-06 06:53:51 +02:00
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 123 ) ;
env - > sendAndApply ( & iw ) ;
return ESpellCastResult : : CANCEL ;
}
}
else if ( env - > getMap ( ) - > isInTheMap ( parameters . pos ) )
2015-02-02 11:22:19 +02:00
{
2017-06-06 06:53:51 +02:00
const TerrainTile & tile = env - > getMap ( ) - > getTile ( parameters . pos ) ;
if ( tile . visitableObjects . empty ( ) | | tile . visitableObjects . back ( ) - > ID ! = Obj : : TOWN )
2015-02-02 11:22:19 +02:00
{
2017-06-06 06:53:51 +02:00
env - > complain ( " No town at destination tile " ) ;
return ESpellCastResult : : ERROR ;
2015-02-02 11:22:19 +02:00
}
2017-06-06 06:53:51 +02:00
destination = dynamic_cast < CGTownInstance * > ( tile . visitableObjects . back ( ) ) ;
if ( nullptr = = destination )
2015-02-02 11:22:19 +02:00
{
2017-06-06 06:53:51 +02:00
env - > complain ( " [Internal error] invalid town object " ) ;
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : ERROR ;
2015-02-02 11:22:19 +02:00
}
2015-02-26 19:59:18 +02:00
2017-06-06 06:53:51 +02:00
const auto relations = env - > getCb ( ) - > getPlayerRelations ( destination - > tempOwner , parameters . caster - > tempOwner ) ;
2016-02-15 12:34:37 +02:00
2017-06-06 06:53:51 +02:00
if ( relations = = PlayerRelations : : ENEMIES )
{
env - > complain ( " Can't teleport to enemy! " ) ;
return ESpellCastResult : : ERROR ;
}
2017-07-03 20:09:27 +02:00
if ( parameters . caster - > movement < moveCost )
2017-06-06 06:53:51 +02:00
{
env - > complain ( " This hero has not enough movement points! " ) ;
return ESpellCastResult : : ERROR ;
}
2016-02-15 12:34:37 +02:00
2017-06-06 06:53:51 +02:00
if ( destination - > visitingHero )
{
env - > complain ( " Can't teleport to occupied town! " ) ;
return ESpellCastResult : : ERROR ;
}
}
else
2015-04-01 03:48:50 +02:00
{
2017-06-06 06:53:51 +02:00
env - > complain ( " Invalid destination tile " ) ;
2016-02-15 12:34:37 +02:00
return ESpellCastResult : : ERROR ;
2015-04-01 03:48:50 +02:00
}
2016-02-15 12:34:37 +02:00
2017-07-03 20:09:27 +02:00
if ( env - > moveHero ( parameters . caster - > id , destination - > visitablePos ( ) + parameters . caster - > getVisitableOffset ( ) , true ) )
2015-04-01 03:48:50 +02:00
{
SetMovePoints smp ;
smp . hid = parameters . caster - > id ;
2017-07-03 20:09:27 +02:00
smp . val = std : : max < ui32 > ( 0 , parameters . caster - > movement - moveCost ) ;
2016-02-15 12:34:37 +02:00
env - > sendAndApply ( & smp ) ;
2015-04-01 03:48:50 +02:00
}
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : OK ;
2015-02-02 11:22:19 +02:00
}
2015-02-02 14:02:27 +02:00
2017-07-03 20:09:27 +02:00
ESpellCastResult TownPortalMechanics : : beginCast ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
{
std : : vector < const CGTownInstance * > towns = getPossibleTowns ( env , parameters ) ;
if ( towns . empty ( ) )
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 124 ) ;
env - > sendAndApply ( & iw ) ;
return ESpellCastResult : : CANCEL ;
}
const int moveCost = movementCost ( parameters ) ;
if ( parameters . caster - > movement < moveCost )
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 125 ) ;
env - > sendAndApply ( & iw ) ;
return ESpellCastResult : : CANCEL ;
}
2017-07-04 00:32:40 +02:00
if ( ! parameters . pos . valid ( ) & & parameters . caster - > getSpellSchoolLevel ( owner ) > = 2 )
2017-07-03 20:09:27 +02:00
{
auto queryCallback = [ = ] ( const JsonNode & reply ) - > void
{
2017-11-26 23:18:18 +02:00
if ( reply . getType ( ) = = JsonNode : : JsonType : : DATA_INTEGER )
2017-07-03 20:09:27 +02:00
{
ObjectInstanceID townId ( reply . Integer ( ) ) ;
const CGObjectInstance * o = env - > getCb ( ) - > getObj ( townId , true ) ;
if ( o = = nullptr )
{
env - > complain ( " Invalid object instance selected " ) ;
return ;
}
if ( ! dynamic_cast < const CGTownInstance * > ( o ) )
{
env - > complain ( " Object instance is not town " ) ;
return ;
}
AdventureSpellCastParameters p ;
p . caster = parameters . caster ;
p . pos = o - > visitablePos ( ) ;
performCast ( env , p ) ;
}
} ;
MapObjectSelectDialog request ;
for ( auto t : towns )
{
2017-07-04 00:32:40 +02:00
if ( t - > visitingHero = = nullptr ) //empty town
2017-07-03 20:09:27 +02:00
request . objects . push_back ( t - > id ) ;
}
if ( request . objects . empty ( ) )
{
InfoWindow iw ;
iw . player = parameters . caster - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 124 ) ;
env - > sendAndApply ( & iw ) ;
return ESpellCastResult : : CANCEL ;
}
request . player = parameters . caster - > getOwner ( ) ;
2017-07-04 00:32:40 +02:00
request . title . addTxt ( MetaString : : JK_TXT , 40 ) ;
request . description . addTxt ( MetaString : : JK_TXT , 41 ) ;
request . icon . id = Component : : SPELL ;
request . icon . subtype = owner - > id . toEnum ( ) ;
2017-07-03 20:09:27 +02:00
env - > genericQuery ( & request , request . player , queryCallback ) ;
return ESpellCastResult : : PENDING ;
}
return ESpellCastResult : : OK ;
}
2017-06-06 06:53:51 +02:00
const CGTownInstance * TownPortalMechanics : : findNearestTown ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters , const std : : vector < const CGTownInstance * > & pool ) const
{
if ( pool . empty ( ) )
return nullptr ;
auto nearest = pool . cbegin ( ) ; //nearest town's iterator
si32 dist = ( * nearest ) - > pos . dist2dSQ ( parameters . caster - > pos ) ;
2017-07-04 00:32:40 +02:00
for ( auto i = nearest + 1 ; i ! = pool . cend ( ) ; + + i )
2017-06-06 06:53:51 +02:00
{
si32 curDist = ( * i ) - > pos . dist2dSQ ( parameters . caster - > pos ) ;
2017-07-04 00:32:40 +02:00
if ( curDist < dist )
2017-06-06 06:53:51 +02:00
{
nearest = i ;
dist = curDist ;
}
}
return * nearest ;
}
std : : vector < const CGTownInstance * > TownPortalMechanics : : getPossibleTowns ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
{
std : : vector < const CGTownInstance * > ret ;
const TeamState * team = env - > getCb ( ) - > getPlayerTeam ( parameters . caster - > getOwner ( ) ) ;
for ( const auto & color : team - > players )
{
for ( auto currTown : env - > getCb ( ) - > getPlayer ( color ) - > towns )
{
ret . push_back ( currTown . get ( ) ) ;
}
}
return ret ;
}
2017-07-03 20:09:27 +02:00
int TownPortalMechanics : : movementCost ( const AdventureSpellCastParameters & parameters ) const
{
return GameConstants : : BASE_MOVEMENT_COST * ( ( parameters . caster - > getSpellSchoolLevel ( owner ) > = 3 ) ? 2 : 3 ) ;
}
2017-06-06 06:53:51 +02:00
///ViewMechanics
ViewMechanics : : ViewMechanics ( const CSpell * s ) :
AdventureSpellMechanics ( s )
{
}
ESpellCastResult ViewMechanics : : applyAdventureEffects ( const SpellCastEnvironment * env , const AdventureSpellCastParameters & parameters ) const
2015-02-26 16:15:17 +02:00
{
ShowWorldViewEx pack ;
2015-02-26 19:59:18 +02:00
2016-09-28 06:58:15 +02:00
pack . player = parameters . caster - > getOwner ( ) ;
2015-02-26 19:59:18 +02:00
2015-02-26 16:15:17 +02:00
const int spellLevel = parameters . caster - > getSpellSchoolLevel ( owner ) ;
2015-02-26 19:59:18 +02:00
2016-09-28 06:58:15 +02:00
const auto & fowMap = env - > getCb ( ) - > getPlayerTeam ( parameters . caster - > getOwner ( ) ) - > fogOfWarMap ;
2015-02-26 16:15:17 +02:00
for ( const CGObjectInstance * obj : env - > getMap ( ) - > objects )
{
2016-09-28 06:58:15 +02:00
//deleted object remain as empty pointer
if ( obj & & filterObject ( obj , spellLevel ) )
{
ObjectPosInfo posInfo ( obj ) ;
2016-02-15 12:34:37 +02:00
2016-09-28 06:58:15 +02:00
if ( fowMap [ posInfo . pos . x ] [ posInfo . pos . y ] [ posInfo . pos . z ] = = 0 )
pack . objectPositions . push_back ( posInfo ) ;
}
2015-02-26 19:59:18 +02:00
}
2015-02-26 16:15:17 +02:00
env - > sendAndApply ( & pack ) ;
2015-02-26 19:59:18 +02:00
2015-04-13 05:12:23 +02:00
return ESpellCastResult : : OK ;
2015-02-26 16:15:17 +02:00
}
2015-02-02 14:02:27 +02:00
2017-06-06 06:53:51 +02:00
///ViewAirMechanics
ViewAirMechanics : : ViewAirMechanics ( const CSpell * s ) :
ViewMechanics ( s )
{
}
2015-02-26 16:15:17 +02:00
bool ViewAirMechanics : : filterObject ( const CGObjectInstance * obj , const int spellLevel ) const
2015-02-02 14:02:27 +02:00
{
2017-06-06 06:53:51 +02:00
return ( obj - > ID = = Obj : : ARTIFACT ) | | ( spellLevel > 1 & & obj - > ID = = Obj : : HERO ) | | ( spellLevel > 2 & & obj - > ID = = Obj : : TOWN ) ;
}
///ViewEarthMechanics
ViewEarthMechanics : : ViewEarthMechanics ( const CSpell * s ) :
ViewMechanics ( s )
{
2015-02-02 14:02:27 +02:00
}
2015-02-26 16:15:17 +02:00
bool ViewEarthMechanics : : filterObject ( const CGObjectInstance * obj , const int spellLevel ) const
2015-02-02 14:02:27 +02:00
{
2017-06-06 06:53:51 +02:00
return ( obj - > ID = = Obj : : RESOURCE ) | | ( spellLevel > 1 & & obj - > ID = = Obj : : MINE ) ;
2015-02-02 14:02:27 +02:00
}
2015-02-26 16:15:17 +02:00