2018-03-29 17:01:57 -04:00
# include "StdAfx.h"
# include "SpellcastingManager.h"
# include "WeenieObject.h"
# include "World.h"
# include "SpellProjectile.h"
# include "WeenieFactory.h"
# include "InferredPortalData.h"
# include "WClassID.h"
# include "Container.h"
# include "Player.h"
# include "Client.h"
# include "Config.h"
# include "CombatFormulas.h"
2018-04-20 00:02:07 -05:00
# include "RandomRange.h"
# include "Random.h"
# include <random>
2018-03-29 17:01:57 -04:00
const float MAX_HEADING_TO_TARGET_FOR_CAST = 45.0f ;
2018-07-02 01:39:47 -05:00
const float MAX_TURN_TIME_FOR_CAST = 9999.0f ;
2018-03-29 17:01:57 -04:00
const float MAX_MOTION_TIME_FOR_CAST = 4.0f ;
const float MAX_PROJECTILE_CAST_RANGE = 100.0 ;
2018-07-02 01:39:47 -05:00
const float CAST_UPDATE_RATE = 1.25f ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
CSpellcastingManager : : CSpellcastingManager ( CWeenieObject * pWeenie )
2018-03-29 17:01:57 -04:00
{
m_pWeenie = pWeenie ;
}
CSpellcastingManager : : ~ CSpellcastingManager ( )
{
}
void CSpellcastingManager : : EndCast ( int error )
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > DoForcedStopCompletely ( ) ;
m_pWeenie - > NotifyUseDone ( error ) ;
2018-03-29 17:01:57 -04:00
m_bCasting = false ;
m_SpellCastData = SpellCastData ( ) ;
m_PendingMotions . clear ( ) ;
m_bTurningToObject = false ;
2018-07-11 04:53:32 +00:00
m_bTurned = false ;
2018-03-29 17:01:57 -04:00
}
bool CSpellcastingManager : : ResolveSpellBeingCasted ( )
{
if ( ! m_SpellCastData . spell_id )
return false ;
CSpellTable * pSpellTable = MagicSystem : : GetSpellTable ( ) ;
if ( ! pSpellTable )
return false ;
m_SpellCastData . spell = pSpellTable - > GetSpellBase ( m_SpellCastData . spell_id ) ;
if ( ! m_SpellCastData . spell )
return false ;
CSpellTableEx * pSpellTableEx = g_pPortalDataEx - > GetSpellTableEx ( ) ;
if ( pSpellTableEx )
m_SpellCastData . spellEx = pSpellTableEx - > GetSpellBase ( m_SpellCastData . spell_id ) ;
m_SpellCastData . spell_formula = m_SpellCastData . spell - > InqSpellFormula ( ) ;
m_SpellCastData . power_level_of_power_component = m_SpellCastData . spell_formula . GetPowerLevelOfPowerComponent ( ) ;
m_SpellCastData . current_skill = DetermineSkillLevelForSpell ( ) ;
m_SpellCastData . max_range = DetermineSpellRange ( ) ;
if ( m_SpellCastData . spell - > _bitfield & SelfTargeted_SpellIndex )
{
m_SpellCastData . target_id = m_SpellCastData . source_id ;
}
if ( m_SpellCastData . equipped & & m_SpellCastData . spell - > InqTargetType ( ) = = ITEM_TYPE : : TYPE_ITEM_ENCHANTABLE_TARGET )
{
m_SpellCastData . target_id = m_SpellCastData . caster_id ;
}
// item enchantment
if ( m_SpellCastData . equipped & & ( m_SpellCastData . spell - > _school = = 3 ) & & ( m_SpellCastData . spell - > _bitfield & SelfTargeted_SpellIndex ) )
{
2018-04-01 18:33:48 -05:00
if ( m_SpellCastData . spell - > _category = = 152 | | m_SpellCastData . spell - > _category = = 154 | | m_SpellCastData . spell - > _category = = 156 | | m_SpellCastData . spell - > _category = = 158 | | m_SpellCastData . spell - > _category = = 195 | | m_SpellCastData . spell - > _category = = 695 )
{
m_SpellCastData . target_id = m_SpellCastData . source_id ;
}
else {
m_SpellCastData . target_id = m_SpellCastData . caster_id ;
}
2018-03-29 17:01:57 -04:00
}
return true ;
}
std : : string appendSpellText ( std : : string text , std : : string newText , SpellComponentType componentType , SpellComponentType lastComponentType )
{
if ( ! newText . size ( ) )
return text ;
switch ( componentType )
{
default :
case SpellComponentType : : Undef_SpellComponentType :
case SpellComponentType : : Action_SpellComponentType :
case SpellComponentType : : ConceptPrefix_SpellComponentType :
2018-04-28 12:32:16 -04:00
{
if ( ! text . empty ( ) )
text + = " " ;
text + = newText ;
break ;
}
case SpellComponentType : : ConceptSuffix_SpellComponentType :
{
switch ( lastComponentType )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
default :
case SpellComponentType : : Undef_SpellComponentType :
case SpellComponentType : : Action_SpellComponentType :
2018-03-29 17:01:57 -04:00
if ( ! text . empty ( ) )
text + = " " ;
text + = newText ;
break ;
2018-04-28 12:32:16 -04:00
case SpellComponentType : : ConceptPrefix_SpellComponentType :
case SpellComponentType : : ConceptSuffix_SpellComponentType :
newText [ 0 ] = : : tolower ( newText [ 0 ] ) ;
text + = newText ;
2018-03-29 17:01:57 -04:00
break ;
}
2018-04-28 12:32:16 -04:00
break ;
}
2018-03-29 17:01:57 -04:00
}
return text ;
}
bool CSpellcastingManager : : AddMotionsForSpell ( )
{
SpellComponentTable * pSpellComponents = MagicSystem : : GetSpellComponentTable ( ) ;
if ( ! pSpellComponents )
return false ;
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
std : : string spellWords ;
SpellComponentType lastComponentType = Undef_SpellComponentType ;
bool firstMotion = true ;
for ( DWORD i = 0 ; i < SPELLFORMULA_MAX_COMPS ; i + + )
{
DWORD comp = m_SpellCastData . spell_formula . _comps [ i ] ;
if ( ! comp )
break ;
const SpellComponentBase * pSpellComponent = pSpellComponents - > InqSpellComponentBase ( comp ) ;
if ( ! pSpellComponent )
return false ;
if ( pSpellComponent - > _category = = Scarab_SpellComponentCategory & & m_SpellCastData . spell - > _bitfield & FastCast_SpellIndex )
continue ;
DWORD gesture = pSpellComponent - > _gesture ;
if ( gesture & & ( gesture & 0xFFFF ) ! = 0 )
{
if ( gesture = = 0x1000012F )
gesture = 0x13000132 ; // level 7's are wrong for some reason
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("Component \"%s\": %s %f %f 0x%08X (%u)", pSpellComponent->_name.c_str(), pSpellComponent->_text.c_str(), pSpellComponent->_time, pSpellComponent->_CDM, pSpellComponent->_gesture, pSpellComponent->_gesture & 0xFFFF), 1);
2018-03-29 17:01:57 -04:00
m_PendingMotions . push_back ( SpellCastingMotion ( gesture , 2.0f , firstMotion , firstMotion , pSpellComponent - > _time ) ) ;
firstMotion = false ;
}
if ( ! pSpellComponent - > _text . empty ( ) )
{
spellWords = appendSpellText ( spellWords , pSpellComponent - > _text , pSpellComponent - > _type , lastComponentType ) ;
lastComponentType = pSpellComponent - > _type ;
}
}
if ( ! spellWords . empty ( ) )
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SpeakLocal ( spellWords . c_str ( ) , LTT_MAGIC_CASTING_CHANNEL ) ;
2018-03-29 17:01:57 -04:00
}
m_SpellCastData . power_level_of_power_component = m_SpellCastData . spell_formula . GetPowerLevelOfPowerComponent ( ) ;
return true ;
}
void CSpellcastingManager : : BeginCast ( )
{
m_bCasting = true ;
m_PendingMotions . clear ( ) ;
m_bTurningToObject = false ;
2018-07-02 01:39:47 -05:00
m_bTurned = false ;
2018-03-29 17:01:57 -04:00
AddMotionsForSpell ( ) ;
BeginNextMotion ( ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CSpellcastingManager : : GetCastTarget ( )
2018-03-29 17:01:57 -04:00
{
if ( ! m_bCasting | | ! m_SpellCastData . target_id )
return NULL ;
return g_pWorld - > FindObject ( m_SpellCastData . target_id ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CSpellcastingManager : : GetCastCaster ( )
2018-03-29 17:01:57 -04:00
{
// could be a contained item casting a spell on the player
return g_pWorld - > FindObject ( m_SpellCastData . caster_id ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CSpellcastingManager : : GetCastSource ( )
2018-03-29 17:01:57 -04:00
{
return g_pWorld - > FindObject ( m_SpellCastData . source_id ) ;
}
float CSpellcastingManager : : HeadingToTarget ( )
{
if ( ! m_SpellCastData . target_id )
{
// Untargeted spell
return 0.0 ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * pTarget = GetCastTarget ( ) ;
2018-03-29 17:01:57 -04:00
if ( ! pTarget )
{
// Don't know where the target is
EndCast ( WERROR_OBJECT_GONE ) ;
return 0.0 ;
}
2018-07-12 14:41:21 -07:00
if ( pTarget - > parent )
2018-03-29 17:01:57 -04:00
{
// Target has a parent (in inventory?)
// This needs additional logic
return 0.0 ;
}
// Return difference in heading.
2018-07-12 14:41:21 -07:00
float fHeadingToTarget = m_pWeenie - > m_Position . heading_diff ( pTarget - > m_Position ) ;
2018-03-29 17:01:57 -04:00
fHeadingToTarget = fabs ( fHeadingToTarget ) ;
if ( fHeadingToTarget > = 180.0 )
fHeadingToTarget = 360.0 - fHeadingToTarget ;
return fHeadingToTarget ;
}
bool CSpellcastingManager : : MotionRequiresHeading ( )
{
if ( ! m_SpellCastData . target_id | | m_SpellCastData . target_id = = m_SpellCastData . caster_id | | m_SpellCastData . target_id = = m_SpellCastData . source_id )
return false ;
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * target = g_pWorld - > FindObject ( m_SpellCastData . target_id ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * owner = target - > GetWorldTopLevelOwner ( ) )
2018-03-29 17:01:57 -04:00
{
if ( owner - > GetID ( ) = = m_SpellCastData . source_id )
return false ;
}
}
if ( m_PendingMotions . empty ( ) )
return true ; // last motion requires heading
return m_PendingMotions . begin ( ) - > requiresHeading ;
}
void CSpellcastingManager : : BeginNextMotion ( )
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > IsDead ( ) )
2018-03-29 17:01:57 -04:00
{
EndCast ( 0 ) ;
return ;
}
bool bNeedsTurnToObject = false ;
if ( MotionRequiresHeading ( ) & & HeadingToTarget ( ) > MAX_HEADING_TO_TARGET_FOR_CAST )
{
bNeedsTurnToObject = true ;
}
if ( ! m_bCasting )
{
// Must have errored...
return ;
}
if ( bNeedsTurnToObject )
{
m_bTurningToObject = true ;
MovementParameters params ;
params . speed = 1.0f ;
2018-07-12 14:41:21 -07:00
params . action_stamp = + + m_pWeenie - > m_wAnimSequence ;
2018-03-29 17:01:57 -04:00
params . modify_interpreted_state = 0 ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > last_move_was_autonomous = false ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
m_pWeenie - > cancel_moveto ( ) ;
m_pWeenie - > TurnToObject ( m_SpellCastData . target_id , & params ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . cast_timeout = Timer : : cur_time + MAX_TURN_TIME_FOR_CAST ;
}
else
{
m_bTurningToObject = false ;
if ( m_PendingMotions . empty ( ) )
{
2018-08-27 22:16:42 -05:00
int bitfield = m_pWeenie - > m_SpellcastingManager - > m_SpellCastData . spell - > _bitfield ;
if ( ( bitfield & Resistable_SpellIndex ) & & ( bitfield & PKSensitive_SpellIndex ) & & ( bitfield & FastCast_SpellIndex ) ) //streaks
{
if ( m_pWeenie - > m_Qualities . GetFloat ( NEXT_SPELLCAST_TIMESTAMP_FLOAT , 0.0 ) < = Timer : : cur_time )
{
int error = LaunchSpellEffect ( false ) ;
EndCast ( error ) ;
m_pWeenie - > m_Qualities . SetFloat ( NEXT_SPELLCAST_TIMESTAMP_FLOAT , Timer : : cur_time + 2.0 ) ;
}
else
EndCast ( WERROR_ACTIONS_LOCKED ) ;
}
else //everything else
{
int error = LaunchSpellEffect ( false ) ;
EndCast ( error ) ;
}
2018-03-29 17:01:57 -04:00
}
else
{
m_SpellCastData . cast_timeout = Timer : : cur_time + MAX_MOTION_TIME_FOR_CAST ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > StopCompletely ( 0 ) ;
2018-03-29 17:01:57 -04:00
SpellCastingMotion & cast_motion = * m_PendingMotions . begin ( ) ;
MovementParameters params ;
2018-07-12 14:41:21 -07:00
params . action_stamp = + + m_pWeenie - > m_wAnimSequence ;
2018-03-29 17:01:57 -04:00
params . speed = cast_motion . speed ;
MovementStruct mvs ;
mvs . type = MovementTypes : : RawCommand ;
mvs . motion = cast_motion . motion ;
mvs . params = & params ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > last_move_was_autonomous = false ;
2018-03-29 17:01:57 -04:00
int errorCode ;
2018-07-12 14:41:21 -07:00
if ( ! ( errorCode = m_pWeenie - > PerformMovement ( mvs ) ) )
2018-03-29 17:01:57 -04:00
{
m_fNextCastTime = Timer : : cur_time + ( cast_motion . min_time * 0.5f ) ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > _server_control_timestamp + + ;
m_pWeenie - > Animation_Update ( ) ;
2018-03-29 17:01:57 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
// m_pWeenie->PerformMovement(mvs);
2018-03-29 17:01:57 -04:00
EndCast ( WERROR_MAGIC_GENERAL_FAILURE ) ;
}
}
}
}
2018-07-12 14:41:21 -07:00
Position CSpellcastingManager : : GetSpellProjectileSpawnPosition ( CSpellProjectile * pProjectile , CWeenieObject * pTarget , float * pDistToTarget , double dDir , bool bRing )
2018-03-29 17:01:57 -04:00
{
bool bArc = pProjectile - > InqBoolQuality ( GRAVITY_STATUS_BOOL , FALSE ) ? true : false ;
2018-07-12 14:41:21 -07:00
CWeenieObject * pSource = GetCastSource ( ) ;
2018-03-29 17:01:57 -04:00
Position spawnPosition = pSource - > m_Position . add_offset ( Vector ( 0 , 0 , pSource - > GetHeight ( ) * ( bArc ? 1.0 : ( 2.0 / 3.0 ) ) ) ) ;
Vector targetOffset ;
if ( pTarget = = pSource )
{
2018-05-12 20:51:40 +00:00
// rotate by dDir
double cs = cos ( dDir ) ;
double sn = sin ( dDir ) ;
double x = - 1000 * sn ;
double y = 1000 * cs ;
float z = pSource - > GetHeight ( ) * ( 2.0 / 3.0 ) ;
if ( bRing )
2018-05-14 23:10:50 +01:00
z * = 1.5 ;
2018-05-12 20:51:40 +00:00
targetOffset = spawnPosition . get_offset ( pTarget - > m_Position . add_offset ( pTarget - > m_Position . localtoglobalvec ( Vector ( x , y , z ) ) ) ) ;
2018-03-29 17:01:57 -04:00
}
else
{
targetOffset = spawnPosition . get_offset ( pTarget - > m_Position . add_offset ( Vector ( 0 , 0 , pTarget - > GetHeight ( ) * ( bArc ? ( 5.0 / 6.0 ) : ( 2.0 / 3.0 ) ) ) ) ) ;
//targetOffset = spawnPosition.get_offset(pTarget->m_Position.add_offset(Vector(0, 0, pTarget->GetHeight() * (bArc ? (5.0 / 6.0) : (0.5)))));
2018-05-12 20:51:40 +00:00
// rotate by dDir
double cs = cos ( dDir ) ;
double sn = sin ( dDir ) ;
targetOffset . x = targetOffset . x * cs - targetOffset . y * sn ;
targetOffset . y = targetOffset . x * sn + targetOffset . y * cs ;
2018-03-29 17:01:57 -04:00
}
Vector targetDir = targetOffset ;
if ( targetDir . normalize_check_small ( ) )
{
targetDir = spawnPosition . frame . get_vector_heading ( ) ;
// spawnPosition.frame.m_origin += targetDir * minSpawnDist;
spawnPosition . frame . set_vector_heading ( targetDir ) ;
* pDistToTarget = 0.0f ;
}
else
{
2018-05-12 20:51:40 +00:00
double minSpawnDist = ( pSource - > GetRadius ( ) + pProjectile - > GetRadius ( ) ) + 0.1f ;
if ( bRing )
2018-12-12 22:18:28 +00:00
minSpawnDist + = 0.5f ; //this will influence ring projectile start position. 1.0 will cause small targets to be inside the spawn radius at point blank.
2018-03-29 17:01:57 -04:00
spawnPosition . frame . m_origin + = targetDir * minSpawnDist ;
spawnPosition . frame . set_vector_heading ( targetDir ) ;
* pDistToTarget = targetOffset . magnitude ( ) ;
}
return spawnPosition ;
}
2018-07-12 14:41:21 -07:00
Vector CSpellcastingManager : : GetSpellProjectileSpawnVelocity ( Position * pSpawnPosition , CWeenieObject * pTarget , float speed , bool tracked , bool gravity , Vector * pTargetDir , double dDir , bool bRing )
2018-03-29 17:01:57 -04:00
{
Vector targetOffset ;
double targetDist ;
2018-07-12 14:41:21 -07:00
CWeenieObject * pSource = GetCastSource ( ) ;
2018-03-29 17:01:57 -04:00
if ( pTarget = = pSource )
{
2018-05-12 20:51:40 +00:00
// rotate by dDir
double cs = cos ( dDir ) ;
double sn = sin ( dDir ) ;
double x = - 1000 * sn ;
double y = 1000 * cs ;
float z = pTarget - > GetHeight ( ) * ( 2.0 / 3.0 ) ;
if ( bRing )
z * = 1.5 ;
targetOffset = pSpawnPosition - > get_offset ( pTarget - > m_Position . add_offset ( pTarget - > m_Position . localtoglobalvec ( Vector ( x , y , z ) ) ) ) ;
2018-03-29 17:01:57 -04:00
tracked = false ;
}
else
2018-05-12 20:51:40 +00:00
{
2018-03-29 17:01:57 -04:00
targetOffset = pSpawnPosition - > get_offset ( pTarget - > m_Position . add_offset ( Vector ( 0 , 0 , pTarget - > GetHeight ( ) * ( 2.0 / 3.0 ) ) ) ) ;
2018-05-12 20:51:40 +00:00
// rotate by dDir
double cs = cos ( dDir ) ;
double sn = sin ( dDir ) ;
targetOffset . x = targetOffset . x * cs - targetOffset . y * sn ;
targetOffset . y = targetOffset . x * sn + targetOffset . y * cs ;
}
2018-04-28 12:32:16 -04:00
//targetOffset = pSpawnPosition->get_offset(pTarget->m_Position.add_offset(Vector(0, 0, pTarget->GetHeight() * 0.5f)));
2018-03-29 17:01:57 -04:00
targetDist = targetOffset . magnitude ( ) ;
2018-05-12 20:51:40 +00:00
Vector v ;
2018-03-29 17:01:57 -04:00
if ( ! tracked )
{
double t = targetDist / speed ;
2018-05-12 20:51:40 +00:00
v = targetOffset / t ;
2018-03-29 17:01:57 -04:00
if ( gravity )
v . z + = ( 9.8 * t ) / 2.0f ;
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
Vector targetDir = v ;
targetDir . normalize ( ) ;
if ( pTargetDir )
* pTargetDir = targetDir ;
}
2018-05-12 20:51:40 +00:00
else
2018-03-29 17:01:57 -04:00
{
2018-05-12 20:51:40 +00:00
Vector P0 = targetOffset ;
Vector P1 ( 0 , 0 , 0 ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
float s0 = pTarget - > get_velocity ( ) . magnitude ( ) ;
Vector V0 = pTarget - > get_velocity ( ) ;
if ( V0 . normalize_check_small ( ) )
V0 = Vector ( 0 , 0 , 0 ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
float s1 = speed ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
double a = ( V0 . x * V0 . x ) + ( V0 . y * V0 . y ) - ( s1 * s1 ) ;
double b = 2 * ( ( P0 . x * V0 . x ) + ( P0 . y * V0 . y ) - ( P1 . x * V0 . x ) - ( P1 . y * V0 . y ) ) ;
double c = ( P0 . x * P0 . x ) + ( P0 . y * P0 . y ) + ( P1 . x * P1 . x ) + ( P1 . y * P1 . y ) - ( 2 * P1 . x * P0 . x ) - ( 2 * P1 . y * P0 . y ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
double t1 = ( - b + sqrt ( ( b * b ) - ( 4 * a * c ) ) ) / ( 2 * a ) ;
double t2 = ( - b - sqrt ( ( b * b ) - ( 4 * a * c ) ) ) / ( 2 * a ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
if ( t1 < 0 )
t1 = FLT_MAX ;
if ( t2 < 0 )
t2 = FLT_MAX ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
double t = min ( t1 , t2 ) ;
if ( t > = 100.0 )
{
return GetSpellProjectileSpawnVelocity ( pSpawnPosition , pTarget , speed , false , gravity , pTargetDir , dDir , bRing ) ;
}
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
v . x = ( P0 . x + ( t * s0 * V0 . x ) ) / ( t ) ; // * s1);
v . y = ( P0 . y + ( t * s0 * V0 . y ) ) / ( t ) ; // * s1);
v . z = ( P0 . z + ( t * s0 * V0 . z ) ) / ( t ) ; // * s1);
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
if ( gravity )
{
v . z + = ( 9.8 * t ) / 2.0f ;
}
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
if ( pTargetDir )
{
Vector targetDir = v ;
if ( targetDir . normalize_check_small ( ) )
targetDir = Vector ( 0 , 0 , 0 ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
* pTargetDir = targetDir ;
}
2018-03-29 17:01:57 -04:00
}
2018-05-12 20:51:40 +00:00
return v ;
2018-03-29 17:01:57 -04:00
}
bool CSpellcastingManager : : LaunchProjectileSpell ( ProjectileSpellEx * meta )
{
if ( ! meta )
return false ;
2018-07-12 14:41:21 -07:00
CWeenieObject * pTarget = GetCastTarget ( ) ;
2018-03-29 17:01:57 -04:00
if ( ! pTarget | | ! pTarget - > InValidCell ( ) )
{
// Don't know where the target is
return false ;
}
int numX = ( int ) ( meta - > _dims . x + 0.5f ) ;
int numY = ( int ) ( meta - > _dims . y + 0.5f ) ;
int numZ = ( int ) ( meta - > _dims . z + 0.5f ) ;
2018-07-12 14:41:21 -07:00
CWeenieObject * pSource = GetCastSource ( ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
if ( ! pSource )
{
return false ;
}
2018-05-11 19:55:42 +01:00
bool isLifeProjectile = false ;
double selfDrainedAmount = 0 ;
float selfDrainedDamageRatio = 0 ;
if ( meta - > AsLifeProjectileSpell ( ) )
{
isLifeProjectile = true ;
ProjectileLifeSpellEx * lifeProjectile = meta - > AsLifeProjectileSpell ( ) ;
DAMAGE_TYPE damageType = static_cast < DAMAGE_TYPE > ( lifeProjectile - > _etype ) ;
selfDrainedDamageRatio = lifeProjectile - > _damage_ratio ;
float drainPercentage = lifeProjectile - > _drain_percentage ;
switch ( damageType )
{
case HEALTH_DAMAGE_TYPE :
{
int amount = round ( ( float ) pSource - > GetHealth ( ) * drainPercentage ) ;
2018-07-11 04:53:32 +00:00
if ( amount > = pSource - > GetHealth ( ) )
{
selfDrainedAmount = pSource - > GetHealth ( ) - 1 ;
pSource - > SetHealth ( 1 ) ;
}
else
selfDrainedAmount = abs ( pSource - > AdjustHealth ( - amount ) ) ;
2018-05-11 19:55:42 +01:00
break ;
}
case STAMINA_DAMAGE_TYPE :
{
int amount = round ( ( float ) pSource - > GetStamina ( ) * drainPercentage ) ;
selfDrainedAmount = abs ( pSource - > AdjustStamina ( - amount ) ) ;
break ;
}
case MANA_DAMAGE_TYPE :
{
int amount = round ( ( float ) pSource - > GetMana ( ) * drainPercentage ) ;
selfDrainedAmount = abs ( pSource - > AdjustMana ( - amount ) ) ;
break ;
}
}
}
2018-05-12 20:51:40 +00:00
bool bAngled = meta - > _spreadAngle > 0 & & numX > 1 ;
2018-03-29 17:01:57 -04:00
for ( int x = 0 ; x < numX ; x + + )
{
for ( int y = 0 ; y < numY ; y + + )
{
for ( int z = 0 ; z < numZ ; z + + )
{
//DWORD damage = Random::GenUInt(meta->_baseIntensity, meta->_baseIntensity + meta->_variance);
2018-05-14 23:21:12 +01:00
int target = m_SpellCastData . target_id ;
if ( numX > 1 | | numY > 1 | | numZ > 1 )
{
// volleys, blasts, rings aren't limited to one target
target = 0 ;
}
2018-07-12 14:41:21 -07:00
CSpellProjectile * pProjectile = new CSpellProjectile ( m_SpellCastData , target ) ;
2018-03-29 17:01:57 -04:00
// create the initial object
float distToTarget ;
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
// spawn default object properties
g_pWeenieFactory - > ApplyWeenieDefaults ( pProjectile , meta - > _wcid ) ;
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
pProjectile - > m_Qualities . SetInt ( DAMAGE_TYPE_INT , meta - > _etype ) ;
// set spell id (is this even needed?)
pProjectile - > SetSpellID ( m_SpellCastData . spell_id ) ;
pProjectile - > SetInitialPosition ( GetCastSource ( ) - > m_Position ) ;
pProjectile - > InitPhysicsObj ( ) ;
2018-04-28 12:32:16 -04:00
pProjectile - > m_PhysicsState | = MISSILE_PS | REPORT_COLLISIONS_PS ;
2018-03-29 17:01:57 -04:00
pProjectile - > m_PhysicsState & = ~ IGNORE_COLLISIONS_PS ;
2018-04-28 12:32:16 -04:00
2018-05-12 20:51:40 +00:00
double maxVelocity = 5.0 ;
pProjectile - > m_Qualities . InqFloat ( MAXIMUM_VELOCITY_FLOAT , maxVelocity ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
bool bGravity = false ;
if ( pProjectile - > InqBoolQuality ( GRAVITY_STATUS_BOOL , FALSE ) )
{
pProjectile - > m_PhysicsState | = GRAVITY_PS ;
bGravity = true ;
}
bool bTracking = ! meta - > _bNonTracking ;
// angle at which to spawn from the caster
double theta = 0 ;
bool bRing = false ;
if ( bAngled )
{
double xRatio = x / ( double ) numX ;
xRatio - = ( numX - 1.0 ) / ( double ) ( 2 * numX ) ;
theta = DEG2RAD ( xRatio * meta - > _spreadAngle ) ;
// if a ring we want it to start a little further out
if ( meta - > _spreadAngle > 180 )
{
bRing = true ;
}
}
Position projSpawnPos = GetSpellProjectileSpawnPosition ( pProjectile , pTarget , & distToTarget , theta , bRing ) ;
if ( bRing )
{
// adjust for player casting position
Vector ringOffset = pSource - > m_Position . localtoglobalvec ( Vector ( 0 , 0.1f , 0 ) ) ;
projSpawnPos = projSpawnPos . add_offset ( ringOffset ) ;
}
2018-03-29 17:01:57 -04:00
2018-05-14 23:10:50 +01:00
// overall offset
2018-05-12 20:51:40 +00:00
Vector createOffset = projSpawnPos . localtoglobalvec ( meta - > _createOffset ) ;
2018-03-29 17:01:57 -04:00
projSpawnPos = projSpawnPos . add_offset (
Vector (
Random : : GenFloat ( - 1.0 , 1.0 ) * meta - > _peturbation . x * meta - > _padding . x ,
Random : : GenFloat ( - 1.0 , 1.0 ) * meta - > _peturbation . y * meta - > _padding . y ,
Random : : GenFloat ( - 1.0 , 1.0 ) * meta - > _peturbation . z * meta - > _padding . z ) ) ;
projSpawnPos = projSpawnPos . add_offset ( createOffset ) ;
2018-05-14 23:10:50 +01:00
Vector spawnVelocity = GetSpellProjectileSpawnVelocity ( & projSpawnPos , pTarget , maxVelocity , bTracking , bGravity , NULL , theta , bRing ) ;
// individual offset
2018-05-12 20:51:40 +00:00
if ( ! bAngled )
{
Vector sizePerProjectile = meta - > _padding ; // * radius;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
Vector projectileGroupOffset = Vector ( x , y , z ) ;
projectileGroupOffset . x * = sizePerProjectile . x ;
projectileGroupOffset . y * = sizePerProjectile . y ;
projectileGroupOffset . z * = sizePerProjectile . z ;
2018-04-28 12:32:16 -04:00
2018-05-12 20:51:40 +00:00
projectileGroupOffset . x - = sizePerProjectile . x * ( ( meta - > _dims . x - 1.0 ) / 2.0 ) ;
projectileGroupOffset . y - = sizePerProjectile . y * ( ( meta - > _dims . y - 1.0 ) / 2.0 ) ;
projectileGroupOffset . z - = sizePerProjectile . z * ( ( meta - > _dims . z - 1.0 ) / 2.0 ) ;
2018-03-29 17:01:57 -04:00
2018-05-12 20:51:40 +00:00
projectileGroupOffset = projSpawnPos . localtoglobalvec ( projectileGroupOffset ) ;
projSpawnPos = projSpawnPos . add_offset ( projectileGroupOffset ) ;
}
2018-03-29 17:01:57 -04:00
pProjectile - > m_Position = projSpawnPos ;
2018-05-12 20:51:40 +00:00
pProjectile - > set_velocity ( spawnVelocity , 0 ) ;
2018-03-29 17:01:57 -04:00
2018-05-14 23:10:50 +01:00
pProjectile - > m_PhysicsState | = INELASTIC_PS | SCRIPTED_COLLISION_PS | LIGHTING_ON_PS ;
2018-03-29 17:01:57 -04:00
// pProjectile->m_PhysicsState |= ETHEREAL_PS;
2018-05-11 19:55:42 +01:00
if ( isLifeProjectile )
{
pProjectile - > makeLifeProjectile ( selfDrainedAmount , selfDrainedDamageRatio ) ;
}
2018-03-29 17:01:57 -04:00
// insert the object into the world
if ( g_pWorld - > CreateEntity ( pProjectile ) )
{
// launch particle effect
pProjectile - > EmitEffect ( 4 , 0.8f ) ;
/*
LOG ( Temp , Normal , " Projectile Offset @ %.3f %.3f %.3f %f \n " ,
createOffset . x + projectileGroupOffset . x ,
createOffset . y + projectileGroupOffset . y ,
createOffset . z + projectileGroupOffset . z , pProjectile - > m_velocityVector . magnitude ( ) ) ;
*/
}
}
}
}
// LOG(Temp, Normal, "-\n");
return true ;
}
void CSpellcastingManager : : PerformCastParticleEffects ( )
{
if ( ! m_bCasting )
return ;
// self effect
if ( m_SpellCastData . spell - > _caster_effect )
{
GetCastSource ( ) - > EmitEffect ( m_SpellCastData . spell - > _caster_effect , max ( 0.0 , min ( 1.0 , ( m_SpellCastData . power_level_of_power_component - 1.0 ) / 7.0 ) ) ) ;
}
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
// target effect
if ( m_SpellCastData . spell - > _target_effect )
{
2018-07-11 04:53:32 +00:00
if ( ( m_SpellCastData . spell - > _category = = 162 | | m_SpellCastData . spell - > _category = = 164 | | m_SpellCastData . spell - > _category = = 166 | | m_SpellCastData . spell - > _category = = 168 | |
m_SpellCastData . spell - > _category = = 170 | | m_SpellCastData . spell - > _category = = 172 | | m_SpellCastData . spell - > _category = = 174 | | m_SpellCastData . spell - > _category = = 160 ) & &
( m_SpellCastData . source_id = = m_SpellCastData . target_id ) )
2018-07-12 22:55:52 -05:00
{
2018-06-16 12:56:46 -05:00
return ;
2018-06-25 21:08:26 +01:00
}
else
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * pTarget = GetCastTarget ( ) )
2018-06-25 21:08:26 +01:00
{
2018-06-16 12:56:46 -05:00
pTarget - > EmitEffect ( m_SpellCastData . spell - > _target_effect , max ( 0.0 , min ( 1.0 , ( m_SpellCastData . power_level_of_power_component - 1.0 ) / 7.0 ) ) ) ;
2018-06-25 21:08:26 +01:00
}
2018-06-16 12:56:46 -05:00
}
2018-07-12 22:55:52 -05:00
}
2018-07-12 14:41:21 -07:00
2018-03-29 17:01:57 -04:00
}
2018-04-24 02:03:00 -05:00
void CSpellcastingManager : : PerformFellowCastParticleEffects ( Fellowship * fellow )
{
if ( ! m_bCasting )
return ;
// self effect
if ( m_SpellCastData . spell - > _caster_effect )
{
GetCastSource ( ) - > EmitEffect ( m_SpellCastData . spell - > _caster_effect , max ( 0.0 , min ( 1.0 , ( m_SpellCastData . power_level_of_power_component - 1.0 ) / 7.0 ) ) ) ;
}
// target effect
if ( m_SpellCastData . spell - > _target_effect )
{
for ( auto & entry : fellow - > _fellowship_table )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * member = g_pWorld - > FindPlayer ( entry . first ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( member )
2018-04-24 02:03:00 -05:00
member - > EmitEffect ( m_SpellCastData . spell - > _target_effect , max ( 0.0 , min ( 1.0 , ( m_SpellCastData . power_level_of_power_component - 1.0 ) / 7.0 ) ) ) ;
}
}
}
}
2018-03-29 17:01:57 -04:00
void CSpellcastingManager : : BeginPortalSend ( const Position & targetPos )
{
2018-07-12 14:41:21 -07:00
if ( CPlayerWeenie * player = m_pWeenie - > AsPlayer ( ) )
2018-03-29 17:01:57 -04:00
{
if ( ! player - > IsRecalling ( ) )
{
player - > BeginRecall ( targetPos ) ;
}
}
2018-08-05 16:25:40 -05:00
else if ( m_pWeenie - > HasOwner ( ) )
{
if ( CPlayerWeenie * gemtarget = m_pWeenie - > GetWorldTopLevelOwner ( ) - > AsPlayer ( ) )
{
if ( ! gemtarget - > IsRecalling ( ) )
{
gemtarget - > BeginRecall ( targetPos ) ;
}
}
}
2018-03-29 17:01:57 -04:00
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > Movement_Teleport ( targetPos , false ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-07-02 01:39:47 -05:00
int CSpellcastingManager : : LaunchSpellEffect ( bool bFizzled )
2018-03-29 17:01:57 -04:00
{
2018-07-20 18:23:49 -05:00
if ( bFizzled )
return WERROR_NONE ;
2018-05-11 19:30:05 +01:00
int targetError = CheckTargetValidity ( ) ;
if ( targetError & & m_SpellCastData . range_check )
2018-03-29 17:01:57 -04:00
{
switch ( targetError )
{
2018-05-11 19:30:05 +01:00
case WERROR_MISSILE_OUT_OF_RANGE :
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * pTarget = GetCastTarget ( ) ;
2018-04-28 12:32:16 -04:00
if ( pTarget )
2018-07-12 14:41:21 -07:00
pTarget - > SendText ( csprintf ( " %s tried to cast a spell on you, but was too far away! " , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " That target is too far away! " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
break ;
}
2018-03-29 17:01:57 -04:00
}
return targetError ;
}
2018-07-12 14:41:21 -07:00
2018-03-29 17:01:57 -04:00
// cast source is assumed to be valid at this point
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > AsPlayer ( ) & & m_SpellCastData . uses_mana )
2018-03-29 17:01:57 -04:00
{
double chance = GetMagicSkillChance ( m_SpellCastData . current_skill , m_SpellCastData . spell - > _power ) ;
if ( chance < Random : : RollDice ( 0.0 , 1.0 ) )
{
// fizzle
2018-07-12 14:41:21 -07:00
m_pWeenie - > EmitEffect ( PS_Fizzle , 0.542734265f ) ;
m_pWeenie - > AdjustMana ( - 5 ) ;
2018-07-17 01:14:23 -05:00
bFizzled = true ;
2018-07-12 14:41:21 -07:00
}
2018-07-20 18:19:00 -05:00
else if ( ! bFizzled & & m_pWeenie - > m_Position . distance ( m_SpellCastData . initial_cast_position ) > = 6.0 & & m_pWeenie - > m_Qualities . GetInt ( PLAYER_KILLER_STATUS_INT , 0 ) = = PK_PKStatus )
{
// fizzle
m_pWeenie - > EmitEffect ( PS_Fizzle , 0.542734265f ) ;
m_pWeenie - > AdjustMana ( - 5 ) ;
m_pWeenie - > SendText ( " Your movement disrupted spell casting! " , LTT_MAGIC ) ;
m_pWeenie - > SendText ( " Your movement disrupted spell casting! " , LTT_ERROR ) ;
2018-07-18 02:12:17 -05:00
2018-07-20 18:19:00 -05:00
return WERROR_NONE ;
}
2018-03-29 17:01:57 -04:00
if ( ! m_UsedComponents . empty ( ) ) //we used components, so check if any need burning
{
//Each spell and each component type has a burn rate, where the lower level spells typically burn less.
//This rate is increased when fizzling. Your magic skill is not a factor except indirectly through fizzling.
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
SpellComponentTable * pSpellComponents = MagicSystem : : GetSpellComponentTable ( ) ;
float spellComponentLossMod = m_SpellCastData . spell - > _component_loss ;
2018-07-02 01:39:47 -05:00
if ( bFizzled )
2018-03-29 17:01:57 -04:00
spellComponentLossMod * = 1.5 ; //made up value: 50% extra chance of burning components on fizzles.
if ( pSpellComponents )
{
std : : string componentsConsumedString = " " ;
for ( std : : map < DWORD , DWORD > : : iterator iter = m_UsedComponents . begin ( ) ; iter ! = m_UsedComponents . end ( ) ; + + iter )
{
2018-07-12 14:41:21 -07:00
CWeenieObject * component = g_pWorld - > FindObject ( iter - > first ) ;
2018-04-28 12:32:16 -04:00
if ( ! component ) // where did it go? force fizzle.
2018-03-29 17:01:57 -04:00
return WERROR_MAGIC_FIZZLE ;
int compId = component - > InqDIDQuality ( SPELL_COMPONENT_DID , 0 ) ;
2018-04-19 17:14:14 -05:00
int spellPower = m_SpellCastData . spell - > _power ;
int currentSkill = m_SpellCastData . current_skill ;
2018-03-29 17:01:57 -04:00
const SpellComponentBase * componentBase = pSpellComponents - > InqSpellComponentBase ( compId ) ;
2018-04-19 00:56:18 -05:00
float burnChance = componentBase - > _CDM * spellComponentLossMod ;
2018-04-28 12:32:16 -04:00
burnChance * = min ( 1.0 , ( double ) spellPower / ( double ) currentSkill ) ;
if ( Random : : RollDice ( 0.0 , 1.0 ) < burnChance )
{
for ( int i = 0 ; i < getRandomNumber ( 1 , iter - > second , eRandomFormula : : favorMid , 1.5 , 0 ) ; + + i )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
component - > DecrementStackOrStructureNum ( ) ;
if ( componentsConsumedString . length ( ) > 0 )
componentsConsumedString . append ( " , " ) ;
componentsConsumedString . append ( componentBase - > _name ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
}
m_UsedComponents . clear ( ) ;
if ( componentsConsumedString . length ( ) > 0 )
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " The spell consumed the following components: %s " , componentsConsumedString . c_str ( ) ) , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-07-02 01:39:47 -05:00
if ( bFizzled )
2018-03-29 17:01:57 -04:00
return WERROR_MAGIC_FIZZLE ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > AdjustMana ( - GenerateManaCost ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
else if ( ( m_pWeenie - > AsMeleeWeapon ( ) | | m_pWeenie - > AsMissileLauncher ( ) ) & & m_SpellCastData . uses_mana )
2018-07-03 15:42:54 -05:00
{
// Drain mana from weapon on Cast on Strike
2018-07-12 14:41:21 -07:00
m_pWeenie - > m_Qualities . SetInt ( ITEM_CUR_MANA_INT , m_pWeenie - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 , 0 ) - m_SpellCastData . spell - > _base_mana ) ;
2018-07-03 15:42:54 -05:00
}
2018-03-29 17:01:57 -04:00
bool bSpellPerformed = false ;
if ( m_SpellCastData . spellEx & & m_SpellCastData . spellEx - > _meta_spell . _spell )
{
switch ( m_SpellCastData . spellEx - > _meta_spell . _sp_type )
{
case SpellType : : Transfer_SpellType :
2018-04-28 12:32:16 -04:00
{
TransferSpellEx * meta = ( TransferSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
bSpellPerformed = DoTransferSpell ( GetCastTarget ( ) , meta ) ;
break ;
}
2018-03-29 17:01:57 -04:00
case SpellType : : Boost_SpellType :
2018-04-28 12:32:16 -04:00
{
//bSpellPerformed = AdjustVital(GetCastTarget(), Random::GenInt(boostMin, boostMax), meta->_dt);
bSpellPerformed = AdjustVital ( GetCastTarget ( ) ) ;
break ;
}
2018-04-24 02:03:00 -05:00
case SpellType : : FellowBoost_SpellType :
{
FellowshipBoostSpellEx * meta = ( FellowshipBoostSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
2018-07-12 14:41:21 -07:00
CWeenieObject * target = GetCastTarget ( ) ;
2018-04-24 02:03:00 -05:00
if ( ! target - > HasFellowship ( ) )
break ;
else
{
Fellowship * fellow = target - > GetFellowship ( ) ;
CWorldLandBlock * block = target - > GetBlock ( ) ;
for ( auto & entry : fellow - > _fellowship_table )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * member = g_pWorld - > FindPlayer ( entry . first ) )
2018-04-24 02:03:00 -05:00
{
if ( member - > GetBlock ( ) = = block )
{
bSpellPerformed = AdjustVital ( member ) ;
}
}
}
PerformFellowCastParticleEffects ( fellow ) ;
}
break ;
}
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
case SpellType : : Dispel_SpellType :
2018-04-28 12:32:16 -04:00
{
DispelSpellEx * meta = ( DispelSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
int minNum = ( int ) ( ( meta - > _number * meta - > _number_variance ) + F_EPSILON ) ;
int maxNum = ( int ) ( ( meta - > _number * ( 1.0 / meta - > _number_variance ) ) + F_EPSILON ) ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
int numToDispel = Random : : GenInt ( minNum , maxNum ) ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
CWeenieObject * pTarget = GetCastTarget ( ) ;
2018-04-28 12:32:16 -04:00
if ( pTarget )
{
if ( ! ( m_SpellCastData . spell - > _bitfield & Beneficial_SpellIndex ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( pTarget - > GetWorldTopLevelOwner ( ) - > ImmuneToDamage ( m_pWeenie ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
break ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
PackableListWithJson < DWORD > possibleToDispel ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
if ( pTarget - > m_Qualities . _enchantment_reg )
{
if ( pTarget - > m_Qualities . _enchantment_reg - > _add_list )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
for ( auto & entry : * pTarget - > m_Qualities . _enchantment_reg - > _add_list )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( entry . _power_level > meta - > _max_power )
continue ;
if ( entry . _power_level < meta - > _min_power )
continue ;
if ( entry . _duration < = 0.0 )
continue ;
if ( ( entry . _id & 0xFFFF ) = = 666 ) // vitae
continue ;
if ( CSpellTableEx * pSpellTableEx = g_pPortalDataEx - > GetSpellTableEx ( ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( const CSpellBaseEx * spellBaseEx = pSpellTableEx - > GetSpellBase ( entry . _id & 0xFFFF ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( meta - > _school & & meta - > _school ! = spellBaseEx - > _school )
continue ;
switch ( meta - > _align )
{
case 0 : // neutral
{
break ;
}
case 1 : // good only
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( ! ( spellBaseEx - > _bitfield & Beneficial_SpellIndex ) )
2018-03-29 17:01:57 -04:00
continue ;
2018-04-28 12:32:16 -04:00
break ;
}
case 2 : // bad only
{
if ( spellBaseEx - > _bitfield & Beneficial_SpellIndex )
continue ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
break ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
}
possibleToDispel . push_back ( entry . _id ) ;
2018-03-29 17:01:57 -04:00
}
}
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
if ( pTarget - > m_Qualities . _enchantment_reg - > _mult_list )
{
for ( auto & entry : * pTarget - > m_Qualities . _enchantment_reg - > _mult_list )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( entry . _power_level > meta - > _max_power )
continue ;
if ( entry . _power_level < meta - > _min_power )
continue ;
if ( entry . _duration < = 0.0 )
continue ;
if ( ( entry . _id & 0xFFFF ) = = 666 ) // vitae
continue ;
if ( CSpellTableEx * pSpellTableEx = g_pPortalDataEx - > GetSpellTableEx ( ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( const CSpellBaseEx * spellBaseEx = pSpellTableEx - > GetSpellBase ( entry . _id & 0xFFFF ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( meta - > _school & & meta - > _school ! = spellBaseEx - > _school )
continue ;
switch ( meta - > _align )
{
case 0 : // neutral
{
break ;
}
case 1 : // good only
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( ! ( spellBaseEx - > _bitfield & Beneficial_SpellIndex ) )
2018-03-29 17:01:57 -04:00
continue ;
2018-04-28 12:32:16 -04:00
break ;
}
case 2 : // bad only
{
if ( spellBaseEx - > _bitfield & Beneficial_SpellIndex )
continue ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
break ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
}
possibleToDispel . push_back ( entry . _id ) ;
2018-03-29 17:01:57 -04:00
}
}
}
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
PackableListWithJson < DWORD > listToDispel ;
if ( meta - > _number < 0 )
{
// dispel all
listToDispel = possibleToDispel ;
}
else
{
while ( numToDispel > 0 & & ! possibleToDispel . empty ( ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
std : : list < DWORD > : : iterator randomEntry = possibleToDispel . begin ( ) ;
std : : advance ( randomEntry , Random : : GenUInt ( 0 , ( DWORD ) ( possibleToDispel . size ( ) - 1 ) ) ) ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
listToDispel . push_back ( * randomEntry ) ;
possibleToDispel . erase ( randomEntry ) ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
numToDispel - - ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
std : : string spellNames ;
for ( auto entry : listToDispel )
{
if ( CSpellTableEx * pSpellTableEx = g_pPortalDataEx - > GetSpellTableEx ( ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( const CSpellBaseEx * spellBaseEx = pSpellTableEx - > GetSpellBase ( entry & 0xFFFF ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( spellNames . empty ( ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
spellNames = spellBaseEx - > _name ;
}
else
{
spellNames + = " , " ;
spellNames + = spellBaseEx - > _name ;
2018-03-29 17:01:57 -04:00
}
}
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
// "You cast Incantation of Nullify All Magic Self on yourself and dispel: ..."
// "Tusker's Friend casts Nullify All Magic Other on you, but the dispel fails."
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
if ( listToDispel . size ( ) > 0 )
{
2018-07-12 14:41:21 -07:00
if ( pTarget = = m_pWeenie )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself and dispel: %s " , m_SpellCastData . spell - > _name . c_str ( ) , spellNames . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s and dispel: %s " , m_SpellCastData . spell - > _name . c_str ( ) , pTarget - > GetName ( ) . c_str ( ) , spellNames . c_str ( ) ) , LTT_MAGIC ) ;
pTarget - > SendText ( csprintf ( " %s casts %s on you and dispels: %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) , spellNames . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
if ( pTarget - > m_Qualities . _enchantment_reg )
{
pTarget - > m_Qualities . _enchantment_reg - > RemoveEnchantments ( & listToDispel ) ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
BinaryWriter expireMessage ;
expireMessage . Write < DWORD > ( 0x2C8 ) ;
listToDispel . Pack ( & expireMessage ) ;
pTarget - > SendNetMessage ( & expireMessage , PRIVATE_MSG , TRUE , FALSE ) ;
}
}
else
{
2018-07-12 14:41:21 -07:00
if ( pTarget = = m_pWeenie )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself, but the dispel fails. " , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s, but the dispel fails. " , m_SpellCastData . spell - > _name . c_str ( ) , pTarget - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
pTarget - > SendText ( csprintf ( " %s casts %s on you, but the dispel fails. " , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
2018-03-29 17:01:57 -04:00
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
break ;
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
case SpellType : : FellowDispel_SpellType :
{
FellowshipDispelSpellEx * meta = ( FellowshipDispelSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
int minNum = ( int ) ( ( meta - > _number * meta - > _number_variance ) + F_EPSILON ) ;
int maxNum = ( int ) ( ( meta - > _number * ( 1.0 / meta - > _number_variance ) ) + F_EPSILON ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
int numToDispel = Random : : GenInt ( minNum , maxNum ) ;
2018-04-24 02:03:00 -05:00
2018-07-12 14:41:21 -07:00
CWeenieObject * target = GetCastTarget ( ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
if ( ! target - > HasFellowship ( ) )
break ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
else
{
Fellowship * fellow = target - > GetFellowship ( ) ;
CWorldLandBlock * block = target - > GetBlock ( ) ;
for ( auto & entry : fellow - > _fellowship_table )
2018-04-24 02:03:00 -05:00
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * member = g_pWorld - > FindPlayer ( entry . first ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( member - > GetBlock ( ) = = block )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( member )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( ! ( m_SpellCastData . spell - > _bitfield & Beneficial_SpellIndex ) )
2018-04-24 02:03:00 -05:00
{
2018-07-12 14:41:21 -07:00
if ( member - > GetWorldTopLevelOwner ( ) - > ImmuneToDamage ( m_pWeenie ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
break ;
}
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
PackableListWithJson < DWORD > possibleToDispel ;
if ( member - > m_Qualities . _enchantment_reg )
{
if ( member - > m_Qualities . _enchantment_reg - > _add_list )
{
for ( auto & entry : * member - > m_Qualities . _enchantment_reg - > _add_list )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( entry . _power_level > meta - > _max_power )
continue ;
if ( entry . _power_level < meta - > _min_power )
continue ;
if ( entry . _duration < = 0.0 )
continue ;
if ( ( entry . _id & 0xFFFF ) = = 666 ) // vitae
continue ;
if ( CSpellTableEx * pSpellTableEx = g_pPortalDataEx - > GetSpellTableEx ( ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( const CSpellBaseEx * spellBaseEx = pSpellTableEx - > GetSpellBase ( entry . _id & 0xFFFF ) )
{
if ( meta - > _school & & meta - > _school ! = spellBaseEx - > _school )
continue ;
switch ( meta - > _align )
{
case 0 : // neutral
{
break ;
}
case 1 : // good only
{
if ( ! ( spellBaseEx - > _bitfield & Beneficial_SpellIndex ) )
continue ;
break ;
}
case 2 : // bad only
{
if ( spellBaseEx - > _bitfield & Beneficial_SpellIndex )
continue ;
break ;
}
}
possibleToDispel . push_back ( entry . _id ) ;
}
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
}
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
if ( member - > m_Qualities . _enchantment_reg - > _mult_list )
{
for ( auto & entry : * member - > m_Qualities . _enchantment_reg - > _mult_list )
{
if ( entry . _power_level > meta - > _max_power )
continue ;
if ( entry . _power_level < meta - > _min_power )
continue ;
if ( entry . _duration < = 0.0 )
continue ;
if ( ( entry . _id & 0xFFFF ) = = 666 ) // vitae
continue ;
if ( CSpellTableEx * pSpellTableEx = g_pPortalDataEx - > GetSpellTableEx ( ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( const CSpellBaseEx * spellBaseEx = pSpellTableEx - > GetSpellBase ( entry . _id & 0xFFFF ) )
{
if ( meta - > _school & & meta - > _school ! = spellBaseEx - > _school )
continue ;
switch ( meta - > _align )
{
case 0 : // neutral
{
break ;
}
case 1 : // good only
{
if ( ! ( spellBaseEx - > _bitfield & Beneficial_SpellIndex ) )
continue ;
break ;
}
case 2 : // bad only
{
if ( spellBaseEx - > _bitfield & Beneficial_SpellIndex )
continue ;
break ;
}
}
possibleToDispel . push_back ( entry . _id ) ;
}
2018-04-24 02:03:00 -05:00
}
}
}
}
2018-04-28 12:32:16 -04:00
PackableListWithJson < DWORD > listToDispel ;
if ( meta - > _number < 0 )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
// dispel all
listToDispel = possibleToDispel ;
}
else
{
while ( numToDispel > 0 & & ! possibleToDispel . empty ( ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
std : : list < DWORD > : : iterator randomEntry = possibleToDispel . begin ( ) ;
std : : advance ( randomEntry , Random : : GenUInt ( 0 , ( DWORD ) ( possibleToDispel . size ( ) - 1 ) ) ) ;
listToDispel . push_back ( * randomEntry ) ;
possibleToDispel . erase ( randomEntry ) ;
numToDispel - - ;
}
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
std : : string spellNames ;
for ( auto entry : listToDispel )
{
if ( CSpellTableEx * pSpellTableEx = g_pPortalDataEx - > GetSpellTableEx ( ) )
{
if ( const CSpellBaseEx * spellBaseEx = pSpellTableEx - > GetSpellBase ( entry & 0xFFFF ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( spellNames . empty ( ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
spellNames = spellBaseEx - > _name ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
else
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
spellNames + = " , " ;
spellNames + = spellBaseEx - > _name ;
2018-04-24 02:03:00 -05:00
}
}
}
}
2018-04-28 12:32:16 -04:00
// "You cast Incantation of Nullify All Magic Self on yourself and dispel: ..."
// "Tusker's Friend casts Nullify All Magic Other on you, but the dispel fails."
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
if ( listToDispel . size ( ) > 0 )
{
2018-07-12 14:41:21 -07:00
if ( member = = m_pWeenie )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself and dispel: %s " , m_SpellCastData . spell - > _name . c_str ( ) , spellNames . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s and dispel: %s " , m_SpellCastData . spell - > _name . c_str ( ) , member - > GetName ( ) . c_str ( ) , spellNames . c_str ( ) ) , LTT_MAGIC ) ;
member - > SendText ( csprintf ( " %s casts %s on you and dispels: %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) , spellNames . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
if ( member - > m_Qualities . _enchantment_reg )
{
member - > m_Qualities . _enchantment_reg - > RemoveEnchantments ( & listToDispel ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
BinaryWriter expireMessage ;
expireMessage . Write < DWORD > ( 0x2C8 ) ;
listToDispel . Pack ( & expireMessage ) ;
member - > SendNetMessage ( & expireMessage , PRIVATE_MSG , TRUE , FALSE ) ;
}
2018-04-24 02:03:00 -05:00
}
else
{
2018-07-12 14:41:21 -07:00
if ( member = = m_pWeenie )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself, but the dispel fails. " , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s, but the dispel fails. " , m_SpellCastData . spell - > _name . c_str ( ) , member - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
member - > SendText ( csprintf ( " %s casts %s on you, but the dispel fails. " , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
2018-04-24 02:03:00 -05:00
}
}
}
2018-04-28 12:32:16 -04:00
}
PerformFellowCastParticleEffects ( fellow ) ;
}
break ;
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
case SpellType : : PortalLink_SpellType :
{
2018-08-19 15:53:55 -05:00
//if (m_pWeenie->HasOwner())
//break;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
PortalLinkSpellEx * meta = ( PortalLinkSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
2018-04-24 02:03:00 -05:00
2018-07-12 14:41:21 -07:00
CWeenieObject * pTarget = GetCastTarget ( ) ;
2018-04-28 12:32:16 -04:00
if ( pTarget )
{
// portal bitmask, 0x10 = cannot be summoned
// portal bitmask, 0x20 = cannot be linked/recalled
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
int minLevel = pTarget - > InqIntQuality ( MIN_LEVEL_INT , 0 ) ;
int maxLevel = pTarget - > InqIntQuality ( MAX_LEVEL_INT , 0 ) ;
2018-12-27 13:25:47 -06:00
DWORD origPortID = pTarget - > InqDIDQuality ( ORIGINAL_PORTAL_DID , 0 ) ;
2018-04-28 12:32:16 -04:00
2018-07-12 14:41:21 -07:00
int currentLevel = m_pWeenie - > InqIntQuality ( LEVEL_INT , 1 ) ;
2018-04-28 12:32:16 -04:00
if ( minLevel & & currentLevel < minLevel )
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You are not powerful enough to tie to this portal yet. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
break ;
}
else if ( maxLevel & & currentLevel > maxLevel )
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You are too powerful to tie to this portal. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
break ;
}
2018-12-27 13:25:47 -06:00
else if ( origPortID = = W_PORTALGATEWAY_CLASS ) // Don't tie to portals with no original portal set.
{
m_pWeenie - > SendText ( " This portal has no destination set. " , LTT_MAGIC ) ;
break ;
}
2018-04-28 12:32:16 -04:00
switch ( meta - > _index )
{
case 1 :
if ( pTarget - > m_Qualities . m_WeenieType = = LifeStone_WeenieType )
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > m_Qualities . SetPosition ( LINKED_LIFESTONE_POSITION , m_pWeenie - > m_Position ) ;
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have successfully linked with the life stone. " , LTT_MAGIC ) ;
2018-04-24 02:03:00 -05:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You cannot link that. " , LTT_MAGIC ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
break ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
case 2 : // primary portal tie
if ( pTarget - > m_Qualities . m_WeenieType = = Portal_WeenieType & &
! ( pTarget - > m_Qualities . GetInt ( PORTAL_BITMASK_INT , 0 ) & 0x20 ) )
2018-12-27 13:25:47 -06:00
{
if ( origPortID > 0 )
{
// This is a summoned portal with an original portal ID
m_pWeenie - > m_Qualities . SetDataID ( LINKED_PORTAL_ONE_DID , origPortID ) ;
m_pWeenie - > m_Qualities . SetPosition ( LINKED_PORTAL_ONE_POSITION , pTarget - > InqPositionQuality ( DESTINATION_POSITION , Position ( ) ) ) ;
}
else
{
// This is not a summoned portal
m_pWeenie - > m_Qualities . SetDataID ( LINKED_PORTAL_ONE_DID , pTarget - > m_Qualities . id ) ;
m_pWeenie - > m_Qualities . SetPosition ( LINKED_PORTAL_ONE_POSITION , pTarget - > InqPositionQuality ( DESTINATION_POSITION , Position ( ) ) ) ;
}
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have successfully linked with the portal. " , LTT_MAGIC ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You cannot link that portal. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
break ;
case 3 : // secondary portal tie
if ( pTarget - > m_Qualities . m_WeenieType = = Portal_WeenieType & &
! ( pTarget - > m_Qualities . GetInt ( PORTAL_BITMASK_INT , 0 ) & 0x20 ) )
2018-12-27 13:25:47 -06:00
{
if ( origPortID > 0 )
{
// This is a summoned portal with an original portal ID
m_pWeenie - > m_Qualities . SetDataID ( LINKED_PORTAL_TWO_DID , origPortID ) ;
m_pWeenie - > m_Qualities . SetPosition ( LINKED_PORTAL_TWO_POSITION , pTarget - > InqPositionQuality ( DESTINATION_POSITION , Position ( ) ) ) ;
}
else
{
// This is not a summoned portal
m_pWeenie - > m_Qualities . SetDataID ( LINKED_PORTAL_TWO_DID , pTarget - > m_Qualities . id ) ;
m_pWeenie - > m_Qualities . SetPosition ( LINKED_PORTAL_TWO_POSITION , pTarget - > InqPositionQuality ( DESTINATION_POSITION , Position ( ) ) ) ;
}
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have successfully linked with the portal. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You cannot link that portal. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
break ;
2018-04-24 02:03:00 -05:00
}
}
2018-04-28 12:32:16 -04:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > IsAdmin ( ) )
2018-04-28 12:32:16 -04:00
{
// lifestone tie = 1
// primary portal tie = 2
// secondary portal tie = 3
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("Index: %d", meta->_index), LTT_DEFAULT);
2018-04-28 12:32:16 -04:00
}
break ;
}
case SpellType : : PortalRecall_SpellType :
{
2018-08-05 16:25:40 -05:00
/*if (m_pWeenie->HasOwner()) //Needed to comment out for Rare gems.
break ; */
2018-04-28 12:32:16 -04:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > AsPlayer ( ) & & m_pWeenie - > AsPlayer ( ) - > CheckPKActivity ( ) )
2018-05-19 19:21:17 +01:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have been involved in Player Killer combat too recently! " , LTT_MAGIC ) ;
2018-05-19 19:21:17 +01:00
break ;
}
2018-04-28 12:32:16 -04:00
PortalRecallSpellEx * meta = ( PortalRecallSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
switch ( meta - > _index )
{
2018-08-25 21:20:11 -05:00
case 1 : // lifestone sending
{
Position lifestone ;
if ( m_pWeenie - > m_Qualities . InqPosition ( SANCTUARY_POSITION , lifestone ) & & lifestone . objcell_id ! = 0 )
{
BeginPortalSend ( lifestone ) ;
}
else
{
2019-01-09 02:01:58 +00:00
m_pWeenie - > SendText ( " Your soul is not bound to a lifestone. " , LTT_MAGIC ) ;
2018-08-25 21:20:11 -05:00
}
bSpellPerformed = true ;
break ;
}
2018-04-28 12:32:16 -04:00
case 2 : // lifestone recall
{
Position lifestone ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > m_Qualities . InqPosition ( LINKED_LIFESTONE_POSITION , lifestone ) & & lifestone . objcell_id ! = 0 )
2018-04-28 12:32:16 -04:00
{
BeginPortalSend ( lifestone ) ;
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have no lifestone tied. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
bSpellPerformed = true ;
2018-04-24 02:03:00 -05:00
break ;
}
2018-04-28 12:32:16 -04:00
case 3 : // portal recall
2018-03-29 17:01:57 -04:00
{
2018-11-09 22:55:00 -06:00
DWORD portalDID = 0 ;
if ( m_pWeenie - > m_Qualities . InqDataID ( LAST_PORTAL_DID , portalDID ) & & portalDID ! = 0 )
2018-08-05 16:25:40 -05:00
{
2018-11-09 22:55:00 -06:00
CWeenieDefaults * portalDefaults = NULL ;
if ( portalDID & & ! ( 1955 = = portalDID ) )
{
portalDefaults = g_pWeenieFactory - > GetWeenieDefaults ( portalDID ) ;
}
else if ( portalDID & & ( 1955 = = portalDID ) )
{
portalDefaults = g_pWeenieFactory - > GetWeenieDefaults ( portalDID ) ;
2018-12-09 22:37:45 -06:00
portalDefaults - > m_Qualities . SetPosition ( DESTINATION_POSITION , m_pWeenie - > InqPositionQuality ( LAST_PORTAL_POSITION , Position ( ) ) ) ;
2018-11-09 22:55:00 -06:00
}
2018-11-19 00:48:17 -06:00
if ( portalDefaults )
{
int minLevel = 0 ;
int maxLevel = 0 ;
portalDefaults - > m_Qualities . InqInt ( MIN_LEVEL_INT , minLevel ) ;
portalDefaults - > m_Qualities . InqInt ( MAX_LEVEL_INT , maxLevel ) ;
2018-11-09 22:55:00 -06:00
2018-11-19 00:48:17 -06:00
int currentLevel = m_pWeenie - > InqIntQuality ( LEVEL_INT , 1 ) ;
2018-11-09 22:55:00 -06:00
2018-11-19 00:48:17 -06:00
if ( minLevel & & currentLevel < minLevel )
{
m_pWeenie - > SendText ( " You are not powerful enough to recall this portal yet. " , LTT_MAGIC ) ;
break ;
}
else if ( maxLevel & & currentLevel > maxLevel )
{
m_pWeenie - > SendText ( " You are too powerful to recall this portal. " , LTT_MAGIC ) ;
break ;
}
2018-11-09 22:55:00 -06:00
2018-11-19 00:48:17 -06:00
std : : string restriction ;
if ( portalDefaults - > m_Qualities . InqString ( QUEST_RESTRICTION_STRING , restriction ) )
2018-11-09 22:55:00 -06:00
{
2018-11-19 00:48:17 -06:00
if ( CPlayerWeenie * player = m_pWeenie - > AsPlayer ( ) )
2018-11-09 22:55:00 -06:00
{
2018-11-19 00:48:17 -06:00
if ( ! player - > InqQuest ( restriction . c_str ( ) ) )
{
m_pWeenie - > SendText ( " You try to recall the portal but there is no effect. " , LTT_MAGIC ) ;
break ;
}
2018-11-09 22:55:00 -06:00
}
}
2018-11-19 00:48:17 -06:00
Position portalDest ;
if ( portalDefaults - > m_Qualities . InqPosition ( DESTINATION_POSITION , portalDest ) & & portalDest . objcell_id ! = 0 )
{
BeginPortalSend ( portalDest ) ;
}
else
{
m_pWeenie - > SendText ( " The portal you last used has no destination set. " , LTT_MAGIC ) ;
}
2018-11-09 22:55:00 -06:00
}
2018-08-05 16:25:40 -05:00
}
2018-04-28 12:32:16 -04:00
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have not used a recallable portal yet. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
break ;
}
2018-03-29 17:01:57 -04:00
2018-11-09 22:55:00 -06:00
break ;
2018-04-28 12:32:16 -04:00
case 4 : // primary portal recall
{
DWORD portalDID = 0 ;
2018-05-21 23:20:21 +01:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > m_Qualities . InqDataID ( LINKED_PORTAL_ONE_DID , portalDID ) & & portalDID ! = 0 )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
CWeenieDefaults * portalDefaults = NULL ;
2018-08-19 15:53:55 -05:00
if ( portalDID & & ! ( 1955 = = portalDID ) )
{
portalDefaults = g_pWeenieFactory - > GetWeenieDefaults ( portalDID ) ;
}
else if ( portalDID & & ( 1955 = = portalDID ) )
2018-04-28 12:32:16 -04:00
{
portalDefaults = g_pWeenieFactory - > GetWeenieDefaults ( portalDID ) ;
2018-08-19 15:53:55 -05:00
portalDefaults - > m_Qualities . SetPosition ( DESTINATION_POSITION , m_pWeenie - > InqPositionQuality ( LINKED_PORTAL_ONE_POSITION , Position ( ) ) ) ;
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-11-19 00:48:17 -06:00
if ( portalDefaults )
{
int minLevel = 0 ;
int maxLevel = 0 ;
portalDefaults - > m_Qualities . InqInt ( MIN_LEVEL_INT , minLevel ) ;
portalDefaults - > m_Qualities . InqInt ( MAX_LEVEL_INT , maxLevel ) ;
2018-08-19 15:53:55 -05:00
2018-11-19 00:48:17 -06:00
int currentLevel = m_pWeenie - > InqIntQuality ( LEVEL_INT , 1 ) ;
2018-03-29 17:01:57 -04:00
2018-11-19 00:48:17 -06:00
if ( minLevel & & currentLevel < minLevel )
{
m_pWeenie - > SendText ( " You are not powerful enough to recall this portal yet. " , LTT_MAGIC ) ;
break ;
}
else if ( maxLevel & & currentLevel > maxLevel )
{
m_pWeenie - > SendText ( " You are too powerful to recall this portal. " , LTT_MAGIC ) ;
break ;
}
2018-03-29 17:01:57 -04:00
2018-11-19 00:48:17 -06:00
std : : string restriction ;
if ( portalDefaults - > m_Qualities . InqString ( QUEST_RESTRICTION_STRING , restriction ) )
2018-03-29 17:01:57 -04:00
{
2018-11-19 00:48:17 -06:00
if ( CPlayerWeenie * player = m_pWeenie - > AsPlayer ( ) )
2018-04-28 12:32:16 -04:00
{
2018-11-19 00:48:17 -06:00
if ( ! player - > InqQuest ( restriction . c_str ( ) ) )
{
m_pWeenie - > SendText ( " You try to recall the portal but there is no effect. " , LTT_MAGIC ) ;
break ;
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
}
2018-11-19 00:48:17 -06:00
Position portalDest ;
if ( portalDefaults - > m_Qualities . InqPosition ( DESTINATION_POSITION , portalDest ) & & portalDest . objcell_id ! = 0 )
{
BeginPortalSend ( portalDest ) ;
}
else
{
m_pWeenie - > SendText ( " The primary portal you have tied has no destination set. " , LTT_MAGIC ) ;
}
2018-03-29 17:01:57 -04:00
}
}
2018-04-28 12:32:16 -04:00
else
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have no primary portal tied. " , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
2018-03-29 17:01:57 -04:00
break ;
}
2018-04-28 12:32:16 -04:00
break ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
case 5 : // secondary portal recall
{
DWORD portalDID = 0 ;
2018-05-22 00:06:53 +01:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > m_Qualities . InqDataID ( LINKED_PORTAL_TWO_DID , portalDID ) & & portalDID ! = 0 )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
CWeenieDefaults * portalDefaults = NULL ;
2018-03-29 17:01:57 -04:00
2018-08-19 15:53:55 -05:00
if ( portalDID & & ! ( 1955 = = portalDID ) )
{
portalDefaults = g_pWeenieFactory - > GetWeenieDefaults ( portalDID ) ;
}
else if ( portalDID & & ( 1955 = = portalDID ) )
2018-04-28 12:32:16 -04:00
{
portalDefaults = g_pWeenieFactory - > GetWeenieDefaults ( portalDID ) ;
2018-08-19 15:53:55 -05:00
portalDefaults - > m_Qualities . SetPosition ( DESTINATION_POSITION , m_pWeenie - > InqPositionQuality ( LINKED_PORTAL_TWO_POSITION , Position ( ) ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-12-25 06:14:20 -06:00
if ( portalDefaults )
{
int minLevel = 0 ;
int maxLevel = 0 ;
portalDefaults - > m_Qualities . InqInt ( MIN_LEVEL_INT , minLevel ) ;
portalDefaults - > m_Qualities . InqInt ( MAX_LEVEL_INT , maxLevel ) ;
2018-03-29 17:01:57 -04:00
2018-12-25 06:14:20 -06:00
int currentLevel = m_pWeenie - > InqIntQuality ( LEVEL_INT , 1 ) ;
2018-04-28 12:32:16 -04:00
2018-12-25 06:14:20 -06:00
if ( minLevel & & currentLevel < minLevel )
{
m_pWeenie - > SendText ( " You are not powerful enough to recall this portal yet. " , LTT_MAGIC ) ;
break ;
}
else if ( maxLevel & & currentLevel > maxLevel )
{
m_pWeenie - > SendText ( " You are too powerful to recall this portal. " , LTT_MAGIC ) ;
break ;
}
2018-03-29 17:01:57 -04:00
2018-12-25 06:14:20 -06:00
std : : string restriction ;
if ( portalDefaults - > m_Qualities . InqString ( QUEST_RESTRICTION_STRING , restriction ) )
2018-03-29 17:01:57 -04:00
{
2018-12-25 06:14:20 -06:00
if ( CPlayerWeenie * player = m_pWeenie - > AsPlayer ( ) )
2018-03-29 17:01:57 -04:00
{
2018-12-25 06:14:20 -06:00
if ( ! player - > InqQuest ( restriction . c_str ( ) ) )
{
m_pWeenie - > SendText ( " You try to recall the portal but there is no effect. " , LTT_MAGIC ) ;
break ;
}
2018-03-29 17:01:57 -04:00
}
}
2018-12-25 06:14:20 -06:00
Position portalDest ;
if ( portalDefaults - > m_Qualities . InqPosition ( DESTINATION_POSITION , portalDest ) & & portalDest . objcell_id ! = 0 )
{
BeginPortalSend ( portalDest ) ;
}
else
{
m_pWeenie - > SendText ( " The secondary portal you have tied has no destination set. " , LTT_MAGIC ) ;
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
else
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have no secondary portal tied. " , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
bSpellPerformed = true ;
break ;
}
2018-04-28 12:32:16 -04:00
break ;
}
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > IsAdmin ( ) )
2018-04-28 12:32:16 -04:00
{
// lifestone recall = 2
// portal recall = 3
// primary portal recall = 4
// secondary portal recall = 5
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("Index: %d", meta->_index), LTT_DEFAULT);
2018-04-28 12:32:16 -04:00
}
bSpellPerformed = true ;
break ;
}
2018-03-29 17:01:57 -04:00
case SpellType : : Enchantment_SpellType :
2018-04-28 12:32:16 -04:00
{
EnchantmentSpellEx * meta = ( EnchantmentSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
Enchantment enchant ;
2018-07-12 14:41:21 -07:00
int buffDuration = m_pWeenie - > InqIntQuality ( AUGMENTATION_INCREASED_SPELL_DURATION_INT , 0 ) ;
2018-04-28 12:32:16 -04:00
enchant . _id = meta - > _spell_id | ( ( DWORD ) m_SpellCastData . serial < < ( DWORD ) 16 ) ;
enchant . m_SpellSetID = 0 ; // ???
enchant . _spell_category = m_SpellCastData . spell - > _category ; // meta->_spellCategory;
enchant . _power_level = m_SpellCastData . spell - > _power ;
enchant . _start_time = Timer : : cur_time ;
2018-04-28 12:34:30 -04:00
enchant . _duration = m_SpellCastData . equipped ? - 1.0 : meta - > _duration * ( buffDuration * 0.2 + 1 ) ;
2018-07-12 14:41:21 -07:00
enchant . _caster = m_pWeenie - > GetID ( ) ;
2018-04-28 12:32:16 -04:00
enchant . _degrade_modifier = meta - > _degrade_modifier ;
enchant . _degrade_limit = meta - > _degrade_limit ;
enchant . _last_time_degraded = - 1.0 ;
enchant . _smod = meta - > _smod ;
if ( enchant . _smod . type & Skill_EnchantmentType )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
enchant . _smod . key = ( DWORD ) SkillTable : : OldToNewSkill ( ( STypeSkill ) enchant . _smod . key ) ;
}
2018-03-29 20:49:54 -04:00
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > targets ;
2018-03-29 20:49:54 -04:00
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * castTarget = GetCastTarget ( ) )
2018-04-28 12:32:16 -04:00
{
2018-07-20 16:28:32 -05:00
// NPKs should not be able to buff PKs
if ( m_pWeenie & & castTarget & & m_pWeenie - > AsPlayer ( ) & & castTarget - > AsPlayer ( ) )
{
2018-08-04 19:10:13 -05:00
if ( ! m_pWeenie - > IsPK ( ) & & castTarget - > IsPK ( ) )
2018-07-20 16:28:32 -05:00
{
bSpellPerformed = false ;
break ;
}
}
2018-04-28 12:32:16 -04:00
if ( m_SpellCastData . spell - > InqTargetType ( ) ! = ITEM_TYPE : : TYPE_ITEM_ENCHANTABLE_TARGET )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
targets . push_back ( castTarget ) ;
}
else
{
2018-07-12 14:41:21 -07:00
CContainerWeenie * container = castTarget - > AsContainer ( ) ;
2018-04-28 12:32:16 -04:00
if ( container & & ! container - > HasOwner ( ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
for ( auto wielded : container - > m_Wielded )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( wielded - > GetItemType ( ) & m_SpellCastData . spell - > _non_component_target_type )
2018-03-29 17:01:57 -04:00
{
2018-08-20 22:32:23 -05:00
if ( castTarget = = m_pWeenie | | wielded - > parent | | m_pWeenie - > GetWorldTopLevelOwner ( ) = = castTarget - > GetWorldTopLevelOwner ( ) ) // for other targets, only physically wielded allowed, TopLevelOwner for buff gems.
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
targets . push_back ( wielded ) ;
2018-03-29 17:01:57 -04:00
}
}
}
2018-04-28 12:32:16 -04:00
}
else
{
if ( castTarget - > GetItemType ( ) & m_SpellCastData . spell - > _non_component_target_type )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( castTarget = = m_pWeenie | | castTarget - > parent | | ! castTarget - > HasOwner ( ) | | castTarget - > GetWorldTopLevelOwner ( ) = = m_pWeenie ) // for other targets, only physically wielded allowed
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
targets . push_back ( castTarget ) ;
2018-03-29 17:01:57 -04:00
}
}
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
for ( auto target : targets )
{
// You cast Harlune's Blessing on yourself, refreshing Harlune's Blessing
// You cast Impenetrability III on Pathwarden Robe, surpassing Impenetrability II
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
CWeenieObject * topLevelOwner = target - > GetWorldTopLevelOwner ( ) ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
if ( target - > InqIntQuality ( MAX_STACK_SIZE_INT , 1 ) > 1 ) //do not allow enchanting stackable items(ammunition)
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " The %s can't be enchanted. " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
continue ;
}
2018-04-01 15:03:58 -04:00
2018-09-20 00:30:57 +01:00
int text_option = 0 ; // 0 = normal cast text, 1 = refreshes text, 2 = surpassed by text, 3 = surpasses text
2018-09-20 00:33:01 +01:00
std : : string existing_spell_name = " " ;
2018-09-20 00:30:57 +01:00
if ( CEnchantmentRegistry * enchant_reg = target - > m_Qualities . _enchantment_reg )
{
2018-09-20 00:33:01 +01:00
if ( Enchantment * highest_enchant = enchant_reg - > GetHighestEnchantOfCategory ( enchant . _spell_category , enchant . _smod . type ) ) // check if spell of this category already exists
2018-09-20 00:30:57 +01:00
{
2018-11-09 22:55:00 -06:00
if ( ( highest_enchant - > _id & 0xFFFF ) = = enchant . _id )
2018-09-20 00:30:57 +01:00
text_option = 1 ;
else
{
// if the current highest enchant is more powerful than the one being cast, use surpassed by text (2), otherwise use surpasses text (3)
text_option = highest_enchant - > _power_level > enchant . _power_level ? 2 : 3 ;
CSpellTable * st = MagicSystem : : GetSpellTable ( ) ;
2018-11-09 22:55:00 -06:00
existing_spell_name = st - > GetSpellBase ( ( highest_enchant - > _id & 0xFFFF ) ) - > _name ;
2018-09-20 00:30:57 +01:00
}
}
}
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = target )
2018-04-28 12:32:16 -04:00
{
if ( ! ( m_SpellCastData . spell - > _bitfield & Beneficial_SpellIndex ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie & & target & & m_pWeenie - > AsPlayer ( ) & & target - > AsPlayer ( ) )
2018-05-20 17:53:49 +01:00
{
2018-07-18 02:46:30 -05:00
// Only Update PK Activity if both target and caster are PK, Prevents PKs from tagging NPKs for PK activity.
2018-08-04 19:10:13 -05:00
if ( m_pWeenie - > IsPK ( ) & & target - > IsPK ( ) )
2018-07-18 02:46:30 -05:00
{
m_pWeenie - > AsPlayer ( ) - > UpdatePKActivity ( ) ;
target - > AsPlayer ( ) - > UpdatePKActivity ( ) ;
}
2018-05-20 17:53:49 +01:00
}
2018-07-12 14:41:21 -07:00
if ( target - > AsPlayer ( ) & & target - > GetWorldTopLevelOwner ( ) - > ImmuneToDamage ( m_pWeenie ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
continue ;
2018-03-29 17:01:57 -04:00
}
}
2018-04-28 12:32:16 -04:00
if ( m_SpellCastData . spell - > _bitfield & Resistable_SpellIndex )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
if ( topLevelOwner - > TryMagicResist ( m_SpellCastData . current_skill ) )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
topLevelOwner - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-11 04:53:32 +00:00
topLevelOwner - > SendText ( csprintf ( " You resist the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
topLevelOwner - > OnResistSpell ( m_pWeenie ) ;
2018-07-03 16:44:24 -05:00
// Cast on Strike
2018-07-18 02:09:35 -05:00
if ( m_pWeenie ! = m_pWeenie - > GetWorldTopLevelOwner ( ) )
2018-07-03 16:44:24 -05:00
{
2018-07-11 04:53:32 +00:00
m_pWeenie - > GetWorldTopLevelOwner ( ) - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-07-03 16:44:24 -05:00
}
2018-04-28 12:32:16 -04:00
continue ;
2018-03-29 17:01:57 -04:00
}
}
2018-04-28 12:32:16 -04:00
if ( int resistMagic = target - > InqIntQuality ( RESIST_MAGIC_INT , 0 , FALSE ) )
2018-04-24 02:03:00 -05:00
{
2018-07-17 02:02:17 -05:00
if ( resistMagic > = 9999 & & topLevelOwner = = m_pWeenie )
continue ;
2018-04-28 12:32:16 -04:00
if ( resistMagic > = 9999 | | : : TryMagicResist ( m_SpellCastData . current_skill , ( DWORD ) resistMagic ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
target - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-04-24 02:03:00 -05:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = topLevelOwner )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " %s resists the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-04-24 02:03:00 -05:00
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > OnResistSpell ( m_pWeenie ) ;
2018-04-28 12:32:16 -04:00
continue ;
}
}
if ( int resistLifeMagic = target - > InqIntQuality ( LIFE_RESIST_RATING_INT , 0 , FALSE ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( resistLifeMagic > = 9999 | | : : TryMagicResist ( m_SpellCastData . current_skill , ( DWORD ) resistLifeMagic ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
target - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = topLevelOwner )
2018-04-24 02:03:00 -05:00
{
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " %s resists the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > OnResistSpell ( m_pWeenie ) ;
2018-04-28 12:32:16 -04:00
continue ;
2018-04-24 02:03:00 -05:00
}
}
2018-04-28 12:32:16 -04:00
if ( bool resistProjectileMagic = target - > InqBoolQuality ( NON_PROJECTILE_MAGIC_IMMUNE_BOOL , 0 ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( resistProjectileMagic = = 1 | | : : TryMagicResist ( m_SpellCastData . current_skill , ( DWORD ) resistProjectileMagic ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
target - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = topLevelOwner )
2018-04-24 02:03:00 -05:00
{
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " %s resists the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
2018-07-11 04:53:32 +00:00
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > OnResistSpell ( m_pWeenie ) ;
2018-04-28 12:32:16 -04:00
continue ;
2018-04-24 02:03:00 -05:00
}
}
}
2018-07-12 14:41:21 -07:00
topLevelOwner - > HandleAggro ( m_pWeenie ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
target - > m_Qualities . UpdateEnchantment ( & enchant ) ;
target - > NotifyEnchantmentUpdated ( & enchant ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
target - > CheckVitalRanges ( ) ;
2018-09-20 00:30:57 +01:00
const char * spell_name = m_SpellCastData . spell - > _name . c_str ( ) ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie = = target )
2018-04-28 12:32:16 -04:00
{
2018-09-20 00:30:57 +01:00
switch ( text_option )
{
default :
case 0 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself " , spell_name ) , LTT_MAGIC ) ;
break ;
case 1 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself, refreshing %s " , spell_name , spell_name ) , LTT_MAGIC ) ;
break ;
case 2 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself, but it is surpassed by %s " , spell_name , existing_spell_name . c_str ( ) ) , LTT_MAGIC ) ;
break ;
case 3 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself, surpassing %s " , spell_name , existing_spell_name . c_str ( ) ) , LTT_MAGIC ) ;
}
2018-04-28 12:32:16 -04:00
}
else
{
2018-09-20 00:30:57 +01:00
switch ( text_option )
2018-04-24 02:03:00 -05:00
{
2018-09-20 00:30:57 +01:00
default :
case 0 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s " , spell_name , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
if ( m_pWeenie ! = topLevelOwner )
topLevelOwner - > SendText ( csprintf ( " %s cast %s on %s " , m_pWeenie - > GetName ( ) . c_str ( ) , spell_name , target = = topLevelOwner ? " you " : target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
break ;
case 1 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s, refreshing %s " , spell_name , target - > GetName ( ) . c_str ( ) , spell_name ) , LTT_MAGIC ) ;
if ( m_pWeenie ! = topLevelOwner )
topLevelOwner - > SendText ( csprintf ( " %s cast %s on %s, refreshing %s " , m_pWeenie - > GetName ( ) . c_str ( ) , spell_name , target = = topLevelOwner ? " you " : target - > GetName ( ) . c_str ( ) , spell_name ) , LTT_MAGIC ) ;
break ;
case 2 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s, but it is surpassed by %s " , spell_name , target - > GetName ( ) . c_str ( ) , existing_spell_name . c_str ( ) ) , LTT_MAGIC ) ;
if ( m_pWeenie ! = topLevelOwner )
topLevelOwner - > SendText ( csprintf ( " %s cast %s on %s, but it is surpassed by %s " , m_pWeenie - > GetName ( ) . c_str ( ) , spell_name , target = = topLevelOwner ? " you " : target - > GetName ( ) . c_str ( ) , existing_spell_name . c_str ( ) ) , LTT_MAGIC ) ;
break ;
case 3 :
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s, surpassing %s " , spell_name , target - > GetName ( ) . c_str ( ) , existing_spell_name . c_str ( ) ) , LTT_MAGIC ) ;
if ( m_pWeenie ! = topLevelOwner )
topLevelOwner - > SendText ( csprintf ( " %s cast %s on %s, surpassing %s " , m_pWeenie - > GetName ( ) . c_str ( ) , spell_name , target = = topLevelOwner ? " you " : target - > GetName ( ) . c_str ( ) , existing_spell_name . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
}
bSpellPerformed = true ;
}
}
break ;
}
case SpellType : : FellowEnchantment_SpellType :
{
FellowshipEnchantmentSpellEx * meta = ( FellowshipEnchantmentSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
Enchantment enchant ;
enchant . _id = meta - > _spell_id | ( ( DWORD ) m_SpellCastData . serial < < ( DWORD ) 16 ) ;
enchant . m_SpellSetID = 0 ; // ???
enchant . _spell_category = m_SpellCastData . spell - > _category ; // meta->_spellCategory;
enchant . _power_level = m_SpellCastData . spell - > _power ;
enchant . _start_time = Timer : : cur_time ;
enchant . _duration = m_SpellCastData . equipped ? - 1.0 : meta - > _duration ;
2018-07-12 14:41:21 -07:00
enchant . _caster = m_pWeenie - > GetID ( ) ;
2018-04-28 12:32:16 -04:00
enchant . _degrade_modifier = meta - > _degrade_modifier ;
enchant . _degrade_limit = meta - > _degrade_limit ;
enchant . _last_time_degraded = - 1.0 ;
enchant . _smod = meta - > _smod ;
2018-07-12 14:41:21 -07:00
CWeenieObject * target = GetCastTarget ( ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
if ( ! target - > HasFellowship ( ) )
break ;
2018-04-24 02:03:00 -05:00
2018-07-20 16:28:32 -05:00
// NPKs should not be able to buff PKs
2018-08-06 01:33:54 -05:00
if ( m_pWeenie & & target & & m_pWeenie - > IsPK ( ) & & target - > IsPK ( ) )
2018-07-20 16:28:32 -05:00
{
bSpellPerformed = false ;
break ;
}
2018-04-28 12:32:16 -04:00
else
{
Fellowship * fellow = target - > GetFellowship ( ) ;
CWorldLandBlock * block = target - > GetBlock ( ) ;
for ( auto & entry : fellow - > _fellowship_table )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * member = g_pWorld - > FindPlayer ( entry . first ) )
2018-04-28 12:32:16 -04:00
{
if ( member - > GetBlock ( ) = = block )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( enchant . _smod . type & Skill_EnchantmentType )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
enchant . _smod . key = ( DWORD ) SkillTable : : OldToNewSkill ( ( STypeSkill ) enchant . _smod . key ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > targets ;
2018-04-28 12:32:16 -04:00
if ( member )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( m_SpellCastData . spell - > InqTargetType ( ) ! = ITEM_TYPE : : TYPE_ITEM_ENCHANTABLE_TARGET )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
targets . push_back ( member ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
else
2018-04-24 02:03:00 -05:00
{
2018-07-12 14:41:21 -07:00
CContainerWeenie * container = member - > AsContainer ( ) ;
2018-04-28 12:32:16 -04:00
if ( container & & ! container - > HasOwner ( ) )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
for ( auto wielded : container - > m_Wielded )
{
2018-07-12 14:41:21 -07:00
if ( wielded - > GetItemType ( ) & m_SpellCastData . spell - > _non_component_target_type )
2018-06-21 23:32:21 +01:00
{
2018-07-12 14:41:21 -07:00
if ( member = = m_pWeenie | | wielded - > parent ) // for other targets, only physically wielded allowed
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
targets . push_back ( wielded ) ;
2018-04-28 12:32:16 -04:00
}
}
}
}
else
{
if ( member - > GetItemType ( ) & m_SpellCastData . spell - > _non_component_target_type )
{
2018-07-12 14:41:21 -07:00
if ( member = = m_pWeenie | | member - > parent | | ! member - > HasOwner ( ) | | member - > GetWorldTopLevelOwner ( ) = = m_pWeenie ) // for other targets, only physically wielded allowed
2018-04-28 12:32:16 -04:00
{
targets . push_back ( member ) ;
}
}
2018-04-24 02:03:00 -05:00
}
}
2018-04-28 12:32:16 -04:00
for ( auto target : targets )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
// You cast Harlune's Blessing on yourself, refreshing Harlune's Blessing
// You cast Impenetrability III on Pathwarden Robe, surpassing Impenetrability II
2018-07-12 14:41:21 -07:00
CWeenieObject * topLevelOwner = target - > GetWorldTopLevelOwner ( ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
if ( target - > InqIntQuality ( MAX_STACK_SIZE_INT , 1 ) > 1 ) //do not allow enchanting stackable items(ammunition)
2018-04-24 02:03:00 -05:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " The %s can't be enchanted. " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
continue ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
bool bAlreadyExisted = false ;
if ( target - > m_Qualities . _enchantment_reg & & target - > m_Qualities . _enchantment_reg - > IsEnchanted ( enchant . _id ) )
bAlreadyExisted = true ;
2018-04-24 02:03:00 -05:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = target )
2018-04-24 02:03:00 -05:00
{
2018-04-28 12:32:16 -04:00
if ( ! ( m_SpellCastData . spell - > _bitfield & Beneficial_SpellIndex ) )
{
2018-07-18 02:46:30 -05:00
// Only Update PK Activity if both target and caster are PK, Prevents PKs from tagging NPKs for PK activity.
2018-08-03 17:26:05 +01:00
if ( m_pWeenie - > IsPK ( ) & & target - > IsPK ( ) )
2018-07-18 02:46:30 -05:00
{
m_pWeenie - > AsPlayer ( ) - > UpdatePKActivity ( ) ;
target - > AsPlayer ( ) - > UpdatePKActivity ( ) ;
}
2018-07-12 14:41:21 -07:00
if ( target - > AsPlayer ( ) & & target - > GetWorldTopLevelOwner ( ) - > ImmuneToDamage ( m_pWeenie ) )
2018-04-28 12:32:16 -04:00
{
continue ;
}
}
if ( m_SpellCastData . spell - > _bitfield & Resistable_SpellIndex )
{
if ( topLevelOwner - > TryMagicResist ( m_SpellCastData . current_skill ) )
{
topLevelOwner - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " You resist the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
topLevelOwner - > OnResistSpell ( m_pWeenie ) ;
2018-04-28 12:32:16 -04:00
continue ;
}
}
if ( int resistMagic = target - > InqIntQuality ( RESIST_MAGIC_INT , 0 , FALSE ) )
{
2018-07-17 02:02:17 -05:00
if ( resistMagic > = 9999 & & topLevelOwner = = m_pWeenie )
continue ;
2018-04-28 12:32:16 -04:00
if ( resistMagic > = 9999 | | : : TryMagicResist ( m_SpellCastData . current_skill , ( DWORD ) resistMagic ) )
{
target - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = topLevelOwner )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " %s resists the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > OnResistSpell ( m_pWeenie ) ;
2018-04-28 12:32:16 -04:00
continue ;
}
}
if ( int resistLifeMagic = target - > InqIntQuality ( LIFE_RESIST_RATING_INT , 0 , FALSE ) )
{
if ( resistLifeMagic > = 9999 | | : : TryMagicResist ( m_SpellCastData . current_skill , ( DWORD ) resistLifeMagic ) )
{
target - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = topLevelOwner )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " %s resists the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > OnResistSpell ( m_pWeenie ) ;
2018-04-28 12:32:16 -04:00
continue ;
}
}
if ( bool resistProjectileMagic = target - > InqBoolQuality ( NON_PROJECTILE_MAGIC_IMMUNE_BOOL , 0 ) )
{
if ( resistProjectileMagic = = 1 | | : : TryMagicResist ( m_SpellCastData . current_skill , ( DWORD ) resistProjectileMagic ) )
{
target - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = topLevelOwner )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " %s resists the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > OnResistSpell ( m_pWeenie ) ;
2018-04-28 12:32:16 -04:00
continue ;
}
}
2018-04-24 02:03:00 -05:00
}
2018-07-12 14:41:21 -07:00
topLevelOwner - > HandleAggro ( m_pWeenie ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
target - > m_Qualities . UpdateEnchantment ( & enchant ) ;
target - > NotifyEnchantmentUpdated ( & enchant ) ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
target - > CheckVitalRanges ( ) ;
2018-04-24 02:03:00 -05:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie = = target )
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on yourself " , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s on %s " , m_SpellCastData . spell - > _name . c_str ( ) , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-24 02:03:00 -05:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = topLevelOwner )
2018-04-28 12:32:16 -04:00
{
if ( target = = topLevelOwner )
2018-07-12 14:41:21 -07:00
target - > SendText ( csprintf ( " %s cast %s on you " , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
else
2018-07-12 14:41:21 -07:00
topLevelOwner - > SendText ( csprintf ( " %s cast %s on %s " , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
}
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
bSpellPerformed = true ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
}
}
2018-04-24 02:03:00 -05:00
}
}
}
2018-04-28 12:32:16 -04:00
PerformFellowCastParticleEffects ( fellow ) ;
}
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
break ;
}
case SpellType : : PortalSummon_SpellType :
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie & & m_pWeenie - > AsPlayer ( ) & & m_pWeenie - > AsPlayer ( ) - > CheckPKActivity ( ) )
2018-05-19 19:21:17 +01:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have been involved in Player Killer combat too recently! " , LTT_MAGIC ) ;
2018-05-19 19:21:17 +01:00
break ;
}
2018-04-28 12:32:16 -04:00
PortalSummonSpellEx * meta = ( PortalSummonSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
if ( ! meta & & ( meta - > _link = = 1 | | meta - > _link = = 2 ) )
2018-04-24 02:03:00 -05:00
break ;
2018-04-28 12:32:16 -04:00
Position spawnPos ;
2018-07-12 14:41:21 -07:00
if ( ! m_pWeenie - > m_Qualities . InqPosition ( PORTAL_SUMMON_LOC_POSITION , spawnPos ) )
2018-04-28 12:32:16 -04:00
{
spawnPos = GetCastSource ( ) - > m_Position ;
spawnPos . frame . m_origin + = spawnPos . localtoglobalvec ( Vector ( 0 , 7 , 0 ) ) ;
2018-04-24 02:03:00 -05:00
}
2018-04-28 12:32:16 -04:00
DWORD portalDID = 0 ;
2018-04-24 02:03:00 -05:00
2018-04-28 12:32:16 -04:00
Position dummyPos ;
bool bNoLink = false ;
2018-08-19 15:53:55 -05:00
Position portalPos ;
2018-04-28 12:32:16 -04:00
switch ( meta - > _link )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
case 1 :
2018-07-12 14:41:21 -07:00
portalDID = m_pWeenie - > InqDIDQuality ( LINKED_PORTAL_ONE_DID , 0 ) ;
2018-08-19 15:53:55 -05:00
portalPos = m_pWeenie - > InqPositionQuality ( LINKED_PORTAL_ONE_POSITION , Position ( ) ) ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
if ( ! portalDID & & ! m_pWeenie - > m_Qualities . InqPosition ( LINKED_PORTAL_ONE_POSITION , dummyPos ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You do not have a primary portal tied. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
bNoLink = true ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
break ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
case 2 :
2018-07-12 14:41:21 -07:00
portalDID = m_pWeenie - > InqDIDQuality ( LINKED_PORTAL_TWO_DID , 0 ) ;
2018-08-19 15:53:55 -05:00
portalPos = m_pWeenie - > InqPositionQuality ( LINKED_PORTAL_TWO_POSITION , Position ( ) ) ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
if ( ! portalDID & & ! m_pWeenie - > m_Qualities . InqPosition ( LINKED_PORTAL_TWO_POSITION , dummyPos ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You do not have a secondary portal tied. " , LTT_MAGIC ) ;
2018-04-28 12:32:16 -04:00
bNoLink = true ;
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
break ;
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
if ( bNoLink )
{
break ;
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
CWeenieDefaults * portalDefaults = NULL ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
bool canFlagForQuest = false ;
if ( portalDID )
{
2018-12-25 03:12:26 -06:00
portalDefaults = g_pWeenieFactory - > GetWeenieDefaults ( portalDID ) ;
2018-03-29 17:01:57 -04:00
2018-12-25 03:13:03 -06:00
if ( portalDefaults )
2018-03-29 17:01:57 -04:00
{
2018-12-25 03:13:03 -06:00
int minLevel = 0 ;
int maxLevel = 0 ;
portalDefaults - > m_Qualities . InqInt ( MIN_LEVEL_INT , minLevel ) ;
portalDefaults - > m_Qualities . InqInt ( MAX_LEVEL_INT , maxLevel ) ;
2018-03-29 17:01:57 -04:00
2018-12-25 03:13:03 -06:00
if ( m_pWeenie - > AsPlayer ( ) )
2018-12-25 03:12:26 -06:00
{
2018-12-25 03:13:03 -06:00
int currentLevel = m_pWeenie - > InqIntQuality ( LEVEL_INT , 1 ) ;
if ( minLevel & & currentLevel < minLevel )
{
m_pWeenie - > SendText ( " You are not powerful enough to summon this portal yet. " , LTT_MAGIC ) ;
break ;
}
else if ( maxLevel & & currentLevel > maxLevel )
{
m_pWeenie - > SendText ( " You are too powerful to summon this portal. " , LTT_MAGIC ) ;
break ;
}
if ( ( portalDefaults - > m_Qualities . GetInt ( PORTAL_BITMASK_INT , 0 ) & 0x10 ) )
{
m_pWeenie - > SendText ( " That portal may not be summoned. " , LTT_MAGIC ) ;
break ;
}
2018-12-25 03:12:26 -06:00
}
2018-12-25 03:13:03 -06:00
else
canFlagForQuest = true ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
}
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
CWeenieObject * weenie = g_pWeenieFactory - > CreateWeenieByClassID ( W_PORTALGATEWAY_CLASS , & spawnPos , false ) ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
if ( weenie )
{
weenie - > _timeToRot = Timer : : cur_time + meta - > _portal_lifetime ;
weenie - > _beganRot = false ;
weenie - > m_Qualities . SetFloat ( TIME_TO_ROT_FLOAT , weenie - > _timeToRot ) ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
bool bHasDestination = false ;
if ( portalDefaults )
{
weenie - > CopyPositionStat ( DESTINATION_POSITION , & portalDefaults - > m_Qualities ) ;
weenie - > CopyIntStat ( MIN_LEVEL_INT , & portalDefaults - > m_Qualities ) ;
weenie - > CopyIntStat ( MAX_LEVEL_INT , & portalDefaults - > m_Qualities ) ;
weenie - > CopyIntStat ( PORTAL_BITMASK_INT , & portalDefaults - > m_Qualities ) ;
weenie - > CopyStringStat ( QUEST_RESTRICTION_STRING , & portalDefaults - > m_Qualities ) ;
2018-12-27 13:25:47 -06:00
switch ( meta - > _link )
{
case 1 :
weenie - > m_Qualities . SetDataID ( ORIGINAL_PORTAL_DID , m_pWeenie - > InqDIDQuality ( LINKED_PORTAL_ONE_DID , 0 ) ) ;
break ;
case 2 :
weenie - > m_Qualities . SetDataID ( ORIGINAL_PORTAL_DID , m_pWeenie - > InqDIDQuality ( LINKED_PORTAL_TWO_DID , 0 ) ) ;
break ;
}
2018-04-28 12:32:16 -04:00
if ( canFlagForQuest )
weenie - > CopyStringStat ( QUEST_STRING , & portalDefaults - > m_Qualities ) ;
2018-11-23 11:38:02 -06:00
if ( portalDefaults - > m_Qualities . GetBool ( PORTAL_SHOW_DESTINATION_BOOL , 0 ) )
{
weenie - > CopyBoolStat ( PORTAL_SHOW_DESTINATION_BOOL , & portalDefaults - > m_Qualities ) ;
weenie - > CopyStringStat ( APPRAISAL_PORTAL_DESTINATION_STRING , & portalDefaults - > m_Qualities ) ;
}
2018-04-28 12:32:16 -04:00
}
else
{
switch ( meta - > _link )
2018-03-29 17:01:57 -04:00
{
2018-04-28 12:32:16 -04:00
case 1 :
2018-07-12 14:41:21 -07:00
weenie - > m_Qualities . SetPosition ( DESTINATION_POSITION , m_pWeenie - > InqPositionQuality ( LINKED_PORTAL_ONE_POSITION , Position ( ) ) ) ;
2018-12-27 13:25:47 -06:00
weenie - > m_Qualities . SetDataID ( ORIGINAL_PORTAL_DID , m_pWeenie - > InqDIDQuality ( LINKED_PORTAL_ONE_DID , 0 ) ) ;
2018-04-28 12:32:16 -04:00
break ;
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
case 2 :
2018-07-12 14:41:21 -07:00
weenie - > m_Qualities . SetPosition ( DESTINATION_POSITION , m_pWeenie - > InqPositionQuality ( LINKED_PORTAL_TWO_POSITION , Position ( ) ) ) ;
2018-12-27 13:25:47 -06:00
weenie - > m_Qualities . SetDataID ( ORIGINAL_PORTAL_DID , m_pWeenie - > InqDIDQuality ( LINKED_PORTAL_TWO_DID , 0 ) ) ;
2018-04-28 12:32:16 -04:00
break ;
2018-03-29 17:01:57 -04:00
}
}
2018-04-28 12:32:16 -04:00
g_pWorld - > CreateEntity ( weenie ) ;
bSpellPerformed = true ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
break ;
}
2018-03-29 17:01:57 -04:00
2018-04-28 12:32:16 -04:00
case SpellType : : PortalSending_SpellType :
{
PortalSendingSpellEx * meta = ( PortalSendingSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
CWeenieObject * target = GetCastTarget ( ) ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > AsPlayer ( ) & & m_pWeenie - > AsPlayer ( ) - > CheckPKActivity ( ) | | m_pWeenie - > HasOwner ( ) & & target - > AsPlayer ( ) & & target - > AsPlayer ( ) - > CheckPKActivity ( ) )
2018-06-14 18:52:55 -07:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You have been involved in Player Killer combat too recently! " , LTT_MAGIC ) ;
2018-06-14 18:52:55 -07:00
break ;
}
2018-04-28 12:32:16 -04:00
if ( target )
{
PerformCastParticleEffects ( ) ; // perform particle effects early because teleporting will cancel it
target - > Movement_Teleport ( meta - > _pos , false ) ;
target - > SendText ( " You have been teleported. " , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-28 12:32:16 -04:00
break ;
}
2018-04-24 02:03:00 -05:00
case SpellType : : FellowPortalSending_SpellType :
{
FellowshipPortalSendingSpellEx * meta = ( FellowshipPortalSendingSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
2018-07-12 14:41:21 -07:00
CWeenieObject * target = GetCastTarget ( ) ;
2018-04-24 02:03:00 -05:00
if ( ! target - > HasFellowship ( ) )
break ;
else
{
Fellowship * fellow = target - > GetFellowship ( ) ;
CWorldLandBlock * block = target - > GetBlock ( ) ;
for ( auto & entry : fellow - > _fellowship_table )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * member = g_pWorld - > FindPlayer ( entry . first ) )
2018-04-24 02:03:00 -05:00
{
if ( member - > GetBlock ( ) = = block )
{
2018-04-28 12:32:16 -04:00
2018-04-24 02:03:00 -05:00
member - > Movement_Teleport ( meta - > _pos , false ) ;
member - > SendText ( " You have been teleported. " , LTT_MAGIC ) ;
}
}
}
PerformFellowCastParticleEffects ( fellow ) ;
}
break ;
}
2018-03-29 17:01:57 -04:00
case SpellType : : LifeProjectile_SpellType :
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
case SpellType : : Projectile_SpellType :
2018-04-28 12:32:16 -04:00
{
ProjectileSpellEx * meta = ( ProjectileSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
bSpellPerformed = LaunchProjectileSpell ( meta ) ;
break ;
}
2018-03-29 17:01:57 -04:00
}
}
if ( bSpellPerformed )
{
PerformCastParticleEffects ( ) ;
}
return WERROR_NONE ;
}
// You gain 37 points of health due to casting Drain Health Other I on Gelidite Lord
2018-07-12 14:41:21 -07:00
void CSpellcastingManager : : TransferVitalPercent ( CWeenieObject * target , float drainPercent , float infusePercent , STypeAttribute2nd attribute )
2018-03-29 17:01:57 -04:00
{
if ( ! target | | target - > IsDead ( ) )
return ;
bool reversed = ( m_SpellCastData . spell - > _bitfield & Reversed_SpellIndex ) ? true : false ;
int targetAdjust ;
int selfAdjust ;
if ( reversed )
{
// draining target, infusing self
targetAdjust = - ( int ) ceil ( target - > GetHealth ( ) * drainPercent ) ;
if ( targetAdjust < - 50 )
targetAdjust = - 50 ;
selfAdjust = ( int ) floor ( - targetAdjust * infusePercent ) ;
}
else
{
// draining self, infusing target
2018-07-12 14:41:21 -07:00
selfAdjust = - ( int ) ceil ( m_pWeenie - > GetHealth ( ) * drainPercent ) ;
2018-03-29 17:01:57 -04:00
targetAdjust = ( int ) floor ( - selfAdjust * infusePercent ) ;
}
2018-07-12 14:41:21 -07:00
if ( targetAdjust < 0 & & target - > ImmuneToDamage ( m_pWeenie ) )
2018-03-29 17:01:57 -04:00
{
// send notice they are immune?
return ;
}
const char * vitalName ;
switch ( attribute )
{
case HEALTH_ATTRIBUTE_2ND :
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
selfAdjust = m_pWeenie - > AdjustHealth ( selfAdjust ) ;
2018-04-28 12:32:16 -04:00
targetAdjust = target - > AdjustHealth ( targetAdjust ) ;
vitalName = " health " ;
break ;
}
2018-03-29 17:01:57 -04:00
case STAMINA_ATTRIBUTE_2ND :
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
selfAdjust = m_pWeenie - > AdjustStamina ( selfAdjust ) ;
2018-04-28 12:32:16 -04:00
targetAdjust = target - > AdjustStamina ( targetAdjust ) ;
vitalName = " stamina " ;
break ;
}
2018-03-29 17:01:57 -04:00
case MANA_ATTRIBUTE_2ND :
2018-04-28 12:32:16 -04:00
{
2018-07-12 14:41:21 -07:00
selfAdjust = m_pWeenie - > AdjustMana ( selfAdjust ) ;
2018-04-28 12:32:16 -04:00
targetAdjust = target - > AdjustMana ( targetAdjust ) ;
vitalName = " mana " ;
break ;
}
2018-03-29 17:01:57 -04:00
default :
return ;
}
SendTransferVitalPercentText ( target , reversed ? targetAdjust : selfAdjust , reversed ? selfAdjust : targetAdjust , reversed , vitalName ) ;
if ( target - > IsDead ( ) )
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie = = target )
2018-03-29 17:01:57 -04:00
{
target - > NotifyVictimEvent ( " You died! " ) ;
if ( target - > _IsPlayer ( ) )
{
2018-07-12 14:41:21 -07:00
target - > NotifyDeathMessage ( m_pWeenie - > GetID ( ) , csprintf ( " %s died! " , target - > GetName ( ) . c_str ( ) ) ) ;
2018-03-29 17:01:57 -04:00
}
}
else
{
2018-07-12 14:41:21 -07:00
target - > NotifyVictimEvent ( csprintf ( " You were killed by %s! " , m_pWeenie - > GetName ( ) . c_str ( ) ) ) ;
m_pWeenie - > NotifyKillerEvent ( csprintf ( " You killed %s! " , target - > GetName ( ) . c_str ( ) ) ) ;
2018-03-29 17:01:57 -04:00
if ( target - > _IsPlayer ( ) )
{
2018-07-12 14:41:21 -07:00
target - > NotifyDeathMessage ( m_pWeenie - > GetID ( ) , csprintf ( " %s killed %s! " , m_pWeenie - > GetName ( ) . c_str ( ) , target - > GetName ( ) . c_str ( ) ) ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-07-12 14:41:21 -07:00
target - > OnDeath ( m_pWeenie - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = target & & m_pWeenie - > IsDead ( ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > NotifyVictimEvent ( " You died! " ) ;
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > _IsPlayer ( ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > NotifyDeathMessage ( m_pWeenie - > GetID ( ) , csprintf ( " %s died! " , m_pWeenie - > GetName ( ) . c_str ( ) ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
m_pWeenie - > OnDeath ( m_pWeenie - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-07-12 14:41:21 -07:00
void CSpellcastingManager : : SendTransferVitalPercentText ( CWeenieObject * target , int drained , int infused , bool reversed , const char * vitalName )
2018-03-29 17:01:57 -04:00
{
// You gain 37 points of health due to casting Drain Health Other I on Gelidite Lord
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You %s %d points of %s due to casting %s on %s " ,
2018-03-29 17:01:57 -04:00
reversed ? " gain " : " lose " , reversed ? infused : - drained , vitalName , m_SpellCastData . spell - > _name . c_str ( ) , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-07-12 14:41:21 -07:00
if ( target ! = m_pWeenie )
2018-03-29 17:01:57 -04:00
{
target - > SendText ( csprintf ( " You %s %d points of %s due to %s casting %s on you " ,
2018-07-12 14:41:21 -07:00
! reversed ? " gain " : " lose " , ! reversed ? infused : - drained , vitalName , m_SpellCastData . spell - > _name . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
}
std : : string GetAttribute2ndName ( STypeAttribute2nd attribute2nd )
{
switch ( attribute2nd )
{
case MAX_HEALTH_ATTRIBUTE_2ND :
return " maximum health " ;
case HEALTH_ATTRIBUTE_2ND :
return " health " ;
case MAX_STAMINA_ATTRIBUTE_2ND :
return " maximum stamina " ;
case STAMINA_ATTRIBUTE_2ND :
return " stamina " ;
case MAX_MANA_ATTRIBUTE_2ND :
return " maximum mana " ;
case MANA_ATTRIBUTE_2ND :
return " mana " ;
}
return " " ;
}
2018-07-12 14:41:21 -07:00
bool CSpellcastingManager : : DoTransferSpell ( CWeenieObject * other , const TransferSpellEx * meta )
2018-03-29 17:01:57 -04:00
{
// Calculate source amount
2018-07-12 14:41:21 -07:00
CWeenieObject * source = NULL ;
2018-03-29 17:01:57 -04:00
if ( meta - > _bitfield & TransferSpellEx : : SourceSelf )
source = GetCastSource ( ) ;
else if ( meta - > _bitfield & TransferSpellEx : : SourceOther )
source = other ;
2018-07-12 14:41:21 -07:00
CWeenieObject * dest = NULL ;
2018-03-29 17:01:57 -04:00
if ( meta - > _bitfield & TransferSpellEx : : DestinationSelf )
dest = GetCastSource ( ) ;
else if ( meta - > _bitfield & TransferSpellEx : : DestinationOther )
dest = other ;
if ( ! source | | ! dest )
return false ;
double drainResistMod = 1.0 ;
double boostResistMod = 1.0 ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = source )
2018-03-29 17:01:57 -04:00
{
// negative spell
2018-07-12 14:41:21 -07:00
if ( source - > ImmuneToDamage ( m_pWeenie ) )
2018-03-29 17:01:57 -04:00
{
return false ;
}
2018-04-28 12:32:16 -04:00
2018-07-18 02:46:30 -05:00
// NPKs should not be able to heal PKs
if ( m_pWeenie & & other & & m_pWeenie - > AsPlayer ( ) & & other - > AsPlayer ( ) )
{
2018-08-04 19:10:13 -05:00
if ( ! m_pWeenie - > IsPK ( ) & & other - > IsPK ( ) )
2018-07-18 02:46:30 -05:00
{
return false ;
}
}
2018-03-29 17:01:57 -04:00
// try to resist
if ( m_SpellCastData . spell - > _bitfield & Resistable_SpellIndex )
{
if ( source - > TryMagicResist ( m_SpellCastData . current_skill ) )
{
source - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
source - > SendText ( csprintf ( " You resist the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , source - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
source - > OnResistSpell ( m_pWeenie ) ;
2018-03-29 17:01:57 -04:00
return false ;
}
}
2018-07-12 14:41:21 -07:00
source - > HandleAggro ( m_pWeenie ) ;
2018-03-29 17:01:57 -04:00
switch ( meta - > _src )
{
case HEALTH_ATTRIBUTE_2ND :
source - > m_Qualities . InqFloat ( RESIST_HEALTH_DRAIN_FLOAT , drainResistMod ) ;
break ;
case STAMINA_ATTRIBUTE_2ND :
source - > m_Qualities . InqFloat ( RESIST_STAMINA_DRAIN_FLOAT , drainResistMod ) ;
break ;
case MANA_ATTRIBUTE_2ND :
source - > m_Qualities . InqFloat ( RESIST_MANA_DRAIN_FLOAT , drainResistMod ) ;
break ;
}
2018-04-28 12:32:16 -04:00
if ( source - > AsPlayer ( ) ) //only players have natural resistances.
2018-03-29 17:01:57 -04:00
{
//Some combination of strength and endurance allows one to have a level of "natural resistances" to the 7 damage types.This caps out at a 50 % resistance(the equivalent to level 5 life prots) to these damage types.This resistance is not additive to life protections : higher level life protections will overwrite these natural resistances, although life vulns will take these natural resistances into account, if the player does not have a higher level life protection cast upon them.
//For example, a player will not get a free protective bonus from natural resistances if they have both Prot 7 and Vuln 7 cast upon them.The Prot and Vuln will cancel each other out, and since the Prot has overwritten the natural resistances, there will be no resistance bonus.
//The abilities that Endurance or Endurance/Strength conveys are not increased by Strength or Endurance buffs.It is the raw Strength and/or Endurance scores that determine the various bonuses.
//drain resistances(same formula as natural resistances) allows one to partially resist drain health/stamina/mana and harm attacks, up to a maximum of roughly 50%.
//todo: natural resistances only change when base strength or endurance changes so we could potentially pre-calculate this somewhere else.
DWORD strength = 0 ;
DWORD endurance = 0 ;
source - > m_Qualities . InqAttribute ( STRENGTH_ATTRIBUTE , strength , true ) ;
source - > m_Qualities . InqAttribute ( ENDURANCE_ATTRIBUTE , endurance , true ) ;
float strAndEnd = ( float ) ( strength + endurance ) ;
float resistanceNatural ;
if ( strAndEnd < = 200 ) //formula deduced from values present in the client pdb.
resistanceNatural = 1.0f - ( ( 0.05 * strAndEnd ) / 100.f ) ;
else
resistanceNatural = 1.0f - ( ( ( 0.1666667 * strAndEnd ) - 23.33333 ) / 100.f ) ;
2018-08-27 15:47:05 -05:00
resistanceNatural = max ( resistanceNatural , 0.5f ) ;
2018-03-29 17:01:57 -04:00
if ( resistanceNatural < drainResistMod )
drainResistMod = resistanceNatural ;
}
}
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = dest )
2018-03-29 17:01:57 -04:00
{
switch ( meta - > _src )
{
case HEALTH_ATTRIBUTE_2ND :
dest - > m_Qualities . InqFloat ( RESIST_HEALTH_BOOST_FLOAT , boostResistMod ) ;
break ;
case STAMINA_ATTRIBUTE_2ND :
dest - > m_Qualities . InqFloat ( RESIST_STAMINA_DRAIN_FLOAT , boostResistMod ) ;
break ;
case MANA_ATTRIBUTE_2ND :
dest - > m_Qualities . InqFloat ( RESIST_MANA_DRAIN_FLOAT , boostResistMod ) ;
break ;
}
}
DWORD sourceStartValue = 0 ;
DWORD sourceMinValue = 0 ;
DWORD sourceMaxValue = 0 ;
source - > m_Qualities . InqAttribute2nd ( meta - > _src , sourceStartValue , FALSE ) ;
source - > m_Qualities . InqAttribute2nd ( ( STypeAttribute2nd ) ( ( int ) meta - > _src - 1 ) , sourceMaxValue , FALSE ) ;
DWORD destStartValue = 0 ;
DWORD destMinValue = 0 ;
DWORD destMaxValue = 0 ;
dest - > m_Qualities . InqAttribute2nd ( meta - > _dest , destStartValue , FALSE ) ;
dest - > m_Qualities . InqAttribute2nd ( ( STypeAttribute2nd ) ( ( int ) meta - > _dest - 1 ) , destMaxValue , FALSE ) ;
int sourceTakeAmount = ( int ) ( sourceStartValue * meta - > _proportion * drainResistMod ) ;
if ( meta - > _transferCap & & sourceTakeAmount > meta - > _transferCap )
sourceTakeAmount = meta - > _transferCap ;
int destGiveAmount = ( int ) ( sourceTakeAmount * ( 1.0 - meta - > _lossPercent ) * boostResistMod ) ;
int destResultValue = destStartValue + destGiveAmount ;
if ( destResultValue > destMaxValue )
{
destResultValue = destMaxValue ;
destGiveAmount = destMaxValue - destStartValue ;
sourceTakeAmount = ( int ) ( destGiveAmount / ( 1.0 - meta - > _lossPercent ) ) ;
}
int sourceResultValue = sourceStartValue - sourceTakeAmount ;
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
if ( sourceResultValue ! = sourceStartValue )
{
source - > m_Qualities . SetAttribute2nd ( meta - > _src , sourceResultValue ) ;
source - > NotifyAttribute2ndStatUpdated ( meta - > _src ) ;
}
if ( destResultValue ! = destStartValue )
{
dest - > m_Qualities . SetAttribute2nd ( meta - > _dest , destResultValue ) ;
dest - > NotifyAttribute2ndStatUpdated ( meta - > _dest ) ;
}
if ( source = = dest )
{
// You cast Stamina to Mana Self III on yourself and lose 78 points of stamina and also gain 86 points of mana
2018-07-12 14:41:21 -07:00
if ( m_pWeenie = = source )
2018-03-29 17:01:57 -04:00
{
source - > SendText ( csprintf (
" You cast %s on yourself and lose %d points of %s and also gain %d points of %s " ,
m_SpellCastData . spell - > _name . c_str ( ) , sourceTakeAmount , GetAttribute2ndName ( meta - > _src ) . c_str ( ) , destGiveAmount , GetAttribute2ndName ( meta - > _dest ) . c_str ( )
2018-04-28 12:32:16 -04:00
) , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
else
{
source - > SendText ( csprintf (
" You lose %d points of %s and also gain %d points of %s due to %s casting %s on you " ,
2018-07-12 14:41:21 -07:00
sourceTakeAmount , GetAttribute2ndName ( meta - > _src ) . c_str ( ) , destGiveAmount , GetAttribute2ndName ( meta - > _dest ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( )
2018-03-29 17:01:57 -04:00
) , LTT_MAGIC ) ;
}
}
else
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie = = source )
2018-03-29 17:01:57 -04:00
{
source - > SendText ( csprintf ( " You lose %d points of %s due to casting %s on %s " ,
sourceTakeAmount , GetAttribute2ndName ( meta - > _src ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) , dest - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
dest - > SendText ( csprintf ( " You gain %d points of %s due to %s casting %s on you " ,
2018-07-12 14:41:21 -07:00
destGiveAmount , GetAttribute2ndName ( meta - > _dest ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
else if ( m_pWeenie = = dest )
2018-03-29 17:01:57 -04:00
{
dest - > SendText ( csprintf ( " You gain %d points of %s due to casting %s on %s " ,
destGiveAmount , GetAttribute2ndName ( meta - > _dest ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) , source - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
source - > SendText ( csprintf ( " You lose %d points of %s due to %s casting %s on you " ,
2018-07-12 14:41:21 -07:00
sourceTakeAmount , GetAttribute2ndName ( meta - > _src ) . c_str ( ) , m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) ) , LTT_MAGIC ) ;
2018-05-06 01:19:27 +01:00
2018-07-12 14:41:21 -07:00
if ( dest - > AsPlayer ( ) )
2018-05-06 01:19:27 +01:00
{
// update the target's health on the casting player asap
2018-07-12 14:41:21 -07:00
if ( source - > AsPlayer ( ) )
( ( CPlayerWeenie * ) source ) - > RefreshTargetHealth ( ) ;
2018-05-06 01:19:27 +01:00
}
2018-07-12 14:41:21 -07:00
if ( source - > AsPlayer ( ) )
2018-05-06 01:19:27 +01:00
{
// update the target's health on the casting player asap
2018-07-12 14:41:21 -07:00
if ( dest - > AsPlayer ( ) )
( ( CPlayerWeenie * ) dest ) - > RefreshTargetHealth ( ) ;
2018-05-06 01:19:27 +01:00
}
2018-03-29 17:01:57 -04:00
}
2018-07-12 14:41:21 -07:00
else
{
// should never happen
}
2018-03-29 17:01:57 -04:00
}
if ( meta - > _src = = HEALTH_ATTRIBUTE_2ND )
2018-07-12 14:41:21 -07:00
source - > CheckDeath ( m_pWeenie , DAMAGE_TYPE : : HEALTH_DAMAGE_TYPE ) ;
2018-03-29 17:01:57 -04:00
return true ;
}
2018-07-12 14:41:21 -07:00
bool CSpellcastingManager : : AdjustVital ( CWeenieObject * target )
2018-03-29 17:01:57 -04:00
{
if ( ! target | | target - > IsDead ( ) )
return false ;
2018-07-18 02:46:30 -05:00
// NPKs should not be able to heal PKs
if ( m_pWeenie & & target & & m_pWeenie - > AsPlayer ( ) & & target - > AsPlayer ( ) )
{
2018-08-04 19:10:13 -05:00
if ( ! m_pWeenie - > IsPK ( ) & & target - > IsPK ( ) )
2018-07-18 02:46:30 -05:00
{
return false ;
}
}
2018-03-29 17:01:57 -04:00
BoostSpellEx * meta = ( BoostSpellEx * ) m_SpellCastData . spellEx - > _meta_spell . _spell ;
bool isDamage = ( meta - > _boost < 0 ) ;
int boostMin = abs ( meta - > _boost ) ;
int boostMax = abs ( meta - > _boost + meta - > _boostVariance ) ;
double preVarianceDamage = boostMax ;
double damageOrHealAmount = Random : : RollDice ( boostMin , boostMax ) ;
2018-07-12 14:41:21 -07:00
CWeenieObject * wand = g_pWorld - > FindObject ( m_SpellCastData . wand_id ) ;
2018-04-01 15:03:58 -04:00
if ( wand )
{
double elementalDamageMod = wand - > InqDamageType ( ) = = meta - > _dt ? wand - > InqFloatQuality ( ELEMENTAL_DAMAGE_MOD_FLOAT , 1.0 ) : 1.0 ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > AsPlayer ( ) & & target - > AsPlayer ( ) ) //pvp
2018-04-01 15:03:58 -04:00
elementalDamageMod = ( ( elementalDamageMod - 1.0 ) / 2.0 ) + 1.0 ;
damageOrHealAmount * = elementalDamageMod ;
}
2018-03-29 17:01:57 -04:00
// negative spell
if ( isDamage )
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie & & target & & m_pWeenie - > AsPlayer ( ) & & target - > AsPlayer ( ) )
2018-05-19 19:21:17 +01:00
{
2018-08-04 19:10:13 -05:00
if ( m_pWeenie - > IsPK ( ) & & target - > IsPK ( ) )
2018-07-18 02:46:30 -05:00
{
m_pWeenie - > AsPlayer ( ) - > UpdatePKActivity ( ) ;
target - > AsPlayer ( ) - > UpdatePKActivity ( ) ;
}
2018-05-19 19:21:17 +01:00
}
2018-03-29 17:01:57 -04:00
// try to resist
if ( m_SpellCastData . spell - > _bitfield & Resistable_SpellIndex )
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = target )
2018-03-29 17:01:57 -04:00
{
if ( target - > TryMagicResist ( m_SpellCastData . current_skill ) )
{
target - > EmitSound ( Sound_ResistSpell , 1.0f , false ) ;
2018-07-12 14:41:21 -07:00
if ( m_pWeenie )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
target - > SendText ( csprintf ( " You resist the spell cast by %s " , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
m_pWeenie - > SendText ( csprintf ( " %s resists your spell " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > OnResistSpell ( m_pWeenie ) ;
2018-03-29 17:01:57 -04:00
}
return false ;
}
}
}
DamageEventData dmgEvent ;
2018-07-12 14:41:21 -07:00
dmgEvent . source = m_pWeenie ;
2018-03-29 17:01:57 -04:00
dmgEvent . target = target ;
2018-04-01 15:03:58 -04:00
dmgEvent . weapon = wand ;
2018-03-29 17:01:57 -04:00
dmgEvent . damage_form = DF_MAGIC ;
dmgEvent . damage_type = meta - > _dt ;
dmgEvent . hit_quadrant = DAMAGE_QUADRANT : : DQ_UNDEF ; //should spells have hit quadrants?
dmgEvent . attackSkill = m_SpellCastData . spell - > InqSkillForSpell ( ) ;
dmgEvent . attackSkillLevel = m_SpellCastData . current_skill ;
dmgEvent . preVarianceDamage = preVarianceDamage ;
dmgEvent . baseDamage = damageOrHealAmount ;
dmgEvent . isProjectileSpell = false ;
dmgEvent . spell_name = m_SpellCastData . spell - > _name ;
2018-06-17 15:51:05 -05:00
CalculateCriticalHitData ( & dmgEvent , & m_SpellCastData ) ;
dmgEvent . wasCrit = ( Random : : GenFloat ( 0.0 , 1.0 ) < dmgEvent . critChance ) ? true : false ;
2018-03-29 17:01:57 -04:00
CalculateDamage ( & dmgEvent , & m_SpellCastData ) ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > TryToDealDamage ( dmgEvent ) ;
2018-03-29 17:01:57 -04:00
return true ;
}
else
{
const char * vitalName ;
switch ( meta - > _dt )
{
case HEALTH_DAMAGE_TYPE :
{
damageOrHealAmount = target - > AdjustHealth ( damageOrHealAmount ) ;
vitalName = " health " ;
break ;
}
case STAMINA_DAMAGE_TYPE :
{
damageOrHealAmount = target - > AdjustStamina ( damageOrHealAmount ) ;
vitalName = " stamina " ;
break ;
}
case MANA_DAMAGE_TYPE :
{
damageOrHealAmount = target - > AdjustMana ( damageOrHealAmount ) ;
vitalName = " mana " ;
break ;
}
default :
return false ;
}
SendAdjustVitalText ( target , damageOrHealAmount , vitalName ) ;
target - > CheckDeath ( GetCastSource ( ) , meta - > _dt ) ;
return true ;
}
}
2018-07-12 14:41:21 -07:00
void CSpellcastingManager : : SendAdjustVitalText ( CWeenieObject * target , int amount , const char * vitalName )
2018-03-29 17:01:57 -04:00
{
bool bRestore = true ;
if ( amount < 0 | | ( amount = = 0 & & ! ( m_SpellCastData . spell - > _bitfield & Beneficial_SpellIndex ) ) )
{
bRestore = false ;
amount = - amount ;
}
2018-04-28 12:32:16 -04:00
2018-07-12 14:41:21 -07:00
if ( m_pWeenie ! = target )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " With %s you %s %d points of %s %s %s. " ,
2018-03-29 17:01:57 -04:00
m_SpellCastData . spell - > _name . c_str ( ) , bRestore ? " restore " : " drain " , amount , vitalName , bRestore ? " to " : " from " , target - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
target - > SendText ( csprintf ( " %s casts %s and %s %d points of your %s. " ,
2018-07-12 14:41:21 -07:00
m_pWeenie - > GetName ( ) . c_str ( ) , m_SpellCastData . spell - > _name . c_str ( ) , bRestore ? " restores " : " drains " , amount , vitalName ) , LTT_MAGIC ) ;
2018-05-06 01:40:21 +01:00
if ( vitalName = = " health " )
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > AsPlayer ( ) )
2018-05-06 01:40:21 +01:00
{
// update the target's health on the casting player asap
2018-07-12 14:41:21 -07:00
( ( CPlayerWeenie * ) m_pWeenie ) - > RefreshTargetHealth ( ) ;
2018-05-06 01:40:21 +01:00
}
}
2018-03-29 17:01:57 -04:00
}
else
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( csprintf ( " You cast %s and %s %d points of your %s. " ,
2018-03-29 17:01:57 -04:00
m_SpellCastData . spell - > _name . c_str ( ) , bRestore ? " restore " : " drain " , amount , vitalName ) , LTT_MAGIC ) ;
}
}
int CSpellcastingManager : : CreatureBeginCast ( DWORD target_id , DWORD spell_id )
{
if ( m_bCasting )
return WERROR_ACTIONS_LOCKED ;
m_SpellCastData = SpellCastData ( ) ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . caster_id = m_pWeenie - > GetID ( ) ;
m_SpellCastData . source_id = m_pWeenie - > GetTopLevelID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . target_id = target_id ;
m_SpellCastData . spell_id = spell_id ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . wand_id = m_pWeenie - > GetWieldedCasterID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . cast_timeout = Timer : : cur_time + 10.0f ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . initial_cast_position = m_pWeenie - > m_Position ;
2018-03-29 17:01:57 -04:00
if ( ! ResolveSpellBeingCasted ( ) )
{
2018-04-27 21:03:39 -07:00
SERVER_INFO < < " Player trying to cast unknown spell? " ;
2018-03-29 17:01:57 -04:00
return WERROR_MAGIC_GENERAL_FAILURE ;
}
2018-06-22 15:38:12 +01:00
// if the spell uses mana and we use mana then check we've got enough
2018-07-11 04:53:32 +00:00
if ( m_SpellCastData . uses_mana & & m_pWeenie - > InqBoolQuality ( AI_USES_MANA_BOOL , 1 ) & & m_pWeenie - > GetMana ( ) < m_SpellCastData . spell - > _base_mana )
2018-06-22 15:38:12 +01:00
{
return WERROR_MAGIC_INSUFFICIENT_MANA ;
}
// if we're at max hp, no need to cast self heals
2018-07-11 04:53:32 +00:00
if ( m_SpellCastData . spell - > _category = = 67 & & ( m_pWeenie - > GetHealth ( ) = = m_pWeenie - > GetMaxHealth ( ) ) )
2018-06-22 15:38:12 +01:00
{
return WERROR_NONE ;
}
2018-03-29 17:01:57 -04:00
m_bCasting = true ;
m_PendingMotions . clear ( ) ;
m_bTurningToObject = false ;
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
m_PendingMotions . push_back ( SpellCastingMotion ( Motion_CastSpell , 2.0f , true , true , 2.0f ) ) ;
m_SpellCastData . power_level_of_power_component = m_SpellCastData . spell_formula . GetPowerLevelOfPowerComponent ( ) ;
2018-06-22 15:38:12 +01:00
// if we use our mana pool then adjust it for the spell cost
2018-07-11 04:53:32 +00:00
if ( m_SpellCastData . uses_mana & & m_pWeenie - > InqBoolQuality ( AI_USES_MANA_BOOL , 1 ) )
2018-06-22 15:38:12 +01:00
{
2018-07-11 04:53:32 +00:00
m_pWeenie - > AdjustMana ( - ( m_SpellCastData . spell - > _base_mana ) ) ; //should this use GetManaCost to adjust for skill/mana c?
2018-06-22 15:38:12 +01:00
}
2018-03-29 17:01:57 -04:00
BeginNextMotion ( ) ;
return WERROR_NONE ;
}
int CSpellcastingManager : : CastSpellInstant ( DWORD target_id , DWORD spell_id )
{
int error = WERROR_NONE ;
// incase we are interrupting a cast
SpellCastData oldData = m_SpellCastData ;
bool bOldCasting = m_bCasting ;
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
m_bCasting = true ;
m_SpellCastData = SpellCastData ( ) ;
2018-08-23 01:36:18 -05:00
if ( oldData . caster_id = = 0 )
m_SpellCastData . caster_id = m_pWeenie - > GetID ( ) ;
else
m_SpellCastData . caster_id = oldData . caster_id ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . source_id = m_pWeenie - > GetTopLevelID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . target_id = target_id ;
m_SpellCastData . spell_id = spell_id ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . wand_id = m_pWeenie - > GetWieldedCasterID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . cast_timeout = Timer : : cur_time + 10.0f ;
m_SpellCastData . power_level_of_power_component = m_SpellCastData . spell_formula . GetPowerLevelOfPowerComponent ( ) ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . initial_cast_position = m_pWeenie - > m_Position ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . uses_mana = false ;
if ( ResolveSpellBeingCasted ( ) )
{
2018-07-11 04:53:32 +00:00
LaunchSpellEffect ( false ) ;
2018-03-29 17:01:57 -04:00
}
else
{
error = WERROR_MAGIC_GENERAL_FAILURE ;
}
m_SpellCastData = oldData ;
m_bCasting = bOldCasting ;
return error ;
}
int CSpellcastingManager : : CastSpellEquipped ( DWORD target_id , DWORD spell_id , WORD serial )
{
int error = WERROR_NONE ;
// incase we are interrupting a cast
SpellCastData oldData = m_SpellCastData ;
bool bOldCasting = m_bCasting ;
m_bCasting = true ;
m_SpellCastData = SpellCastData ( ) ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . caster_id = m_pWeenie - > GetID ( ) ;
m_SpellCastData . source_id = m_pWeenie - > GetTopLevelID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . target_id = target_id ;
m_SpellCastData . spell_id = spell_id ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . wand_id = m_pWeenie - > GetWieldedCasterID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . cast_timeout = Timer : : cur_time + 10.0f ;
m_SpellCastData . power_level_of_power_component = m_SpellCastData . spell_formula . GetPowerLevelOfPowerComponent ( ) ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . initial_cast_position = m_pWeenie - > m_Position ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . uses_mana = false ;
m_SpellCastData . equipped = true ;
m_SpellCastData . serial = serial ;
if ( ResolveSpellBeingCasted ( ) )
{
2018-07-11 04:53:32 +00:00
LaunchSpellEffect ( false ) ;
2018-03-29 17:01:57 -04:00
}
else
{
error = WERROR_MAGIC_GENERAL_FAILURE ;
}
m_SpellCastData = oldData ;
m_bCasting = bOldCasting ;
return error ;
}
DWORD CSpellcastingManager : : DetermineSkillLevelForSpell ( )
{
int spellcraft = 0 ;
2018-08-23 01:36:18 -05:00
CWeenieObject * source = g_pWorld - > FindObject ( m_SpellCastData . caster_id ) ;
if ( ! source )
return 0 ;
if ( source - > m_Qualities . InqInt ( ITEM_SPELLCRAFT_INT , spellcraft , FALSE , FALSE ) )
2018-03-29 17:01:57 -04:00
return ( DWORD ) spellcraft ;
if ( ! m_SpellCastData . spell )
return 0 ;
DWORD skillLevel = 0 ;
STypeSkill skill = m_SpellCastData . spell - > InqSkillForSpell ( ) ;
if ( skill )
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > InqSkill ( skill , skillLevel , FALSE ) ;
2018-03-29 17:01:57 -04:00
}
else
{
DWORD creatureEnch = 0 , itemEnch = 0 , life = 0 , war = 0 , voidMagic = 0 ;
2018-07-12 14:41:21 -07:00
m_pWeenie - > InqSkill ( CREATURE_ENCHANTMENT_SKILL , creatureEnch , FALSE ) ;
m_pWeenie - > InqSkill ( ITEM_ENCHANTMENT_SKILL , itemEnch , FALSE ) ;
m_pWeenie - > InqSkill ( LIFE_MAGIC_SKILL , life , FALSE ) ;
m_pWeenie - > InqSkill ( WAR_MAGIC_SKILL , war , FALSE ) ;
m_pWeenie - > InqSkill ( VOID_MAGIC_SKILL , voidMagic , FALSE ) ;
2018-03-29 17:01:57 -04:00
DWORD highestSkill = 0 ;
highestSkill = max ( highestSkill , creatureEnch ) ;
highestSkill = max ( highestSkill , itemEnch ) ;
highestSkill = max ( highestSkill , life ) ;
highestSkill = max ( highestSkill , war ) ;
highestSkill = max ( highestSkill , voidMagic ) ;
skillLevel = highestSkill ;
}
return skillLevel ;
}
double CSpellcastingManager : : DetermineSpellRange ( )
{
if ( ! m_SpellCastData . spell )
return 0.0 ;
2018-11-23 18:23:40 -06:00
double range = 0.0 ;
if ( m_SpellCastData . spellEx )
range = m_SpellCastData . spellEx - > _base_range_constant + m_SpellCastData . spellEx - > _base_range_mod * m_SpellCastData . current_skill ;
else
range = m_SpellCastData . spell - > _base_range_constant + m_SpellCastData . spell - > _base_range_mod * m_SpellCastData . current_skill ;
2018-03-29 17:01:57 -04:00
const float RADAR_OUTDOOR_RADIUS = 75.0f ;
if ( range > RADAR_OUTDOOR_RADIUS )
range = RADAR_OUTDOOR_RADIUS ;
return range ;
}
int CSpellcastingManager : : CheckTargetValidity ( )
{
if ( ! m_SpellCastData . spell )
return WERROR_MAGIC_GENERAL_FAILURE ;
2018-07-12 14:41:21 -07:00
CWeenieObject * pCastSource = GetCastSource ( ) ;
2018-03-29 17:01:57 -04:00
if ( ! pCastSource )
return WERROR_OBJECT_GONE ;
2018-07-12 14:41:21 -07:00
CWeenieObject * pTarget = g_pWorld - > FindWithinPVS ( pCastSource , m_SpellCastData . target_id ) ;
2018-03-29 17:01:57 -04:00
if ( ! ( m_SpellCastData . spell - > _bitfield & SelfTargeted_SpellIndex ) )
{
if ( ! pTarget )
return WERROR_OBJECT_GONE ;
if ( ! pTarget - > HasOwner ( ) | | ! pCastSource - > FindContainedItem ( pTarget - > GetID ( ) ) )
{
if ( pCastSource & & m_SpellCastData . range_check )
{
if ( pCastSource - > DistanceTo ( pTarget , true ) > m_SpellCastData . max_range )
2018-05-11 19:05:24 +01:00
return WERROR_MISSILE_OUT_OF_RANGE ;
2018-03-29 17:01:57 -04:00
}
}
}
2018-12-12 22:18:04 +00:00
2018-03-29 17:01:57 -04:00
int targetType = m_SpellCastData . spell - > InqTargetType ( ) ;
if ( targetType ! = ITEM_TYPE : : TYPE_UNDEF )
{
if ( ! pTarget )
return WERROR_OBJECT_GONE ;
if ( targetType = = ITEM_TYPE : : TYPE_ITEM_ENCHANTABLE_TARGET & & ! m_SpellCastData . equipped )
{
targetType | = TYPE_CREATURE ;
}
if ( ! ( pTarget - > GetItemType ( ) & targetType ) )
{
if ( m_SpellCastData . equipped & & ( m_SpellCastData . spell - > _school = = 3 ) & & ( m_SpellCastData . spell - > _bitfield & SelfTargeted_SpellIndex ) )
{
}
else
{
return WERROR_MAGIC_BAD_TARGET_TYPE ;
}
}
}
if ( pTarget - > IsCreature ( ) )
{
if ( pTarget - > IsVendor ( ) )
return WERROR_MAGIC_BAD_TARGET_TYPE ;
}
2019-01-09 02:01:58 +00:00
if ( ! ( m_SpellCastData . spell - > _bitfield & ( Beneficial_SpellIndex | NotResearchable_SpellIndex | SelfTargeted_SpellIndex ) ) ) //Not researchable bitmask to allow sending spells to function properly. SelfTargeted to allow portal summon gems to function.
2018-12-12 22:18:04 +00:00
{
if ( ! pTarget )
return WERROR_OBJECT_GONE ;
if ( pTarget - > IsCreature ( ) & & ! pTarget - > IsAttackable ( ) & & ( pTarget ! = m_pWeenie ) ) //no harmful spells on unattackable players/admins/sentinels. Exclude self to cast AoE while unattackable.
{
if ( pCastSource & & m_SpellCastData . range_check )
{
if ( pCastSource - > DistanceTo ( pTarget , true ) > m_SpellCastData . max_range )
return WERROR_MISSILE_OUT_OF_RANGE ;
}
return WERROR_PK_PROTECTED_TARGET ;
}
}
if ( m_SpellCastData . spell - > _bitfield & Beneficial_SpellIndex )
{
if ( ! pTarget )
return WERROR_OBJECT_GONE ;
if ( pTarget - > IsCreature ( ) & & ! pTarget - > AsPlayer ( ) & & m_pWeenie - > AsPlayer ( ) ) //no buffing mobs if we are a player.
{
if ( pCastSource & & m_SpellCastData . range_check )
{
if ( pCastSource - > DistanceTo ( pTarget , true ) > m_SpellCastData . max_range )
return WERROR_MISSILE_OUT_OF_RANGE ;
}
2018-12-13 05:03:44 -05:00
return WERROR_MAGIC_BAD_TARGET_TYPE ;
2018-12-12 22:18:04 +00:00
}
}
2018-03-29 17:01:57 -04:00
return WERROR_NONE ;
}
int CSpellcastingManager : : GenerateManaCost ( )
{
2018-07-12 14:41:21 -07:00
DWORD manaConvSkill = m_pWeenie - > GetEffectiveManaConversionSkill ( ) ;
2018-03-29 17:01:57 -04:00
2018-04-20 18:59:55 -05:00
int spellLevel = 0 ;
int scarab = m_SpellCastData . spell_formula . _comps [ 0 ] ;
switch ( scarab )
{
case 110 : spellLevel = 6 ; break ;
case 112 : spellLevel = 7 ; break ;
case 193 : spellLevel = 8 ; break ;
default :
{
2018-04-28 12:32:16 -04:00
if ( scarab < = 110 & & scarab > 0 )
2018-04-20 18:59:55 -05:00
{
spellLevel = scarab ;
break ;
}
else
{
spellLevel = 1 ;
break ;
}
}
}
2018-04-28 12:32:16 -04:00
2018-04-20 18:59:55 -05:00
int difficulty = 50 + ( 25 * ( spellLevel - 1 ) ) ;
return GetManaCost ( m_SpellCastData . current_skill , difficulty , m_SpellCastData . spell - > _base_mana , manaConvSkill ) ;
2018-03-29 17:01:57 -04:00
}
int CSpellcastingManager : : TryBeginCast ( DWORD target_id , DWORD spell_id )
{
if ( m_bCasting )
{
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("DEBUG: Actions Locked, Casting = true, Turning = %s", m_bTurningToObject ? "true" : "false"), LTT_ALL_CHANNELS);
2018-03-29 17:01:57 -04:00
return WERROR_ACTIONS_LOCKED ;
}
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > get_minterp ( ) - > interpreted_state . actions . size ( ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("DEBUG: Actions Locked, Interp state has %d actions.", m_pWeenie->get_minterp()->interpreted_state.actions.size()), LTT_ALL_CHANNELS);
2018-03-29 17:01:57 -04:00
return WERROR_ACTIONS_LOCKED ;
}
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > get_minterp ( ) - > interpreted_state . forward_command ! = 0x41000003 )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("DEBUG: Unprepared, Interp state forward command is 0x%08X, not idle.", m_pWeenie->get_minterp()->interpreted_state.forward_command), LTT_ALL_CHANNELS);
2018-03-29 17:01:57 -04:00
return WERROR_MAGIC_UNPREPARED ;
}
2018-07-12 14:41:21 -07:00
if ( ! m_pWeenie - > m_Qualities . IsSpellKnown ( spell_id ) )
2018-03-29 17:01:57 -04:00
{
2018-07-03 15:42:54 -05:00
// Don't return the unlearned spell error for Cast on Strike
2018-07-11 04:53:32 +00:00
if ( ! ( m_pWeenie - > AsMeleeWeapon ( ) | | m_pWeenie - > AsMissileLauncher ( ) ) & & spell_id ! = m_pWeenie - > InqDIDQuality ( PROC_SPELL_DID , 0 ) )
2018-07-03 15:42:54 -05:00
{
return WERROR_MAGIC_UNLEARNED_SPELL ;
}
2018-03-29 17:01:57 -04:00
}
if ( Timer : : cur_time < m_fNextCastTime )
{
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("DEBUG: Actions Locked, Can't cast for %.3f more seconds.", Timer::cur_time - m_fNextCastTime), LTT_ALL_CHANNELS);
2018-03-29 17:01:57 -04:00
return WERROR_ACTIONS_LOCKED ;
}
m_SpellCastData = SpellCastData ( ) ; // reset
2018-07-12 14:41:21 -07:00
m_SpellCastData . caster_id = m_pWeenie - > GetID ( ) ;
m_SpellCastData . source_id = m_pWeenie - > GetTopLevelID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . target_id = target_id ;
m_SpellCastData . spell_id = spell_id ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . wand_id = m_pWeenie - > GetWieldedCasterID ( ) ;
2018-03-29 17:01:57 -04:00
m_SpellCastData . cast_timeout = Timer : : cur_time + 10.0f ;
2018-07-12 14:41:21 -07:00
m_SpellCastData . initial_cast_position = m_pWeenie - > m_Position ;
2018-03-29 17:01:57 -04:00
if ( ! ResolveSpellBeingCasted ( ) )
{
2018-04-27 21:03:39 -07:00
SERVER_INFO < < " Player trying to cast unknown spell? " ;
2018-03-29 17:01:57 -04:00
return WERROR_MAGIC_GENERAL_FAILURE ;
}
if ( ! m_SpellCastData . current_skill )
{
2018-07-12 14:41:21 -07:00
m_pWeenie - > SendText ( " You are not trained in that skill! " , LTT_MAGIC ) ;
2018-03-29 17:01:57 -04:00
return WERROR_MAGIC_INVALID_SPELL_TYPE ;
}
2018-07-12 14:41:21 -07:00
// m_pWeenie->SendText(csprintf("Casting %d", m_SpellCastData.spell_id), LTT_DEFAULT);
2018-03-29 17:01:57 -04:00
2018-12-12 22:18:04 +00:00
int targetError = CheckTargetValidity ( ) ;
if ( targetError )
{
CWeenieObject * pTarget = g_pWorld - > FindObject ( m_SpellCastData . target_id ) ;
switch ( targetError )
{
case WERROR_PK_PROTECTED_TARGET :
{
if ( pTarget )
{
auto targetName = pTarget - > GetName ( ) ;
pTarget - > SendText ( csprintf ( " %s fails to affect you because you cannot be harmed! " , m_pWeenie - > GetName ( ) . c_str ( ) ) , LTT_MAGIC ) ;
m_pWeenie - > SendText ( csprintf ( " You fail to affect %s because %s cannot be harmed! " , targetName . c_str ( ) , targetName . c_str ( ) ) , LTT_MAGIC ) ;
}
return WERROR_NONE ;
}
2018-12-13 05:03:44 -05:00
case WERROR_MAGIC_BAD_TARGET_TYPE :
2018-12-12 22:18:04 +00:00
{
if ( pTarget )
{
2018-12-13 05:03:44 -05:00
m_pWeenie - > EmitSound ( Sound_UI_GeneralError , 1.0f , true ) ;
m_pWeenie - > NotifyWeenieErrorWithString ( WERROR_MAGIC_BAD_TARGET_TYPE , pTarget - > GetName ( ) . c_str ( ) ) ;
2018-12-12 22:18:04 +00:00
}
return WERROR_NONE ;
}
}
2018-03-29 17:01:57 -04:00
return targetError ;
2018-12-12 22:18:04 +00:00
}
2018-03-29 17:01:57 -04:00
//Components
2018-07-12 14:41:21 -07:00
CContainerWeenie * caster = m_pWeenie - > AsContainer ( ) ;
2018-03-29 17:01:57 -04:00
if ( caster ! = NULL & & caster - > InqBoolQuality ( SPELL_COMPONENTS_REQUIRED_BOOL , FALSE ) = = TRUE )
{
2018-04-26 18:06:54 -04:00
bool foci ;
2018-03-29 17:01:57 -04:00
if ( g_pConfig - > IsSpellFociEnabled ( ) )
{
switch ( m_SpellCastData . spell - > InqSkillForSpell ( ) )
{
2018-04-28 12:32:16 -04:00
case CREATURE_ENCHANTMENT_SKILL : foci = FindFociInContainer ( caster , W_PACKCREATUREESSENCE_CLASS ) | | caster - > InqIntQuality ( AUGMENTATION_INFUSED_CREATURE_MAGIC_INT , 0 ) ; break ;
case ITEM_ENCHANTMENT_SKILL : foci = FindFociInContainer ( caster , W_PACKITEMESSENCE_CLASS ) | | caster - > InqIntQuality ( AUGMENTATION_INFUSED_ITEM_MAGIC_INT , 0 ) ; break ;
case LIFE_MAGIC_SKILL : foci = FindFociInContainer ( caster , W_PACKLIFEESSENCE_CLASS ) | | caster - > InqIntQuality ( AUGMENTATION_INFUSED_LIFE_MAGIC_INT , 0 ) ; break ;
case WAR_MAGIC_SKILL : foci = FindFociInContainer ( caster , W_PACKWARESSENCE_CLASS ) | | caster - > InqIntQuality ( AUGMENTATION_INFUSED_WAR_MAGIC_INT , 0 ) ; break ;
2018-09-12 20:56:36 -04:00
case VOID_MAGIC_SKILL : foci = FindFociInContainer ( caster , W_FOCIOFSHADOW_CLASS ) | | caster - > InqIntQuality ( AUGMENTATION_INFUSED_VOID_MAGIC_INT , 0 ) ; break ;
2018-03-29 17:01:57 -04:00
}
}
2018-04-28 12:32:16 -04:00
2018-03-29 17:01:57 -04:00
SpellFormula randomizedComponents ;
randomizedComponents . CopyFrom ( m_SpellCastData . spell - > InqSpellFormula ( ) ) ;
2018-07-11 04:53:32 +00:00
CPlayerWeenie * player = m_pWeenie - > AsPlayer ( ) ;
2018-07-12 14:41:21 -07:00
if ( player )
2018-03-29 17:01:57 -04:00
randomizedComponents . RandomizeForName ( player - > GetClient ( ) - > GetAccount ( ) , m_SpellCastData . spell - > _formula_version ) ;
std : : map < DWORD , DWORD > componentAmounts ;
for each ( DWORD componentId in randomizedComponents . _comps )
{
if ( componentId = = 0 )
continue ;
2018-04-26 18:06:54 -04:00
if ( foci ! = FALSE )
2018-03-29 17:01:57 -04:00
{
SpellComponentTable * pSpellComponents = MagicSystem : : GetSpellComponentTable ( ) ;
const SpellComponentBase * componentBase = pSpellComponents - > InqSpellComponentBase ( componentId ) ;
switch ( componentBase - > _type )
{
case SpellComponentType : : Power_SpellComponentType : //scarabs
break ;
case SpellComponentType : : Accent_SpellComponentType : //tapers
componentId = 188 ; //turn tapers into prismatic tapers.
break ;
default :
continue ;
}
}
componentAmounts [ componentId ] + + ;
}
2018-04-26 18:06:54 -04:00
if ( foci ! = FALSE )
2018-03-29 17:01:57 -04:00
componentAmounts [ 188 ] + + ; //if using foci, add one more prismatic taper.
m_UsedComponents . clear ( ) ; // clear the list of left overs from previous interrupted spell attempts.
for ( std : : map < DWORD , DWORD > : : iterator iter = componentAmounts . begin ( ) ; iter ! = componentAmounts . end ( ) ; + + iter )
{
DWORD compId = iter - > first ;
DWORD amount = iter - > second ;
std : : map < DWORD , DWORD > components = FindComponentInContainer ( caster , compId , amount ) ;
if ( ! components . empty ( ) )
{
for ( std : : map < DWORD , DWORD > : : iterator iter = components . begin ( ) ; iter ! = components . end ( ) ; + + iter )
m_UsedComponents [ iter - > first ] + = iter - > second ;
}
else
return WERROR_MAGIC_MISSING_COMPONENTS ;
}
}
2018-07-11 04:53:32 +00:00
if ( ! ( m_pWeenie - > AsMeleeWeapon ( ) | | m_pWeenie - > AsMissileLauncher ( ) ) )
2018-07-03 15:42:54 -05:00
{
2018-07-11 04:53:32 +00:00
if ( m_pWeenie - > GetMana ( ) < GenerateManaCost ( ) )
2018-07-03 15:42:54 -05:00
return WERROR_MAGIC_INSUFFICIENT_MANA ;
}
2018-07-11 04:53:32 +00:00
else if ( m_pWeenie - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 , 0 ) < GenerateManaCost ( ) )
2018-03-29 17:01:57 -04:00
return WERROR_MAGIC_INSUFFICIENT_MANA ;
2018-07-03 15:42:54 -05:00
else
{
m_bCasting = true ;
2018-07-11 04:53:32 +00:00
m_SpellCastData . current_skill = m_pWeenie - > InqIntQuality ( ITEM_SPELLCRAFT_INT , 0 , 0 ) ;
2018-07-03 15:42:54 -05:00
int error = LaunchSpellEffect ( FALSE ) ;
EndCast ( error ) ;
2018-10-18 18:52:26 -05:00
return WERROR_NONE ;
2018-07-03 15:42:54 -05:00
}
2018-07-11 04:53:32 +00:00
2018-03-29 17:01:57 -04:00
BeginCast ( ) ;
return WERROR_NONE ;
}
2018-07-12 14:41:21 -07:00
std : : map < DWORD , DWORD > CSpellcastingManager : : FindComponentInContainer ( CContainerWeenie * container , unsigned int componentId , int amountNeeded )
2018-03-29 17:01:57 -04:00
{
std : : map < DWORD , DWORD > foundItems ;
int amountLeftToFind = amountNeeded ;
for ( auto item : container - > m_Items )
{
2018-07-12 14:41:21 -07:00
if ( item - > InqDIDQuality ( SPELL_COMPONENT_DID , 0 ) = = componentId )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
int amount = item - > InqIntQuality ( STACK_SIZE_INT , 1 ) ;
2018-03-29 17:01:57 -04:00
if ( amount > amountLeftToFind )
{
amount = amountLeftToFind ;
amountLeftToFind = 0 ;
}
else
amountLeftToFind - = amount ;
2018-07-12 14:41:21 -07:00
foundItems . emplace ( item - > GetID ( ) , amount ) ;
2018-03-29 17:01:57 -04:00
if ( amountLeftToFind = = 0 )
return foundItems ;
}
}
for ( auto packSlot : container - > m_Packs )
{
2018-07-12 14:41:21 -07:00
CContainerWeenie * pack = packSlot - > AsContainer ( ) ;
if ( pack ! = NULL )
2018-03-29 17:01:57 -04:00
{
for ( auto item : pack - > m_Items )
{
2018-07-12 14:41:21 -07:00
if ( item - > InqDIDQuality ( SPELL_COMPONENT_DID , 0 ) = = componentId )
2018-06-21 23:32:21 +01:00
{
2018-07-12 14:41:21 -07:00
int amount = item - > InqIntQuality ( STACK_SIZE_INT , 1 ) ;
2018-03-29 17:01:57 -04:00
if ( amount > amountLeftToFind )
{
amount = amountLeftToFind ;
amountLeftToFind = 0 ;
}
else
amountLeftToFind - = amount ;
2018-07-12 14:41:21 -07:00
foundItems . emplace ( item - > GetID ( ) , amount ) ;
2018-03-29 17:01:57 -04:00
if ( amountLeftToFind = = 0 )
return foundItems ;
}
}
}
}
//we didnt find everything, so empty our list and return
foundItems . clear ( ) ;
return foundItems ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CSpellcastingManager : : FindFociInContainer ( CContainerWeenie * container , DWORD fociWcid )
2018-03-29 17:01:57 -04:00
{
for ( auto pack : container - > m_Packs )
{
2018-07-12 14:41:21 -07:00
if ( pack - > m_Qualities . id = = fociWcid )
return pack ;
2018-03-29 17:01:57 -04:00
}
return NULL ;
}
void CSpellcastingManager : : Update ( )
{
if ( ! m_bCasting )
{
return ;
}
if ( m_SpellCastData . cast_timeout < = Timer : : cur_time )
{
EndCast ( WERROR_MAGIC_GENERAL_FAILURE ) ;
m_bCasting = false ;
}
2018-07-22 01:46:30 -05:00
if ( m_pWeenie - > AsPlayer ( ) & & m_pWeenie - > IsInPeaceMode ( ) )
2018-07-11 04:53:32 +00:00
{
// fizzle if you're no longer in combat mode.
m_pWeenie - > EmitEffect ( PS_Fizzle , 0.542734265f ) ;
m_pWeenie - > AdjustMana ( - 5 ) ;
int error = LaunchSpellEffect ( TRUE ) ;
EndCast ( error ) ;
}
if ( ( m_SpellCastData . next_update < = Timer : : cur_time ) & & m_bTurned & & m_pWeenie - > m_Position . distance ( m_SpellCastData . initial_cast_position ) > = 6.0 & & m_pWeenie - > m_Qualities . GetInt ( PLAYER_KILLER_STATUS_INT , 0 ) = = PK_PKStatus )
{
// fizzle
m_pWeenie - > EmitEffect ( PS_Fizzle , 0.542734265f ) ;
m_pWeenie - > AdjustMana ( - 5 ) ;
m_pWeenie - > SendText ( " Your movement disrupted spell casting! " , LTT_MAGIC ) ;
2018-07-20 18:19:00 -05:00
m_pWeenie - > SendText ( " Your movement disrupted spell casting! " , LTT_ERROR ) ;
2018-07-11 04:53:32 +00:00
int error = LaunchSpellEffect ( TRUE ) ;
EndCast ( error ) ;
}
if ( m_bTurningToObject )
2018-07-06 23:10:33 -05:00
{
2018-07-12 14:41:21 -07:00
if ( m_pWeenie - > movement_manager - > moveto_manager - > movement_type ! = MovementTypes : : TurnToObject )
2018-07-02 01:39:47 -05:00
{
2018-07-12 14:41:21 -07:00
if ( HeadingToTarget ( ) < = MAX_HEADING_TO_TARGET_FOR_CAST )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
// if (!m_pWeenie->get_minterp()->interpreted_state.turn_command)
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
BeginNextMotion ( ) ;
2018-03-29 17:01:57 -04:00
}
2018-07-11 04:53:32 +00:00
}
else
{
if ( ( m_SpellCastData . next_update < = Timer : : cur_time ) & & ! m_pWeenie - > get_minterp ( ) - > interpreted_state . turn_command )
2018-03-29 17:01:57 -04:00
{
2018-07-11 04:53:32 +00:00
MovementParameters params ;
params . speed = 1.0f ;
params . action_stamp = + + m_pWeenie - > m_wAnimSequence ;
m_pWeenie - > last_move_was_autonomous = false ;
m_pWeenie - > TurnToObject ( m_SpellCastData . target_id , & params ) ;
m_bTurned = true ;
m_SpellCastData . next_update = Timer : : cur_time + CAST_UPDATE_RATE ;
2018-07-12 14:41:21 -07:00
//m_bTurningToObject = true;
//m_fCastTimeout = Timer::cur_time + MAX_TURN_TIME_FOR_CAST;
2018-03-29 17:01:57 -04:00
}
}
2018-07-12 14:41:21 -07:00
}
2018-03-29 17:01:57 -04:00
else
{
/*
2018-07-12 14:41:21 -07:00
CWeenieObject * pTarget = g_pWorld - > FindWithinPVS ( m_pWeenie , m_TargetID ) ;
2018-03-29 17:01:57 -04:00
if ( pTarget )
{
LOG ( Temp , Normal , " %f (%f %f) %08X %f %f %f \n " ,
HeadingToTarget ( ) ,
2018-07-12 14:41:21 -07:00
m_pWeenie - > m_Position . heading ( pTarget - > m_Position ) ,
m_pWeenie - > m_Position . frame . get_heading ( ) ,
m_pWeenie - > get_minterp ( ) - > interpreted_state . turn_command ,
m_pWeenie - > movement_manager - > moveto_manager - > sought_position . frame . get_heading ( ) ,
m_pWeenie - > get_heading ( ) ,
m_pWeenie - > get_heading ( ) - m_pWeenie - > movement_manager - > moveto_manager - > sought_position . frame . get_heading ( ) ) ;
2018-03-29 17:01:57 -04:00
}
*/
}
}
}
void CSpellcastingManager : : Cancel ( )
{
if ( ! m_bCasting )
{
return ;
}
EndCast ( WErrorType : : WERROR_MAGIC_UNPREPARED ) ;
m_bCasting = false ;
}
void CSpellcastingManager : : OnDeath ( DWORD killer_id )
{
Cancel ( ) ;
}
void CSpellcastingManager : : HandleMotionDone ( DWORD motion , BOOL success )
{
if ( ! m_bCasting )
return ;
if ( m_bTurningToObject )
return ;
if ( m_PendingMotions . empty ( ) | | m_PendingMotions . begin ( ) - > motion ! = motion )
return ;
if ( ! success )
{
EndCast ( WERROR_MAGIC_GENERAL_FAILURE ) ;
return ;
}
m_PendingMotions . pop_front ( ) ;
BeginNextMotion ( ) ;
}