2018-03-29 17:01:57 -04:00
# include "StdAfx.h"
# include "WeenieObject.h"
# include "PhysicsObj.h"
# include "Monster.h"
# include "Player.h"
# include "Client.h"
# include "ClientEvents.h"
# include "BinaryWriter.h"
# include "ObjectMsgs.h"
# include "Database.h"
# include "Database2.h"
# include "World.h"
# include "WorldLandBlock.h"
# include "ClientCommands.h"
# include "ChatMsgs.h"
# include "WeenieFactory.h"
# include "InferredPortalData.h"
# include "AllegianceManager.h"
# include "Config.h"
# include "SpellcastingManager.h"
# include "Corpse.h"
# include "House.h"
2018-04-22 11:05:24 -07:00
# include "easylogging++.h"
2018-05-02 21:54:52 -07:00
# include "Util.h"
2018-03-29 17:01:57 -04:00
# define PLAYER_SAVE_INTERVAL 180.0
2018-05-06 01:19:27 +01:00
# define PLAYER_HEALTH_POLL_INTERVAL 5.0
2018-03-29 17:01:57 -04:00
2018-05-05 22:13:16 +01:00
DEFINE_PACK ( SalvageResult )
{
pWriter - > Write < DWORD > ( material ) ;
pWriter - > Write < double > ( workmanship ) ;
pWriter - > Write < int > ( units ) ;
}
DEFINE_UNPACK ( SalvageResult )
{
UNFINISHED ( ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
CPlayerWeenie : : CPlayerWeenie ( CClient * pClient , DWORD dwGUID , WORD instance_ts )
{
m_bDontClear = true ;
m_pClient = pClient ;
SetID ( dwGUID ) ;
_instance_timestamp = instance_ts ;
m_Qualities . SetInt ( CREATION_TIMESTAMP_INT , ( int ) time ( NULL ) ) ;
m_Qualities . SetFloat ( CREATION_TIMESTAMP_FLOAT , Timer : : cur_time ) ;
//if (pClient && pClient->GetAccessLevel() >= SENTINEL_ACCESS)
// SetRadarBlipColor(Sentinel_RadarBlipEnum);
SetLoginPlayerQualities ( ) ;
m_Qualities . SetInt ( PHYSICS_STATE_INT , PhysicsState : : HIDDEN_PS | PhysicsState : : IGNORE_COLLISIONS_PS | PhysicsState : : EDGE_SLIDE_PS | PhysicsState : : GRAVITY_PS ) ;
// Human Female by Default
// Used by physics object
SetSetupID ( 0x2000001 ) ; // 0x0200004E);
SetMotionTableID ( 0x9000001 ) ;
SetSoundTableID ( 0x20000001 ) ; // 0x20000002);
SetPETableID ( 0x34000004 ) ;
SetScale ( 1.0f ) ;
// Moon location... loc_t( 0xEFEA0001, 0, 0, 0 );
// SetInitialPosition(Position(0x9722003A, Vector(168.354004f, 24.618000f, 102.005005f), Quaternion(-0.922790f, 0.000000, 0.000000, -0.385302f)));
m_LastAssessed = 0 ;
m_NextSave = Timer : : cur_time + PLAYER_SAVE_INTERVAL ;
}
CPlayerWeenie : : ~ CPlayerWeenie ( )
{
LeaveFellowship ( ) ;
2018-05-11 00:14:42 +00:00
if ( m_pTradeManager )
{
2018-05-23 13:45:22 +01:00
m_pTradeManager - > CloseTrade ( AsPlayer ( ) ) ;
2018-05-11 00:14:42 +00:00
m_pTradeManager = NULL ;
}
2018-03-29 17:01:57 -04:00
CClientEvents * pEvents ;
if ( m_pClient & & ( pEvents = m_pClient - > GetEvents ( ) ) )
{
pEvents - > DetachPlayer ( ) ;
}
}
void CPlayerWeenie : : DetachClient ( )
{
m_pClient = NULL ;
}
void CPlayerWeenie : : SendNetMessage ( void * _data , DWORD _len , WORD _group , BOOL _event )
{
if ( m_pClient )
m_pClient - > SendNetMessage ( _data , _len , _group , _event ) ;
}
void CPlayerWeenie : : SendNetMessage ( BinaryWriter * _food , WORD _group , BOOL _event , BOOL del )
{
if ( m_pClient )
m_pClient - > SendNetMessage ( _food , _group , _event , del ) ;
}
void CPlayerWeenie : : AddSpellByID ( DWORD id )
{
BinaryWriter AddSpellToSpellbook ;
AddSpellToSpellbook . Write < DWORD > ( 0x02C1 ) ;
AddSpellToSpellbook . Write < DWORD > ( id ) ;
AddSpellToSpellbook . Write < DWORD > ( 0x0 ) ;
SendNetMessage ( AddSpellToSpellbook . GetData ( ) , AddSpellToSpellbook . GetSize ( ) , EVENT_MSG , true ) ;
}
bool CPlayerWeenie : : IsAdvocate ( )
{
return GetAccessLevel ( ) > = ADVOCATE_ACCESS ;
}
bool CPlayerWeenie : : IsSentinel ( )
{
return GetAccessLevel ( ) > = SENTINEL_ACCESS ;
}
bool CPlayerWeenie : : IsAdmin ( )
{
return GetAccessLevel ( ) > = ADMIN_ACCESS ;
}
int CPlayerWeenie : : GetAccessLevel ( )
{
if ( ! m_pClient )
return BASIC_ACCESS ;
2018-04-08 10:04:54 -04:00
2018-03-29 17:01:57 -04:00
return m_pClient - > GetAccessLevel ( ) ;
}
void CPlayerWeenie : : BeginLogout ( )
{
if ( IsLoggingOut ( ) )
return ;
2018-05-21 23:52:54 +01:00
_beginLogoutTime = max ( Timer : : cur_time , m_iPKActivity - 30 ) ;
2018-05-20 17:32:55 +01:00
_logoutTime = _beginLogoutTime + 5.0 ;
2018-03-29 17:01:57 -04:00
ChangeCombatMode ( NONCOMBAT_COMBAT_MODE , false ) ;
LeaveFellowship ( ) ;
2018-05-11 00:14:42 +00:00
if ( m_pTradeManager )
{
2018-05-23 13:45:22 +01:00
m_pTradeManager - > CloseTrade ( AsPlayer ( ) ) ;
2018-05-11 00:14:42 +00:00
m_pTradeManager = NULL ;
}
2018-05-20 17:32:55 +01:00
2018-03-29 17:01:57 -04:00
StopCompletely ( 0 ) ;
2018-05-20 17:32:55 +01:00
}
void CPlayerWeenie : : OnLogout ( )
{
2018-03-29 17:01:57 -04:00
DoForcedMotion ( Motion_LogOut ) ;
Save ( ) ;
}
void CPlayerWeenie : : Tick ( )
{
CMonsterWeenie : : Tick ( ) ;
if ( IsDead ( ) & & ( ! m_bReviveAfterAnim | | get_minterp ( ) - > interpreted_state . forward_command ! = Motion_Dead ) )
{
m_bReviveAfterAnim = false ;
//if (IsDead())
Revive ( ) ;
}
double pkTimestamp ;
if ( m_Qualities . InqFloat ( PK_TIMESTAMP_FLOAT , pkTimestamp , TRUE ) )
{
if ( pkTimestamp < = Timer : : cur_time )
{
m_Qualities . SetInt ( PLAYER_KILLER_STATUS_INT , PKStatusEnum : : PK_PKStatus ) ;
NotifyIntStatUpdated ( PLAYER_KILLER_STATUS_INT , false ) ;
m_Qualities . RemoveFloat ( PK_TIMESTAMP_FLOAT ) ;
NotifyFloatStatUpdated ( PK_TIMESTAMP_FLOAT ) ;
SendText ( " The power of Bael'Zharon flows through you, you are once more a player killer. " , LTT_MAGIC ) ;
}
}
if ( m_pClient )
{
if ( m_NextSave < = Timer : : cur_time )
{
if ( ! IsDead ( ) ) // && !IsBusyOrInAction())
{
Save ( ) ;
m_NextSave = Timer : : cur_time + PLAYER_SAVE_INTERVAL ;
}
}
}
if ( m_fNextMakeAwareCacheFlush < = Timer : : cur_time )
{
FlushMadeAwareof ( ) ;
m_fNextMakeAwareCacheFlush = Timer : : cur_time + 60.0 ;
}
2018-05-20 17:32:55 +01:00
if ( IsLoggingOut ( ) & & _beginLogoutTime < = Timer : : cur_time )
{
OnLogout ( ) ;
_beginLogoutTime = Timer : : cur_time + 999999 ;
}
2018-03-29 17:01:57 -04:00
if ( IsLoggingOut ( ) & & _logoutTime < = Timer : : cur_time )
{
// time to logout
if ( m_pClient & & m_pClient - > GetEvents ( ) )
{
m_pClient - > GetEvents ( ) - > OnLogoutCompleted ( ) ;
}
MarkForDestroy ( ) ;
}
if ( IsRecalling ( ) & & _recallTime < = Timer : : cur_time )
{
_recallTime = - 1.0 ;
Movement_Teleport ( _recallPos , false ) ;
}
2018-05-06 01:19:27 +01:00
2018-05-10 21:07:44 +00:00
if ( m_pTradeManager & & m_fNextTradeCheck < = Timer : : cur_time )
{
m_pTradeManager - > CheckDistance ( ) ;
m_fNextTradeCheck = Timer : : cur_time + 2 ;
}
2018-05-06 01:19:27 +01:00
if ( m_NextHealthUpdate < = Timer : : cur_time )
{
2018-05-24 22:28:15 +01:00
std : : shared_ptr < CWeenieObject > pTarget = g_pWorld - > FindWithinPVS ( GetPointer < CWeenieObject > ( ) , m_LastHealthRequest ) ;
if ( pTarget )
2018-05-06 01:19:27 +01:00
{
2018-05-24 22:28:15 +01:00
if ( std : : shared_ptr < CMonsterWeenie > pMonster = pTarget - > AsMonster ( ) )
{
SendNetMessage ( HealthUpdate ( pMonster ) , PRIVATE_MSG , TRUE , TRUE ) ;
2018-05-06 01:19:27 +01:00
2018-05-24 22:28:15 +01:00
m_NextHealthUpdate = Timer : : cur_time + PLAYER_HEALTH_POLL_INTERVAL ;
return ;
}
2018-05-06 01:19:27 +01:00
}
2018-05-24 22:28:15 +01:00
RemoveLastHealthRequest ( ) ;
2018-05-06 01:19:27 +01:00
}
2018-05-10 16:58:48 -05:00
}
2018-03-29 17:01:57 -04:00
bool CPlayerWeenie : : IsBusy ( )
{
if ( IsRecalling ( ) | | IsLoggingOut ( ) | | CWeenieObject : : IsBusy ( ) )
return true ;
return false ;
}
const double AWARENESS_TIMEOUT = 20.0 ;
bool CPlayerWeenie : : AlreadyMadeAwareOf ( DWORD object_id )
{
std : : unordered_map < DWORD , double > : : iterator entry = _objMadeAwareOf . find ( object_id ) ;
if ( entry ! = _objMadeAwareOf . end ( ) )
{
if ( ( entry - > second + AWARENESS_TIMEOUT ) > Timer : : cur_time )
return true ;
}
return false ;
}
void CPlayerWeenie : : SetMadeAwareOf ( DWORD object_id )
{
_objMadeAwareOf [ object_id ] = Timer : : cur_time ;
}
void CPlayerWeenie : : FlushMadeAwareof ( )
{
for ( std : : unordered_map < DWORD , double > : : iterator i = _objMadeAwareOf . begin ( ) ; i ! = _objMadeAwareOf . end ( ) ; )
{
if ( ( i - > second + AWARENESS_TIMEOUT ) < = Timer : : cur_time )
i = _objMadeAwareOf . erase ( i ) ;
else
i + + ;
}
}
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : MakeAware ( std : : shared_ptr < CWeenieObject > pEntity , bool bForceUpdate )
2018-03-29 17:01:57 -04:00
{
2018-05-31 18:00:27 +01:00
if ( ! pEntity )
{
return ;
}
2018-03-29 17:01:57 -04:00
# ifndef PUBLIC_BUILD
int vis ;
if ( pEntity - > m_Qualities . InqBool ( VISIBILITY_BOOL , vis ) & & ! m_bAdminVision )
return ;
# else
int vis ;
if ( pEntity - > m_Qualities . InqBool ( VISIBILITY_BOOL , vis ) )
return ;
# endif
if ( ! bForceUpdate & & AlreadyMadeAwareOf ( pEntity - > GetID ( ) ) )
return ;
SetMadeAwareOf ( pEntity - > GetID ( ) ) ;
BinaryWriter * CM = pEntity - > CreateMessage ( ) ;
if ( CM )
{
// LOG(Temp, Normal, "Sending object %X in cell %X\n", pEntity->GetID(), pEntity->m_Position.objcell_id);
SendNetMessage ( CM , OBJECT_MSG ) ;
}
if ( pEntity - > children & & pEntity - > children - > num_objects )
{
for ( DWORD i = 0 ; i < pEntity - > children - > num_objects ; i + + )
{
2018-06-16 11:57:58 +01:00
if ( std : : shared_ptr < CPhysicsObj > pChild = pEntity - > children - > objects . array_data [ i ] . lock ( ) )
2018-05-31 18:00:27 +01:00
{
if ( std : : shared_ptr < CWeenieObject > pChildWeenie = pChild - > GetPointer < CWeenieObject > ( ) )
{
if ( BinaryWriter * CM = std : : dynamic_pointer_cast < CWeenieObject > ( pEntity ) - > CreateMessage ( ) )
{
SendNetMessage ( CM , OBJECT_MSG ) ;
}
}
}
2018-03-29 17:01:57 -04:00
}
}
2018-05-24 22:28:15 +01:00
if ( pEntity = = GetPointer < CWeenieObject > ( ) )
2018-03-29 17:01:57 -04:00
{
// make aware of inventory too
for ( auto item : m_Wielded )
{
2018-06-21 23:32:21 +01:00
MakeAware ( item . lock ( ) ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : m_Items )
{
2018-06-21 23:32:21 +01:00
MakeAware ( item . lock ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-04-08 10:04:54 -04:00
2018-03-29 17:01:57 -04:00
for ( auto item : m_Packs )
{
2018-06-21 23:32:21 +01:00
std : : shared_ptr < CWeenieObject > pItem = item . lock ( ) ;
2018-03-29 17:01:57 -04:00
2018-06-21 23:32:21 +01:00
MakeAware ( pItem ) ;
if ( std : : shared_ptr < CContainerWeenie > container = pItem - > AsContainer ( ) )
2018-03-29 17:01:57 -04:00
{
2018-05-24 22:28:15 +01:00
container - > MakeAwareViewContent ( GetPointer < CWeenieObject > ( ) ) ;
2018-03-29 17:01:57 -04:00
}
}
}
}
void CPlayerWeenie : : LoginCharacter ( void )
{
DWORD SC [ 2 ] ;
SC [ 0 ] = 0xF746 ;
SC [ 1 ] = GetID ( ) ;
SendNetMessage ( SC , sizeof ( SC ) , 10 ) ;
2018-05-23 13:45:22 +01:00
BinaryWriter * LC = : : LoginCharacter ( AsPlayer ( ) ) ;
2018-03-29 17:01:57 -04:00
SendNetMessage ( LC - > GetData ( ) , LC - > GetSize ( ) , PRIVATE_MSG , TRUE ) ;
delete LC ;
}
void CPlayerWeenie : : ExitPortal ( )
{
2018-03-29 20:32:02 -04:00
if ( _isFirstPortalInSession )
{
TryToUnloadAllegianceXP ( true ) ;
_isFirstPortalInSession = false ;
}
2018-05-31 18:00:27 +01:00
if ( std : : shared_ptr < CPhysicsObj > pPhysObj = _phys_obj . lock ( ) )
{
pPhysObj - > ExitPortal ( ) ;
}
2018-03-29 17:01:57 -04:00
}
2018-05-06 01:19:27 +01:00
void CPlayerWeenie : : SetLastHealthRequest ( DWORD guid )
{
m_LastHealthRequest = guid ;
m_NextHealthUpdate = Timer : : cur_time + PLAYER_HEALTH_POLL_INTERVAL ;
}
void CPlayerWeenie : : RemoveLastHealthRequest ( )
{
m_LastHealthRequest = 0 ;
// nothing targeted so we don't want to send messages
m_NextHealthUpdate = Timer : : cur_time + 86400.0 ;
}
void CPlayerWeenie : : RefreshTargetHealth ( )
{
m_NextHealthUpdate = 0 ;
}
2018-03-29 17:01:57 -04:00
void CPlayerWeenie : : SetLastAssessed ( DWORD guid )
{
m_LastAssessed = guid ;
}
std : : string CPlayerWeenie : : RemoveLastAssessed ( )
{
if ( m_LastAssessed ! = 0 )
{
2018-05-24 22:28:15 +01:00
std : : shared_ptr < CWeenieObject > pObject = g_pWorld - > FindWithinPVS ( GetPointer < CWeenieObject > ( ) , m_LastAssessed ) ;
2018-03-29 17:01:57 -04:00
2018-05-23 13:45:22 +01:00
if ( pObject & & ! pObject - > AsPlayer ( ) & & ! pObject - > m_bDontClear ) {
2018-03-29 17:01:57 -04:00
std : : string name = pObject - > GetName ( ) ;
2018-06-21 23:32:21 +01:00
g_pWorld - > RemoveEntity ( pObject ) ;
2018-03-29 17:01:57 -04:00
m_LastAssessed = 0 ;
return name ;
}
}
return " " ;
}
void CPlayerWeenie : : OnDeathAnimComplete ( )
{
CMonsterWeenie : : OnDeathAnimComplete ( ) ;
if ( m_bReviveAfterAnim )
{
m_bReviveAfterAnim = false ;
if ( ! g_pConfig - > HardcoreMode ( ) )
{
2018-05-15 00:04:29 -05:00
//clear damage sources on death
m_aDamageSources . clear ( ) ;
2018-03-29 17:01:57 -04:00
//if (IsDead())
Revive ( ) ;
}
}
}
void CPlayerWeenie : : UpdateVitaePool ( DWORD pool )
{
m_Qualities . SetInt ( VITAE_CP_POOL_INT , pool ) ;
NotifyIntStatUpdated ( VITAE_CP_POOL_INT , true ) ;
}
void CPlayerWeenie : : ReduceVitae ( float amount )
{
int level = InqIntQuality ( LEVEL_INT , 1 ) ;
double maxVitaePenalty ;
if ( level < 15 )
maxVitaePenalty = min ( max ( ( level - 1 ) * 3 , 1 ) / 100.0 , 0.4 ) ;
else
maxVitaePenalty = 0.4 ;
double minVitaeEnergy = 1.0 - maxVitaePenalty ;
Enchantment enchant ;
if ( m_Qualities . InqVitae ( & enchant ) )
enchant . _smod . val - = amount ;
else
{
enchant . _id = Vitae_SpellID ;
enchant . m_SpellSetID = 0 ; // ???
enchant . _spell_category = 204 ; // Vitae_SpellCategory;
enchant . _power_level = 30 ;
enchant . _start_time = 0 ;
enchant . _duration = - 1.0 ;
enchant . _caster = 0 ;
enchant . _degrade_modifier = 0 ;
enchant . _degrade_limit = 1 ;
enchant . _last_time_degraded = 0 ;
enchant . _smod . type = SecondAtt_EnchantmentType | Skill_EnchantmentType | MultipleStat_EnchantmentType | Multiplicative_EnchantmentType | Additive_Degrade_EnchantmentType | Vitae_EnchantmentType ;
enchant . _smod . key = 0 ;
enchant . _smod . val = 1.0f - amount ;
}
if ( enchant . _smod . val < minVitaeEnergy )
enchant . _smod . val = minVitaeEnergy ;
if ( enchant . _smod . val > 1.0f )
enchant . _smod . val = 1.0f ;
m_Qualities . UpdateEnchantment ( & enchant ) ;
UpdateVitaeEnchantment ( ) ;
CheckVitalRanges ( ) ;
}
void CPlayerWeenie : : UpdateVitaeEnchantment ( )
{
Enchantment enchant ;
if ( m_Qualities . InqVitae ( & enchant ) )
{
if ( enchant . _smod . val < 1.0f )
{
NotifyEnchantmentUpdated ( & enchant ) ;
}
else
{
PackableListWithJson < DWORD > expired ;
expired . push_back ( 666 ) ;
if ( m_Qualities . _enchantment_reg )
{
m_Qualities . _enchantment_reg - > RemoveEnchantments ( & expired ) ;
}
BinaryWriter expireMessage ;
expireMessage . Write < DWORD > ( 0x2C5 ) ;
expired . Pack ( & expireMessage ) ;
SendNetMessage ( & expireMessage , PRIVATE_MSG , TRUE , FALSE ) ;
EmitSound ( Sound_SpellExpire , 1.0f , true ) ;
}
}
}
void CPlayerWeenie : : OnGivenXP ( long long amount , bool allegianceXP )
{
if ( m_Qualities . GetVitaeValue ( ) < 1.0 & & ! allegianceXP )
{
DWORD64 vitae_pool = InqIntQuality ( VITAE_CP_POOL_INT , 0 ) + min ( amount , 1000000000 ) ;
2018-04-08 10:04:54 -04:00
float new_vitae = 1.0 ;
2018-03-29 17:01:57 -04:00
bool has_new_vitae = VitaeSystem : : DetermineNewVitaeLevel ( m_Qualities . GetVitaeValue ( ) , InqIntQuality ( DEATH_LEVEL_INT , 1 ) , & vitae_pool , & new_vitae ) ;
UpdateVitaePool ( vitae_pool ) ;
if ( has_new_vitae )
{
if ( new_vitae < 1.0f )
{
SendText ( " Your experience has reduced your Vitae penalty! " , LTT_MAGIC ) ;
}
Enchantment enchant ;
if ( m_Qualities . InqVitae ( & enchant ) )
{
enchant . _smod . val = new_vitae ;
m_Qualities . UpdateEnchantment ( & enchant ) ;
}
UpdateVitaeEnchantment ( ) ;
CheckVitalRanges ( ) ;
}
}
else
{
// there should be no vitae...
UpdateVitaeEnchantment ( ) ;
}
}
2018-06-21 23:32:21 +01:00
void addItemsToDropLists ( std : : vector < std : : weak_ptr < CWeenieObject > > items , std : : vector < std : : shared_ptr < CWeenieObject > > & removeList , std : : vector < std : : shared_ptr < CWeenieObject > > & alwaysDropList , std : : vector < std : : shared_ptr < CWeenieObject > > & allValidItems )
2018-05-10 06:21:14 +00:00
{
for ( auto item : items )
{
2018-06-21 23:32:21 +01:00
std : : shared_ptr < CWeenieObject > pItem = item . lock ( ) ;
if ( ! pItem )
{
2018-05-10 06:21:14 +00:00
continue ;
2018-06-21 23:32:21 +01:00
}
if ( pItem - > m_Qualities . id = = W_COINSTACK_CLASS )
continue ;
else if ( pItem - > IsDestroyedOnDeath ( ) )
removeList . push_back ( pItem ) ;
else if ( pItem - > IsDroppedOnDeath ( ) )
alwaysDropList . push_back ( pItem ) ;
else if ( ! pItem - > IsBonded ( ) )
allValidItems . push_back ( pItem ) ;
2018-05-10 06:21:14 +00:00
}
}
2018-05-02 21:12:01 -07:00
//TODO Add nonwielded handling for level > 11 && level < 35
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : CalculateAndDropDeathItems ( std : : shared_ptr < CCorpseWeenie > pCorpse , DWORD killer_id )
2018-03-29 17:01:57 -04:00
{
if ( ! pCorpse )
return ;
if ( IsBonded ( ) ) //we're using the bonded property on the player to determine if they should or not drop items on death.
return ;
int level = InqIntQuality ( LEVEL_INT , 1 ) ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > pKiller = g_pWorld - > FindObject ( killer_id ) ;
2018-04-24 21:07:20 -04:00
int amountOfItemsToDrop = 0 ;
int augDropLess = InqIntQuality ( AUGMENTATION_LESS_DEATH_ITEM_LOSS_INT , 0 ) ; // Take Death Item Augs into Consideration
2018-05-10 06:21:14 +00:00
if ( level < = 10 )
2018-05-02 21:12:01 -07:00
{
2018-05-10 06:21:14 +00:00
amountOfItemsToDrop = 0 ;
2018-05-02 21:12:01 -07:00
}
2018-05-10 06:21:14 +00:00
else if ( level < = 20 )
2018-05-02 21:12:01 -07:00
{
2018-05-10 06:21:14 +00:00
amountOfItemsToDrop = 1 ;
2018-05-02 21:12:01 -07:00
}
2018-04-24 21:07:20 -04:00
else
2018-05-02 21:12:01 -07:00
{
amountOfItemsToDrop = floor ( level / 20 ) + Random : : GenInt ( 0 , 2 ) ;
}
2018-05-10 06:21:14 +00:00
// either we can't find a killer (killed self?) or the killer is not a player
if ( ! pKiller | | ! pKiller - > _IsPlayer ( ) )
2018-05-04 17:10:42 -05:00
amountOfItemsToDrop = max ( 0 , ( amountOfItemsToDrop - ( augDropLess * 5 ) ) ) ;
2018-05-10 06:21:14 +00:00
2018-03-29 17:01:57 -04:00
pCorpse - > _begin_destroy_at = Timer : : cur_time + max ( ( 60.0 * 5 * level ) , 60 * 60 ) ; //override corpse decay time to 5 minutes per level with a minimum of 1 hour.
pCorpse - > _shouldSave = true ;
pCorpse - > m_bDontClear = true ;
2018-05-02 21:12:01 -07:00
DWORD coinConsumed = 0 ;
if ( level > 5 )
{
coinConsumed = ConsumeCoin ( RecalculateCoinAmount ( ) / 2 ) ;
pCorpse - > SpawnInContainer ( W_COINSTACK_CLASS , coinConsumed ) ;
}
2018-03-29 17:01:57 -04:00
2018-05-23 13:45:22 +01:00
std : : vector < std : : shared_ptr < CWeenieObject > > removeList ;
std : : vector < std : : shared_ptr < CWeenieObject > > alwaysDropList ;
std : : vector < std : : shared_ptr < CWeenieObject > > allValidItems ;
2018-03-29 17:01:57 -04:00
2018-05-10 06:21:14 +00:00
addItemsToDropLists ( m_Wielded , removeList , alwaysDropList , allValidItems ) ;
addItemsToDropLists ( m_Items , removeList , alwaysDropList , allValidItems ) ;
2018-03-29 17:01:57 -04:00
for ( auto packAsWeenie : m_Packs )
{
2018-06-21 23:32:21 +01:00
std : : shared_ptr < CWeenieObject > pItem = packAsWeenie . lock ( ) ;
if ( ! pItem )
{
continue ;
}
std : : shared_ptr < CContainerWeenie > pack = pItem - > AsContainer ( ) ;
2018-03-29 17:01:57 -04:00
if ( pack )
{
2018-05-10 06:21:14 +00:00
addItemsToDropLists ( pack - > m_Items , removeList , alwaysDropList , allValidItems ) ;
2018-03-29 17:01:57 -04:00
}
}
for ( auto item : removeList )
item - > Remove ( ) ;
for ( auto item : alwaysDropList )
FinishMoveItemToContainer ( item , pCorpse , 0 , true , true ) ;
2018-05-10 06:21:14 +00:00
// This section calculates the effective value for each item (halved for each previous dupe)
2018-05-23 13:45:22 +01:00
std : : multimap < int , std : : shared_ptr < CWeenieObject > > itemValueList ;
2018-05-10 06:21:14 +00:00
std : : map < std : : string , int > itemNameList ;
std : : string objName ;
2018-03-29 17:01:57 -04:00
for ( auto item : allValidItems )
{
2018-05-10 06:21:14 +00:00
// if this item is stackable
if ( item - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 0 ) )
2018-03-29 17:01:57 -04:00
{
2018-05-10 06:21:14 +00:00
int stack_sz = item - > InqIntQuality ( STACK_SIZE_INT , 0 ) ;
int value = item - > InqIntQuality ( STACK_UNIT_VALUE_INT , 0 ) ;
objName = item - > InqStringQuality ( NAME_STRING , objName ) ;
// initialise to 0 (this will silently fail if it already exists)
itemNameList . insert ( std : : pair < std : : string , int > ( objName , 0 ) ) ;
// reduce value by half for all previous items with same name
value / = 1 < < min ( 15 , itemNameList [ objName ] ) ; // 15 to prevent overflow
itemNameList [ objName ] + = stack_sz ;
2018-03-31 19:34:02 -04:00
for ( int i = 0 ; i < stack_sz ; i + + )
2018-03-29 17:01:57 -04:00
{
2018-05-23 13:45:22 +01:00
itemValueList . insert ( std : : pair < int , std : : shared_ptr < CWeenieObject > > ( value , item ) ) ;
2018-05-10 06:21:14 +00:00
// reduce value by half again
value / = 2 ;
2018-03-29 17:01:57 -04:00
}
}
2018-05-10 06:21:14 +00:00
else // not a stack
2018-03-29 17:01:57 -04:00
{
2018-05-10 06:21:14 +00:00
int value = item - > GetValue ( ) ;
// from item->getName - if it has a material type then it's a randomly generated item and we don't want to add it to the dupe list
if ( item - > InqIntQuality ( MATERIAL_TYPE_INT , 0 ) )
{
objName = item - > InqStringQuality ( NAME_STRING , objName ) ;
// initialise to 0 (this will silently fail if it already exists)
itemNameList . insert ( std : : pair < std : : string , int > ( objName , 0 ) ) ;
// reduce value by half for all previous items with same name
value / = 1 < < itemNameList [ objName ] ;
itemNameList [ objName ] + + ;
}
2018-05-23 13:45:22 +01:00
itemValueList . insert ( std : : pair < int , std : : shared_ptr < CWeenieObject > > ( value , item ) ) ;
2018-03-31 19:34:02 -04:00
}
}
2018-03-29 17:01:57 -04:00
2018-05-10 06:21:14 +00:00
// cap the amount of items to drop to the number of items we can drop so the message properly ends with " and "
2018-05-31 18:00:27 +01:00
amountOfItemsToDrop = min ( amountOfItemsToDrop , static_cast < int > ( itemValueList . size ( ) ) ) ;
2018-05-10 06:21:14 +00:00
int itemsLost = 0 ;
std : : string itemsLostText ;
if ( coinConsumed )
2018-03-31 22:12:40 -04:00
{
2018-05-10 06:21:14 +00:00
itemsLostText = csprintf ( " You've lost %s Pyreal%s " , FormatNumberString ( coinConsumed ) . c_str ( ) , coinConsumed > 1 ? " s " : " " ) ;
2018-04-01 00:31:20 -04:00
2018-05-10 06:21:14 +00:00
// increment itemsLost so the next item starts with " and your " or ", your"
itemsLost + + ;
amountOfItemsToDrop + + ;
}
else
2018-04-01 00:31:20 -04:00
{
2018-05-10 06:21:14 +00:00
itemsLostText = " You've lost " ;
2018-03-29 17:01:57 -04:00
}
2018-03-31 19:34:02 -04:00
// START item dropping BY VALUE
2018-05-10 06:21:14 +00:00
for ( auto iter = itemValueList . rbegin ( ) ; iter ! = itemValueList . rend ( ) ; + + iter )
2018-03-31 19:34:02 -04:00
{
2018-05-10 06:21:14 +00:00
if ( itemsLost > = amountOfItemsToDrop )
{
break ;
}
2018-04-01 13:54:04 -04:00
if ( iter - > second - > InqIntQuality ( STACK_SIZE_INT , 1 ) > 1 )
2018-03-31 19:34:02 -04:00
{
2018-04-01 13:54:04 -04:00
iter - > second - > DecrementStackNum ( ) ;
pCorpse - > SpawnCloneInContainer ( iter - > second , 1 ) ;
2018-03-29 17:01:57 -04:00
}
else
2018-05-10 06:21:14 +00:00
{
2018-04-01 13:54:04 -04:00
FinishMoveItemToContainer ( iter - > second , pCorpse , 0 , true , true ) ;
2018-05-10 06:21:14 +00:00
}
2018-03-31 19:34:02 -04:00
itemsLost + + ;
2018-05-10 06:21:14 +00:00
2018-03-31 19:34:02 -04:00
if ( amountOfItemsToDrop > 1 & & itemsLost = = amountOfItemsToDrop )
itemsLostText . append ( " and your " ) ;
2018-05-10 06:21:14 +00:00
else if ( itemsLost > 1 )
2018-03-31 19:34:02 -04:00
itemsLostText . append ( " , your " ) ;
else
itemsLostText . append ( " your " ) ;
2018-03-29 17:01:57 -04:00
2018-05-10 06:21:14 +00:00
itemsLostText . append ( iter - > second - > GetName ( ) ) ;
2018-03-29 17:01:57 -04:00
}
2018-05-10 06:21:14 +00:00
itemsLostText . append ( " ! " ) ;
2018-04-22 11:05:24 -07:00
2018-05-10 06:21:14 +00:00
DEATH_LOG < < InqStringQuality ( NAME_STRING , " " ) < < " - " < < itemsLostText ;
2018-03-31 19:34:02 -04:00
if ( coinConsumed | | itemsLost )
2018-05-10 06:21:14 +00:00
SendText ( itemsLostText . c_str ( ) , LTT_DEFAULT ) ;
2018-04-24 02:03:00 -05:00
2018-05-31 18:00:27 +01:00
if ( std : : shared_ptr < CCorpseWeenie > pCorpse = _pendingCorpse . lock ( ) )
2018-04-24 02:03:00 -05:00
{
//make the player corpse visible.
2018-05-31 18:00:27 +01:00
pCorpse - > m_Qualities . RemoveBool ( VISIBILITY_BOOL ) ;
pCorpse - > NotifyBoolStatUpdated ( VISIBILITY_BOOL , false ) ;
pCorpse - > NotifyObjectCreated ( false ) ;
pCorpse - > Save ( ) ;
2018-06-06 18:08:32 +01:00
_pendingCorpse = std : : weak_ptr < CCorpseWeenie > ( ) ;
2018-04-24 02:03:00 -05:00
}
2018-03-29 17:01:57 -04:00
}
void CPlayerWeenie : : OnDeath ( DWORD killer_id )
{
_recallTime = - 1.0 ; // cancel any portal recalls
m_bReviveAfterAnim = true ;
CMonsterWeenie : : OnDeath ( killer_id ) ;
2018-04-08 10:04:54 -04:00
2018-03-29 17:01:57 -04:00
m_Qualities . SetFloat ( DEATH_TIMESTAMP_FLOAT , Timer : : cur_time ) ;
NotifyFloatStatUpdated ( DEATH_TIMESTAMP_FLOAT ) ;
m_Qualities . SetInt ( DEATH_LEVEL_INT , m_Qualities . GetInt ( LEVEL_INT , 1 ) ) ;
NotifyIntStatUpdated ( DEATH_LEVEL_INT , true ) ;
2018-03-29 20:32:02 -04:00
if ( ( m_Position . objcell_id & 0xFFFF ) < 0x100 ) //outdoors
{
m_Qualities . SetPosition ( LAST_OUTSIDE_DEATH_POSITION , m_Position ) ;
NotifyPositionStatUpdated ( LAST_OUTSIDE_DEATH_POSITION , true ) ;
}
2018-03-29 17:01:57 -04:00
UpdateVitaePool ( 0 ) ;
ReduceVitae ( 0.05f ) ;
UpdateVitaeEnchantment ( ) ;
if ( killer_id ! = GetID ( ) )
{
2018-05-23 13:45:22 +01:00
if ( std : : shared_ptr < CWeenieObject > pKiller = g_pWorld - > FindObject ( killer_id ) )
2018-03-29 17:01:57 -04:00
{
if ( IsPK ( ) & & pKiller - > _IsPlayer ( ) )
{
m_Qualities . SetFloat ( PK_TIMESTAMP_FLOAT , Timer : : cur_time + g_pConfig - > PKRespiteTime ( ) ) ;
m_Qualities . SetInt ( PLAYER_KILLER_STATUS_INT , PKStatusEnum : : NPK_PKStatus ) ;
NotifyIntStatUpdated ( PLAYER_KILLER_STATUS_INT , false ) ;
SendText ( " Bael'Zharon has granted you respite after your moment of weakness. You are temporarily no longer a player killer. " , LTT_MAGIC ) ;
}
}
}
// create corpse but make it invisible.
_pendingCorpse = CreateCorpse ( false ) ;
2018-05-31 18:00:27 +01:00
if ( std : : shared_ptr < CCorpseWeenie > pCorpse = _pendingCorpse . lock ( ) )
{
CalculateAndDropDeathItems ( pCorpse , killer_id ) ;
}
2018-03-29 17:01:57 -04:00
if ( g_pConfig - > HardcoreMode ( ) )
{
OnDeathAnimComplete ( ) ;
}
}
void CPlayerWeenie : : NotifyAttackDone ( int error )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0x1A7 ) ;
msg . Write < int > ( error ) ; // no error
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : NotifyCommenceAttack ( )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0x1B8 ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : OnMotionDone ( DWORD motion , BOOL success )
{
CMonsterWeenie : : OnMotionDone ( motion , success ) ;
//if (IsAttackMotion(motion) && success)
//{
// NotifyAttackDone();
// /*
// if (ShouldRepeatAttacks() && m_LastAttackTarget)
// {
// NotifyCommenceAttack();
// m_bChargingAttack = true;
// m_ChargingAttackHeight = m_LastAttackHeight;
// m_ChargingAttackTarget = m_LastAttackTarget;
// m_ChargingAttackPower = m_LastAttackPower;
// m_fChargeAttackStartTime = Timer::cur_time;
// }
// */
//}
}
2018-05-07 14:13:40 +01:00
void CPlayerWeenie : : OnRegen ( STypeAttribute2nd currentAttrib , int newAmount )
{
CMonsterWeenie : : OnRegen ( currentAttrib , newAmount ) ;
NotifyAttribute2ndStatUpdated ( currentAttrib ) ;
}
2018-03-29 17:01:57 -04:00
void CPlayerWeenie : : NotifyAttackerEvent ( const char * name , unsigned int dmgType , float healthPercent , unsigned int health , unsigned int crit , unsigned int attackConditions )
{
// when the player deals damage
BinaryWriter msg ;
msg . Write < DWORD > ( 0x1B1 ) ;
msg . WriteString ( name ) ;
msg . Write < DWORD > ( dmgType ) ;
msg . Write < double > ( healthPercent ) ;
msg . Write < DWORD > ( health ) ;
msg . Write < DWORD > ( crit ) ;
msg . Write < DWORD64 > ( attackConditions ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
2018-05-06 01:19:27 +01:00
// Update health of monster ASAP
RefreshTargetHealth ( ) ;
2018-03-29 17:01:57 -04:00
}
void CPlayerWeenie : : NotifyDefenderEvent ( const char * name , unsigned int dmgType , float healthPercent , unsigned int health , BODY_PART_ENUM hitPart , unsigned int crit , unsigned int attackConditions )
{
// when the player receives damage
BinaryWriter msg ;
msg . Write < DWORD > ( 0x1B2 ) ;
msg . WriteString ( name ) ;
msg . Write < DWORD > ( dmgType ) ;
msg . Write < double > ( healthPercent ) ;
msg . Write < DWORD > ( health ) ;
msg . Write < int > ( hitPart ) ;
msg . Write < DWORD > ( crit ) ;
msg . Write < DWORD > ( attackConditions ) ;
msg . Write < DWORD > ( 0 ) ; // probably DWORD align
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : NotifyKillerEvent ( const char * text )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0x1AD ) ;
msg . WriteString ( text ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : NotifyVictimEvent ( const char * text )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0x1AC ) ;
msg . WriteString ( text ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : NotifyUseDone ( int error )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0x1C7 ) ;
msg . Write < int > ( error ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : NotifyWeenieError ( int error )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0x28A ) ;
msg . Write < int > ( error ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : NotifyWeenieErrorWithString ( int error , const char * text )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0x28B ) ;
msg . Write < int > ( error ) ;
msg . WriteString ( text ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
void CPlayerWeenie : : NotifyInventoryFailedEvent ( DWORD object_id , int error )
{
BinaryWriter msg ;
msg . Write < DWORD > ( 0xA0 ) ;
msg . Write < DWORD > ( object_id ) ;
msg . Write < int > ( error ) ;
SendNetMessage ( & msg , PRIVATE_MSG , TRUE , FALSE ) ;
}
2018-05-23 13:45:22 +01:00
bool CPlayerWeenie : : ImmuneToDamage ( std : : shared_ptr < CWeenieObject > other )
2018-03-29 17:01:57 -04:00
{
2018-05-24 22:28:15 +01:00
if ( GetPointer < CWeenieObject > ( ) ! = other )
2018-03-29 17:01:57 -04:00
{
if ( other & & other - > AsPlayer ( ) )
{
if ( IsPK ( ) & & other - > IsPK ( ) )
{
}
else if ( IsPKLite ( ) & & other - > IsPKLite ( ) )
{
}
else
{
2018-04-08 10:04:54 -04:00
PKStatusEnum selfStatus = ( PKStatusEnum ) InqIntQuality ( PLAYER_KILLER_STATUS_INT , PKStatusEnum : : Undef_PKStatus ) ;
PKStatusEnum otherStatus = ( PKStatusEnum ) other - > InqIntQuality ( PLAYER_KILLER_STATUS_INT , PKStatusEnum : : Undef_PKStatus ) ;
2018-03-29 17:01:57 -04:00
if ( selfStatus = = PKStatusEnum : : Baelzharon_PKStatus | | otherStatus = = PKStatusEnum : : Baelzharon_PKStatus )
{
}
else
return true ;
}
}
}
return CMonsterWeenie : : ImmuneToDamage ( other ) ;
}
bool CPlayerWeenie : : IsDead ( )
{
return CMonsterWeenie : : IsDead ( ) ;
}
2018-05-23 13:45:22 +01:00
DWORD CPlayerWeenie : : OnReceiveInventoryItem ( std : : shared_ptr < CWeenieObject > source , std : : shared_ptr < CWeenieObject > item , DWORD desired_slot )
2018-03-29 17:01:57 -04:00
{
item - > ReleaseFromAnyWeenieParent ( false , true ) ;
item - > SetWieldedLocation ( INVENTORY_LOC : : NONE_LOC ) ;
item - > SetWeenieContainer ( GetID ( ) ) ;
item - > ReleaseFromBlock ( ) ;
DWORD result = Container_InsertInventoryItem ( source - > GetLandcell ( ) , item , desired_slot ) ;
if ( item - > m_Qualities . id = = W_COINSTACK_CLASS )
RecalculateCoinAmount ( ) ;
return result ;
}
/*
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : HandleKilledEvent ( std : : shared_ptr < CWeenieObject > victim , DAMAGE_TYPE damageType )
2018-03-29 17:01:57 -04:00
{
switch ( damageType )
{
case BLUDGEON_DAMAGE_TYPE :
{
switch ( Random : : GenInt ( 0 , 7 ) )
{
case 0 :
{
NotifyKillerEvent ( csprintf ( " You flatten %s's body with the force of your assault! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 1 :
{
NotifyKillerEvent ( csprintf ( " You beat %s to a lifeless pulp! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 2 :
{
NotifyKillerEvent ( csprintf ( " You smite %s mightily! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 3 :
{
NotifyKillerEvent ( csprintf ( " You knock %s into next Morningthaw! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 4 :
{
NotifyKillerEvent ( csprintf ( " %s is utterly destroyed by your attack! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 5 :
{
NotifyKillerEvent ( csprintf ( " %s catches your attack, with dire consequences! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 6 :
{
NotifyKillerEvent ( csprintf ( " The deadly force of your attack is so strong that %s's ancestors feel it! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 7 :
{
NotifyKillerEvent ( csprintf ( " The thunder of crushing %s is followed by the deafening silence of death! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
}
}
}
}
*/
/*
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : NotifyVictimEvent ( std : : shared_ptr < CWeenieObject > killer , DAMAGE_TYPE damageType )
2018-03-29 17:01:57 -04:00
{
}
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : OnDealtDamage ( std : : shared_ptr < CWeenieObject > attacker , DAMAGE_TYPE damageType , unsigned int damage )
2018-03-29 17:01:57 -04:00
{
if ( ! pTarget - > IsDead ( ) )
{
NotifyAttackerEvent ( pTarget - > GetName ( ) . c_str ( ) , 4 , damageDone / ( double ) ( pTarget - > GetMaxHealth ( ) ) , damageDone , 0 , 0 ) ;
}
else
{
switch ( Random : : GenInt ( 0 , 7 ) )
{
case 0 :
{
NotifyKillerEvent ( csprintf ( " You flatten %s's body with the force of your assault! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 1 :
{
NotifyKillerEvent ( csprintf ( " You beat %s to a lifeless pulp! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 2 :
{
NotifyKillerEvent ( csprintf ( " You smite %s mightily! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 3 :
{
NotifyKillerEvent ( csprintf ( " You knock %s into next Morningthaw! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 4 :
{
NotifyKillerEvent ( csprintf ( " %s is utterly destroyed by your attack! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 5 :
{
NotifyKillerEvent ( csprintf ( " %s catches your attack, with dire consequences! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 6 :
{
NotifyKillerEvent ( csprintf ( " The deadly force of your attack is so strong that %s's ancestors feel it! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
case 7 :
{
NotifyKillerEvent ( csprintf ( " The thunder of crushing %s is followed by the deafening silence of death! " , pTarget - > GetName ( ) . c_str ( ) ) ) ;
break ;
}
}
}
}
*/
void CPlayerWeenie : : PreSpawnCreate ( )
{
}
2018-05-23 13:45:22 +01:00
struct CompareManaNeeds //: public std::binary_function<std::shared_ptr<CWeenieObject>, std::shared_ptr<CWeenieObject>, bool>
2018-04-26 02:37:29 +00:00
{
2018-05-23 13:45:22 +01:00
bool operator ( ) ( std : : shared_ptr < CWeenieObject > left , std : : shared_ptr < CWeenieObject > right )
2018-04-26 02:37:29 +00:00
{
// comparator for making a min-heap based on remaining mana
return ( ( left - > InqIntQuality ( ITEM_MAX_MANA_INT , 0 , TRUE ) - left - > InqIntQuality ( ITEM_CUR_MANA_INT , - 1 , TRUE ) )
> ( right - > InqIntQuality ( ITEM_MAX_MANA_INT , 0 , TRUE ) - right - > InqIntQuality ( ITEM_CUR_MANA_INT , - 1 , TRUE ) ) ) ;
}
} ;
2018-05-23 13:45:22 +01:00
int CPlayerWeenie : : UseEx ( std : : shared_ptr < CWeenieObject > pTool , std : : shared_ptr < CWeenieObject > pTarget )
2018-03-29 17:01:57 -04:00
{
2018-05-06 18:30:12 +01:00
// Save these for later as we may have to send a confirmation
m_pCraftingTool = pTool ;
m_pCraftingTarget = pTarget ;
return UseEx ( false ) ;
}
int CPlayerWeenie : : UseEx ( bool bConfirmed )
{
// Load the saved crafting targets
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pTool = m_pCraftingTool . lock ( ) ;
std : : shared_ptr < CWeenieObject > pTarget = m_pCraftingTarget . lock ( ) ;
2018-05-06 18:30:12 +01:00
2018-05-31 18:00:27 +01:00
if ( ! pTool | | ! pTarget )
2018-05-06 18:30:12 +01:00
{
// no queued crafting op
return WERROR_NONE ;
}
2018-03-29 17:01:57 -04:00
int toolType = pTool - > InqIntQuality ( ITEM_TYPE_INT , 0 ) ;
switch ( toolType )
{
case TYPE_MANASTONE :
{
2018-04-25 19:28:00 -07:00
// TODO: move this logic to ManaStone.cpp
2018-03-29 17:01:57 -04:00
int targetType = pTarget - > InqIntQuality ( ITEM_TYPE_INT , 0 ) ;
2018-04-26 02:37:29 +00:00
if ( ! ( targetType & TYPE_ITEM ) & & ! ( targetType & TYPE_CREATURE ) ) {
2018-03-29 17:01:57 -04:00
SendText ( csprintf ( " That's not a valid target for the %s " , pTool - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
break ;
}
int manaStoneCurrentMana = pTool - > InqIntQuality ( ITEM_CUR_MANA_INT , - 1 , TRUE ) ;
double manaStoneDestroyChance = pTool - > InqFloatQuality ( MANA_STONE_DESTROY_CHANCE_FLOAT , - 1 , TRUE ) ;
double manaStoneEfficiency = pTool - > InqFloatQuality ( ITEM_EFFICIENCY_FLOAT , - 1 , TRUE ) ;
int targetCurrentMana = pTarget - > InqIntQuality ( ITEM_CUR_MANA_INT , - 1 , TRUE ) ;
int targetMaxMana = pTarget - > InqIntQuality ( ITEM_MAX_MANA_INT , - 1 , TRUE ) ;
2018-04-26 02:37:29 +00:00
if ( manaStoneCurrentMana < = 0 ) {
if ( targetType & TYPE_CREATURE ) {
//player attempting to use an uncharged mana stone on themselves...what do we do
SendText ( " Despite your best efforts, you fail to destroy yourself. " , LTT_DEFAULT ) ; // TODO: better text
break ;
}
2018-05-02 15:42:03 -07:00
if ( targetCurrentMana < = 0 ) {
2018-03-29 17:01:57 -04:00
SendText ( csprintf ( " The %s has no mana to drain. " , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
break ;
}
2018-04-26 02:37:29 +00:00
if ( ! pTarget - > InqBoolQuality ( RETAINED_BOOL , FALSE ) ) {
int drainedMana = round ( targetCurrentMana * manaStoneEfficiency ) ;
pTool - > m_Qualities . SetInt ( ITEM_CUR_MANA_INT , drainedMana ) ;
pTool - > m_Qualities . SetInt ( UI_EFFECTS_INT , 1 ) ;
pTool - > NotifyIntStatUpdated ( ITEM_CUR_MANA_INT , false ) ;
pTool - > NotifyIntStatUpdated ( UI_EFFECTS_INT , false ) ;
pTarget - > Remove ( ) ;
RecalculateEncumbrance ( ) ;
// The Mana Stone drains 4,434 points of mana from the Pocket Watch.
// The Pocket Watch is destroyed.
SendText ( csprintf ( " The %s drains %s points of mana from the %s. \n The %s is destroyed. " , pTool - > GetName ( ) . c_str ( ) , FormatNumberString ( drainedMana ) . c_str ( ) , pTarget - > GetName ( ) . c_str ( ) , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
}
else {
SendText ( " Retained items can't be drained. " , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
break ;
}
}
else { // mana stone is being emptied, not filled
int remainingMana ;
if ( targetType & TYPE_CREATURE ) { // manastone being emptied into the user
if ( pTarget - > id ! = id ) {
// somehow not using on self. shouldn't be possible with the client. Made up message.
SendText ( csprintf ( " You cannot use the %s on other creatures or players. " , pTool - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
break ;
2018-03-29 17:01:57 -04:00
}
2018-05-23 13:45:22 +01:00
priority_queue < std : : shared_ptr < CWeenieObject > , vector < std : : shared_ptr < CWeenieObject > > , CompareManaNeeds > itemsNeedingMana , itemsStillNeedingMana ; // MIN heaps sorted by mana deficit
2018-04-26 02:37:29 +00:00
for ( auto wielded : m_Wielded )
2018-03-29 17:01:57 -04:00
{
2018-06-21 23:32:21 +01:00
std : : shared_ptr < CWeenieObject > pItem = wielded . lock ( ) ;
if ( ! pItem )
{
continue ;
}
int curMana = pItem - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 , TRUE ) ;
int maxMana = pItem - > InqIntQuality ( ITEM_MAX_MANA_INT , 0 , TRUE ) ;
2018-05-02 15:42:03 -07:00
int deficit = maxMana - curMana ;
2018-04-26 02:37:29 +00:00
if ( deficit > 0 ) {
2018-06-21 23:32:21 +01:00
itemsNeedingMana . push ( pItem ) ;
2018-04-26 02:37:29 +00:00
}
}
if ( itemsNeedingMana . empty ( ) ) {
SendText ( " None of your items need mana " , LTT_DEFAULT ) ; // What's the correct text?
2018-03-29 17:01:57 -04:00
break ;
}
2018-04-26 02:37:29 +00:00
int manaToDistribute = manaStoneCurrentMana ;
int manaDistributed = 0 ;
2018-05-23 13:45:22 +01:00
std : : set < std : : shared_ptr < CWeenieObject > > objectsReceivingMana ; // for the chatmessage at the end
2018-04-26 02:37:29 +00:00
while ( manaToDistribute > 0 & & ! ( itemsNeedingMana . empty ( ) ) ) {
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > itemNeedingLeastMana = itemsNeedingMana . top ( ) ;
2018-04-26 02:37:29 +00:00
int deficit = itemNeedingLeastMana - > InqIntQuality ( ITEM_MAX_MANA_INT , 0 , TRUE ) - itemNeedingLeastMana - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 , TRUE ) ;
2018-05-02 15:42:03 -07:00
unsigned int manaToApplyToEach = 0 ;
2018-04-26 02:37:29 +00:00
2018-04-30 22:39:01 -07:00
try
{
if ( deficit * itemsNeedingMana . size ( ) > = manaToDistribute ) {
2018-05-02 15:42:03 -07:00
// applying smallest deficit to all items would require more mana than available for distribution
2018-05-31 18:00:27 +01:00
manaToApplyToEach = manaToDistribute / static_cast < unsigned int > ( itemsNeedingMana . size ( ) ) ;
2018-04-30 22:39:01 -07:00
}
else {
manaToApplyToEach = deficit ;
}
2018-04-26 02:37:29 +00:00
}
2018-04-30 22:39:01 -07:00
catch ( . . . )
{
SERVER_ERROR < < " Error in UseEx for mana stones " ;
2018-04-26 02:37:29 +00:00
}
2018-03-29 17:01:57 -04:00
2018-05-02 15:42:03 -07:00
manaToApplyToEach = max ( 1 , manaToApplyToEach ) ; // for when manaToDistribute / itemsNeedingMana rounds down to 0, apply 1 mana until we're out
2018-04-26 02:37:29 +00:00
while ( ! itemsNeedingMana . empty ( ) ) {
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > item = itemsNeedingMana . top ( ) ;
2018-04-26 02:37:29 +00:00
int itemMaxMana = item - > InqIntQuality ( ITEM_MAX_MANA_INT , 0 , TRUE ) ;
itemsNeedingMana . pop ( ) ;
2018-05-02 15:42:03 -07:00
if ( manaToDistribute < = 0 ) {
// from when we rounded up manaToApplyToEach from 0 to 1, once we're out of mana we want to finish this while loop without applying any more mana to items
itemsStillNeedingMana . push ( item ) ;
continue ;
}
2018-04-26 02:37:29 +00:00
2018-05-02 15:42:03 -07:00
unsigned int newManaAmount = item - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 , TRUE ) + manaToApplyToEach ;
2018-04-26 02:37:29 +00:00
manaToDistribute - = manaToApplyToEach ;
manaDistributed + = manaToApplyToEach ;
if ( newManaAmount < itemMaxMana ) {
itemsStillNeedingMana . push ( item ) ;
}
if ( manaToApplyToEach > 0 ) { // handle case when you use a stone that doesn't even have enough mana to give 1 to each deficit item
objectsReceivingMana . insert ( item ) ;
}
2018-05-02 15:42:03 -07:00
item - > m_Qualities . SetInt ( ITEM_CUR_MANA_INT , min ( newManaAmount , itemMaxMana ) ) ;
2018-04-26 02:37:29 +00:00
item - > NotifyIntStatUpdated ( ITEM_CUR_MANA_INT , false ) ; // todo: is second positional arg correct?
}
2018-03-29 17:01:57 -04:00
2018-04-26 02:37:29 +00:00
itemsNeedingMana . swap ( itemsStillNeedingMana ) ;
}
remainingMana = manaToDistribute ;
std : : stringstream ss ;
ss < < csprintf ( " The %s gives %s points of mana to the following items: " , pTool - > GetName ( ) . c_str ( ) , FormatNumberString ( manaDistributed ) . c_str ( ) ) ;
2018-05-23 13:45:22 +01:00
std : : set < std : : shared_ptr < CWeenieObject > > : : iterator it = objectsReceivingMana . begin ( ) ;
2018-04-26 02:37:29 +00:00
while ( it ! = objectsReceivingMana . end ( ) ) {
if ( it ! = objectsReceivingMana . begin ( ) ) {
ss < < " , " ;
2018-04-26 17:00:08 +00:00
}
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > item = * it ;
2018-04-26 17:00:08 +00:00
ss < < item - > GetName ( ) ;
it + + ;
2018-04-26 02:37:29 +00:00
}
SendText ( ss . str ( ) . c_str ( ) , LTT_DEFAULT ) ;
int remainingDeficit = 0 ;
while ( ! itemsNeedingMana . empty ( ) ) {
remainingDeficit + = ( itemsNeedingMana . top ( ) - > InqIntQuality ( ITEM_MAX_MANA_INT , 0 , TRUE ) - itemsNeedingMana . top ( ) - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 , TRUE ) ) ;
itemsNeedingMana . pop ( ) ;
}
if ( remainingDeficit = = 0 ) {
SendText ( " Your items are fully charged. " , LTT_DEFAULT ) ;
}
else {
SendText ( csprintf ( " You need %s more mana to fully charge your items. " , FormatNumberString ( remainingDeficit ) . c_str ( ) ) , LTT_DEFAULT ) ;
}
2018-03-29 17:01:57 -04:00
}
2018-04-26 02:37:29 +00:00
else { // manastone being emptied into an item
2018-03-29 17:01:57 -04:00
2018-04-26 02:37:29 +00:00
if ( targetMaxMana < = 0 )
2018-03-29 17:01:57 -04:00
{
2018-04-26 02:37:29 +00:00
SendText ( csprintf ( " The %s does not require mana. " , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
break ;
2018-03-29 17:01:57 -04:00
}
2018-04-26 02:37:29 +00:00
else if ( targetCurrentMana > = targetMaxMana )
2018-04-25 16:58:31 -07:00
{
2018-04-26 02:37:29 +00:00
SendText ( csprintf ( " The %s is already fully charged. " , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
break ;
2018-04-26 01:49:12 +00:00
}
else
{
2018-04-26 02:37:29 +00:00
int manaNeeded = targetMaxMana - targetCurrentMana ;
if ( manaStoneCurrentMana > = manaNeeded )
{
pTarget - > m_Qualities . SetInt ( ITEM_CUR_MANA_INT , targetMaxMana ) ;
pTarget - > NotifyIntStatUpdated ( ITEM_CUR_MANA_INT , false ) ;
2018-04-26 01:49:12 +00:00
2018-04-26 02:37:29 +00:00
remainingMana = manaStoneCurrentMana - manaNeeded ;
SendText ( csprintf ( " The %s gives %s mana to the %s. " , pTool - > GetName ( ) . c_str ( ) , FormatNumberString ( manaNeeded ) . c_str ( ) , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
SendText ( csprintf ( " The %s is fully charged. " , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
}
else
2018-04-26 01:49:12 +00:00
{
2018-04-26 02:37:29 +00:00
int newManaAmount = targetCurrentMana + manaStoneCurrentMana ;
int manaStillNeeded = targetMaxMana - newManaAmount ;
remainingMana = 0 ;
pTarget - > m_Qualities . SetInt ( ITEM_CUR_MANA_INT , newManaAmount ) ;
pTarget - > NotifyIntStatUpdated ( ITEM_CUR_MANA_INT , false ) ;
SendText ( csprintf ( " The %s gives %s mana to the %s. " , pTool - > GetName ( ) . c_str ( ) , FormatNumberString ( manaStoneCurrentMana ) . c_str ( ) , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
SendText ( csprintf ( " You need %s more mana to fully charge the %s. " , FormatNumberString ( manaStillNeeded ) . c_str ( ) , pTarget - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ; //todo: made up message, confirm if it's correct
2018-04-26 01:49:12 +00:00
}
2018-04-25 16:58:31 -07:00
}
}
2018-04-26 02:37:29 +00:00
if ( manaStoneDestroyChance > = 1.0 | | Random : : RollDice ( 0.0 , 1.0 ) < = manaStoneDestroyChance ) {
SendText ( csprintf ( " The %s is destroyed. " , pTool - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
pTool - > Remove ( ) ;
RecalculateEncumbrance ( ) ;
}
else {
pTool - > m_Qualities . SetInt ( ITEM_CUR_MANA_INT , remainingMana ) ;
pTool - > NotifyIntStatUpdated ( ITEM_CUR_MANA_INT , false ) ;
if ( remainingMana = = 0 )
{
pTool - > m_Qualities . SetInt ( UI_EFFECTS_INT , 0 ) ;
pTool - > NotifyIntStatUpdated ( UI_EFFECTS_INT , false ) ;
}
}
2018-03-29 17:01:57 -04:00
}
2018-04-26 02:37:29 +00:00
2018-03-29 17:01:57 -04:00
break ;
}
default :
{
CCraftOperation * op = g_pPortalDataEx - > GetCraftOperation ( pTool - > m_Qualities . id , pTarget - > m_Qualities . id ) ;
if ( ! op )
{
//Try inversing the combination.
op = g_pPortalDataEx - > GetCraftOperation ( pTarget - > m_Qualities . id , pTool - > m_Qualities . id ) ;
if ( ! op )
return WERROR_NONE ;
//swap things around
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > swapHelper = pTool ;
2018-03-29 17:01:57 -04:00
pTool = pTarget ;
pTarget = swapHelper ;
}
2018-04-08 10:04:54 -04:00
if ( pTool - > IsWielded ( ) | | pTarget - > IsWielded ( ) )
2018-03-29 17:01:57 -04:00
return WERROR_CRAFT_ALL_OBJECTS_NOT_FROZEN ;
if ( get_minterp ( ) - > interpreted_state . current_style ! = Motion_NonCombat )
return WERROR_CRAFT_NOT_IN_PEACE_MODE ;
//if (GetWielded(WEAPON_LOC) != NULL || GetWielded(SHIELD_LOC) != NULL)
// return WERROR_HANDS_NOT_FREE;
int requiredHealth = 0 ;
int requiredStamina = 0 ;
int requiredMana = 0 ;
for ( int i = 0 ; i < 4 ; i + + )
{
if ( op - > _mods [ i ] . _RequiresHealth )
requiredHealth + = - op - > _mods [ i ] . _ModifyHealth ;
if ( op - > _mods [ i ] . _RequiresStamina )
requiredStamina + = - op - > _mods [ i ] . _ModifyStamina ;
if ( op - > _mods [ i ] . _RequiresMana )
requiredMana + = - op - > _mods [ i ] . _ModifyMana ;
}
if ( GetHealth ( ) < requiredHealth )
{
SendText ( " You don't have enough health to do that. " , LTT_CRAFT ) ;
return WERROR_CRAFT_FAILED_REQUIREMENTS ;
}
if ( requiredStamina ! = 0 )
{
if ( GetStamina ( ) < requiredStamina )
{
//SendText("You don't have enough stamina to do that.", LTT_CRAFT);
return WERROR_STAMINA_TOO_LOW ;
}
}
else if ( GetStamina ( ) < 5 ) //I can't find a source but I'm pretty sure use actions always consumed some amount of stamina.
{
//SendText("You don't have enough stamina to do that.", LTT_CRAFT);
return WERROR_STAMINA_TOO_LOW ;
}
if ( GetMana ( ) < requiredMana )
{
//SendText("You don't have enough mana to do that.", LTT_CRAFT);
return WERROR_MAGIC_INSUFFICIENT_MANA ;
}
//unk: always 0
//op->_mod unknown7 - known values: true, false - true on dying items? = Recalculate Icon?
//op->_mod unknown9 - known values: 1 in stamping failures, attaching fetish of the dark idol
//op->_mod unknown10 - always 0
if ( ! CheckUseRequirements ( 0 , op , pTool , pTarget ) )
return WERROR_CRAFT_FAILED_REQUIREMENTS ;
if ( ! CheckUseRequirements ( 1 , op , pTool , pTarget ) )
return WERROR_CRAFT_FAILED_REQUIREMENTS ;
if ( ! CheckUseRequirements ( 2 , op , pTool , pTarget ) )
return WERROR_CRAFT_FAILED_REQUIREMENTS ;
int targetStackSize = pTarget - > GetStackOrStructureNum ( ) ;
int toolStackSize = pTool - > GetStackOrStructureNum ( ) ;
if ( targetStackSize < op - > _successConsumeTargetAmount | | toolStackSize < op - > _successConsumeToolAmount | |
targetStackSize < op - > _failureConsumeTargetAmount | | toolStackSize < op - > _failureConsumeToolAmount )
return WERROR_CRAFT_DONT_CONTAIN_EVERYTHING ;
DWORD skillLevel = 0 ;
if ( op - > _skill ! = 0 )
{
SKILL_ADVANCEMENT_CLASS sac ;
m_Qualities . InqSkillAdvancementClass ( ( STypeSkill ) op - > _skill , sac ) ;
if ( sac < TRAINED_SKILL_ADVANCEMENT_CLASS )
return WERROR_CRAFT_NOT_HAVE_SKILL ;
2018-04-21 18:22:52 -05:00
InqSkill ( op - > _skill , skillLevel , FALSE ) ;
2018-03-29 17:01:57 -04:00
}
2018-05-06 18:30:12 +01:00
double successChance ;
2018-03-29 17:01:57 -04:00
switch ( op - > _SkillCheckFormulaType )
{
case 0 :
if ( skillLevel = = 0 )
2018-05-06 18:30:12 +01:00
{
// success = true
successChance = 1.0 ;
}
2018-03-29 17:01:57 -04:00
else
2018-05-06 18:30:12 +01:00
{
successChance = GetSkillChance ( skillLevel , op - > _difficulty ) ;
}
2018-03-29 17:01:57 -04:00
break ;
case 1 : //tinkers
2018-05-06 18:30:12 +01:00
case 2 : //imbues
2018-03-29 17:01:57 -04:00
{
double toolWorkmanship = pTool - > InqIntQuality ( ITEM_WORKMANSHIP_INT , 0 ) ;
2018-04-14 14:02:33 -05:00
double itemWorkmanship = pTarget - > InqIntQuality ( ITEM_WORKMANSHIP_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
if ( pTool - > InqIntQuality ( ITEM_TYPE_INT , 0 ) = = ITEM_TYPE : : TYPE_TINKERING_MATERIAL )
toolWorkmanship / = ( double ) pTool - > InqIntQuality ( NUM_ITEMS_IN_MATERIAL_INT , 1 ) ;
int amountOfTimesTinkered = pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 ) ;
2018-05-06 18:30:12 +01:00
2018-05-16 23:47:32 +00:00
if ( amountOfTimesTinkered > 9 ) // Don't allow 10 tinked items to have any more tinkers/imbues (Ivory & Leather don't use this case)
{
return WERROR_NONE ;
}
2018-05-06 18:30:12 +01:00
int salvageMod ;
if ( op - > _SkillCheckFormulaType = = 1 )
{
salvageMod = GetMaterialMod ( pTool - > InqIntQuality ( MATERIAL_TYPE_INT , 0 ) ) ;
}
else
{
2018-05-16 23:47:32 +00:00
salvageMod = 20 ; // All imbue materials have mod of 20
2018-05-06 18:30:12 +01:00
}
2018-05-02 21:12:01 -07:00
2018-04-14 14:02:33 -05:00
int multiple = 1 ;
2018-05-16 23:47:32 +00:00
double aDifficulty [ 10 ] = { 1 , 1.1 , 1.3 , 1.6 , 2.0 , 2.5 , 3.0 , 3.5 , 4.0 , 4.5 } ; // Attempt difficulty numbers from Endy's Tinker Calc 2.3.2
double difficulty = aDifficulty [ amountOfTimesTinkered ] ;
2018-03-29 17:01:57 -04:00
2018-04-24 21:07:20 -04:00
if ( toolWorkmanship > = itemWorkmanship )
{
multiple = 2 ;
}
2018-05-06 18:30:12 +01:00
successChance = GetSkillChance ( skillLevel , ( ( int ) floor ( ( ( 5 * salvageMod ) + ( 2 * itemWorkmanship * salvageMod ) - ( toolWorkmanship * multiple * salvageMod / 5 ) ) * difficulty ) ) ) ; //Formulas from Endy's Tinkering Calculator
2018-04-25 23:07:52 -05:00
2018-05-06 18:30:12 +01:00
if ( op - > _SkillCheckFormulaType = = 2 ) // imbue
{
successChance / = 3 ;
2018-04-25 23:07:52 -05:00
}
2018-05-06 18:30:12 +01:00
break ;
}
default :
SendText ( csprintf ( " Unsupported skill check formula type: %u. " , op - > _SkillCheckFormulaType ) , LTT_CRAFT ) ;
return WERROR_CRAFT_DONT_CONTAIN_EVERYTHING ;
}
2018-04-25 23:07:52 -05:00
2018-05-06 18:36:41 +01:00
// 0x80000000 : Use Crafting Chance of Success Dialog
if ( _playerModule . options_ & 0x80000000 & & ! bConfirmed )
2018-05-06 18:30:12 +01:00
{
std : : ostringstream sstrMessage ;
sstrMessage . precision ( 3 ) ;
sstrMessage < < " You have a " < < successChance * 100 < < " % chance of using " < < pTool - > GetName ( ) < < " on " < < pTarget - > GetName ( ) < < " . " ;
2018-04-25 23:07:52 -05:00
2018-05-02 21:12:01 -07:00
2018-05-06 18:30:12 +01:00
BinaryWriter confirmCrafting ;
confirmCrafting . Write < DWORD > ( 0x274 ) ; // Message Type
confirmCrafting . Write < DWORD > ( 0x05 ) ; // Confirm type (craft)
confirmCrafting . Write < int > ( 0 ) ; // Sequence number??
confirmCrafting . WriteString ( sstrMessage . str ( ) ) ;
2018-05-02 21:12:01 -07:00
2018-05-06 18:30:12 +01:00
SendNetMessage ( & confirmCrafting , PRIVATE_MSG , TRUE , FALSE ) ;
return WERROR_NONE ;
2018-03-29 17:01:57 -04:00
}
2018-05-06 18:30:12 +01:00
double successRoll = Random : : RollDice ( 0.0 , 1.0 ) ;
2018-04-14 14:02:33 -05:00
2018-05-06 18:30:12 +01:00
if ( successRoll < = successChance )
{
// Results!
// Create item(s)
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > newItem = g_pWeenieFactory - > CreateWeenieByClassID ( op - > _successWcid , NULL , false ) ;
2018-05-06 18:30:12 +01:00
if ( op - > _successAmount > 1 )
newItem - > SetStackSize ( op - > _successAmount ) ;
// if we can't put the item in inventory
if ( op - > _successWcid ! = 0 & & ! SpawnInContainer ( newItem , op - > _successAmount ) )
2018-04-14 14:02:33 -05:00
{
2018-05-06 18:30:12 +01:00
SendText ( " Unable to create result! " , LTT_ERROR ) ;
// Return before we delete the tool/target
// TODO: is this to do with pack space? should check before the roll if so
return WERROR_NONE ;
2018-04-14 14:02:33 -05:00
}
2018-05-06 18:40:25 +01:00
SendText ( op - > _successMessage . c_str ( ) , LTT_CRAFT ) ;
2018-05-06 18:30:12 +01:00
// Broadcast messages for tinkering
switch ( op - > _SkillCheckFormulaType )
2018-04-14 14:02:33 -05:00
{
2018-05-06 18:30:12 +01:00
case 1 : //tinkers
case 2 : //imbues
{
double toolWorkmanship = pTool - > InqIntQuality ( ITEM_WORKMANSHIP_INT , 0 ) ;
double itemWorkmanship = pTarget - > InqIntQuality ( ITEM_WORKMANSHIP_INT , 0 ) ;
if ( pTool - > InqIntQuality ( ITEM_TYPE_INT , 0 ) = = ITEM_TYPE : : TYPE_TINKERING_MATERIAL )
toolWorkmanship / = ( double ) pTool - > InqIntQuality ( NUM_ITEMS_IN_MATERIAL_INT , 1 ) ;
int amountOfTimesTinkered = pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
2018-04-26 17:00:08 +00:00
std : : string text = csprintf ( " %s successfully applies the %s (workmanship %.2f) to the %s. " , GetName ( ) . c_str ( ) , pTool - > GetName ( ) . c_str ( ) , toolWorkmanship , pTarget - > GetName ( ) . c_str ( ) ) ;
if ( ! text . empty ( ) )
{
g_pWorld - > BroadcastLocal ( GetLandcell ( ) , text ) ;
2018-04-25 23:07:52 -05:00
}
2018-03-29 17:01:57 -04:00
2018-05-06 18:30:12 +01:00
IMBUE_LOG < < " P: " < < InqStringQuality ( NAME_STRING , " " ) < < " SL: " < < skillLevel < < " T: " < < pTarget - > InqStringQuality ( NAME_STRING , " " ) < < " TW: " < < itemWorkmanship < < " TT: " < < amountOfTimesTinkered < <
" M: " < < pTool - > InqStringQuality ( NAME_STRING , " " ) < < " MW: " < < toolWorkmanship < < " %: " < < successChance < < " Roll: " < < successRoll < < " S/F: " < < ( successChance ? " TRUE " : " FALSE " ) ;
2018-03-29 17:01:57 -04:00
2018-05-06 18:30:12 +01:00
break ;
}
}
2018-03-29 17:01:57 -04:00
PerformUseModifications ( 0 , op , pTool , pTarget , newItem ) ;
PerformUseModifications ( 1 , op , pTool , pTarget , newItem ) ;
PerformUseModifications ( 2 , op , pTool , pTarget , newItem ) ;
PerformUseModifications ( 3 , op , pTool , pTarget , newItem ) ;
if ( requiredStamina = = 0 )
AdjustStamina ( - 5 ) ; //if we don't have any stamina usage specified let's use 5.
if ( op - > _successConsumeTargetChance = = 1.0 | | Random : : RollDice ( 0.0 , 1.0 ) < = op - > _successConsumeTargetChance )
{
pTarget - > DecrementStackNum ( op - > _successConsumeTargetAmount ) ;
if ( ! op - > _successConsumeTargetMessage . empty ( ) )
SendText ( op - > _successConsumeTargetMessage . c_str ( ) , LTT_CRAFT ) ;
}
if ( op - > _successConsumeToolChance = = 1.0 | | Random : : RollDice ( 0.0 , 1.0 ) < = op - > _successConsumeToolChance )
{
pTool - > DecrementStackNum ( op - > _successConsumeToolAmount ) ;
if ( ! op - > _successConsumeToolMessage . empty ( ) )
SendText ( op - > _successConsumeToolMessage . c_str ( ) , LTT_CRAFT ) ;
}
}
2018-05-06 18:30:12 +01:00
else // Not successful
2018-03-29 17:01:57 -04:00
{
2018-05-06 18:30:12 +01:00
// Results!
// Create item(s)
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > newItem = g_pWeenieFactory - > CreateWeenieByClassID ( op - > _failWcid , NULL , false ) ;
2018-05-06 18:30:12 +01:00
if ( op - > _failAmount > 1 )
newItem - > SetStackSize ( op - > _failAmount ) ;
// if we can't put the item in inventory
if ( op - > _failWcid ! = 0 & & ! SpawnInContainer ( newItem , op - > _failAmount ) )
{
SendText ( " Unable to create result! " , LTT_ERROR ) ;
// Return before we delete the tool/target
// TODO: is this to do with pack space? should check before the roll if so
return WERROR_NONE ;
}
2018-05-06 18:40:25 +01:00
SendText ( op - > _failMessage . c_str ( ) , LTT_CRAFT ) ;
// Broadcast messages for tinkering
2018-05-06 18:30:12 +01:00
switch ( op - > _SkillCheckFormulaType )
{
case 1 : //tinkers
case 2 : //imbues
{
double toolWorkmanship = pTool - > InqIntQuality ( ITEM_WORKMANSHIP_INT , 0 ) ;
double itemWorkmanship = pTarget - > InqIntQuality ( ITEM_WORKMANSHIP_INT , 0 ) ;
if ( pTool - > InqIntQuality ( ITEM_TYPE_INT , 0 ) = = ITEM_TYPE : : TYPE_TINKERING_MATERIAL )
toolWorkmanship / = ( double ) pTool - > InqIntQuality ( NUM_ITEMS_IN_MATERIAL_INT , 1 ) ;
int amountOfTimesTinkered = pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 ) ;
std : : string text = csprintf ( " %s fails to apply the %s (workmanship %.2f) to the %s. The target is destroyed. " , GetName ( ) . c_str ( ) , pTool - > GetName ( ) . c_str ( ) , toolWorkmanship , pTarget - > GetName ( ) . c_str ( ) ) ;
if ( ! text . empty ( ) )
{
g_pWorld - > BroadcastLocal ( GetLandcell ( ) , text ) ;
}
IMBUE_LOG < < " P: " < < InqStringQuality ( NAME_STRING , " " ) < < " SL: " < < skillLevel < < " T: " < < pTarget - > InqStringQuality ( NAME_STRING , " " ) < < " TW: " < < itemWorkmanship < < " TT: " < < amountOfTimesTinkered < <
" M: " < < pTool - > InqStringQuality ( NAME_STRING , " " ) < < " MW: " < < toolWorkmanship < < " %: " < < successChance < < " Roll: " < < successRoll < < " S/F: " < < ( successChance ? " TRUE " : " FALSE " ) ;
break ;
}
}
2018-03-29 17:01:57 -04:00
PerformUseModifications ( 4 , op , pTool , pTarget , newItem ) ;
PerformUseModifications ( 5 , op , pTool , pTarget , newItem ) ;
PerformUseModifications ( 6 , op , pTool , pTarget , newItem ) ;
PerformUseModifications ( 7 , op , pTool , pTarget , newItem ) ;
if ( requiredStamina = = 0 )
AdjustStamina ( - 5 ) ; //if we don't have any stamina usage specified let's use 5.
if ( op - > _failureConsumeTargetChance = = 1.0 | | Random : : RollDice ( 0.0 , 1.0 ) < = op - > _failureConsumeTargetChance )
{
pTarget - > DecrementStackNum ( op - > _failureConsumeTargetAmount ) ;
if ( ! op - > _failureConsumeTargetMessage . empty ( ) )
SendText ( op - > _failureConsumeTargetMessage . c_str ( ) , LTT_CRAFT ) ;
}
if ( op - > _failureConsumeToolChance = = 1.0 | | Random : : RollDice ( 0.0 , 1.0 ) < = op - > _failureConsumeToolChance )
{
pTool - > DecrementStackNum ( op - > _failureConsumeToolAmount ) ;
if ( ! op - > _failureConsumeToolMessage . empty ( ) )
SendText ( op - > _failureConsumeToolMessage . c_str ( ) , LTT_CRAFT ) ;
}
2018-05-05 21:14:26 +01:00
// Your craft attempt fails.
NotifyWeenieError ( 0x432 ) ;
2018-03-29 17:01:57 -04:00
}
2018-05-06 18:40:25 +01:00
// We don't need these anymore
2018-06-06 18:08:32 +01:00
m_pCraftingTool = std : : weak_ptr < CWeenieObject > ( ) ;
m_pCraftingTarget = std : : weak_ptr < CWeenieObject > ( ) ;
2018-05-06 18:40:25 +01:00
2018-03-29 17:01:57 -04:00
RecalculateEncumbrance ( ) ;
break ;
}
}
return WERROR_NONE ;
}
2018-05-05 09:12:22 -07:00
int CPlayerWeenie : : GetMaterialMod ( int materialInt )
2018-05-02 21:12:01 -07:00
{
2018-05-05 09:12:22 -07:00
switch ( materialInt )
{
case Gold_MaterialType :
case Oak_MaterialType :
{
2018-05-02 21:12:01 -07:00
return 10 ;
2018-05-05 09:12:22 -07:00
}
case Ebony_MaterialType :
case Teak_MaterialType :
case Steel_MaterialType :
case Satin_MaterialType :
case Porcelain_MaterialType :
case Mahogany_MaterialType :
case Iron_MaterialType :
case Green_Garnet_MaterialType :
{
2018-05-02 21:12:01 -07:00
return 12 ;
2018-05-05 09:12:22 -07:00
}
case Alabaster_MaterialType :
case Brass_MaterialType :
case Armoredillo_Hide_MaterialType :
case Wool_MaterialType :
case Velvet_MaterialType :
case Reed_Shark_Hide_MaterialType :
case Pine_MaterialType :
case Opal_MaterialType :
case Marble_MaterialType :
case Linen_MaterialType :
case Granite_MaterialType :
case Ceramic_MaterialType :
case Bronze_MaterialType :
case Moonstone_MaterialType :
{
2018-05-02 21:12:01 -07:00
return 11 ;
2018-05-05 09:12:22 -07:00
}
case Bloodstone_MaterialType :
case Rose_Quartz_MaterialType :
case Red_Jade_MaterialType :
case Malachite_MaterialType :
case Lavender_Jade_MaterialType :
case Hematite_MaterialType :
case Citrine_MaterialType :
case Carnelian_MaterialType :
{
2018-05-02 21:12:01 -07:00
return 25 ;
2018-05-05 09:12:22 -07:00
}
default :
return 20 ; // Imbue material
}
2018-05-02 21:12:01 -07:00
}
2018-05-02 21:54:52 -07:00
std : : string CPlayerWeenie : : ToUpperCase ( string tName )
2018-05-02 21:12:01 -07:00
{
transform ( tName . begin ( ) , tName . end ( ) , tName . begin ( ) , : : toupper ) ;
return tName ;
}
2018-05-23 13:45:22 +01:00
bool CPlayerWeenie : : CheckUseRequirements ( int index , CCraftOperation * op , std : : shared_ptr < CWeenieObject > pTool , std : : shared_ptr < CWeenieObject > pTarget )
2018-03-29 17:01:57 -04:00
{
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > requirementTarget ;
2018-03-29 17:01:57 -04:00
switch ( index )
{
case 0 :
requirementTarget = pTarget ;
break ;
case 1 :
requirementTarget = pTool ;
break ;
case 2 :
2018-05-24 22:28:15 +01:00
requirementTarget = GetPointer < CWeenieObject > ( ) ;
2018-03-29 17:01:57 -04:00
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
return false ; //should never happen
}
if ( ! op - > _requirements [ index ] . _intRequirement . empty ( ) )
{
for each ( TYPERequirement < STypeInt , int > intRequirement in op - > _requirements [ index ] . _intRequirement )
{
int value = 0 ;
bool exists = requirementTarget - > m_Qualities . InqInt ( intRequirement . _stat , value , true , true ) ;
switch ( intRequirement . _operationType )
{
case 0 : //> - unconfirmed
if ( value > intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 1 : //<=
if ( value < = intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 2 : //<
if ( value < intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 3 : //>=
if ( value > = intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 4 : //!=
if ( value ! = intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 5 : //doesnt exist or !=
if ( ! exists | | value ! = intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 6 : //exists and ==
if ( exists & & value = = intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 7 : //doesnt exist
if ( ! exists )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 8 : //exists and != (or maybe just exists)
if ( exists & & value ! = intRequirement . _value )
{
SendText ( intRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
2018-04-24 21:07:20 -04:00
}
2018-03-29 17:01:57 -04:00
}
if ( ! op - > _requirements [ index ] . _boolRequirement . empty ( ) )
{
for each ( TYPERequirement < STypeBool , BOOL > boolRequirement in op - > _requirements [ index ] . _boolRequirement )
{
int value = 0 ;
bool exists = requirementTarget - > m_Qualities . InqBool ( boolRequirement . _stat , value ) ;
switch ( boolRequirement . _operationType )
{
case 0 : //> - unconfirmed
if ( value > boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 1 : //<=
if ( value < = boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 2 : //<
if ( value < boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 3 : //>=
if ( value > = boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 4 : //!=
if ( value ! = boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 5 : //doesnt exist or !=
if ( ! exists | | value ! = boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 6 : //exists and ==
if ( exists & & value = = boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 7 : //doesnt exist
if ( ! exists )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 8 : //exists and != (or maybe just exists)
if ( exists & & value ! = boolRequirement . _value )
{
SendText ( boolRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
}
}
if ( ! op - > _requirements [ index ] . _floatRequirement . empty ( ) )
{
for each ( TYPERequirement < STypeFloat , double > floatRequirement in op - > _requirements [ index ] . _floatRequirement )
{
double value = 0 ;
bool exists = requirementTarget - > m_Qualities . InqFloat ( floatRequirement . _stat , value , true ) ;
switch ( floatRequirement . _operationType )
{
case 0 : //> - unconfirmed
if ( value > floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 1 : //<=
if ( value < = floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 2 : //<
if ( value < floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 3 : //>=
if ( value > = floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 4 : //!=
if ( value ! = floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 5 : //doesnt exist or !=
if ( ! exists | | value ! = floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 6 : //exists and ==
if ( exists & & value = = floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 7 : //doesnt exist
if ( ! exists )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 8 : //exists and != (or maybe just exists)
if ( exists & & value ! = floatRequirement . _value )
{
SendText ( floatRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
}
}
if ( ! op - > _requirements [ index ] . _stringRequirement . empty ( ) )
{
for each ( TYPERequirement < STypeString , std : : string > stringRequirement in op - > _requirements [ index ] . _stringRequirement )
{
std : : string value = " " ;
bool exists = requirementTarget - > m_Qualities . InqString ( stringRequirement . _stat , value ) ;
switch ( stringRequirement . _operationType )
{
case 0 : //> - unconfirmed
if ( value > stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 1 : //<=
if ( value < = stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 2 : //<
if ( value < stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 3 : //>=
if ( value > = stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 4 : //!=
if ( value ! = stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 5 : //doesnt exist or !=
if ( ! exists | | value ! = stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 6 : //exists and ==
if ( exists & & value = = stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 7 : //doesnt exist
if ( ! exists )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 8 : //exists and != (or maybe just exists)
if ( exists & & value ! = stringRequirement . _value )
{
SendText ( stringRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
}
}
if ( ! op - > _requirements [ index ] . _didRequirement . empty ( ) )
{
for each ( TYPERequirement < STypeDID , DWORD > dIDRequirement in op - > _requirements [ index ] . _didRequirement )
{
DWORD value = 0 ;
bool exists = requirementTarget - > m_Qualities . InqDataID ( dIDRequirement . _stat , value ) ;
switch ( dIDRequirement . _operationType )
{
case 0 : //> - unconfirmed
if ( value > dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 1 : //<=
if ( value < = dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 2 : //<
if ( value < dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 3 : //>=
if ( value > = dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 4 : //!=
if ( value ! = dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 5 : //doesnt exist or !=
if ( ! exists | | value ! = dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 6 : //exists and ==
if ( exists & & value = = dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 7 : //doesnt exist
if ( ! exists )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 8 : //exists and != (or maybe just exists)
if ( exists & & value ! = dIDRequirement . _value )
{
SendText ( dIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
}
}
if ( ! op - > _requirements [ index ] . _iidRequirement . empty ( ) )
{
for each ( TYPERequirement < STypeIID , DWORD > iIDRequirement in op - > _requirements [ index ] . _iidRequirement )
{
DWORD value = 0 ;
bool exists = requirementTarget - > m_Qualities . InqInstanceID ( iIDRequirement . _stat , value ) ;
switch ( iIDRequirement . _operationType )
{
case 0 : //> - unconfirmed
if ( value > iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 1 : //<=
if ( value < = iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 2 : //<
if ( value < iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 3 : //>=
if ( value > = iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 4 : //!=
if ( value ! = iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 5 : //doesnt exist or !=
if ( ! exists | | value ! = iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 6 : //exists and ==
if ( exists & & value = = iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 7 : //doesnt exist
if ( ! exists )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
case 8 : //exists and != (or maybe just exists)
if ( exists & & value ! = iIDRequirement . _value )
{
SendText ( iIDRequirement . _message . c_str ( ) , LTT_CRAFT ) ;
return false ;
}
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
}
}
return true ;
}
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : PerformUseModificationScript ( DWORD scriptId , CCraftOperation * op , std : : shared_ptr < CWeenieObject > pTool , std : : shared_ptr < CWeenieObject > pTarget , std : : shared_ptr < CWeenieObject > pCreatedItem )
2018-03-29 17:01:57 -04:00
{
2018-04-03 19:33:51 -04:00
double currentVar = pTarget - > InqFloatQuality ( DAMAGE_VARIANCE_FLOAT , 0 , TRUE ) ;
2018-03-29 17:01:57 -04:00
switch ( scriptId )
{
case 0x3800000f : //flag stamp failure
//not sure what is supposed to be done here.
break ;
case 0x38000011 : //steel
pTarget - > m_Qualities . SetInt ( ARMOR_LEVEL_INT , pTarget - > InqIntQuality ( ARMOR_LEVEL_INT , 0 , TRUE ) + 20 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000012 : //armoredillo hide
pTarget - > m_Qualities . SetFloat ( ARMOR_MOD_VS_ACID_FLOAT , min ( pTarget - > InqFloatQuality ( ARMOR_MOD_VS_ACID_FLOAT , 0 , TRUE ) + 0.4 , 2.0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000013 : //marble
pTarget - > m_Qualities . SetFloat ( ARMOR_MOD_VS_BLUDGEON_FLOAT , min ( pTarget - > InqFloatQuality ( ARMOR_MOD_VS_BLUDGEON_FLOAT , 0 , TRUE ) + 0.2 , 2.0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000014 : //wool
pTarget - > m_Qualities . SetFloat ( ARMOR_MOD_VS_COLD_FLOAT , min ( pTarget - > InqFloatQuality ( ARMOR_MOD_VS_COLD_FLOAT , 0 , TRUE ) + 0.4 , 2.0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000015 : //reedshark hide
pTarget - > m_Qualities . SetFloat ( ARMOR_MOD_VS_ELECTRIC_FLOAT , min ( pTarget - > InqFloatQuality ( ARMOR_MOD_VS_ELECTRIC_FLOAT , 0 , TRUE ) + 0.4 , 2.0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000016 : //ceramic
pTarget - > m_Qualities . SetFloat ( ARMOR_MOD_VS_FIRE_FLOAT , min ( pTarget - > InqFloatQuality ( ARMOR_MOD_VS_FIRE_FLOAT , 0 , TRUE ) + 0.4 , 2.0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000017 : //alabaster
pTarget - > m_Qualities . SetFloat ( ARMOR_MOD_VS_PIERCE_FLOAT , min ( pTarget - > InqFloatQuality ( ARMOR_MOD_VS_PIERCE_FLOAT , 0 , TRUE ) + 0.2 , 2.0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000018 : //bronze
pTarget - > m_Qualities . SetFloat ( ARMOR_MOD_VS_SLASH_FLOAT , min ( pTarget - > InqFloatQuality ( ARMOR_MOD_VS_SLASH_FLOAT , 0 , TRUE ) + 0.2 , 2.0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000019 : //linen
{
double newEncumbrance = pTarget - > InqIntQuality ( ENCUMB_VAL_INT , 1 , TRUE ) ;
newEncumbrance = max ( newEncumbrance * 0.85 , 1 ) ;
pTarget - > m_Qualities . SetInt ( ENCUMB_VAL_INT , ( int ) round ( newEncumbrance ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
}
case 0x3800001a : //iron
pTarget - > m_Qualities . SetInt ( DAMAGE_INT , pTarget - > InqIntQuality ( DAMAGE_INT , 0 , TRUE ) + 1 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800001b : //mahogany
pTarget - > m_Qualities . SetFloat ( DAMAGE_MOD_FLOAT , pTarget - > InqFloatQuality ( DAMAGE_MOD_FLOAT , 0 , TRUE ) + 0.04 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800001c : //granite
2018-04-03 19:33:51 -04:00
pTarget - > m_Qualities . SetFloat ( DAMAGE_VARIANCE_FLOAT , max ( currentVar - ( currentVar / 5 ) , 0.0 ) ) ;
2018-03-29 17:01:57 -04:00
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800001d : //oak
pTarget - > m_Qualities . SetInt ( WEAPON_TIME_INT , max ( pTarget - > InqIntQuality ( WEAPON_TIME_INT , 0 , TRUE ) - 50 , 0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800001e : //pine
pTarget - > m_Qualities . SetInt ( VALUE_INT , max ( pTarget - > InqIntQuality ( VALUE_INT , 0 , TRUE ) * 0.75 , 1 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800001f : //gold
pTarget - > m_Qualities . SetInt ( VALUE_INT , pTarget - > InqIntQuality ( VALUE_INT , 0 , TRUE ) * 1.25 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000020 : //brass
pTarget - > m_Qualities . SetFloat ( WEAPON_DEFENSE_FLOAT , pTarget - > InqFloatQuality ( WEAPON_DEFENSE_FLOAT , 0 , TRUE ) + 0.01 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000021 : //velvet
pTarget - > m_Qualities . SetFloat ( WEAPON_OFFENSE_FLOAT , pTarget - > InqFloatQuality ( WEAPON_OFFENSE_FLOAT , 0 , TRUE ) + 0.01 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000023 : //black opal
pTarget - > AddImbueEffect ( ImbuedEffectType : : CriticalStrike_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000024 : //fire opal
pTarget - > AddImbueEffect ( ImbuedEffectType : : CripplingBlow_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000025 : //sunstone
pTarget - > AddImbueEffect ( ImbuedEffectType : : ArmorRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800002e : //opal
pTarget - > m_Qualities . SetFloat ( MANA_CONVERSION_MOD_FLOAT , pTarget - > InqFloatQuality ( MANA_CONVERSION_MOD_FLOAT , 0 , TRUE ) + 0.01 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800002f : //moonstone
pTarget - > m_Qualities . SetInt ( ITEM_MAX_MANA_INT , max ( pTarget - > InqIntQuality ( ITEM_MAX_MANA_INT , 0 , TRUE ) + 500 , 0 ) ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000034 : //silver
{
STypeSkill oldRequirement = ( STypeSkill ) pTarget - > InqIntQuality ( WIELD_SKILLTYPE_INT , 0 ) ;
if ( oldRequirement = = MELEE_DEFENSE_SKILL )
{
pTarget - > m_Qualities . SetInt ( WIELD_SKILLTYPE_INT , MISSILE_DEFENSE_SKILL ) ;
pTarget - > m_Qualities . SetDataID ( ITEM_SKILL_LIMIT_DID , MISSILE_DEFENSE_SKILL ) ;
int oldValue = pTarget - > InqIntQuality ( WIELD_DIFFICULTY_INT , 0 ) ;
int newValue ;
switch ( oldValue )
{
case 200 : newValue = 160 ; break ;
case 250 : newValue = 205 ; break ;
case 300 : newValue = 245 ; break ;
case 325 : newValue = 270 ; break ;
case 350 : newValue = 290 ; break ;
case 370 : newValue = 305 ; break ;
case 400 : newValue = 330 ; break ;
default :
newValue = oldValue * 0.8 ; //todo: figure out the exact formula for this conversion.
break ;
}
pTarget - > m_Qualities . SetInt ( WIELD_DIFFICULTY_INT , newValue ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
}
break ;
}
case 0x38000035 : //copper
{
STypeSkill oldRequirement = ( STypeSkill ) pTarget - > InqIntQuality ( WIELD_SKILLTYPE_INT , 0 ) ;
if ( oldRequirement = = MISSILE_DEFENSE_SKILL )
{
pTarget - > m_Qualities . SetInt ( WIELD_SKILLTYPE_INT , MELEE_DEFENSE_SKILL ) ;
pTarget - > m_Qualities . SetDataID ( ITEM_SKILL_LIMIT_DID , MELEE_DEFENSE_SKILL ) ;
int oldValue = pTarget - > InqIntQuality ( WIELD_DIFFICULTY_INT , 0 ) ;
int newValue ;
switch ( oldValue )
{
case 160 : newValue = 200 ; break ;
case 205 : newValue = 250 ; break ;
case 245 : newValue = 300 ; break ;
case 270 : newValue = 325 ; break ;
case 290 : newValue = 350 ; break ;
case 305 : newValue = 370 ; break ;
case 330 : newValue = 400 ; break ;
default :
newValue = oldValue * 1.25 ; //todo: figure out the exact formula for this conversion.
break ;
}
pTarget - > m_Qualities . SetInt ( WIELD_DIFFICULTY_INT , newValue ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
}
break ;
}
case 0x38000036 : //silk
{
int allegianceRank ;
if ( pTarget - > m_Qualities . InqInt ( ITEM_ALLEGIANCE_RANK_LIMIT_INT , allegianceRank , TRUE ) )
{
pTarget - > m_Qualities . RemoveInt ( ITEM_ALLEGIANCE_RANK_LIMIT_INT ) ;
int spellCraft = pTarget - > InqIntQuality ( ITEM_SPELLCRAFT_INT , 0 , TRUE ) ;
pTarget - > m_Qualities . SetInt ( ITEM_DIFFICULTY_INT , pTarget - > InqIntQuality ( ITEM_DIFFICULTY_INT , 0 , TRUE ) + spellCraft ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
}
break ;
}
case 0x38000037 : //zircon
pTarget - > AddImbueEffect ( ImbuedEffectType : : MagicDefense_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000038 : //peridot
pTarget - > AddImbueEffect ( ImbuedEffectType : : MeleeDefense_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000039 : //yellow topaz
pTarget - > AddImbueEffect ( ImbuedEffectType : : MissileDefense_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800003a : //emerald
pTarget - > AddImbueEffect ( ImbuedEffectType : : AcidRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800003b : //white sapphire
pTarget - > AddImbueEffect ( ImbuedEffectType : : BludgeonRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800003c : //aquamarine
pTarget - > AddImbueEffect ( ImbuedEffectType : : ColdRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800003d : //jet
pTarget - > AddImbueEffect ( ImbuedEffectType : : ElectricRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800003e : //red garnet
pTarget - > AddImbueEffect ( ImbuedEffectType : : FireRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x3800003f : //black garnet
pTarget - > AddImbueEffect ( ImbuedEffectType : : PierceRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000040 : //imperial topaz
pTarget - > AddImbueEffect ( ImbuedEffectType : : SlashRending_ImbuedEffectType ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000041 : //azurite, malachite, citrine, hematite, lavender jade, red jade, carnelian, lapis lazuli, agate, rose quartz, smokey quartz, bloodstone
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
case 0x38000042 : //ebony, porcelain, teak
{
HeritageGroup heritageRequirement = ( HeritageGroup ) pTarget - > InqIntQuality ( HERITAGE_GROUP_INT , 0 , TRUE ) ;
if ( heritageRequirement ! = Invalid_HeritageGroup )
{
HeritageGroup heritageTarget ;
switch ( pTool - > InqIntQuality ( MATERIAL_TYPE_INT , 0 , TRUE ) )
{
case MaterialType : : Ebony_MaterialType :
heritageTarget = Gharundim_HeritageGroup ;
break ;
case MaterialType : : Porcelain_MaterialType :
heritageTarget = Sho_HeritageGroup ;
break ;
case MaterialType : : Teak_MaterialType :
heritageTarget = Aluvian_HeritageGroup ;
break ;
default :
return ;
}
pTarget - > m_Qualities . SetInt ( HERITAGE_GROUP_INT , heritageTarget ) ;
switch ( heritageTarget )
{
case Aluvian_HeritageGroup :
pTarget - > m_Qualities . SetString ( ITEM_HERITAGE_GROUP_RESTRICTION_STRING , " Aluvian " ) ;
break ;
case Gharundim_HeritageGroup :
pTarget - > m_Qualities . SetString ( ITEM_HERITAGE_GROUP_RESTRICTION_STRING , " Gharu'ndim " ) ;
break ;
case Sho_HeritageGroup :
pTarget - > m_Qualities . SetString ( ITEM_HERITAGE_GROUP_RESTRICTION_STRING , " Sho " ) ;
break ;
}
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
}
break ;
}
case 0x38000043 : //leather
pTarget - > m_Qualities . SetBool ( RETAINED_BOOL , 1 ) ;
break ;
2018-04-04 21:07:40 -05:00
case 0x38000044 : //green garnet
pTarget - > m_Qualities . SetFloat ( ELEMENTAL_DAMAGE_MOD_FLOAT , pTarget - > InqFloatQuality ( ELEMENTAL_DAMAGE_MOD_FLOAT , 0 , TRUE ) + 0.01 ) ;
pTarget - > m_Qualities . SetInt ( NUM_TIMES_TINKERED_INT , pTarget - > InqIntQuality ( NUM_TIMES_TINKERED_INT , 0 , TRUE ) + 1 ) ;
break ;
2018-03-29 17:01:57 -04:00
case 0x38000046 : //fetish of the dark idol
pTarget - > AddImbueEffect ( ImbuedEffectType : : IgnoreSomeMagicProjectileDamage_ImbuedEffectType ) ;
break ;
default :
SendText ( csprintf ( " Tried to run unsupported modification script: %u. " , scriptId ) , LTT_CRAFT ) ;
break ;
}
}
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : PerformUseModifications ( int index , CCraftOperation * op , std : : shared_ptr < CWeenieObject > pTool , std : : shared_ptr < CWeenieObject > pTarget , std : : shared_ptr < CWeenieObject > pCreatedItem )
2018-03-29 17:01:57 -04:00
{
if ( op - > _mods [ index ] . _modificationScriptId )
PerformUseModificationScript ( op - > _mods [ index ] . _modificationScriptId , op , pTool , pTarget , pCreatedItem ) ;
if ( op - > _mods [ index ] . _ModifyHealth )
AdjustHealth ( op - > _mods [ index ] . _ModifyHealth ) ;
if ( op - > _mods [ index ] . _ModifyStamina )
AdjustStamina ( op - > _mods [ index ] . _ModifyStamina ) ;
if ( op - > _mods [ index ] . _ModifyMana )
AdjustMana ( op - > _mods [ index ] . _ModifyMana ) ;
if ( ! op - > _mods [ index ] . _intMod . empty ( ) )
{
for each ( TYPEMod < STypeInt , int > intMod in op - > _mods [ index ] . _intMod )
{
bool applyToCreatedItem = false ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > modificationSource = NULL ;
2018-03-29 17:01:57 -04:00
switch ( intMod . _unk ) //this is a guess
{
case 0 :
2018-05-24 22:28:15 +01:00
modificationSource = GetPointer < CWeenieObject > ( ) ;
2018-03-29 17:01:57 -04:00
break ;
case 1 :
modificationSource = pTool ;
break ;
case 60 :
//dying armor entries have a second entry to armor reduction that has -30 armor and _unk value of 60
//not sure what to do with that so we skip it.
continue ;
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ; //should never happen
}
int value = pTarget - > InqIntQuality ( intMod . _stat , 0 , true ) ;
switch ( intMod . _operationType )
{
case 1 : //=
value = intMod . _value ;
break ;
case 2 : //+
value + = intMod . _value ;
if ( value < 0 )
value = 0 ;
break ;
case 3 : //copy value from modificationSource to target
2018-04-08 10:04:54 -04:00
if ( modificationSource )
2018-03-29 17:01:57 -04:00
value = modificationSource - > InqIntQuality ( intMod . _stat , 0 ) ;
break ;
case 4 : //copy value from modificationSource to created item
applyToCreatedItem = true ;
if ( modificationSource )
value = modificationSource - > InqIntQuality ( intMod . _stat , 0 ) ;
break ;
case 7 : //add spell
{
CSpellTable * pSpellTable = MagicSystem : : GetSpellTable ( ) ;
if ( ! intMod . _stat | | ! pSpellTable | | ! pSpellTable - > GetSpellBase ( intMod . _stat ) )
break ;
pTarget - > m_Qualities . AddSpell ( intMod . _stat ) ;
break ;
}
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
if ( pCreatedItem & & applyToCreatedItem )
{
pCreatedItem - > m_Qualities . SetInt ( intMod . _stat , value ) ;
pCreatedItem - > NotifyIntStatUpdated ( intMod . _stat , false ) ;
}
else
{
pTarget - > m_Qualities . SetInt ( intMod . _stat , value ) ;
pTarget - > NotifyIntStatUpdated ( intMod . _stat , false ) ;
}
}
2018-04-24 21:07:20 -04:00
}
2018-03-29 17:01:57 -04:00
if ( ! op - > _mods [ index ] . _boolMod . empty ( ) )
{
for each ( TYPEMod < STypeBool , BOOL > boolMod in op - > _mods [ index ] . _boolMod )
{
bool applyToCreatedItem = false ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > modificationSource = NULL ;
2018-03-29 17:01:57 -04:00
switch ( boolMod . _unk ) //this is a guess
{
case 0 :
2018-05-24 22:28:15 +01:00
modificationSource = GetPointer < CWeenieObject > ( ) ;
2018-03-29 17:01:57 -04:00
break ;
case 1 :
modificationSource = pTool ;
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ; //should never happen
}
int value = pTarget - > InqBoolQuality ( boolMod . _stat , 0 ) ;
switch ( boolMod . _operationType )
{
case 1 : //=
value = boolMod . _value ;
break ;
case 2 : //+
value + = boolMod . _value ;
break ;
case 3 : //copy value from modificationSource to target
if ( modificationSource )
value = modificationSource - > InqBoolQuality ( boolMod . _stat , 0 ) ;
break ;
case 4 : //copy value from modificationSource to created item
applyToCreatedItem = true ;
if ( modificationSource )
value = modificationSource - > InqBoolQuality ( boolMod . _stat , 0 ) ;
break ;
case 7 : //add spell
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
if ( pCreatedItem & & applyToCreatedItem )
{
pCreatedItem - > m_Qualities . SetBool ( boolMod . _stat , value ) ;
pCreatedItem - > NotifyBoolStatUpdated ( boolMod . _stat , false ) ;
}
else
{
pTarget - > m_Qualities . SetBool ( boolMod . _stat , value ) ;
pTarget - > NotifyBoolStatUpdated ( boolMod . _stat , false ) ;
}
2018-04-24 21:07:20 -04:00
}
}
2018-03-29 17:01:57 -04:00
if ( ! op - > _mods [ index ] . _floatMod . empty ( ) )
{
for each ( TYPEMod < STypeFloat , double > floatMod in op - > _mods [ index ] . _floatMod )
{
bool applyToCreatedItem = false ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > modificationSource = NULL ;
2018-03-29 17:01:57 -04:00
switch ( floatMod . _unk ) //this is a guess
{
case 0 :
2018-05-24 22:28:15 +01:00
modificationSource = GetPointer < CWeenieObject > ( ) ;
2018-03-29 17:01:57 -04:00
break ;
case 1 :
modificationSource = pTool ;
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ; //should never happen
}
double value = pTarget - > InqFloatQuality ( floatMod . _stat , 0 , true ) ;
switch ( floatMod . _operationType )
{
case 1 : //=
value = floatMod . _value ;
break ;
case 2 : //+
value + = floatMod . _value ;
if ( value < 0.0 )
value = 0.0 ;
break ;
case 3 : //copy value from modificationSource to target
if ( modificationSource )
value = modificationSource - > InqFloatQuality ( floatMod . _stat , 0 ) ;
break ;
case 4 : //copy value from modificationSource to created item
applyToCreatedItem = true ;
if ( modificationSource )
value = modificationSource - > InqFloatQuality ( floatMod . _stat , 0 ) ;
break ;
case 7 : //add spell
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
if ( pCreatedItem & & applyToCreatedItem )
{
pCreatedItem - > m_Qualities . SetFloat ( floatMod . _stat , value ) ;
pCreatedItem - > NotifyFloatStatUpdated ( floatMod . _stat , false ) ;
}
else
{
pTarget - > m_Qualities . SetFloat ( floatMod . _stat , value ) ;
pTarget - > NotifyFloatStatUpdated ( floatMod . _stat , false ) ;
}
2018-04-24 21:07:20 -04:00
}
}
2018-03-29 17:01:57 -04:00
if ( ! op - > _mods [ index ] . _stringMod . empty ( ) )
{
for each ( TYPEMod < STypeString , std : : string > stringMod in op - > _mods [ index ] . _stringMod )
{
bool applyToCreatedItem = false ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > modificationSource = NULL ;
2018-03-29 17:01:57 -04:00
switch ( stringMod . _unk ) //this is a guess
{
case 0 :
2018-05-24 22:28:15 +01:00
modificationSource = GetPointer < CWeenieObject > ( ) ;
2018-03-29 17:01:57 -04:00
break ;
case 1 :
modificationSource = pTool ;
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ; //should never happen
}
std : : string value = pTarget - > InqStringQuality ( stringMod . _stat , " " ) ;
switch ( stringMod . _operationType )
{
case 1 : //=
value = stringMod . _value ;
break ;
case 2 : //+
value + = stringMod . _value ;
break ;
case 3 : //copy value from modificationSource to target
if ( modificationSource )
{
switch ( stringMod . _stat )
{
case TINKER_NAME_STRING :
case IMBUER_NAME_STRING :
case CRAFTSMAN_NAME_STRING :
2018-04-05 16:56:20 -05:00
value = this - > InqStringQuality ( NAME_STRING , " " ) ;
2018-03-29 17:01:57 -04:00
break ;
default :
value = modificationSource - > InqStringQuality ( stringMod . _stat , " " ) ;
break ;
}
}
break ;
case 4 : //copy value from modificationSource to created item
applyToCreatedItem = true ;
if ( modificationSource )
{
switch ( stringMod . _stat )
{
case TINKER_NAME_STRING :
case IMBUER_NAME_STRING :
case CRAFTSMAN_NAME_STRING :
2018-04-05 16:56:20 -05:00
value = this - > InqStringQuality ( NAME_STRING , " " ) ;
2018-03-29 17:01:57 -04:00
break ;
default :
value = modificationSource - > InqStringQuality ( stringMod . _stat , " " ) ;
break ;
}
}
break ;
case 7 : //add spell
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
if ( pCreatedItem & & applyToCreatedItem )
{
pCreatedItem - > m_Qualities . SetString ( stringMod . _stat , value ) ;
pCreatedItem - > NotifyStringStatUpdated ( stringMod . _stat , false ) ;
}
else
{
pTarget - > m_Qualities . SetString ( stringMod . _stat , value ) ;
pTarget - > NotifyStringStatUpdated ( stringMod . _stat , false ) ;
}
2018-04-24 21:07:20 -04:00
}
}
2018-03-29 17:01:57 -04:00
if ( ! op - > _mods [ index ] . _didMod . empty ( ) )
{
for each ( TYPEMod < STypeDID , DWORD > didMod in op - > _mods [ index ] . _didMod )
{
bool applyToCreatedItem = false ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > modificationSource = NULL ;
2018-03-29 17:01:57 -04:00
switch ( didMod . _unk ) //this is a guess
{
case 0 :
2018-05-24 22:28:15 +01:00
modificationSource = GetPointer < CWeenieObject > ( ) ;
2018-03-29 17:01:57 -04:00
break ;
case 1 :
modificationSource = pTool ;
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ; //should never happen
}
DWORD value = pTarget - > InqDIDQuality ( didMod . _stat , 0 ) ;
switch ( didMod . _operationType )
{
case 1 : //=
value = didMod . _value ;
break ;
case 2 : //+
value + = didMod . _value ;
break ;
case 3 : //copy value from modificationSource to target
if ( modificationSource )
value = modificationSource - > InqDIDQuality ( didMod . _stat , 0 ) ;
break ;
case 4 : //copy value from modificationSource to created item
applyToCreatedItem = true ;
if ( modificationSource )
value = modificationSource - > InqDIDQuality ( didMod . _stat , 0 ) ;
break ;
case 7 : //add spell
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
if ( pCreatedItem & & applyToCreatedItem )
{
pCreatedItem - > m_Qualities . SetDataID ( didMod . _stat , value ) ;
pCreatedItem - > NotifyDIDStatUpdated ( didMod . _stat , false ) ;
}
else
{
pTarget - > m_Qualities . SetDataID ( didMod . _stat , value ) ;
pTarget - > NotifyDIDStatUpdated ( didMod . _stat , false ) ;
}
2018-04-24 21:07:20 -04:00
}
}
2018-03-29 17:01:57 -04:00
if ( ! op - > _mods [ index ] . _iidMod . empty ( ) )
{
for each ( TYPEMod < STypeIID , DWORD > iidMod in op - > _mods [ index ] . _iidMod )
{
bool applyToCreatedItem = false ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > modificationSource = NULL ;
2018-03-29 17:01:57 -04:00
switch ( iidMod . _unk ) //this is a guess
{
case 0 :
2018-05-24 22:28:15 +01:00
modificationSource = GetPointer < CWeenieObject > ( ) ;
2018-03-29 17:01:57 -04:00
break ;
case 1 :
modificationSource = pTool ;
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ; //should never happen
}
DWORD value = pTarget - > InqIIDQuality ( iidMod . _stat , 0 ) ;
switch ( iidMod . _operationType )
{
case 1 : //=
value = iidMod . _value ;
break ;
case 2 : //+
value + = iidMod . _value ;
break ;
case 3 : //copy value from modificationSource to target
if ( modificationSource )
{
switch ( iidMod . _stat )
{
case ALLOWED_WIELDER_IID :
case ALLOWED_ACTIVATOR_IID :
2018-04-05 16:56:20 -05:00
value = this - > GetID ( ) ;
2018-03-29 17:01:57 -04:00
break ;
default :
value = modificationSource - > InqIIDQuality ( iidMod . _stat , 0 ) ;
break ;
2018-04-08 10:04:54 -04:00
}
2018-03-29 17:01:57 -04:00
}
break ;
case 4 : //copy value from modificationSource to created item
applyToCreatedItem = true ;
if ( modificationSource )
{
switch ( iidMod . _stat )
{
case ALLOWED_WIELDER_IID :
case ALLOWED_ACTIVATOR_IID :
2018-04-05 16:56:20 -05:00
value = this - > GetID ( ) ;
2018-03-29 17:01:57 -04:00
break ;
default :
value = modificationSource - > InqIIDQuality ( iidMod . _stat , 0 ) ;
break ;
}
}
break ;
case 7 : //add spell
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
default :
# ifdef _DEBUG
assert ( false ) ;
# endif
break ;
}
if ( pCreatedItem & & applyToCreatedItem )
{
pCreatedItem - > m_Qualities . SetInstanceID ( iidMod . _stat , value ) ;
pCreatedItem - > NotifyIIDStatUpdated ( iidMod . _stat , false ) ;
}
else
{
pTarget - > m_Qualities . SetInstanceID ( iidMod . _stat , value ) ;
pTarget - > NotifyIIDStatUpdated ( iidMod . _stat , false ) ;
}
2018-04-24 21:07:20 -04:00
}
}
2018-03-29 17:01:57 -04:00
if ( op - > _mods [ index ] . _unknown7 ) //this is a guess
{
//update icon
DWORD clothing_table_id = pTarget - > InqDIDQuality ( CLOTHINGBASE_DID , 0 ) ;
DWORD palette_template_key = pTarget - > InqIntQuality ( PALETTE_TEMPLATE_INT , 0 ) ;
if ( clothing_table_id & & palette_template_key )
{
if ( ! pTarget - > InqBoolQuality ( IGNORE_CLO_ICONS_BOOL , FALSE ) )
{
if ( ClothingTable * clothingTable = ClothingTable : : Get ( clothing_table_id ) )
{
if ( const CloPaletteTemplate * pPaletteTemplate = clothingTable - > _paletteTemplatesHash . lookup ( palette_template_key ) )
{
if ( pPaletteTemplate - > iconID )
{
pTarget - > m_Qualities . SetDataID ( ICON_DID , pPaletteTemplate - > iconID ) ;
pTarget - > NotifyDIDStatUpdated ( ICON_DID ) ;
}
}
ClothingTable : : Release ( clothingTable ) ;
}
}
}
}
2018-04-24 21:07:20 -04:00
}
2018-03-29 17:01:57 -04:00
DWORD CPlayerWeenie : : MaterialToSalvageBagId ( MaterialType material )
{
switch ( material )
{
case Ceramic_MaterialType :
return W_MATERIALCERAMIC_CLASS ;
case Porcelain_MaterialType :
return W_MATERIALPORCELAIN_CLASS ;
case Linen_MaterialType :
return W_MATERIALLINEN_CLASS ;
case Satin_MaterialType :
return W_MATERIALSATIN_CLASS ;
case Silk_MaterialType :
return W_MATERIALSILK_CLASS ;
case Velvet_MaterialType :
return W_MATERIALVELVET_CLASS ;
case Wool_MaterialType :
return W_MATERIALWOOL_CLASS ;
case Agate_MaterialType :
return W_MATERIALAGATE_CLASS ;
case Amber_MaterialType :
return W_MATERIALAMBER_CLASS ;
case Amethyst_MaterialType :
return W_MATERIALAMETHYST_CLASS ;
case Aquamarine_MaterialType :
return W_MATERIALAQUAMARINE_CLASS ;
case Azurite_MaterialType :
return W_MATERIALAZURITE_CLASS ;
case Black_Garnet_MaterialType :
return W_MATERIALBLACKGARNET_CLASS ;
case Black_Opal_MaterialType :
return W_MATERIALBLACKOPAL_CLASS ;
case Bloodstone_MaterialType :
return W_MATERIALBLOODSTONE_CLASS ;
case Carnelian_MaterialType :
return W_MATERIALCARNELIAN_CLASS ;
case Citrine_MaterialType :
return W_MATERIALCITRINE_CLASS ;
case Diamond_MaterialType :
return W_MATERIALDIAMOND_CLASS ;
case Emerald_MaterialType :
return W_MATERIALEMERALD_CLASS ;
case Fire_Opal_MaterialType :
return W_MATERIALFIREOPAL_CLASS ;
case Green_Garnet_MaterialType :
return W_MATERIALGREENGARNET_CLASS ;
case Green_Jade_MaterialType :
return W_MATERIALGREENJADE_CLASS ;
case Hematite_MaterialType :
return W_MATERIALHEMATITE_CLASS ;
case Imperial_Topaz_MaterialType :
return W_MATERIALIMPERIALTOPAZ_CLASS ;
case Jet_MaterialType :
return W_MATERIALJET_CLASS ;
case Lapis_Lazuli_MaterialType :
return W_MATERIALLAPISLAZULI_CLASS ;
case Lavender_Jade_MaterialType :
return W_MATERIALLAVENDERJADE_CLASS ;
case Malachite_MaterialType :
return W_MATERIALMALACHITE_CLASS ;
case Moonstone_MaterialType :
return W_MATERIALMOONSTONE_CLASS ;
case Onyx_MaterialType :
return W_MATERIALONYX_CLASS ;
case Opal_MaterialType :
return W_MATERIALOPAL_CLASS ;
case Peridot_MaterialType :
return W_MATERIALPERIDOT_CLASS ;
case Red_Garnet_MaterialType :
return W_MATERIALREDGARNET_CLASS ;
case Red_Jade_MaterialType :
return W_MATERIALREDJADE_CLASS ;
case Rose_Quartz_MaterialType :
return W_MATERIALROSEQUARTZ_CLASS ;
case Ruby_MaterialType :
return W_MATERIALRUBY_CLASS ;
case Sapphire_MaterialType :
return W_MATERIALSAPPHIRE_CLASS ;
case Smoky_Quartz_MaterialType :
return W_MATERIALSMOKYQUARTZ_CLASS ;
case Sunstone_MaterialType :
return W_MATERIALSUNSTONE_CLASS ;
case Tiger_Eye_MaterialType :
return W_MATERIALTIGEREYE_CLASS ;
case Tourmaline_MaterialType :
return W_MATERIALTOURMALINE_CLASS ;
case Turquoise_MaterialType :
return W_MATERIALTURQUOISE_CLASS ;
case White_Jade_MaterialType :
return W_MATERIALWHITEJADE_CLASS ;
case White_Quartz_MaterialType :
return W_MATERIALWHITEQUARTZ_CLASS ;
case White_Sapphire_MaterialType :
return W_MATERIALWHITESAPPHIRE_CLASS ;
case Yellow_Garnet_MaterialType :
return W_MATERIALYELLOWGARNET_CLASS ;
case Yellow_Topaz_MaterialType :
return W_MATERIALYELLOWTOPAZ_CLASS ;
case Zircon_MaterialType :
return W_MATERIALZIRCON_CLASS ;
case Ivory_MaterialType :
return W_MATERIALIVORY_CLASS ;
case Leather_MaterialType :
return W_MATERIALLEATHER_CLASS ;
case Armoredillo_Hide_MaterialType :
return W_MATERIALARMOREDILLOHIDE_CLASS ;
case Gromnie_Hide_MaterialType :
return W_MATERIALGROMNIEHIDE_CLASS ;
case Reed_Shark_Hide_MaterialType :
return W_MATERIALREEDSHARKHIDE_CLASS ;
case Brass_MaterialType :
return W_MATERIALBRASS_CLASS ;
case Bronze_MaterialType :
return W_MATERIALBRONZE_CLASS ;
case Copper_MaterialType :
return W_MATERIALCOPPER_CLASS ;
case Gold_MaterialType :
return W_MATERIALGOLD_CLASS ;
case Iron_MaterialType :
return W_MATERIALIRON_CLASS ;
case Pyreal_MaterialType :
return W_MATERIALPYREAL_CLASS ;
case Silver_MaterialType :
return W_MATERIALSILVER_CLASS ;
case Steel_MaterialType :
return W_MATERIALSTEEL_CLASS ;
case Alabaster_MaterialType :
return W_MATERIALALABASTER_CLASS ;
case Granite_MaterialType :
return W_MATERIALGRANITE_CLASS ;
case Marble_MaterialType :
return W_MATERIALMARBLE_CLASS ;
case Obsidian_MaterialType :
return W_MATERIALOBSIDIAN_CLASS ;
case Sandstone_MaterialType :
return W_MATERIALSANDSTONE_CLASS ;
case Serpentine_MaterialType :
return W_MATERIALSERPENTINE_CLASS ;
case Ebony_MaterialType :
return W_MATERIALEBONY_CLASS ;
case Mahogany_MaterialType :
return W_MATERIALMAHOGANY_CLASS ;
case Oak_MaterialType :
return W_MATERIALOAK_CLASS ;
case Pine_MaterialType :
return W_MATERIALPINE_CLASS ;
case Teak_MaterialType :
return W_MATERIALTEAK_CLASS ;
default :
return 0 ;
}
}
struct SalvageInfo
{
int amount = 0 ;
int totalValue = 0 ;
int totalWorkmanship = 0 ;
2018-04-03 21:38:10 -04:00
//int itemsSalvagedCount = 0;
//Discrete/Continous vars into the structure of salvageMap
int itemsSalvagedCountCont = 0 ;
int itemsSalvagedCountDiscrete = 0 ;
2018-03-29 17:01:57 -04:00
} ;
void CPlayerWeenie : : PerformSalvaging ( DWORD toolId , PackableList < DWORD > items )
{
if ( items . empty ( ) )
return ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > pTool = g_pWorld - > FindObject ( toolId ) ;
2018-03-29 17:01:57 -04:00
if ( ! pTool )
return ;
2018-05-24 22:28:15 +01:00
if ( pTool - > GetWorldTopLevelOwner ( ) ! = GetPointer < CWeenieObject > ( ) )
2018-03-29 17:01:57 -04:00
{
NotifyWeenieError ( WERROR_SALVAGE_DONT_OWN_TOOL ) ;
return ;
}
2018-04-03 20:23:40 -04:00
//SALVAGING SKILL DETERMINES SALVAGE AMOUNT
2018-05-07 06:57:51 +00:00
DWORD salvagingSkillValue ;
InqSkill ( STypeSkill : : SALVAGING_SKILL , salvagingSkillValue , false ) ;
DWORD highestTinkeringSkillValue ;
DWORD tinkeringSkills [ 4 ] ;
InqSkill ( STypeSkill : : ARMOR_APPRAISAL_SKILL , tinkeringSkills [ 0 ] , false ) ;
InqSkill ( STypeSkill : : WEAPON_APPRAISAL_SKILL , tinkeringSkills [ 1 ] , false ) ;
InqSkill ( STypeSkill : : MAGIC_ITEM_APPRAISAL_SKILL , tinkeringSkills [ 2 ] , false ) ;
InqSkill ( STypeSkill : : ITEM_APPRAISAL_SKILL , tinkeringSkills [ 3 ] , false ) ;
highestTinkeringSkillValue = max ( max ( max ( tinkeringSkills [ 0 ] , tinkeringSkills [ 1 ] ) , tinkeringSkills [ 2 ] ) , tinkeringSkills [ 3 ] ) ;
2018-05-08 23:13:37 +00:00
int numAugs = max ( 0 , min ( 4 , InqIntQuality ( AUGMENTATION_BONUS_SALVAGE_INT , 0 ) ) ) ;
2018-03-29 17:01:57 -04:00
std : : map < MaterialType , SalvageInfo > salvageMap ;
2018-05-23 13:45:22 +01:00
std : : list < std : : shared_ptr < CWeenieObject > > itemsToDestroy ;
2018-03-29 17:01:57 -04:00
2018-05-05 22:13:16 +01:00
//Lists for the success message
PackableList < SalvageResult > salvageResults ;
PackableList < DWORD > notSalvagable ;
2018-03-29 17:01:57 -04:00
for ( auto itemId : items )
{
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > pItem = g_pWorld - > FindObject ( itemId ) ;
2018-03-29 17:01:57 -04:00
if ( ! pItem )
{
NotifyWeenieError ( WERROR_SALVAGE_INVALID_LOOT_LIST ) ;
return ;
}
2018-05-24 22:28:15 +01:00
if ( pItem - > GetWorldTopLevelOwner ( ) ! = GetPointer < CWeenieObject > ( ) )
2018-03-29 17:01:57 -04:00
{
NotifyWeenieError ( WERROR_SALVAGE_DONT_OWN_LOOT ) ;
2018-05-05 22:13:16 +01:00
notSalvagable . push_back ( pItem - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
continue ;
}
bool isRetained = pItem - > InqBoolQuality ( RETAINED_BOOL , FALSE ) ;
ITEM_TYPE itemType = ( ITEM_TYPE ) pItem - > InqIntQuality ( ITEM_TYPE_INT , 0 , TRUE ) ;
MaterialType material = ( MaterialType ) pItem - > InqIntQuality ( MATERIAL_TYPE_INT , 0 , TRUE ) ;
int workmanship = pItem - > InqIntQuality ( ITEM_WORKMANSHIP_INT , 0 , TRUE ) ;
int itemValue = pItem - > InqIntQuality ( VALUE_INT , 0 , TRUE ) ;
if ( workmanship < 1 | | material = = MaterialType : : Undef_MaterialType | | isRetained )
{
NotifyWeenieError ( WERROR_SALVAGE_NOT_SUITABLE ) ;
2018-05-05 22:13:16 +01:00
notSalvagable . push_back ( pItem - > GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
continue ;
}
itemsToDestroy . push_back ( pItem ) ;
2018-04-03 21:38:10 -04:00
/*keep Discrete and Continous .itemsSalvaged
Discrete for immediate calculations , Continous for reference sake and foolish number porn */
if ( itemType = = ITEM_TYPE : : TYPE_TINKERING_MATERIAL )
{
2018-03-29 17:01:57 -04:00
salvageMap [ material ] . amount + = pItem - > InqIntQuality ( STRUCTURE_INT , 1 ) ;
salvageMap [ material ] . totalValue + = itemValue ;
2018-04-03 21:38:10 -04:00
salvageMap [ material ] . itemsSalvagedCountCont + = pItem - > InqIntQuality ( NUM_ITEMS_IN_MATERIAL_INT , 1 ) ;
2018-04-04 10:27:02 -04:00
//salvageMap[material].itemsSalvagedCountDiscrete++;
2018-03-29 17:01:57 -04:00
}
else
{
2018-05-08 23:13:37 +00:00
int salvagingAmount = CalculateSalvageAmount ( salvagingSkillValue , workmanship , numAugs ) ;
2018-05-07 06:57:51 +00:00
// tinkering can at best return the workmanship as the amount
int tinkeringAmount = min ( CalculateSalvageAmount ( highestTinkeringSkillValue , workmanship , 0 ) , workmanship ) ;
// We choose the one that gives best results
int salvageAmount = max ( salvagingAmount , tinkeringAmount ) ;
// formula taken from http://asheron.wikia.com/wiki/Salvaging/Value_Pre2013
2018-05-15 00:14:44 +01:00
int salvageValue = itemValue * ( salvagingSkillValue / 387.0 ) * ( 1 + numAugs * 0.25 ) ;
2018-03-29 17:01:57 -04:00
salvageMap [ material ] . totalValue + = salvageValue ;
2018-04-03 21:38:10 -04:00
salvageMap [ material ] . amount + = salvageAmount ;
salvageMap [ material ] . itemsSalvagedCountCont + + ;
2018-03-29 17:01:57 -04:00
}
2018-04-03 21:38:10 -04:00
salvageMap [ material ] . totalWorkmanship + = workmanship ;
2018-03-29 17:01:57 -04:00
}
if ( itemsToDestroy . empty ( ) )
return ;
2018-05-07 06:57:51 +00:00
// Check if we have enough pack space first!
int numBags = 0 ;
for ( auto salvageEntry : salvageMap )
{
SalvageInfo salvageInfo = salvageEntry . second ;
numBags + = ceil ( salvageInfo . amount / 100.0 ) ;
}
if ( numBags > Container_GetNumFreeMainPackSlots ( ) )
{
SendText ( " Not enough pack space! " , LTT_ERROR ) ;
return ;
}
2018-03-29 17:01:57 -04:00
for ( auto item : itemsToDestroy )
item - > Remove ( ) ;
for ( auto salvageEntry : salvageMap )
{
MaterialType material = salvageEntry . first ;
SalvageInfo salvageInfo = salvageEntry . second ;
int valuePerUnit = salvageInfo . totalValue / salvageInfo . amount ;
2018-05-07 06:57:51 +00:00
2018-05-15 22:46:05 +01:00
double workmanship = salvageInfo . totalWorkmanship / ( double ) salvageInfo . itemsSalvagedCountCont ;
int fullBagItems = ceil ( salvageInfo . itemsSalvagedCountCont / ( salvageInfo . amount / 100.0 ) ) ;
2018-05-07 06:57:51 +00:00
2018-05-15 22:46:05 +01:00
int remainingAmount = salvageInfo . amount ;
int remainingItems = salvageInfo . itemsSalvagedCountCont ;
2018-05-07 06:57:51 +00:00
2018-05-15 22:46:05 +01:00
while ( remainingAmount > 0 )
2018-05-05 22:13:16 +01:00
{
2018-05-15 22:46:05 +01:00
int amount = min ( remainingAmount , 100 ) ;
int numItems = min ( max ( 1 , remainingItems ) , fullBagItems ) ;
SpawnSalvageBagInContainer ( material , amount , floor ( numItems * workmanship ) , min ( valuePerUnit * amount , 75000 ) , numItems ) ;
2018-05-05 22:13:16 +01:00
SalvageResult salvageResult ;
salvageResult . material = material ;
2018-05-15 22:46:05 +01:00
salvageResult . units = amount ;
salvageResult . workmanship = floor ( numItems * workmanship ) / ( double ) numItems ;
2018-05-05 22:13:16 +01:00
salvageResults . push_back ( salvageResult ) ;
2018-05-15 22:46:05 +01:00
remainingAmount - = 100 ;
remainingItems - = fullBagItems ;
}
2018-03-29 17:01:57 -04:00
}
2018-05-05 22:13:16 +01:00
BinaryWriter salvageMsg ;
salvageMsg . Write < DWORD > ( 0x02B4 ) ;
salvageMsg . Write < DWORD > ( 0x28 ) ; // SkillID: Salvaging
notSalvagable . Pack ( & salvageMsg ) ; // PackableList<ObjectID>
salvageResults . Pack ( & salvageMsg ) ; // PackableList<SalvageResult>
salvageMsg . Write < int > ( 0 ) ; // int: Aug bonus - not implemented?
SendNetMessage ( & salvageMsg , PRIVATE_MSG , TRUE , FALSE ) ;
2018-03-29 17:01:57 -04:00
}
2018-05-08 23:13:37 +00:00
// See http://web.archive.org/web/20170130213649/http://www.thejackcat.com/AC/Shopping/Crafts/Salvage_old.htm
// and http://web.archive.org/web/20170130194012/http://www.thejackcat.com/AC/Shopping/Crafts/Salvage.htm
2018-05-07 06:57:51 +00:00
int CPlayerWeenie : : CalculateSalvageAmount ( int salvagingSkill , int workmanship , int numAugs )
{
2018-05-16 22:30:21 +01:00
return 1 + floor ( salvagingSkill / 195.0 * workmanship * ( 1 + 0.25 * numAugs ) ) ;
2018-05-07 06:57:51 +00:00
}
2018-03-29 17:01:57 -04:00
bool CPlayerWeenie : : SpawnSalvageBagInContainer ( MaterialType material , int amount , int workmanship , int value , int numItems )
{
int salvageWcid = MaterialToSalvageBagId ( material ) ;
if ( salvageWcid = = 0 )
return false ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > weenie = g_pWeenieFactory - > CreateWeenieByClassID ( salvageWcid , NULL , false ) ;
2018-04-11 15:57:07 -05:00
weenie - > m_Qualities . SetString ( NAME_STRING , csprintf ( " Salvage (%s) " , FormatNumberString ( amount ) . c_str ( ) ) ) ; //modern client prepends the salvage type automatically so we need to adapt to this.
2018-03-29 17:01:57 -04:00
if ( ! weenie )
return false ;
weenie - > m_Qualities . SetInt ( ITEM_WORKMANSHIP_INT , workmanship ) ;
weenie - > m_Qualities . SetInt ( VALUE_INT , value ) ;
weenie - > m_Qualities . SetInt ( STRUCTURE_INT , amount ) ;
weenie - > m_Qualities . SetInt ( NUM_ITEMS_IN_MATERIAL_INT , numItems ) ;
2018-04-04 19:38:17 -04:00
//weenie->m_Qualities.SetFloat(SalvageWorkmanship, )
2018-03-29 17:01:57 -04:00
2018-04-04 10:27:02 -04:00
//Which one of these is Vtank missing to make it not calculate the real workmanship
2018-04-04 19:38:17 -04:00
//none. it has them all. where is SalvageWorkmanship double being calculated
//NumberItemsSalvagedFrom = 170, // 0x000000AA
//SalvageWorkmanship = 167772169, // 0x0A000009
// Divide SalvageWorkmanship by NumberItemsSalvagedFrom
2018-04-04 10:27:02 -04:00
2018-03-29 17:01:57 -04:00
return SpawnInContainer ( weenie ) ;
}
void CPlayerWeenie : : SetLoginPlayerQualities ( )
{
2018-04-03 21:16:39 -05:00
//Temporary as a way to fix existing characters
if ( m_Qualities . _skillStatsTable )
{
for ( PackableHashTableWithJson < STypeSkill , Skill > : : iterator entry = m_Qualities . _skillStatsTable - > begin ( ) ; entry ! = m_Qualities . _skillStatsTable - > end ( ) ; entry + + )
{
Skill skill = entry - > second ;
if ( skill . _sac = = SKILL_ADVANCEMENT_CLASS : : SPECIALIZED_SKILL_ADVANCEMENT_CLASS )
m_Qualities . SetSkillLevel ( entry - > first , 10 ) ;
else if ( skill . _sac = = SKILL_ADVANCEMENT_CLASS : : TRAINED_SKILL_ADVANCEMENT_CLASS )
m_Qualities . SetSkillLevel ( entry - > first , 5 ) ;
else
m_Qualities . SetSkillLevel ( entry - > first , 0 ) ;
}
}
//End of temporary code
2018-05-24 22:28:15 +01:00
g_pAllegianceManager - > SetWeenieAllegianceQualities ( GetPointer < CWeenieObject > ( ) ) ;
2018-03-29 17:01:57 -04:00
m_Qualities . SetFloat ( LOGIN_TIMESTAMP_FLOAT , Timer : : cur_time ) ;
// Position startPos = Position(0xDB75003B, Vector(186.000000f, 65.000000f, 36.088333f), Quaternion(1.000000, 0.000000, 0.000000, 0.000000));
// Position startPos = Position(0xA9B4001F, Vector(87.750603f, 147.722321f, 66.005005f), Quaternion(0.011819f, 0.000000, 0.000000, -0.999930f));
2018-04-08 10:04:54 -04:00
2018-03-29 17:01:57 -04:00
// Your location is: 0xC98C0028 [113.665604 190.259003 22.004999] -0.707107 0.000000 0.000000 -0.707107 Rithwic
// Position startPos = Position(0xC98C0028, Vector(113.665604f, 190.259003f, 22.004999f), Quaternion(-0.707107f, 0.000000, 0.000000, -0.707107f));
// SetInitialPosition(startPos);
// m_Qualities.SetPosition(SANCTUARY_POSITION, startPos);
extern bool g_bStartOverride ;
extern Position g_StartPosition ;
if ( g_bStartOverride )
{
SetInitialPosition ( g_StartPosition ) ;
m_Qualities . SetPosition ( SANCTUARY_POSITION , g_StartPosition ) ;
}
// should never be in a fellowship when logging in, but let's be sure
m_Qualities . RemoveString ( FELLOWSHIP_STRING ) ;
m_Qualities . SetInt ( ARMOR_LEVEL_INT , 0 ) ;
m_Qualities . SetInt ( PHYSICS_STATE_INT , PhysicsState : : HIDDEN_PS | PhysicsState : : IGNORE_COLLISIONS_PS | PhysicsState : : EDGE_SLIDE_PS | PhysicsState : : GRAVITY_PS ) ;
m_Qualities . SetBool ( ROT_PROOF_BOOL , FALSE ) ;
m_Qualities . RemoveInt ( RADARBLIP_COLOR_INT ) ;
if ( atoi ( g_pConfig - > GetValue ( " player_killer_only " , " 0 " ) ) ! = 0 )
{
double pkTimestamp ;
if ( ! m_Qualities . InqFloat ( PK_TIMESTAMP_FLOAT , pkTimestamp , TRUE ) )
{
m_Qualities . SetInt ( PLAYER_KILLER_STATUS_INT , PK_PKStatus ) ;
}
}
if ( IsAdvocate ( ) )
{
m_Qualities . SetBool ( IS_ADVOCATE_BOOL , TRUE ) ;
m_Qualities . SetBool ( ADVOCATE_STATE_BOOL , TRUE ) ;
}
else
{
m_Qualities . RemoveBool ( IS_ADVOCATE_BOOL ) ;
m_Qualities . RemoveBool ( ADVOCATE_STATE_BOOL ) ;
}
if ( IsSentinel ( ) )
{
m_Qualities . SetBool ( IS_SENTINEL_BOOL , TRUE ) ;
}
else
{
m_Qualities . RemoveBool ( IS_SENTINEL_BOOL ) ;
}
if ( IsAdmin ( ) )
{
m_Qualities . SetBool ( IS_ADMIN_BOOL , TRUE ) ;
m_Qualities . SetBool ( IS_ARCH_BOOL , TRUE ) ;
m_Qualities . SetBool ( SPELL_COMPONENTS_REQUIRED_BOOL , FALSE ) ;
m_Qualities . SetInt ( BONDED_INT , 1 ) ; //do not drop items on death
}
else
{
m_Qualities . RemoveBool ( IS_ADMIN_BOOL ) ;
m_Qualities . RemoveBool ( IS_ARCH_BOOL ) ;
m_Qualities . SetBool ( SPELL_COMPONENTS_REQUIRED_BOOL , TRUE ) ;
m_Qualities . SetInt ( BONDED_INT , 0 ) ; //drop items on death
}
for ( auto wielded : m_Wielded )
{
2018-06-21 23:32:21 +01:00
std : : shared_ptr < CWeenieObject > pItem = wielded . lock ( ) ;
if ( ! pItem )
{
continue ;
}
if ( pItem - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 , true ) > 0 )
2018-03-29 17:01:57 -04:00
{
double manaRate = 0.0f ;
2018-06-21 23:32:21 +01:00
if ( pItem - > m_Qualities . InqFloat ( MANA_RATE_FLOAT , manaRate , TRUE ) & & manaRate ! = 0.0 )
pItem - > _nextManaUse = Timer : : cur_time + ( - manaRate * 1000 ) ;
2018-03-29 17:01:57 -04:00
}
}
if ( ! InqBoolQuality ( FIRST_ENTER_WORLD_DONE_BOOL , FALSE ) )
{
for ( auto item : m_Items )
{
2018-06-21 23:32:21 +01:00
std : : shared_ptr < CWeenieObject > pItem = item . lock ( ) ;
if ( ! pItem )
2018-03-29 17:01:57 -04:00
{
2018-06-21 23:32:21 +01:00
continue ;
}
if ( pItem - > m_Qualities . id = = W_TUTORIALBOOK_CLASS )
{
pItem - > Use ( AsPlayer ( ) ) ;
2018-03-29 17:01:57 -04:00
break ;
}
}
m_Qualities . SetBool ( FIRST_ENTER_WORLD_DONE_BOOL , TRUE ) ;
}
//check if we still own our house.
if ( DWORD houseId = InqDIDQuality ( HOUSEID_DID , 0 ) )
{
CHouseData * houseData = g_pHouseManager - > GetHouseData ( houseId ) ;
if ( houseData - > _ownerId ! = GetID ( ) )
m_Qualities . SetDataID ( HOUSEID_DID , 0 ) ;
}
}
void CPlayerWeenie : : HandleItemManaRequest ( DWORD itemId )
{
if ( ! itemId )
return ;
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > item = FindValidNearbyItem ( itemId , 60 ) ;
2018-03-29 17:01:57 -04:00
if ( ! item )
return ;
m_pClient - > SendNetMessage ( ItemManaUpdate ( item ) , PRIVATE_MSG , TRUE , TRUE ) ;
}
void CPlayerWeenie : : UpdateModuleFromClient ( PlayerModule & module )
{
bool bOldShowHelm = ShowHelm ( ) ;
_playerModule = module ;
if ( bOldShowHelm ! = ShowHelm ( ) )
{
UpdateModel ( ) ;
}
}
void CPlayerWeenie : : LoadEx ( CWeenieSave & save )
{
CContainerWeenie : : LoadEx ( save ) ;
if ( save . _playerModule )
_playerModule = * save . _playerModule ;
if ( save . _questTable )
_questTable = * save . _questTable ;
CheckVitalRanges ( ) ;
}
void CPlayerWeenie : : SaveEx ( CWeenieSave & save )
{
DebugValidate ( ) ;
CContainerWeenie : : SaveEx ( save ) ;
SafeDelete ( save . _playerModule ) ;
save . _playerModule = new PlayerModule ;
* save . _playerModule = _playerModule ;
SafeDelete ( save . _questTable ) ;
save . _questTable = new QuestTable ;
* save . _questTable = _questTable ;
}
bool CPlayerWeenie : : ShowHelm ( )
{
if ( _playerModule . options2_ & ShowHelm_CharacterOptions2 )
return true ;
return false ;
}
bool CPlayerWeenie : : InqQuest ( const char * questName )
{
return _questTable . InqQuest ( questName ) ;
}
int CPlayerWeenie : : InqTimeUntilOkayToComplete ( const char * questName )
{
return _questTable . InqTimeUntilOkayToComplete ( questName ) ;
}
unsigned int CPlayerWeenie : : InqQuestSolves ( const char * questName )
{
return _questTable . InqQuestSolves ( questName ) ;
}
bool CPlayerWeenie : : UpdateQuest ( const char * questName )
{
return _questTable . UpdateQuest ( questName ) ;
}
void CPlayerWeenie : : StampQuest ( const char * questName )
{
_questTable . StampQuest ( questName ) ;
}
void CPlayerWeenie : : IncrementQuest ( const char * questName )
{
_questTable . IncrementQuest ( questName ) ;
}
void CPlayerWeenie : : DecrementQuest ( const char * questName )
{
_questTable . DecrementQuest ( questName ) ;
}
void CPlayerWeenie : : EraseQuest ( const char * questName )
{
_questTable . RemoveQuest ( questName ) ;
}
CWandSpellUseEvent : : CWandSpellUseEvent ( DWORD wandId , DWORD targetId )
{
_wandId = wandId ;
_targetId = targetId ;
}
void CWandSpellUseEvent : : OnReadyToUse ( )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > wand = g_pWorld - > FindObject ( _wandId ) ;
2018-03-29 17:01:57 -04:00
if ( ! wand )
{
Cancel ( ) ;
return ;
}
_spellId = wand - > InqDIDQuality ( SPELL_DID , 0 ) ;
2018-04-08 10:04:54 -04:00
if ( ! _spellId )
2018-03-29 17:01:57 -04:00
{
Cancel ( ) ;
return ;
}
STypeSkill skill = ( STypeSkill ) wand - > InqDIDQuality ( ITEM_SKILL_LIMIT_DID , 0 ) ;
DWORD skillValue ;
2018-05-31 18:00:27 +01:00
if ( skill ! = 0 & & pWeenie - > InqSkill ( skill , skillValue , false ) )
2018-03-29 17:01:57 -04:00
{
2018-04-08 10:04:54 -04:00
if ( skillValue < wand - > InqIntQuality ( ITEM_SKILL_LEVEL_LIMIT_INT , 0 ) )
2018-03-29 17:01:57 -04:00
{
SkillTable * pSkillTable = SkillSystem : : GetSkillTable ( ) ;
const SkillBase * pSkillBase = pSkillTable - > GetSkillBase ( skill ) ;
if ( pSkillBase ! = NULL )
2018-05-31 18:00:27 +01:00
pWeenie - > NotifyWeenieErrorWithString ( WERROR_ACTIVATION_SKILL_TOO_LOW , pSkillBase - > _name . c_str ( ) ) ;
2018-03-29 17:01:57 -04:00
Cancel ( ) ;
return ;
}
}
DWORD motion = wand - > InqDIDQuality ( USE_USER_ANIMATION_DID , 0 ) ;
int manaCost = wand - > InqIntQuality ( ITEM_MANA_COST_INT , 0 ) ;
if ( manaCost > 0 )
{
CSpellTable * pSpellTable = MagicSystem : : GetSpellTable ( ) ;
if ( ! pSpellTable )
{
Cancel ( ) ;
return ;
}
const CSpellBase * spell = pSpellTable - > GetSpellBase ( _spellId ) ;
if ( ! spell )
{
Cancel ( ) ;
return ;
}
2018-05-31 18:00:27 +01:00
DWORD manaConvSkill = pWeenie - > GetEffectiveManaConversionSkill ( ) ;
2018-03-29 17:01:57 -04:00
int spellCraft = wand - > InqIntQuality ( ITEM_SPELLCRAFT_INT , 0 ) ;
manaCost = GetManaCost ( spellCraft , spell - > _power , manaCost , manaConvSkill ) ;
int itemCurrentMana = wand - > InqIntQuality ( ITEM_CUR_MANA_INT , 0 ) ;
if ( manaCost > itemCurrentMana )
{
Cancel ( WERROR_ACTIVATION_NOT_ENOUGH_MANA ) ;
return ;
}
_newManaValue = itemCurrentMana - manaCost ;
}
2018-05-31 18:00:27 +01:00
pWeenie - > MakeSpellcastingManager ( ) - > m_bCasting = true ;
2018-04-08 10:04:54 -04:00
2018-03-29 17:01:57 -04:00
if ( motion )
ExecuteUseAnimation ( motion ) ;
else
OnUseAnimSuccess ( motion ) ;
}
void CWandSpellUseEvent : : OnUseAnimSuccess ( DWORD motion )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
2018-03-29 17:01:57 -04:00
if ( _newManaValue ! = - 1 )
{
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > wand = g_pWorld - > FindObject ( _wandId ) ;
2018-03-29 17:01:57 -04:00
if ( ! wand )
{
Cancel ( ) ;
return ;
}
wand - > m_Qualities . SetInt ( ITEM_CUR_MANA_INT , _newManaValue ) ;
wand - > NotifyIntStatUpdated ( ITEM_CUR_MANA_INT , false ) ;
}
2018-05-31 18:00:27 +01:00
pWeenie - > MakeSpellcastingManager ( ) - > CastSpellInstant ( _targetId , _spellId ) ;
pWeenie - > DoForcedStopCompletely ( ) ;
2018-03-29 17:01:57 -04:00
Done ( ) ;
}
2018-04-08 10:04:54 -04:00
void CWandSpellUseEvent : : Cancel ( DWORD error )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > MakeSpellcastingManager ( ) - > m_bCasting = false ;
2018-04-08 10:04:54 -04:00
CUseEventData : : Cancel ( error ) ;
}
void CWandSpellUseEvent : : Done ( DWORD error )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > MakeSpellcastingManager ( ) - > m_bCasting = false ;
2018-04-08 10:04:54 -04:00
CUseEventData : : Done ( error ) ;
}
2018-03-29 17:01:57 -04:00
void CLifestoneRecallUseEvent : : OnReadyToUse ( )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > ChangeCombatMode ( NONCOMBAT_COMBAT_MODE , false ) ;
2018-03-29 17:01:57 -04:00
ExecuteUseAnimation ( Motion_LifestoneRecall ) ;
2018-05-31 18:00:27 +01:00
pWeenie - > SendText ( csprintf ( " %s is recalling to the lifestone. " , pWeenie - > GetName ( ) . c_str ( ) ) , LTT_RECALL ) ;
2018-03-29 17:01:57 -04:00
}
void CLifestoneRecallUseEvent : : OnUseAnimSuccess ( DWORD motion )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > TeleportToLifestone ( ) ;
2018-03-29 17:01:57 -04:00
Done ( ) ;
}
void CHouseRecallUseEvent : : OnReadyToUse ( )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > ChangeCombatMode ( NONCOMBAT_COMBAT_MODE , false ) ;
2018-03-29 17:01:57 -04:00
ExecuteUseAnimation ( Motion_HouseRecall ) ;
2018-05-31 18:00:27 +01:00
pWeenie - > SendText ( csprintf ( " %s is recalling home. " , pWeenie - > GetName ( ) . c_str ( ) ) , LTT_RECALL ) ;
2018-03-29 17:01:57 -04:00
}
void CHouseRecallUseEvent : : OnUseAnimSuccess ( DWORD motion )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > TeleportToHouse ( ) ;
2018-03-29 17:01:57 -04:00
Done ( ) ;
}
void CMansionRecallUseEvent : : OnReadyToUse ( )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > ChangeCombatMode ( NONCOMBAT_COMBAT_MODE , false ) ;
2018-03-29 17:01:57 -04:00
ExecuteUseAnimation ( Motion_HouseRecall ) ;
2018-05-31 18:00:27 +01:00
pWeenie - > SendText ( csprintf ( " %s is recalling to the Allegiance housing. " , pWeenie - > GetName ( ) . c_str ( ) ) , LTT_RECALL ) ;
2018-03-29 17:01:57 -04:00
}
void CMansionRecallUseEvent : : OnUseAnimSuccess ( DWORD motion )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > TeleportToMansion ( ) ;
2018-03-29 17:01:57 -04:00
Done ( ) ;
}
void CMarketplaceRecallUseEvent : : OnReadyToUse ( )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > ChangeCombatMode ( NONCOMBAT_COMBAT_MODE , false ) ;
2018-03-29 17:01:57 -04:00
ExecuteUseAnimation ( Motion_MarketplaceRecall ) ;
2018-05-31 18:00:27 +01:00
pWeenie - > SendText ( csprintf ( " %s is going to the Marketplace. " , pWeenie - > GetName ( ) . c_str ( ) ) , LTT_RECALL ) ;
2018-03-29 17:01:57 -04:00
}
void CMarketplaceRecallUseEvent : : OnUseAnimSuccess ( DWORD motion )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
if ( pWeenie - > IsDead ( ) | | pWeenie - > IsInPortalSpace ( ) )
2018-03-29 17:01:57 -04:00
{
Cancel ( ) ;
return ;
}
2018-05-31 18:00:27 +01:00
pWeenie - > Movement_Teleport ( Position ( 0x016C01BC , Vector ( 49.11f , - 31.22f , 0.005f ) , Quaternion ( 0.7009f , 0 , 0 , - 0.7132f ) ) ) ;
2018-03-29 17:01:57 -04:00
Done ( ) ;
}
void CAllegianceHometownRecallUseEvent : : OnReadyToUse ( )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > ChangeCombatMode ( NONCOMBAT_COMBAT_MODE , false ) ;
2018-03-29 17:01:57 -04:00
ExecuteUseAnimation ( Motion_AllegianceHometownRecall ) ;
2018-05-31 18:00:27 +01:00
pWeenie - > SendText ( csprintf ( " %s is going to the Allegiance hometown. " , pWeenie - > GetName ( ) . c_str ( ) ) , LTT_RECALL ) ;
2018-03-29 17:01:57 -04:00
}
void CAllegianceHometownRecallUseEvent : : OnUseAnimSuccess ( DWORD motion )
{
2018-05-31 18:00:27 +01:00
std : : shared_ptr < CWeenieObject > pWeenie = _weenie . lock ( ) ;
if ( ! pWeenie )
{
return ;
}
pWeenie - > TeleportToAllegianceHometown ( ) ;
2018-03-29 17:01:57 -04:00
Done ( ) ;
}
void CPlayerWeenie : : BeginRecall ( const Position & targetPos )
{
EmitEffect ( PS_Hide , 1.0f ) ;
_recallTime = Timer : : cur_time + 2.0 ;
_recallPos = targetPos ;
}
void CPlayerWeenie : : OnTeleported ( )
{
CWeenieObject : : OnTeleported ( ) ;
_recallTime = - 1.0 ; // cancel any teleport
}
DWORD CPlayerWeenie : : GetAccountHouseId ( )
{
2018-05-01 01:56:48 -05:00
2018-03-29 17:01:57 -04:00
for ( auto & character : GetClient ( ) - > GetCharacters ( ) )
{
2018-05-01 01:56:48 -05:00
if ( character . weenie_id = = id )
2018-03-29 17:01:57 -04:00
{
if ( DWORD houseID = InqDIDQuality ( HOUSEID_DID , 0 ) )
return houseID ;
}
else
{
2018-05-23 13:45:22 +01:00
std : : shared_ptr < CWeenieObject > otherCharacter = CWeenieObject : : Load ( character . weenie_id ) ;
2018-03-29 17:01:57 -04:00
if ( DWORD houseID = otherCharacter - > InqDIDQuality ( HOUSEID_DID , 0 ) )
{
return houseID ;
}
}
}
return 0 ;
}
2018-05-10 21:07:44 +00:00
TradeManager * CPlayerWeenie : : GetTradeManager ( )
{
return m_pTradeManager ;
}
void CPlayerWeenie : : SetTradeManager ( TradeManager * tradeManager )
{
m_pTradeManager = tradeManager ;
}
2018-05-23 13:45:22 +01:00
void CPlayerWeenie : : ReleaseContainedItemRecursive ( std : : shared_ptr < CWeenieObject > item )
2018-05-10 21:07:44 +00:00
{
CContainerWeenie : : ReleaseContainedItemRecursive ( item ) ;
}
void CPlayerWeenie : : ChangeCombatMode ( COMBAT_MODE mode , bool playerRequested )
{
CMonsterWeenie : : ChangeCombatMode ( mode , playerRequested ) ;
if ( m_pTradeManager & & mode ! = NONCOMBAT_COMBAT_MODE )
{
2018-05-23 13:45:22 +01:00
m_pTradeManager - > CloseTrade ( AsPlayer ( ) , 2 ) ; // EnteredCombat
2018-05-10 21:07:44 +00:00
}
}
2018-06-21 23:32:21 +01:00
void CPlayerWeenie : : MarkForDestroy ( )
{
m_dDestroyTime = Timer : : cur_time + 2 ; // give some time to wrap up
}