2019-07-07 20:56:15 +00:00
# include <StdAfx.h>
2018-03-29 17:01:57 -04:00
# include "WeenieObject.h"
2019-07-30 02:19:05 +00:00
# include "AllegianceManager.h"
2018-03-29 17:01:57 -04:00
# include "Monster.h"
# include "World.h"
# include "GameMode.h"
# include "Lifestone.h"
# include "ChatMsgs.h"
# include "SpellProjectile.h"
# include "MonsterAI.h"
# include "WeenieFactory.h"
# include "InferredPortalData.h"
# include "ObjectMsgs.h"
# include "EmoteManager.h"
# include "Corpse.h"
# include "AttackManager.h"
# include "WClassID.h"
# include "InferredPortalData.h"
# include "Config.h"
# include "DatabaseIO.h"
# include "InferredPortalData.h"
# include "SpellTableExtendedData.h"
# include "Door.h"
# include "Player.h"
# include "House.h"
2019-10-06 08:35:22 -07:00
# include <chrono>
2018-03-29 17:01:57 -04:00
CMonsterWeenie : : CMonsterWeenie ( )
{
SetItemType ( TYPE_CREATURE ) ;
m_Qualities . SetInt ( LEVEL_INT , 1 ) ;
m_Qualities . SetAttribute ( STRENGTH_ATTRIBUTE , 100 ) ;
m_Qualities . SetAttribute ( ENDURANCE_ATTRIBUTE , 100 ) ;
m_Qualities . SetAttribute ( COORDINATION_ATTRIBUTE , 100 ) ;
m_Qualities . SetAttribute ( QUICKNESS_ATTRIBUTE , 100 ) ;
m_Qualities . SetAttribute ( FOCUS_ATTRIBUTE , 100 ) ;
m_Qualities . SetAttribute ( SELF_ATTRIBUTE , 100 ) ;
m_Qualities . SetAttribute2nd ( MAX_HEALTH_ATTRIBUTE_2ND , 0 ) ;
m_Qualities . SetAttribute2nd ( HEALTH_ATTRIBUTE_2ND , 50 ) ;
m_Qualities . SetAttribute2nd ( MAX_STAMINA_ATTRIBUTE_2ND , 0 ) ;
m_Qualities . SetAttribute2nd ( STAMINA_ATTRIBUTE_2ND , 100 ) ;
m_Qualities . SetAttribute2nd ( MAX_MANA_ATTRIBUTE_2ND , 0 ) ;
m_Qualities . SetAttribute2nd ( MANA_ATTRIBUTE_2ND , 100 ) ;
m_Qualities . SetInt ( SHOWABLE_ON_RADAR_INT , ShowAlways_RadarEnum ) ;
m_Qualities . SetBool ( STUCK_BOOL , TRUE ) ;
m_Qualities . SetBool ( ATTACKABLE_BOOL , TRUE ) ;
m_Qualities . SetInt ( ITEM_USEABLE_INT , USEABLE_NO ) ;
2019-07-11 09:35:09 -07:00
m_Qualities . SetFloat ( HEARTBEAT_INTERVAL_FLOAT , DEFAULT_HEARTBEAT_INTERVAL ) ;
_nextHeartBeat = Timer : : cur_time + DEFAULT_HEARTBEAT_INTERVAL ;
2018-03-29 17:01:57 -04:00
}
CMonsterWeenie : : ~ CMonsterWeenie ( )
{
SafeDelete ( m_MonsterAI ) ;
}
void CMonsterWeenie : : ApplyQualityOverrides ( )
{
2018-11-30 15:22:40 -06:00
int group = 1 ;
int gender = 1 ;
2018-11-30 15:53:57 -06:00
2019-01-25 17:10:21 -06:00
if ( ! m_Qualities . InqInt ( HERITAGE_GROUP_INT , group ) )
{
int species = 0 ;
if ( m_Qualities . InqInt ( CREATURE_TYPE_INT , species ) & & species = = CreatureType : : human )
{
group = Random : : GenInt ( 1 , 4 ) ;
2020-09-27 15:36:43 +00:00
m_Qualities . SetInt ( HERITAGE_GROUP_INT , group ) ;
2019-01-25 17:10:21 -06:00
}
else
return ;
}
if ( ! m_Qualities . InqInt ( GENDER_INT , gender ) )
{
std : : string sex ;
if ( ! m_Qualities . InqString ( SEX_STRING , sex ) )
return ;
if ( sex = = " Male " ) gender = 1 ;
else if ( sex = = " Female " ) gender = 2 ;
m_Qualities . SetInt ( GENDER_INT , gender ) ;
}
2018-11-30 15:22:40 -06:00
HeritageGroup_CG * heritage = CachedCharGenData - > mHeritageGroupList . lookup ( group ) ;
Sex_CG * sex = heritage - > mGenderList . lookup ( gender ) ;
2019-07-07 20:56:15 +00:00
uint32_t tmp = 0 ;
uint32_t tmp_default = 0 ;
2018-11-30 15:22:40 -06:00
int max = 0 ;
int idx = 0 ;
ObjDesc * desc = nullptr ;
HairStyle_CG * hair = nullptr ;
// hair/head
if ( m_Qualities . InqDataID ( HEAD_OBJECT_DID , tmp ) )
{
2019-01-04 15:55:47 -06:00
hair = sex - > FindHairStyle ( tmp ) ;
2018-11-30 15:22:40 -06:00
}
else
{
max = sex - > mHairStyleList . num_used / 2 ;
idx = Random : : GenInt ( 0 , max ) ;
hair = & ( sex - > mHairStyleList . array_data [ idx ] ) ;
2019-02-26 13:23:25 -08:00
AnimPartChange * change = hair - > objDesc . GetAnimPartChange ( Head ) ;
2019-01-25 17:10:21 -06:00
if ( change )
m_Qualities . SetDataID ( HEAD_OBJECT_DID , change - > part_id ) ;
2018-11-30 15:22:40 -06:00
}
// eyes
if ( ! m_Qualities . InqDataID ( DEFAULT_EYES_TEXTURE_DID , tmp_default ) )
{
max = sex - > mEyeStripList . num_used / 2 ;
idx = Random : : GenInt ( 0 , max ) ;
EyesStrip_CG * eyes = & ( sex - > mEyeStripList . array_data [ idx ] ) ;
desc = hair - > bald ? & eyes - > objDesc_Bald : & eyes - > objDesc ;
if ( desc - > firstTMChange )
{
m_Qualities . SetDataID ( DEFAULT_EYES_TEXTURE_DID , desc - > firstTMChange - > old_tex_id ) ;
m_Qualities . SetDataID ( EYES_TEXTURE_DID , desc - > firstTMChange - > new_tex_id ) ;
}
2019-12-19 16:07:24 -05:00
2018-11-30 15:22:40 -06:00
//if (desc->paletteID)
//{
//
//}
}
// nose
if ( ! m_Qualities . InqDataID ( DEFAULT_NOSE_TEXTURE_DID , tmp_default ) )
{
max = sex - > mNoseStripList . num_used / 2 ;
idx = Random : : GenInt ( 0 , max ) ;
FaceStrip_CG * nose = & ( sex - > mNoseStripList . array_data [ idx ] ) ;
desc = & nose - > objDesc ;
if ( desc - > firstTMChange )
{
m_Qualities . SetDataID ( DEFAULT_NOSE_TEXTURE_DID , desc - > firstTMChange - > old_tex_id ) ;
m_Qualities . SetDataID ( NOSE_TEXTURE_DID , desc - > firstTMChange - > new_tex_id ) ;
}
}
// mouth
if ( ! m_Qualities . InqDataID ( DEFAULT_MOUTH_TEXTURE_DID , tmp_default ) )
{
max = sex - > mMouthStripList . num_used / 2 ;
idx = Random : : GenInt ( 0 , max ) ;
FaceStrip_CG * mouth = & ( sex - > mMouthStripList . array_data [ idx ] ) ;
desc = & mouth - > objDesc ;
if ( desc - > firstTMChange )
{
m_Qualities . SetDataID ( DEFAULT_MOUTH_TEXTURE_DID , desc - > firstTMChange - > old_tex_id ) ;
m_Qualities . SetDataID ( MOUTH_TEXTURE_DID , desc - > firstTMChange - > new_tex_id ) ;
}
}
2019-07-07 20:56:15 +00:00
//uint32_t skin_palette_id;
2018-11-30 15:22:40 -06:00
//if (m_Qualities.InqDataID(SKIN_PALETTE_DID, skin_palette_id))
// objDesc.AddSubpalette(new Subpalette(skin_palette_id, 0 << 3, 0x18 << 3));
2019-07-07 20:56:15 +00:00
//uint32_t hair_palette_id;
2018-11-30 15:22:40 -06:00
//if (m_Qualities.InqDataID(HAIR_PALETTE_DID, hair_palette_id))
// objDesc.AddSubpalette(new Subpalette(hair_palette_id, 0x18 << 3, 0x8 << 3));
2019-07-07 20:56:15 +00:00
//uint32_t eye_palette_id;
2018-11-30 15:22:40 -06:00
//if (m_Qualities.InqDataID(EYES_PALETTE_DID, eye_palette_id))
// objDesc.AddSubpalette(new Subpalette(eye_palette_id, 0x20 << 3, 0x8 << 3));
2018-03-29 17:01:57 -04:00
}
void CMonsterWeenie : : PreSpawnCreate ( )
{
if ( m_Qualities . _create_list )
2018-07-12 14:41:21 -07:00
g_pWeenieFactory - > AddFromCreateList ( this , m_Qualities . _create_list , ( DestinationType ) ( Wield_DestinationType | WieldTreasure_DestinationType ) ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
if ( uint32_t wieldedTreasureType = InqDIDQuality ( WIELDED_TREASURE_TYPE_DID , 0 ) )
2018-07-12 14:41:21 -07:00
g_pWeenieFactory - > GenerateFromTypeOrWcid ( this , DestinationType : : WieldTreasure_DestinationType , wieldedTreasureType ) ;
2018-08-24 16:16:12 -05:00
if ( m_Qualities . GetDID ( PHYSICS_SCRIPT_DID , 0 ) )
{
// Add one here or else the wrong script will play. e.g. Frost Breath for Olthoi and Sewer Rats instead of Acid Breath.
2019-04-13 18:19:31 +00:00
m_DefaultScript = m_Qualities . GetDID ( PHYSICS_SCRIPT_DID , 0 ) ;
2018-08-24 16:16:12 -05:00
m_DefaultScriptIntensity = m_Qualities . GetFloat ( PHYSICS_SCRIPT_INTENSITY_FLOAT , 1.0 ) ;
}
2018-03-29 17:01:57 -04:00
}
void CMonsterWeenie : : PostSpawn ( )
{
CWeenieObject : : PostSpawn ( ) ;
// check if we need to create a monster AI
if ( IsCreature ( ) & & ! AsPlayer ( ) & & ! IsVendor ( ) & & m_Qualities . GetInt ( PLAYER_KILLER_STATUS_INT , 0 ) ! = RubberGlue_PKStatus )
{
2018-07-12 14:41:21 -07:00
m_MonsterAI = new MonsterAIManager ( this , m_Position ) ;
2018-03-29 17:01:57 -04:00
}
if ( ! _IsPlayer ( ) )
{
EmitEffect ( PS_Create , 1.0f ) ;
}
}
2019-07-07 20:56:15 +00:00
CWeenieObject * CMonsterWeenie : : SpawnWielded ( uint32_t index , SmartArray < Style_CG > possibleStyles , uint32_t color , SmartArray < uint32_t > validColors , double shade )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
index = max ( min ( index , ( uint32_t ) possibleStyles . num_used - 1 ) , ( uint32_t ) 0 ) ;
shade = max ( min ( shade , 1.0 ) , 0.0 ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t wcid = possibleStyles . array_data [ index ] . weenieDefault ;
uint32_t clothingTable = possibleStyles . array_data [ index ] . clothingTable ;
2018-03-29 17:01:57 -04:00
bool validColor = false ;
for ( int i = 0 ; i < validColors . num_used ; i + + )
{
if ( color = = validColors . array_data [ i ] )
{
validColor = true ;
break ;
}
}
if ( ! validColor )
color = validColors . array_data [ 0 ] ;
2018-07-12 14:41:21 -07:00
CWeenieObject * weenie = SpawnWielded ( wcid , color , shade ) ;
2018-03-29 17:01:57 -04:00
weenie - > m_Qualities . SetDataID ( CLOTHINGBASE_DID , clothingTable ) ;
return weenie ;
}
2019-07-07 20:56:15 +00:00
CWeenieObject * CMonsterWeenie : : SpawnWielded ( uint32_t wcid , int ptid , float shade )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * item = g_pWeenieFactory - > CreateWeenieByClassID ( wcid , NULL , false ) ;
2018-03-29 17:01:57 -04:00
if ( ptid )
item - > m_Qualities . SetInt ( PALETTE_TEMPLATE_INT , ptid ) ;
if ( shade > 0.0 )
item - > m_Qualities . SetFloat ( SHADE_FLOAT , shade ) ;
return SpawnWielded ( item ) ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * CMonsterWeenie : : SpawnWielded ( CWeenieObject * item , bool deleteItemOnFailure )
2018-03-29 17:01:57 -04:00
{
if ( ! item )
return NULL ;
if ( ! item - > IsEquippable ( ) )
{
LOG_PRIVATE ( Temp , Warning , " Trying to SpawnWielded an unwieldable item %u \n " , item - > m_Qualities . id ) ;
2018-07-12 14:41:21 -07:00
delete item ;
2018-03-29 17:01:57 -04:00
return NULL ;
}
2018-11-09 13:39:05 -06:00
item - > SetID ( g_pWorld - > GenerateGUID ( m_Qualities . GetInt ( HERITAGE_GROUP_INT , 0 ) = = 0 ? eEphemeral : eDynamicGUID ) ) ;
2018-03-29 17:01:57 -04:00
if ( ! g_pWorld - > CreateEntity ( item , false ) )
{
2020-03-21 09:23:59 -07:00
//delete item;
2018-03-29 17:01:57 -04:00
return NULL ;
}
if ( ! FinishMoveItemToWield ( item , item - > m_Qualities . GetInt ( LOCATIONS_INT , 0 ) ) )
{
g_pWorld - > RemoveEntity ( item ) ;
item = NULL ;
}
return item ;
}
2019-07-07 20:56:15 +00:00
CWeenieObject * CMonsterWeenie : : FindValidNearbyItem ( uint32_t itemId , float maxDistance )
2018-03-29 17:01:57 -04:00
{
//do we have it?
2018-07-12 14:41:21 -07:00
CWeenieObject * item = FindContainedItem ( itemId ) ;
2018-03-29 17:01:57 -04:00
if ( ! item )
{
// maybe it's in an external container
if ( _lastOpenedRemoteContainerId ! = 0 )
{
2018-07-12 14:41:21 -07:00
CContainerWeenie * externalContainer = FindContainer ( _lastOpenedRemoteContainerId ) ;
2018-03-29 17:01:57 -04:00
if ( externalContainer & & externalContainer - > _openedById = = GetID ( ) )
{
item = externalContainer - > FindContainedItem ( itemId ) ;
}
}
if ( ! item )
{
// maybe it's on the ground
2018-09-29 11:05:26 -07:00
item = g_pWorld - > FindObject ( itemId , false , true ) ;
2018-03-29 17:01:57 -04:00
if ( ! item | | item - > HasOwner ( ) | | ! item - > InValidCell ( ) )
{
NotifyInventoryFailedEvent ( itemId , WERROR_OBJECT_GONE ) ;
return NULL ;
}
if ( DistanceTo ( item , true ) > maxDistance )
{
NotifyInventoryFailedEvent ( itemId , WERROR_TOO_FAR ) ;
return NULL ; ;
}
}
}
if ( ! item - > CanPickup ( ) )
{
NotifyInventoryFailedEvent ( itemId , WERROR_NONE ) ;
return NULL ;
}
return item ;
}
2019-07-07 20:56:15 +00:00
CContainerWeenie * CMonsterWeenie : : FindValidNearbyContainer ( uint32_t containerId , float maxDistance )
2018-03-29 17:01:57 -04:00
{
//do we have it?
2018-07-12 14:41:21 -07:00
CContainerWeenie * container = FindContainer ( containerId ) ;
2018-03-29 17:01:57 -04:00
if ( ! container )
{
// maybe it's in the external container
if ( _lastOpenedRemoteContainerId ! = 0 )
{
2018-07-12 14:41:21 -07:00
CContainerWeenie * externalContainer = FindContainer ( _lastOpenedRemoteContainerId ) ;
2018-03-29 17:01:57 -04:00
if ( externalContainer & & externalContainer - > _openedById = = GetID ( ) )
container = externalContainer - > FindContainer ( containerId ) ;
}
if ( ! container )
{
// maybe it's on the ground
2018-07-12 14:41:21 -07:00
CWeenieObject * object = g_pWorld - > FindObject ( containerId ) ;
2018-05-07 01:25:39 -05:00
if ( ! object )
{
NotifyInventoryFailedEvent ( containerId , WERROR_OBJECT_GONE ) ;
return NULL ;
}
2018-11-09 13:39:05 -06:00
2018-03-29 17:01:57 -04:00
container = object - > AsContainer ( ) ;
if ( ! container | | container - > HasOwner ( ) | | ! container - > InValidCell ( ) )
{
NotifyInventoryFailedEvent ( containerId , WERROR_OBJECT_GONE ) ;
return NULL ;
}
if ( DistanceTo ( container , true ) > maxDistance )
{
NotifyInventoryFailedEvent ( containerId , WERROR_TOO_FAR ) ;
return NULL ; ;
}
}
}
if ( container - > GetID ( ) ! = GetID ( ) & & container - > IsCreature ( ) )
{
NotifyInventoryFailedEvent ( containerId , WERROR_NONE ) ;
return NULL ;
}
return container ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : GetEquipPlacementAndHoldLocation ( CWeenieObject * item , uint32_t location , uint32_t * pPlacementFrame , uint32_t * pHoldLocation )
2018-03-29 17:01:57 -04:00
{
2018-04-02 16:34:35 -05:00
if ( location & ( MELEE_WEAPON_LOC | TWO_HANDED_LOC ) )
2018-03-29 17:01:57 -04:00
{
2020-08-15 11:08:01 -07:00
int leftTethered = 0 ;
if ( item - > m_Qualities . InqBool ( AUTOWIELD_LEFT_BOOL , leftTethered ) & & leftTethered = = 1 )
{
* pPlacementFrame = Placement : : LeftHand ;
* pHoldLocation = PARENT_LEFT_HAND ;
}
else
{
* pPlacementFrame = Placement : : RightHandCombat ;
* pHoldLocation = PARENT_RIGHT_HAND ;
}
2018-03-29 17:01:57 -04:00
}
else if ( location & MISSILE_WEAPON_LOC )
{
int combatStyle = item - > InqIntQuality ( DEFAULT_COMBAT_STYLE_INT , 0 ) ;
if ( combatStyle = = ThrownWeapon_CombatStyle | | combatStyle = = Atlatl_CombatStyle )
{
* pPlacementFrame = Placement : : RightHandCombat ;
* pHoldLocation = PARENT_RIGHT_HAND ;
}
else
{
* pPlacementFrame = Placement : : LeftHand ;
* pHoldLocation = PARENT_LEFT_HAND ;
}
}
else if ( location & SHIELD_LOC )
{
2018-11-16 00:39:07 -06:00
if ( item - > InqIntQuality ( LOCATIONS_INT , 0 , TRUE ) ! = SHIELD_LOC )
2018-11-09 13:39:05 -06:00
{
2018-11-16 00:39:07 -06:00
int combatStyle = item - > InqIntQuality ( DEFAULT_COMBAT_STYLE_INT , 0 ) ;
2018-11-15 23:24:23 -06:00
* pPlacementFrame = Placement : : LeftWeapon ;
2018-11-16 00:39:07 -06:00
* pHoldLocation = ( combatStyle = = Unarmed_CombatStyle ) ? PARENT_LEFT_HAND : PARENT_LEFT_WEAPON ;
2018-11-09 13:39:05 -06:00
}
else
{
* pPlacementFrame = Placement : : Shield ;
* pHoldLocation = PARENT_SHIELD ;
}
2018-03-29 17:01:57 -04:00
}
else if ( location & HELD_LOC )
{
* pPlacementFrame = Placement : : RightHandCombat ;
* pHoldLocation = PARENT_RIGHT_HAND ;
}
else if ( location & MISSILE_AMMO_LOC )
{
//*pPlacementFrame = Placement::RightHandCombat;
//*pHoldLocation = PARENT_RIGHT_HAND;
* pPlacementFrame = 0 ;
* pHoldLocation = 0 ;
}
else if ( location & ( ARMOR_LOC | CLOTHING_LOC ) )
{
* pPlacementFrame = 0 ;
* pHoldLocation = 0 ;
return false ;
}
else
{
// LOG(Temp, Normal, "Trying to place %s but don't know how with coverage 0x%08X\n", item->GetName().c_str(), location);
* pPlacementFrame = 0 ;
* pHoldLocation = 0 ;
return false ;
}
return true ;
}
BYTE CMonsterWeenie : : GetEnchantmentSerialByteForMask ( int priority )
{
if ( ! priority )
return 0 ;
2019-07-07 20:56:15 +00:00
for ( uint32_t i = 0 ; i < 32 ; i + + )
2018-03-29 17:01:57 -04:00
{
if ( priority & 1 )
return i + 1 ;
priority > > = 1 ;
}
return 0 ;
}
2018-07-12 14:41:21 -07:00
int CMonsterWeenie : : CheckWieldRequirements ( CWeenieObject * item , CWeenieObject * wielder , STypeInt requirementStat , STypeInt skillStat , STypeInt difficultyStat )
2018-03-29 17:01:57 -04:00
{
int requirementType = item - > InqIntQuality ( requirementStat , 0 , TRUE ) ;
if ( ! requirementType )
return WERROR_NONE ;
int skillType = item - > InqIntQuality ( skillStat , 0 , TRUE ) ;
int wieldDifficulty = item - > InqIntQuality ( difficultyStat , 0 , TRUE ) ;
switch ( requirementType )
{
case 1 : // skill
{
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! wielder - > m_Qualities . InqSkill ( ( STypeSkill ) skillType , skillLevel , FALSE ) | | ( int ) skillLevel < wieldDifficulty )
2018-04-02 22:46:54 -05:00
return WERROR_SKILL_TOO_LOW ;
2018-03-29 17:01:57 -04:00
break ;
}
case 2 : // base skill
{
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! wielder - > m_Qualities . InqSkill ( ( STypeSkill ) skillType , skillLevel , TRUE ) | | ( int ) skillLevel < wieldDifficulty )
2018-04-02 22:46:54 -05:00
return WERROR_SKILL_TOO_LOW ;
2018-03-29 17:01:57 -04:00
break ;
}
case 3 : // attribute
{
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! wielder - > m_Qualities . InqAttribute ( ( STypeAttribute ) skillType , skillLevel , FALSE ) | | ( int ) skillLevel < wieldDifficulty )
return WERROR_ACTIVATION_SKILL_TOO_LOW ;
break ;
}
case 4 : // base attribute
{
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! wielder - > m_Qualities . InqAttribute ( ( STypeAttribute ) skillType , skillLevel , TRUE ) | | ( int ) skillLevel < wieldDifficulty )
return WERROR_ACTIVATION_SKILL_TOO_LOW ;
break ;
}
case 5 : // attribute 2nd
{
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! wielder - > m_Qualities . InqAttribute2nd ( ( STypeAttribute2nd ) skillType , skillLevel , FALSE ) | | ( int ) skillLevel < wieldDifficulty )
return WERROR_ACTIVATION_SKILL_TOO_LOW ;
break ;
}
case 6 : // attribute 2nd base
{
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! wielder - > m_Qualities . InqAttribute2nd ( ( STypeAttribute2nd ) skillType , skillLevel , TRUE ) | | ( int ) skillLevel < wieldDifficulty )
return WERROR_ACTIVATION_SKILL_TOO_LOW ;
break ;
}
case 7 : // level
{
if ( wielder - > InqIntQuality ( LEVEL_INT , 1 , TRUE ) < wieldDifficulty )
return WERROR_LEVEL_TOO_LOW ;
break ;
}
case 8 : // skill advancement class
{
SKILL_ADVANCEMENT_CLASS sac = SKILL_ADVANCEMENT_CLASS : : UNDEF_SKILL_ADVANCEMENT_CLASS ;
if ( ! wielder - > m_Qualities . InqSkillAdvancementClass ( ( STypeSkill ) skillType , sac ) | | ( int ) sac < wieldDifficulty )
return WERROR_ACTIVATION_NOT_SPECIALIZED ;
break ;
}
case 9 : // faction
{
return WERROR_NONE ; //todo
}
case 10 : // unknown
{
return WERROR_NONE ; //todo
}
case 11 : // type
{
if ( wielder - > InqIntQuality ( CREATURE_TYPE_INT , 0 , TRUE ) ! = wieldDifficulty )
return WERROR_ACTIVATION_WRONG_RACE ;
break ;
}
case 12 : // race
{
if ( wielder - > InqIntQuality ( HERITAGE_GROUP_INT , 0 , TRUE ) ! = wieldDifficulty )
return WERROR_ACTIVATION_WRONG_RACE ;
break ;
}
}
return WERROR_NONE ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : MoveItemToContainer ( uint32_t sourceItemId , uint32_t targetContainerId , uint32_t targetSlot , bool animationDone )
2018-03-29 17:01:57 -04:00
{
if ( ! animationDone & & IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * sourceItem = FindValidNearbyItem ( sourceItemId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! sourceItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CContainerWeenie * targetContainer = FindValidNearbyContainer ( targetContainerId , USEDISTANCE_FAR ) ;
2019-02-26 22:24:48 +00:00
if ( ! targetContainer | | targetContainer - > IsCorpse ( ) | | ! targetContainer - > Container_CanStore ( sourceItem ) )
2018-03-29 17:01:57 -04:00
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
if ( sourceItem - > IsAttunedOrContainsAttuned ( ) & & targetContainer - > GetTopLevelID ( ) ! = GetID ( ) )
{
NotifyInventoryFailedEvent ( sourceItem - > id , WERROR_ATTUNED_ITEM ) ;
return false ;
}
2020-07-08 19:53:24 +00:00
uint32_t freezer = sourceItem - > InqIIDQuality ( FREEZER_IID , 0 ) ;
if ( freezer ! = 0 & & freezer ! = GetID ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_FROZEN ) ;
return false ;
}
2020-07-30 16:30:26 -07:00
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , GetID ( ) ) ;
2020-07-08 19:53:24 +00:00
2018-03-29 17:01:57 -04:00
bool isExternalTargetContainer = ( targetContainer - > GetTopLevelID ( ) ! = GetID ( ) ) ;
if ( ! animationDone & & ( ! FindContainedItem ( sourceItem - > GetID ( ) ) | | isExternalTargetContainer ) )
{
//from ground or external container or to external container.
CPickupInventoryUseEvent * pickupEvent = new CPickupInventoryUseEvent ( ) ;
pickupEvent - > _target_id = sourceItemId ;
pickupEvent - > _source_item_id = sourceItemId ;
pickupEvent - > _target_container_id = targetContainerId ;
pickupEvent - > _target_slot = targetSlot ;
ExecuteUseEvent ( pickupEvent ) ;
}
else
{
//from our inventory or have already done the animation.
FinishMoveItemToContainer ( sourceItem , targetContainer , targetSlot ) ;
}
return true ;
}
2019-07-07 20:56:15 +00:00
void CMonsterWeenie : : FinishMoveItemToContainer ( CWeenieObject * sourceItem , CContainerWeenie * targetContainer , uint32_t targetSlot , bool bSendEvent , bool silent )
2018-03-29 17:01:57 -04:00
{
// Scenarios to consider:
// 1. Item being stored is equipped.
// 2. Item being stored is on the GROUND!
// 3. Item being stored is already in the inventory.
// 4. Item being stored is in an external container (chest) or being moved to an external container (chest)
bool wasWielded = sourceItem - > IsWielded ( ) ;
2018-07-12 14:41:21 -07:00
bool isPickup = sourceItem - > GetWorldTopLevelOwner ( ) ! = this ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t dwCell = GetLandcell ( ) ;
2018-03-29 17:01:57 -04:00
//if (!sourceItem->HasOwner())
//{
2018-11-09 13:39:05 -06:00
if ( CWeenieObject * generator = g_pWorld - > FindObject ( sourceItem - > InqIIDQuality ( GENERATOR_IID , 0 ) ) )
generator - > NotifyGeneratedPickedUp ( sourceItem ) ;
2018-03-29 17:01:57 -04:00
//}
// Take it out of whatever slot it's in.
2019-10-02 02:47:23 +00:00
//if (sourceItem->m_Qualities.m_WeenieType == WeenieType::Caster_WeenieType || sourceItem->m_Qualities.m_WeenieType == WeenieType::Clothing_WeenieType ||
// sourceItem->m_Qualities.m_WeenieType == WeenieType::MeleeWeapon_WeenieType || sourceItem->m_Qualities.m_WeenieType == WeenieType::MissileLauncher_WeenieType ||
// sourceItem->m_Qualities.m_WeenieType == WeenieType::Missile_WeenieType)
//{
//}
2019-12-19 16:07:24 -05:00
if ( sourceItem - > GetItemType ( ) & ( TYPE_VESTEMENTS | TYPE_WEAPON_OR_CASTER ) )
2019-10-02 02:47:23 +00:00
{
sourceItem - > ReleaseFromAnyWeenieParent ( true , true ) ;
}
else
{
sourceItem - > ReleaseFromAnyWeenieParent ( false , true ) ;
}
2018-03-29 17:01:57 -04:00
sourceItem - > SetWieldedLocation ( INVENTORY_LOC : : NONE_LOC ) ;
sourceItem - > SetWeenieContainer ( targetContainer - > GetID ( ) ) ;
sourceItem - > ReleaseFromBlock ( ) ;
2020-07-08 19:53:24 +00:00
if ( AsPlayer ( ) )
sourceItem - > m_Qualities . SetInstanceID ( OWNER_IID , GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
2018-08-24 02:35:14 -05:00
//store the current motion here for use later.
2019-07-07 20:56:15 +00:00
uint32_t oldmotion = get_minterp ( ) - > InqStyle ( ) ;
2018-08-24 02:35:14 -05:00
2018-03-29 17:01:57 -04:00
// The container will auto-correct this slot into a valid range.
targetSlot = targetContainer - > Container_InsertInventoryItem ( dwCell , sourceItem , targetSlot ) ;
if ( ! silent )
{
if ( wasWielded )
EmitSound ( Sound_UnwieldObject , 1.0f ) ;
else
EmitSound ( Sound_PickUpItem , 1.0f ) ;
}
if ( isPickup )
2018-07-12 14:41:21 -07:00
sourceItem - > OnPickedUp ( this ) ;
2018-03-29 17:01:57 -04:00
if ( bSendEvent )
{
if ( sourceItem - > AsContainer ( ) )
2018-07-12 14:41:21 -07:00
sourceItem - > AsContainer ( ) - > MakeAwareViewContent ( this ) ;
2018-03-29 17:01:57 -04:00
SendNetMessage ( InventoryMove ( sourceItem - > GetID ( ) , targetContainer - > GetID ( ) , targetSlot , sourceItem - > RequiresPackSlot ( ) ? 1 : 0 ) , PRIVATE_MSG , TRUE ) ;
}
2020-07-08 19:53:24 +00:00
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , 0 ) ;
2020-05-29 11:27:05 -07:00
if ( AsPlayer ( ) & & wasWielded )
2020-05-22 22:19:09 -07:00
{
2020-07-08 19:53:24 +00:00
int setId = 0 ;
if ( sourceItem - > m_Qualities . InqInt ( EQUIPMENT_SET_ID_INT , setId ) )
2020-05-29 01:34:33 -07:00
{
2020-07-08 19:53:24 +00:00
AsPlayer ( ) - > UpdateSetSpells ( setId , sourceItem - > GetID ( ) ) ;
2020-05-29 01:34:33 -07:00
}
2020-06-02 17:44:03 -07:00
if ( sourceItem - > IsAetheria ( ) )
{
AsPlayer ( ) - > UpdateSigilProcRate ( ) ;
}
2020-05-22 22:19:09 -07:00
}
2020-07-08 19:53:24 +00:00
2020-05-22 22:19:09 -07:00
2018-07-12 14:41:21 -07:00
if ( targetContainer - > GetWorldTopLevelOwner ( ) ! = this )
2018-03-29 17:01:57 -04:00
RecalculateEncumbrance ( ) ;
if ( sourceItem - > GetItemType ( ) & ( TYPE_ARMOR | TYPE_CLOTHING ) )
2018-12-18 17:02:31 -06:00
{
if ( m_Qualities . GetInt ( HERITAGE_GROUP_INT , 1 ) ! = Gearknight_HeritageGroup ) // TODO: Update JUST cloak on gearknight unequip rather than whole model.
UpdateModel ( ) ;
}
2018-03-29 17:01:57 -04:00
2018-08-24 02:35:14 -05:00
// Checks the old motion vs Motion_NonCombat to prevent getting stuck while adjusting to the new combat style.
if ( wasWielded & & oldmotion ! = Motion_NonCombat )
2018-03-29 17:01:57 -04:00
AdjustToNewCombatMode ( ) ;
2019-10-27 17:56:23 +00:00
if ( AsPlayer ( ) & & sourceItem - > m_Qualities . id = = W_COINSTACK_CLASS )
RecalculateCoinAmount ( W_COINSTACK_CLASS ) ;
2018-03-29 17:01:57 -04:00
2018-11-09 00:21:21 +00:00
if ( ! sourceItem - > m_Qualities . GetInt ( LIFESPAN_INT , 0 ) )
{
sourceItem - > m_Qualities . RemoveFloat ( TIME_TO_ROT_FLOAT ) ;
sourceItem - > _timeToRot = - 1.0 ;
sourceItem - > _beganRot = false ;
}
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : MoveItemTo3D ( uint32_t sourceItemId , bool animationDone )
2018-03-29 17:01:57 -04:00
{
// Scenarios to consider:
// 1. Item being stored is equipped.
// 3. Item being stored is in the inventory.
if ( ! animationDone & & IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * sourceItem = FindValidNearbyItem ( sourceItemId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! sourceItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
if ( sourceItem - > IsAttunedOrContainsAttuned ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ATTUNED_ITEM ) ;
return false ;
}
2020-07-30 16:30:26 -07:00
2020-07-08 19:53:24 +00:00
uint32_t freezer = sourceItem - > InqIIDQuality ( FREEZER_IID , 0 ) ;
if ( freezer ! = 0 & & freezer ! = GetID ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_FROZEN ) ;
return false ;
}
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
if ( ! animationDone )
{
CDropInventoryUseEvent * dropEvent = new CDropInventoryUseEvent ( ) ;
dropEvent - > _target_id = sourceItemId ;
ExecuteUseEvent ( dropEvent ) ;
}
else
{
FinishMoveItemTo3D ( sourceItem ) ;
}
return true ;
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : FinishMoveItemTo3D ( CWeenieObject * sourceItem )
2018-03-29 17:01:57 -04:00
{
// Scenarios to consider:
// 1. Item being dropped is equipped.
// 3. Item being dropped is in the inventory.
BOOL bWasWielded = sourceItem - > IsWielded ( ) ;
2018-08-24 02:35:14 -05:00
//store the current motion here for use later.
2019-07-07 20:56:15 +00:00
uint32_t oldmotion = get_minterp ( ) - > InqStyle ( ) ;
2018-08-24 02:35:14 -05:00
2018-03-29 17:01:57 -04:00
// Take it out of whatever slot it's in.
sourceItem - > ReleaseFromAnyWeenieParent ( false , true ) ;
sourceItem - > SetWeenieContainer ( 0 ) ;
sourceItem - > SetWielderID ( 0 ) ;
sourceItem - > SetWieldedLocation ( INVENTORY_LOC : : NONE_LOC ) ;
EmitSound ( Sound_DropItem , 1.0f ) ;
SendNetMessage ( InventoryDrop ( sourceItem - > GetID ( ) ) , PRIVATE_MSG , TRUE ) ;
sourceItem - > m_Qualities . SetInt ( PARENT_LOCATION_INT , 0 ) ;
sourceItem - > unset_parent ( ) ;
sourceItem - > enter_world ( & m_Position ) ;
2018-11-09 13:39:05 -06:00
if ( ! sourceItem - > m_Qualities . m_PositionStats )
2018-10-26 14:18:40 -05:00
sourceItem - > m_Qualities . SetPosition ( LOCATION_POSITION , m_Position ) ;
2018-03-29 17:01:57 -04:00
sourceItem - > SetPlacementFrame ( 0x65 , FALSE ) ;
//if (!pItem->HasAnims())
// pItem->SetPlacementFrame(pItem->CanPickup() ? 0x65 : 0, 1);
if ( sourceItem - > AsClothing ( ) )
2018-12-18 17:02:31 -06:00
{
if ( m_Qualities . GetInt ( HERITAGE_GROUP_INT , 1 ) ! = Gearknight_HeritageGroup ) // TODO: Update JUST cloak on gearknight unequip rather than whole model.
UpdateModel ( ) ;
}
2018-03-29 17:01:57 -04:00
g_pWorld - > InsertEntity ( sourceItem ) ;
sourceItem - > Movement_Teleport ( GetPosition ( ) ) ;
2018-11-09 00:21:21 +00:00
if ( ! sourceItem - > m_Qualities . GetInt ( LIFESPAN_INT , 0 ) )
{
sourceItem - > _timeToRot = Timer : : cur_time + 300.0 ;
sourceItem - > _beganRot = false ;
sourceItem - > m_Qualities . SetFloat ( TIME_TO_ROT_FLOAT , sourceItem - > _timeToRot ) ;
}
2018-03-29 17:01:57 -04:00
RecalculateEncumbrance ( ) ;
2019-10-27 17:56:23 +00:00
if ( AsPlayer ( ) & & sourceItem - > m_Qualities . id = = W_COINSTACK_CLASS )
RecalculateCoinAmount ( W_COINSTACK_CLASS ) ;
2018-03-29 17:01:57 -04:00
2018-08-24 02:35:14 -05:00
// Checks the old motion vs Motion_NonCombat to prevent getting stuck while adjusting to the new combat style.
if ( bWasWielded & & oldmotion ! = Motion_NonCombat )
2018-03-29 17:01:57 -04:00
AdjustToNewCombatMode ( ) ;
2018-11-09 13:39:05 -06:00
if ( bWasWielded )
2020-05-16 18:39:12 -07:00
{
2018-07-12 14:41:21 -07:00
sourceItem - > OnUnwield ( this ) ;
2020-05-29 11:27:05 -07:00
}
if ( AsPlayer ( ) & & bWasWielded )
{
2020-05-29 01:34:33 -07:00
int setSpell ;
if ( sourceItem - > m_Qualities . InqInt ( EQUIPMENT_SET_ID_INT , setSpell ) )
{
2020-07-08 19:53:24 +00:00
AsPlayer ( ) - > UpdateSetSpells ( setSpell , sourceItem - > GetID ( ) ) ;
2020-05-29 01:34:33 -07:00
}
2020-06-02 17:44:03 -07:00
if ( sourceItem - > IsAetheria ( ) )
{
AsPlayer ( ) - > UpdateSigilProcRate ( ) ;
}
2020-05-16 18:39:12 -07:00
}
2018-07-12 14:41:21 -07:00
sourceItem - > OnDropped ( this ) ;
2018-11-12 00:31:10 -06:00
2020-07-15 09:29:24 -07:00
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , 0 ) ;
2020-07-08 19:53:24 +00:00
2018-11-12 00:31:10 -06:00
sourceItem - > m_bDontClear = false ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : MoveItemToWield ( uint32_t sourceItemId , uint32_t targetLoc , bool animationDone )
2018-03-29 17:01:57 -04:00
{
// Scenarios to consider:
// 1. Item being equipped from the GROUND!
// 2. Item being equipped from different equip slot.
// 3. Item being equipped from the player's inventory.
if ( ! animationDone & & IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * sourceItem = FindValidNearbyItem ( sourceItemId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! sourceItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
if ( ! Container_CanEquip ( sourceItem , targetLoc ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_BE_WIELDED_FAILURE ) ;
return false ;
}
2020-07-08 19:53:24 +00:00
uint32_t freezer = sourceItem - > InqIIDQuality ( FREEZER_IID , 0 ) ;
if ( freezer ! = 0 & & freezer ! = GetID ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_FROZEN ) ;
return false ;
}
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , GetID ( ) ) ;
2020-05-31 10:58:37 -07:00
if ( sourceItem - > IsAetheria ( ) )
{
int aetheriaUnlock ;
if ( m_Qualities . InqInt ( AETHERIA_BITFIELD_INT , aetheriaUnlock ) )
{
int aetheriaLevel ;
if ( sourceItem - > m_Qualities . InqInt ( WIELD_DIFFICULTY_INT , aetheriaLevel ) )
{
if ( aetheriaLevel = = 75 & & ! ( aetheriaUnlock & 0x1 ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_BE_WIELDED_FAILURE ) ;
return false ;
}
else if ( aetheriaLevel = = 150 & & ! ( aetheriaUnlock & 0x2 ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_BE_WIELDED_FAILURE ) ;
return false ;
}
else if ( aetheriaLevel = = 225 & & ! ( aetheriaUnlock & 0x4 ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_BE_WIELDED_FAILURE ) ;
return false ;
}
}
}
else
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_BE_WIELDED_FAILURE ) ;
return false ;
}
}
2018-03-29 17:01:57 -04:00
if ( ! animationDone & & ! FindContainedItem ( sourceItem - > GetID ( ) ) )
{
//from ground or external container.
CMoveToWieldInventoryUseEvent * pickupEvent = new CMoveToWieldInventoryUseEvent ( ) ;
pickupEvent - > _target_id = sourceItemId ;
pickupEvent - > _sourceItemId = sourceItemId ;
pickupEvent - > _targetLoc = targetLoc ;
ExecuteUseEvent ( pickupEvent ) ;
}
else
{
//from our inventory or have already done the animation.
return FinishMoveItemToWield ( sourceItem , targetLoc ) ;
}
return true ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : FinishMoveItemToWield ( CWeenieObject * sourceItem , uint32_t targetLoc )
2018-03-29 17:01:57 -04:00
{
// Scenarios to consider:
// 1. Item being equipped from the GROUND!
// 2. Item being equipped from different equip slot.
// 3. Item being equipped from the player's inventory.
2018-07-12 14:41:21 -07:00
bool isPickup = sourceItem - > GetWorldTopLevelOwner ( ) ! = this ;
2018-03-29 17:01:57 -04:00
2020-03-28 15:41:45 -07:00
if ( AsPlayer ( ) )
2018-03-29 17:01:57 -04:00
{
2020-03-28 15:41:45 -07:00
int error = CheckWieldRequirements ( sourceItem , this , WIELD_REQUIREMENTS_INT , WIELD_SKILLTYPE_INT , WIELD_DIFFICULTY_INT ) ;
if ( error ! = WERROR_NONE )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , error ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
2020-03-28 15:41:45 -07:00
error = CheckWieldRequirements ( sourceItem , this , WIELD_REQUIREMENTS_2_INT , WIELD_SKILLTYPE_2_INT , WIELD_DIFFICULTY_2_INT ) ;
if ( error ! = WERROR_NONE )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , error ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
2020-03-28 15:41:45 -07:00
error = CheckWieldRequirements ( sourceItem , this , WIELD_REQUIREMENTS_3_INT , WIELD_SKILLTYPE_3_INT , WIELD_DIFFICULTY_3_INT ) ;
if ( error ! = WERROR_NONE )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , error ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
2020-03-28 15:41:45 -07:00
error = CheckWieldRequirements ( sourceItem , this , WIELD_REQUIREMENTS_4_INT , WIELD_SKILLTYPE_4_INT , WIELD_DIFFICULTY_4_INT ) ;
if ( error ! = WERROR_NONE )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , error ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
2020-03-28 15:41:45 -07:00
if ( sourceItem - > InqIIDQuality ( ALLOWED_WIELDER_IID , 0 ) & & sourceItem - > InqIIDQuality ( ALLOWED_WIELDER_IID , 0 ) ! = GetID ( ) )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_ATTUNED_ITEM ) ;
return false ;
}
2018-09-07 23:34:50 -05:00
2020-03-28 15:41:45 -07:00
if ( sourceItem - > InqIntQuality ( HERITAGE_SPECIFIC_ARMOR_INT , 0 ) & & sourceItem - > InqIntQuality ( HERITAGE_SPECIFIC_ARMOR_INT , 0 ) ! = m_Qualities . GetInt ( HERITAGE_GROUP_INT , 1 ) ) // Other heritages cannot wear gearknight armor.
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_SPECIFIC_ARMOR_REQUIRES_HERITAGE ) ;
return false ;
}
2018-11-15 20:53:36 -06:00
2020-03-28 15:41:45 -07:00
if ( m_Qualities . GetInt ( HERITAGE_GROUP_INT , 1 ) = = Gearknight_HeritageGroup & & ! sourceItem - > InqIntQuality ( HERITAGE_SPECIFIC_ARMOR_INT , 0 ) & & sourceItem - > m_Qualities . GetInt ( LOCATIONS_INT , 0 ) < 0x8000 ) // Only restrict Armor, not weapons, cloaks, jewelry, trinkets, etc.
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_HERITAGE_REQUIRES_SPECIFIC_ARMOR ) ;
return false ;
}
2018-11-15 20:53:36 -06:00
}
2018-05-04 16:37:29 +00:00
if ( sourceItem - > InqIntQuality ( ITEM_TYPE_INT , 0 ) = = TYPE_ARMOR & & sourceItem - > InqIntQuality ( LOCATIONS_INT , 0 ) = = SHIELD_LOC )
{
sourceItem - > m_Qualities . SetInt ( SHIELD_VALUE_INT , sourceItem - > InqIntQuality ( ARMOR_LEVEL_INT , 0 ) ) ;
}
2018-03-29 17:01:57 -04:00
//if (!sourceItem->HasOwner())
//{
2018-11-09 13:39:05 -06:00
if ( CWeenieObject * generator = g_pWorld - > FindObject ( sourceItem - > InqIIDQuality ( GENERATOR_IID , 0 ) ) )
generator - > NotifyGeneratedPickedUp ( sourceItem ) ;
2018-03-29 17:01:57 -04:00
//}
2019-07-07 20:56:15 +00:00
uint32_t cell_id = m_Position . objcell_id ;
2018-03-29 17:01:57 -04:00
// Take it out of whatever slot it may be in
sourceItem - > ReleaseFromAnyWeenieParent ( false , false ) ;
2019-07-07 20:56:15 +00:00
uint32_t placement_id , child_location_id ;
2018-03-29 17:01:57 -04:00
bool bShouldPlace = GetEquipPlacementAndHoldLocation ( sourceItem , targetLoc , & placement_id , & child_location_id ) ;
sourceItem - > SetWielderID ( GetID ( ) ) ;
sourceItem - > SetWieldedLocation ( targetLoc ) ;
sourceItem - > ReleaseFromBlock ( ) ;
2018-08-24 02:35:14 -05:00
//store the current motion here for use later.
2019-07-07 20:56:15 +00:00
uint32_t oldmotion = get_minterp ( ) - > InqStyle ( ) ;
2018-08-24 02:35:14 -05:00
2018-03-29 17:01:57 -04:00
// The container will auto-correct this slot into a valid range.
Container_EquipItem ( cell_id , sourceItem , targetLoc , child_location_id , placement_id ) ;
if ( _IsPlayer ( ) )
{
SendNetMessage ( InventoryEquip ( sourceItem - > GetID ( ) , targetLoc ) , PRIVATE_MSG , TRUE ) ;
EmitSound ( Sound_WieldObject , 1.0f ) ;
}
if ( m_bWorldIsAware )
{
sourceItem - > NotifyIIDStatUpdated ( CONTAINER_IID , false ) ;
sourceItem - > NotifyIIDStatUpdated ( WIELDER_IID , false ) ;
sourceItem - > NotifyIntStatUpdated ( CURRENT_WIELDED_LOCATION_INT , false ) ;
2018-08-23 01:36:18 -05:00
sourceItem - > NotifyIntStatUpdated ( PARENT_LOCATION_INT , false ) ;
sourceItem - > NotifyIntStatUpdated ( PLACEMENT_POSITION_INT , false ) ;
2018-03-29 17:01:57 -04:00
}
if ( sourceItem - > AsClothing ( ) & & m_bWorldIsAware )
2018-11-15 20:53:36 -06:00
{
2018-12-18 17:02:31 -06:00
if ( m_Qualities . GetInt ( HERITAGE_GROUP_INT , 1 ) ! = Gearknight_HeritageGroup ) // TODO: Update JUST cloak on gearknight equip rather than whole model.
2018-11-15 20:53:36 -06:00
UpdateModel ( ) ;
}
2018-03-29 17:01:57 -04:00
2018-11-09 00:21:21 +00:00
if ( ! sourceItem - > m_Qualities . GetInt ( LIFESPAN_INT , 0 ) )
{
// Remove all loot items with wcid > g_pConfig->WcidForPurge()
if ( g_pConfig - > InventoryPurgeOnLogin ( ) )
{
if ( sourceItem - > m_Qualities . id > g_pConfig - > WcidForPurge ( ) & & sourceItem - > m_Qualities . GetInt ( ITEM_WORKMANSHIP_INT , 0 ) )
{
sourceItem - > _timeToRot = Timer : : cur_time ;
sourceItem - > _beganRot = true ;
}
}
else
{
sourceItem - > m_Qualities . RemoveFloat ( TIME_TO_ROT_FLOAT ) ;
sourceItem - > _timeToRot = - 1.0 ;
sourceItem - > _beganRot = false ;
}
}
2018-03-29 17:01:57 -04:00
2018-08-24 02:35:14 -05:00
// Checks the old motion vs Motion_NonCombat to prevent getting stuck while adjusting to the new combat style.
if ( oldmotion ! = Motion_NonCombat )
2018-03-29 17:01:57 -04:00
AdjustToNewCombatMode ( ) ;
// apply enchantments
2020-07-09 22:31:36 -07:00
if ( sourceItem - > m_Qualities . _spell_book & & _IsPlayer ( ) )
2018-03-29 17:01:57 -04:00
{
bool bShouldCast = true ;
std : : string name ;
if ( sourceItem - > m_Qualities . InqString ( CRAFTSMAN_NAME_STRING , name ) )
{
if ( ! name . empty ( ) & & name ! = InqStringQuality ( NAME_STRING , " " ) )
{
bShouldCast = false ;
NotifyWeenieErrorWithString ( WERROR_ACTIVATION_NOT_CRAFTSMAN , name . c_str ( ) ) ;
}
}
int difficulty ;
difficulty = 0 ;
if ( sourceItem - > m_Qualities . InqInt ( ITEM_DIFFICULTY_INT , difficulty , TRUE , FALSE ) )
{
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! m_Qualities . InqSkill ( ARCANE_LORE_SKILL , skillLevel , FALSE ) | | ( int ) skillLevel < difficulty )
{
bShouldCast = false ;
NotifyWeenieError ( WERROR_ACTIVATION_ARCANE_LORE_TOO_LOW ) ;
}
}
if ( bShouldCast )
{
difficulty = 0 ;
2019-07-07 20:56:15 +00:00
uint32_t skillActivationTypeDID = 0 ;
2018-05-21 23:20:21 +01:00
2018-05-22 00:06:53 +01:00
2018-03-29 17:01:57 -04:00
if ( sourceItem - > m_Qualities . InqInt ( ITEM_SKILL_LEVEL_LIMIT_INT , difficulty , TRUE , FALSE ) & & sourceItem - > m_Qualities . InqDataID ( ITEM_SKILL_LIMIT_DID , skillActivationTypeDID ) )
{
2018-03-29 20:49:54 -04:00
STypeSkill skillActivationType = SkillTable : : OldToNewSkill ( ( STypeSkill ) skillActivationTypeDID ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t skillLevel = 0 ;
2018-03-29 17:01:57 -04:00
if ( ! m_Qualities . InqSkill ( skillActivationType , skillLevel , FALSE ) | | ( int ) skillLevel < difficulty )
{
bShouldCast = false ;
NotifyWeenieErrorWithString ( WERROR_ACTIVATION_SKILL_TOO_LOW , CachedSkillTable - > GetSkillName ( skillActivationType ) . c_str ( ) ) ;
}
}
}
if ( bShouldCast & & sourceItem - > InqIntQuality ( ITEM_ALLEGIANCE_RANK_LIMIT_INT , 0 ) > InqIntQuality ( ALLEGIANCE_RANK_INT , 0 ) )
{
bShouldCast = false ;
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_ACTIVATION_RANK_TOO_LOW ) ;
}
if ( bShouldCast )
{
int heritageRequirement = sourceItem - > InqIntQuality ( HERITAGE_GROUP_INT , - 1 ) ;
if ( heritageRequirement ! = - 1 & & heritageRequirement ! = InqIntQuality ( HERITAGE_GROUP_INT , 0 ) )
{
bShouldCast = false ;
std : : string heritageString = sourceItem - > InqStringQuality ( ITEM_HERITAGE_GROUP_RESTRICTION_STRING , " of the correct heritage " ) ;
NotifyWeenieErrorWithString ( WERROR_ACTIVATION_WRONG_RACE , heritageString . c_str ( ) ) ;
}
}
int currentMana = 0 ;
if ( bShouldCast & & sourceItem - > m_Qualities . InqInt ( ITEM_CUR_MANA_INT , currentMana , TRUE , FALSE ) )
{
if ( currentMana = = 0 )
{
bShouldCast = false ;
NotifyWeenieError ( WERROR_ACTIVATION_NOT_ENOUGH_MANA ) ;
}
else
sourceItem - > _nextManaUse = Timer : : cur_time ;
}
if ( bShouldCast )
{
2019-07-07 20:56:15 +00:00
uint32_t serial = 0 ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
serial | = ( ( uint32_t ) GetEnchantmentSerialByteForMask ( sourceItem - > InqIntQuality ( LOCATIONS_INT , 0 , TRUE ) ) < < ( uint32_t ) 0 ) ;
serial | = ( ( uint32_t ) GetEnchantmentSerialByteForMask ( sourceItem - > InqIntQuality ( CLOTHING_PRIORITY_INT , 0 , TRUE ) ) < < ( uint32_t ) 8 ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t procspellid = sourceItem - > InqDIDQuality ( PROC_SPELL_DID , 0 ) ;
uint32_t spellid = sourceItem - > InqDIDQuality ( SPELL_DID , 0 ) ;
2020-05-29 01:34:33 -07:00
for ( auto & spellPage : sourceItem - > m_Qualities . _spell_book - > _spellbook )
2020-05-22 22:19:09 -07:00
{
2020-05-29 01:34:33 -07:00
//ignore the spell and don't cast if it's the Proc_spell_DID or the spell_DID
if ( spellid ! = spellPage . first & & procspellid ! = spellPage . first )
sourceItem - > MakeSpellcastingManager ( ) - > CastSpellEquipped ( GetID ( ) , spellPage . first , ( WORD ) serial ) ;
2018-03-29 17:01:57 -04:00
}
}
}
2019-04-22 22:19:31 +00:00
2020-05-29 01:34:33 -07:00
int setSpell ;
2020-05-29 11:27:05 -07:00
if ( AsPlayer ( ) & & sourceItem - > m_Qualities . InqInt ( EQUIPMENT_SET_ID_INT , setSpell ) )
2020-05-29 01:34:33 -07:00
{
2020-07-08 19:53:24 +00:00
AsPlayer ( ) - > UpdateSetSpells ( setSpell , sourceItem - > GetID ( ) ) ;
2020-05-29 01:34:33 -07:00
2020-07-08 19:53:24 +00:00
if ( sourceItem - > IsAetheria ( ) )
2020-06-02 17:44:03 -07:00
{
2020-07-08 19:53:24 +00:00
if ( AsPlayer ( ) )
{
AsPlayer ( ) - > UpdateSigilProcRate ( ) ;
}
2020-06-02 17:44:03 -07:00
}
}
2020-07-09 22:31:36 -07:00
int gearRating ;
2019-04-22 22:19:31 +00:00
for ( int i = 370 ; i < 380 ; i + + )
{
2020-05-18 18:51:20 -07:00
if ( sourceItem - > m_Qualities . InqInt ( ( STypeInt ) i , gearRating ) )
2019-04-22 22:19:31 +00:00
{
2020-05-17 22:21:51 -07:00
UpdateRatingFromGear ( ( STypeInt ) i , gearRating ) ;
2019-04-22 22:19:31 +00:00
}
2020-07-09 22:31:36 -07:00
}
2019-04-22 22:19:31 +00:00
// Damage Rating for Weapon Mastery. Does not apply to quest weapons and loot without WEAPON_TYPE_INT
if ( sourceItem - > m_Qualities . GetInt ( WEAPON_TYPE_INT , 0 ) )
{
2020-05-17 22:21:51 -07:00
int ratingVal ;
if ( m_Qualities . InqInt ( DAMAGE_RATING_INT , ratingVal , true ) )
{
m_Qualities . SetInt ( DAMAGE_RATING_INT , ratingVal + 5 ) ;
NotifyIntStatUpdated ( DAMAGE_RATING_INT ) ;
}
2019-04-22 22:19:31 +00:00
}
2020-07-08 19:53:24 +00:00
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , GetID ( ) ) ;
2020-05-22 22:19:09 -07:00
if ( isPickup )
sourceItem - > OnPickedUp ( this ) ;
sourceItem - > OnWield ( this ) ;
return true ;
}
2018-03-29 17:01:57 -04:00
2020-05-17 22:21:51 -07:00
void CMonsterWeenie : : UpdateRatingFromGear ( STypeInt rating , int gearRating )
{
2020-07-08 19:53:24 +00:00
m_Qualities . AdjInt ( rating , gearRating ) ;
2020-05-17 22:21:51 -07:00
NotifyIntStatUpdated ( rating ) ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : MergeItem ( uint32_t sourceItemId , uint32_t targetItemId , uint32_t amountToTransfer , bool animationDone )
2018-03-29 17:01:57 -04:00
{
if ( ! animationDone & & IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * sourceItem = FindValidNearbyItem ( sourceItemId , USEDISTANCE_FAR ) ;
2018-10-14 20:01:18 -07:00
if ( ! sourceItem )
2018-03-29 17:01:57 -04:00
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * targetItem = FindValidNearbyItem ( targetItemId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! targetItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2020-05-29 12:11:41 -07:00
uint32_t freezer = sourceItem - > InqIIDQuality ( FREEZER_IID , 0 ) ;
if ( freezer ! = 0 & & freezer ! = GetID ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_FROZEN ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
if ( ! animationDone & & ( ! FindContainedItem ( sourceItemId ) | | ! FindContainedItem ( targetItemId ) ) )
{
2020-05-29 12:11:41 -07:00
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
//from ground or other container or to ground or other container.
CStackMergeInventoryUseEvent * mergeEvent = new CStackMergeInventoryUseEvent ( ) ;
2018-11-09 13:39:05 -06:00
if ( sourceItem - > IsContained ( ) | | sourceItem - > IsWielded ( ) )
2018-03-29 17:01:57 -04:00
mergeEvent - > _target_id = targetItemId ;
else
mergeEvent - > _target_id = sourceItemId ;
mergeEvent - > _sourceItemId = sourceItemId ;
mergeEvent - > _targetItemId = targetItemId ;
2018-11-09 13:39:05 -06:00
mergeEvent - > _amountToTransfer = amountToTransfer ;
2018-03-29 17:01:57 -04:00
ExecuteUseEvent ( mergeEvent ) ;
}
else
{
//check if the items is still in range.
if ( FindValidNearbyItem ( sourceItemId , 5.0 ) = = NULL | | FindValidNearbyItem ( targetItemId , 5.0 ) = = NULL )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_TOO_FAR ) ;
return false ;
}
if ( sourceItem - > m_Qualities . id ! = targetItem - > m_Qualities . id )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_NONE ) ;
return false ;
}
2019-07-07 20:56:15 +00:00
uint32_t sourceCurrentAmount = sourceItem - > InqIntQuality ( STACK_SIZE_INT , 1 ) ;
2018-03-29 17:01:57 -04:00
if ( amountToTransfer > sourceCurrentAmount )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_NONE ) ;
return false ;
}
2019-07-07 20:56:15 +00:00
uint32_t targetCurrentAmount = targetItem - > InqIntQuality ( STACK_SIZE_INT , 1 ) ;
uint32_t targetMaxStackSize = targetItem - > InqIntQuality ( MAX_STACK_SIZE_INT , 1 ) ;
2018-03-29 17:01:57 -04:00
int maxTransferAmount = targetMaxStackSize - targetCurrentAmount ;
if ( maxTransferAmount < = 0 )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_NONE ) ;
return false ;
}
2018-09-28 19:07:44 -07:00
2018-03-29 17:01:57 -04:00
if ( maxTransferAmount < amountToTransfer )
amountToTransfer = maxTransferAmount ;
targetItem - > SetStackSize ( targetCurrentAmount + amountToTransfer ) ;
bool wasSourceItemWielded = sourceItem - > IsWielded ( ) ;
bool wasTargetItemWielded = targetItem - > IsWielded ( ) ;
2019-07-07 20:56:15 +00:00
uint32_t sourceItemNewStackSize = sourceCurrentAmount - amountToTransfer ;
2018-03-29 17:01:57 -04:00
if ( sourceItemNewStackSize > 0 ) //partial stack movement
{
//the client seems to forget about the source item when merging using the "place selected object in inventory" keybind
//to split from a stack so we have to remind it. I don't know how we can determine when the client uses the keybind or dragging
//so just do it regarless.
MakeAware ( sourceItem , true ) ;
sourceItem - > SetStackSize ( sourceItemNewStackSize ) ;
}
else //full stack movement
2018-09-28 17:21:03 -07:00
{
2018-03-29 17:01:57 -04:00
sourceItem - > Remove ( ) ;
2018-09-28 17:21:03 -07:00
}
2020-05-29 12:11:41 -07:00
sourceItem - > m_Qualities . SetInstanceID ( FREEZER_IID , 0 ) ;
2018-03-29 17:01:57 -04:00
if ( wasSourceItemWielded )
EmitSound ( Sound_UnwieldObject , 1.0f ) ;
else if ( wasTargetItemWielded )
EmitSound ( Sound_WieldObject , 1.0f ) ;
else if ( ! FindContainedItem ( targetItemId ) ) //Todo: does placing items in external containers make the drop or pickup sound?
EmitSound ( Sound_DropItem , 1.0f ) ;
else
EmitSound ( Sound_PickUpItem , 1.0f ) ;
RecalculateEncumbrance ( ) ;
2019-10-27 17:56:23 +00:00
if ( AsPlayer ( ) & & sourceItem - > m_Qualities . id = = W_COINSTACK_CLASS )
RecalculateCoinAmount ( W_COINSTACK_CLASS ) ;
2018-08-08 19:51:43 -05:00
2018-03-29 17:01:57 -04:00
}
return true ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : SplitItemToContainer ( uint32_t sourceItemId , uint32_t targetContainerId , uint32_t targetSlot , uint32_t amountToTransfer , bool animationDone )
2018-03-29 17:01:57 -04:00
{
if ( ! animationDone & & IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * sourceItem = FindValidNearbyItem ( sourceItemId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! sourceItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2019-12-14 22:00:28 -05:00
if ( sourceItem - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 0 ) < 1 )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CContainerWeenie * targetContainer = FindValidNearbyContainer ( targetContainerId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! targetContainer | | ! targetContainer - > Container_CanStore ( sourceItem ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
bool isExternalTargetContainer = ( targetContainer - > GetTopLevelID ( ) ! = GetID ( ) ) ;
if ( isExternalTargetContainer & & sourceItem - > IsAttunedOrContainsAttuned ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ATTUNED_ITEM ) ;
return false ;
}
if ( ! animationDone & & ( ! FindContainedItem ( sourceItemId ) | | isExternalTargetContainer ) )
{
//from ground or external container or to external container
CStackSplitToContainerInventoryUseEvent * mergeEvent = new CStackSplitToContainerInventoryUseEvent ( ) ;
if ( sourceItem - > IsContained ( ) | | sourceItem - > IsWielded ( ) )
mergeEvent - > _target_id = targetContainerId ;
else
mergeEvent - > _target_id = sourceItemId ;
mergeEvent - > _sourceItemId = sourceItemId ;
mergeEvent - > _targetContainerId = targetContainerId ;
mergeEvent - > _targetSlot = targetSlot ;
mergeEvent - > _amountToTransfer = amountToTransfer ;
ExecuteUseEvent ( mergeEvent ) ;
}
else
{
//check if items are still in range.
if ( FindValidNearbyItem ( sourceItemId , 5.0 ) = = NULL | | FindValidNearbyContainer ( targetContainerId , 5.0 ) = = NULL )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_TOO_FAR ) ;
return false ;
}
int totalAmount = sourceItem - > InqIntQuality ( STACK_SIZE_INT , 1 , TRUE ) ;
if ( amountToTransfer > = totalAmount )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * newStackItem = g_pWeenieFactory - > CloneWeenie ( sourceItem ) ;
2018-03-29 17:01:57 -04:00
if ( ! newStackItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
newStackItem - > SetStackSize ( amountToTransfer ) ;
newStackItem - > SetID ( g_pWorld - > GenerateGUID ( eDynamicGUID ) ) ;
if ( ! g_pWorld - > CreateEntity ( newStackItem ) )
{
2018-07-12 14:41:21 -07:00
delete newStackItem ;
2018-03-29 17:01:57 -04:00
return false ;
}
FinishMoveItemToContainer ( newStackItem , targetContainer , targetSlot ) ;
2019-10-05 15:41:26 -07:00
MakeAware ( newStackItem , true ) ;
2018-03-29 17:01:57 -04:00
//and set original item amount to what remains.
sourceItem - > SetStackSize ( totalAmount - amountToTransfer ) ;
}
return true ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : SplitItemto3D ( uint32_t sourceItemId , uint32_t amountToTransfer , bool animationDone )
2018-03-29 17:01:57 -04:00
{
if ( ! animationDone & & IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * sourceItem = FindValidNearbyItem ( sourceItemId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! sourceItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2019-12-14 22:00:28 -05:00
if ( sourceItem - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 0 ) < 1 )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
if ( sourceItem - > IsAttunedOrContainsAttuned ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ATTUNED_ITEM ) ;
return false ;
2018-10-14 22:51:18 -05:00
}
2020-05-29 12:11:41 -07:00
//// Temporarily disallow dropping stackable items.
//if (sourceItem->m_Qualities.GetInt(MAX_STACK_SIZE_INT, 0) > 1)
//{
// NotifyInventoryFailedEvent(sourceItemId, WERROR_ATTUNED_ITEM);
// return false;
//}
2018-03-29 17:01:57 -04:00
if ( ! animationDone & & ! FindContainedItem ( sourceItem - > GetID ( ) ) )
{
//from ground or other container...
CStackSplitTo3DInventoryUseEvent * splitEvent = new CStackSplitTo3DInventoryUseEvent ( ) ;
splitEvent - > _target_id = sourceItemId ;
splitEvent - > _sourceItemId = sourceItemId ;
splitEvent - > _amountToTransfer = amountToTransfer ;
ExecuteUseEvent ( splitEvent ) ;
}
else
{
//We do this by first splitting the item to our main pack and then dropping it. We could change this to do it directly if this causes any issues.
int totalAmount = sourceItem - > InqIntQuality ( STACK_SIZE_INT , 1 , TRUE ) ;
if ( amountToTransfer > = totalAmount )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * newStackItem = g_pWeenieFactory - > CloneWeenie ( sourceItem ) ;
2018-03-29 17:01:57 -04:00
if ( ! newStackItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
newStackItem - > SetStackSize ( amountToTransfer ) ;
newStackItem - > SetID ( g_pWorld - > GenerateGUID ( eDynamicGUID ) ) ;
if ( ! g_pWorld - > CreateEntity ( newStackItem ) )
{
2018-07-12 14:41:21 -07:00
delete newStackItem ;
2018-03-29 17:01:57 -04:00
return false ;
}
// move the new stack to our main pack in preparation for dropping it.
2018-07-12 14:41:21 -07:00
FinishMoveItemToContainer ( newStackItem , this , 0 ) ;
2019-10-05 15:41:26 -07:00
MakeAware ( newStackItem , true ) ;
2018-03-29 17:01:57 -04:00
// set original item amount to what remains.
sourceItem - > SetStackSize ( totalAmount - amountToTransfer ) ;
2018-11-09 13:39:05 -06:00
if ( newStackItem - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 0 ) > 1 )
2018-09-29 14:10:03 -07:00
newStackItem - > m_Qualities . SetInstanceID ( OWNER_IID , GetID ( ) ) ;
2018-03-29 17:01:57 -04:00
// and now move on to dropping it
CDropInventoryUseEvent * dropEvent = new CDropInventoryUseEvent ( ) ;
dropEvent - > _target_id = newStackItem - > GetID ( ) ;
ExecuteUseEvent ( dropEvent ) ;
}
return true ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : SplitItemToWield ( uint32_t sourceItemId , uint32_t targetLoc , uint32_t amountToTransfer , bool animationDone )
2018-03-29 17:01:57 -04:00
{
if ( ! animationDone & & IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * sourceItem = FindValidNearbyItem ( sourceItemId , USEDISTANCE_FAR ) ;
2018-03-29 17:01:57 -04:00
if ( ! sourceItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2019-12-14 22:00:28 -05:00
if ( sourceItem - > m_Qualities . GetInt ( MAX_STACK_SIZE_INT , 0 ) < 1 )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return false ;
}
2018-03-29 17:01:57 -04:00
if ( ! Container_CanEquip ( sourceItem , targetLoc ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_BE_WIELDED_FAILURE ) ;
return false ;
}
if ( ! animationDone & & ! FindContainedItem ( sourceItem - > GetID ( ) ) )
{
//from ground or other container...
CStackSplitToWieldInventoryUseEvent * stackSplitEvent = new CStackSplitToWieldInventoryUseEvent ( ) ;
stackSplitEvent - > _target_id = sourceItemId ;
stackSplitEvent - > _sourceItemId = sourceItemId ;
stackSplitEvent - > _targetLoc = targetLoc ;
stackSplitEvent - > _amountToTransfer = amountToTransfer ;
ExecuteUseEvent ( stackSplitEvent ) ;
}
else
{
int totalAmount = sourceItem - > InqIntQuality ( STACK_SIZE_INT , 1 , TRUE ) ;
if ( amountToTransfer > = totalAmount )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
2018-07-12 14:41:21 -07:00
CWeenieObject * newStackItem = g_pWeenieFactory - > CloneWeenie ( sourceItem ) ;
2018-03-29 17:01:57 -04:00
if ( ! newStackItem )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return false ;
}
newStackItem - > SetStackSize ( amountToTransfer ) ;
newStackItem - > SetID ( g_pWorld - > GenerateGUID ( eDynamicGUID ) ) ;
if ( ! g_pWorld - > CreateEntity ( newStackItem ) )
{
NotifyInventoryFailedEvent ( newStackItem - > GetID ( ) , WERROR_OBJECT_GONE ) ;
return false ;
}
if ( ! FinishMoveItemToWield ( newStackItem , targetLoc ) )
{
g_pWorld - > RemoveEntity ( newStackItem ) ;
return false ; //no need for notifications here as FinishMoveItemToWield takes care of that.
}
2019-10-05 15:41:26 -07:00
MakeAware ( newStackItem , true ) ;
2018-03-29 17:01:57 -04:00
//and set original item amount to what remains.
sourceItem - > SetStackSize ( totalAmount - amountToTransfer ) ;
}
return true ;
}
2019-07-07 20:56:15 +00:00
void CMonsterWeenie : : GiveItem ( uint32_t targetContainerId , uint32_t sourceItemId , uint32_t transferAmount )
2018-03-29 17:01:57 -04:00
{
2018-08-24 03:50:57 -05:00
if ( sourceItemId = = id )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_NONE ) ;
return ;
}
2018-08-22 21:05:31 -07:00
if ( IsExecutingEmote ( ) )
{
SendText ( csprintf ( " %s is busy. " , GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
NotifyInventoryFailedEvent ( sourceItemId , WERROR_GIVE_NOT_ALLOWED ) ;
return ;
}
2018-03-29 17:01:57 -04:00
if ( IsBusyOrInAction ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ACTIONS_LOCKED ) ;
return ;
}
2018-12-23 12:16:39 +00:00
CWeenieObject * target = g_pWorld - > FindWithinPVS ( this , targetContainerId ) ;
2019-02-26 21:05:30 +00:00
CWeenieObject * sourceItem = FindContainedItem ( sourceItemId ) ;
2018-03-29 17:01:57 -04:00
if ( ! sourceItem | | ! target )
{
2019-02-26 21:05:30 +00:00
if ( ! sourceItem )
{
CWeenieObject * hackItem = g_pWorld - > FindObject ( sourceItemId ) ;
2019-03-09 20:46:32 +00:00
if ( hackItem & & target )
2019-12-19 16:07:24 -05:00
SERVER_ERROR < < GetName ( ) < < " tried to give " < < hackItem - > GetName ( ) < < " to " < < target - > GetName ( ) ;
2019-02-26 21:05:30 +00:00
}
2018-03-29 17:01:57 -04:00
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return ;
}
if ( target - > IsContained ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_OBJECT_GONE ) ;
return ;
}
if ( sourceItem = = target | | ! target - > AsContainer ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_GIVE_NOT_ALLOWED ) ;
return ;
}
if ( sourceItem - > IsAttunedOrContainsAttuned ( ) & & target - > AsPlayer ( ) )
{
NotifyInventoryFailedEvent ( sourceItemId , WERROR_ATTUNED_ITEM ) ;
return ;
}
2018-12-23 12:16:39 +00:00
CGiveEvent * giveEvent = new CGiveEvent ;
giveEvent - > _target_id = targetContainerId ;
giveEvent - > _source_item_id = sourceItemId ;
giveEvent - > _transfer_amount = transferAmount ;
giveEvent - > _max_use_distance = 1.0 ;
giveEvent - > _give_event = true ;
this - > ExecuteUseEvent ( giveEvent ) ; //handles moving if needed and does all error checking during this process. At the completion of AnimSuccess FinishGiveItem is called.
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
void CMonsterWeenie : : FinishGiveItem ( CContainerWeenie * targetContainer , CWeenieObject * sourceItem , uint32_t amountToTransfer )
2018-03-29 17:01:57 -04:00
{
if ( amountToTransfer < = 0 | | amountToTransfer > = 100000 )
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_GIVE_NOT_ALLOWED ) ;
return ;
}
2020-04-29 04:02:09 +00:00
//if (!targetContainer->Container_CanStore(sourceItem))
//{
// NotifyInventoryFailedEvent(sourceItem->GetID(), WERROR_GIVE_NOT_ALLOWED);
// return;
//}
2018-03-29 17:01:57 -04:00
2018-07-12 14:41:21 -07:00
CWeenieObject * targetTopLevel = targetContainer - > GetWorldTopLevelOwner ( ) ;
2018-03-29 17:01:57 -04:00
if ( targetTopLevel ! = sourceItem - > GetWorldTopLevelOwner ( ) & & targetTopLevel & & targetTopLevel - > IsExecutingEmote ( ) )
{
SendText ( csprintf ( " %s is busy. " , targetTopLevel - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_GIVE_NOT_ALLOWED ) ;
return ;
}
2020-04-29 04:02:09 +00:00
//if (CPlayerWeenie *player = targetContainer->AsPlayer())
//{
// if (!(player->GetCharacterOptions() & AllowGive_CharacterOption))
// {
// NotifyInventoryFailedEvent(sourceItem->GetID(), WERROR_GIVE_NOT_ALLOWED);
// return;
// }
//}
//NOTE: A WCID may only exist in an emote table as refused or accepted (which makes sense logically). You either want it or you don't. Make up your mind.
if ( targetTopLevel - > m_Qualities . _emote_table & & targetTopLevel - > HasEmoteForID ( Refuse_EmoteCategory , sourceItem - > m_Qualities . id ) )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
//DO REFUSE EMOTE STUFF
CWeenieObject * topLevelOwner = sourceItem - > GetWorldTopLevelOwner ( ) ;
if ( topLevelOwner )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
if ( ! InqBoolQuality ( NPC_INTERACTS_SILENTLY_BOOL , FALSE ) & & ! topLevelOwner - > InqBoolQuality ( NPC_INTERACTS_SILENTLY_BOOL , FALSE ) )
topLevelOwner - > SendText ( csprintf ( " You allow %s to examine your %s. " , targetTopLevel - > GetName ( ) . c_str ( ) , sourceItem - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
auto emoteCategory = targetTopLevel - > m_Qualities . _emote_table - > _emote_table . lookup ( Refuse_EmoteCategory ) ;
if ( emoteCategory )
{
double dice = Random : : GenFloat ( 0.0 , 1.0 ) ;
double lastProbability = - 1.0 ;
2018-03-29 17:01:57 -04:00
2020-04-29 04:02:09 +00:00
for ( auto & emoteSet : * emoteCategory )
{
if ( emoteSet . classID = = sourceItem - > m_Qualities . id )
{
if ( dice > = emoteSet . probability )
continue ;
if ( lastProbability < 0.0 | | lastProbability = = emoteSet . probability )
{
targetTopLevel - > MakeEmoteManager ( ) - > ExecuteEmoteSet ( emoteSet , topLevelOwner - > GetID ( ) ) ;
lastProbability = emoteSet . probability ;
//There is no point in going through the motions of transfering this object. Fail silently as we triggered what we want.
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , 0 ) ;
return ;
}
}
}
}
}
2018-03-29 17:01:57 -04:00
}
2020-04-29 04:02:09 +00:00
if ( targetTopLevel - > AsMonster ( ) & & targetTopLevel - > AsMonster ( ) - > CanAcceptGive ( sourceItem ) )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
//DO GIVE STUFF HERE
2020-07-08 19:53:24 +00:00
BOOL bWasWielded = sourceItem - > IsWielded ( ) ;
2018-03-29 17:01:57 -04:00
2020-04-29 04:02:09 +00:00
int currentStackSize = sourceItem - > InqIntQuality ( STACK_SIZE_INT , 1 , TRUE ) ;
if ( amountToTransfer > currentStackSize )
2018-03-29 17:01:57 -04:00
{
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_GIVE_NOT_ALLOWED ) ;
return ;
}
2020-04-29 04:02:09 +00:00
CWeenieObject * newStackItem ;
if ( amountToTransfer < currentStackSize )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
// partial stack, make a new object
newStackItem = g_pWeenieFactory - > CloneWeenie ( sourceItem ) ;
newStackItem - > SetID ( g_pWorld - > GenerateGUID ( eDynamicGUID ) ) ;
if ( ! g_pWorld - > CreateEntity ( newStackItem , false ) )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_GIVE_NOT_ALLOWED ) ;
return ;
2018-03-29 17:01:57 -04:00
}
2020-04-29 04:02:09 +00:00
sourceItem - > SetStackSize ( currentStackSize - amountToTransfer ) ;
newStackItem - > SetStackSize ( amountToTransfer ) ;
}
else
{
newStackItem = sourceItem ;
sourceItem - > ReleaseFromAnyWeenieParent ( ) ;
2020-07-08 19:53:24 +00:00
sourceItem - > SetWeenieContainer ( 0 ) ;
sourceItem - > SetWielderID ( 0 ) ;
sourceItem - > SetWieldedLocation ( INVENTORY_LOC : : NONE_LOC ) ;
}
if ( AsPlayer ( ) & & bWasWielded )
{
int setSpell ;
if ( sourceItem - > m_Qualities . InqInt ( EQUIPMENT_SET_ID_INT , setSpell ) )
{
AsPlayer ( ) - > UpdateSetSpells ( setSpell , sourceItem - > GetID ( ) ) ;
}
if ( sourceItem - > IsAetheria ( ) )
{
AsPlayer ( ) - > UpdateSigilProcRate ( ) ;
}
2020-04-29 04:02:09 +00:00
}
2018-03-29 17:01:57 -04:00
2020-07-08 19:53:24 +00:00
// Take it out of whatever slot it's in.
2020-04-29 04:02:09 +00:00
newStackItem - > m_Qualities . SetInstanceID ( CONTAINER_IID , targetContainer - > GetID ( ) ) ;
newStackItem - > _cachedHasOwner = true ;
CWeenieObject * topLevelOwnerObj = newStackItem - > GetWorldTopLevelOwner ( ) ;
assert ( topLevelOwnerObj ) ;
assert ( topLevelOwnerObj - > AsContainer ( ) ) ;
if ( topLevelOwnerObj )
{
if ( CContainerWeenie * topLevelOwner = topLevelOwnerObj - > AsContainer ( ) )
{
if ( newStackItem = = sourceItem )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
SendNetMessage ( InventoryMove ( sourceItem - > GetID ( ) , targetContainer - > GetID ( ) , 0 , sourceItem - > RequiresPackSlot ( ) ? 1 : 0 ) , PRIVATE_MSG , TRUE ) ;
2018-03-29 17:01:57 -04:00
}
2020-04-29 04:02:09 +00:00
if ( ! InqBoolQuality ( NPC_INTERACTS_SILENTLY_BOOL , FALSE ) & & ! topLevelOwner - > InqBoolQuality ( NPC_INTERACTS_SILENTLY_BOOL , FALSE ) )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
targetContainer - > EmitSound ( Sound_ReceiveItem , 1.0f ) ;
if ( amountToTransfer > 1 & & ! ( topLevelOwner - > m_Qualities . _emote_table & & topLevelOwner - > HasEmoteForID ( Refuse_EmoteCategory , newStackItem - > m_Qualities . id ) ) )
2018-07-31 23:56:39 -05:00
{
2020-04-29 04:02:09 +00:00
SendText ( csprintf ( " You give %s %s %s. " , topLevelOwner - > GetName ( ) . c_str ( ) , FormatNumberString ( amountToTransfer ) . c_str ( ) , newStackItem - > GetPluralName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
topLevelOwner - > SendText ( csprintf ( " %s gives you %s %s. " , GetName ( ) . c_str ( ) , FormatNumberString ( amountToTransfer ) . c_str ( ) , newStackItem - > GetPluralName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
2018-07-31 23:56:39 -05:00
}
else
{
SendText ( csprintf ( " You give %s %s. " , topLevelOwner - > GetName ( ) . c_str ( ) , newStackItem - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
topLevelOwner - > SendText ( csprintf ( " %s gives you %s. " , GetName ( ) . c_str ( ) , newStackItem - > GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) ;
}
2018-03-29 17:01:57 -04:00
}
2020-04-29 04:02:09 +00:00
topLevelOwner - > MakeAware ( newStackItem , true ) ;
2018-03-29 17:01:57 -04:00
2020-04-29 04:02:09 +00:00
if ( newStackItem - > AsContainer ( ) )
{
newStackItem - > AsContainer ( ) - > MakeAwareViewContent ( topLevelOwner ) ;
}
2018-03-29 17:01:57 -04:00
2020-04-29 04:02:09 +00:00
if ( AsPlayer ( ) & & newStackItem - > m_Qualities . id = = W_COINSTACK_CLASS )
RecalculateCoinAmount ( W_COINSTACK_CLASS ) ;
2018-03-29 17:01:57 -04:00
2020-04-29 04:02:09 +00:00
topLevelOwner - > OnReceiveInventoryItem ( this , newStackItem , 0 ) ;
//topLevelOwner->DebugValidate();
//DebugValidate();
if ( AsPlayer ( ) )
RecalculateEncumbrance ( ) ;
return ;
}
2018-03-29 17:01:57 -04:00
}
2020-04-29 04:02:09 +00:00
if ( AsPlayer ( ) )
RecalculateEncumbrance ( ) ;
2018-03-29 17:01:57 -04:00
}
2020-04-29 04:02:09 +00:00
NotifyInventoryFailedEvent ( sourceItem - > GetID ( ) , WERROR_GIVE_NOT_ALLOWED ) ;
return ;
2018-03-29 17:01:57 -04:00
}
2018-11-10 09:45:18 -06:00
2018-03-29 17:01:57 -04:00
void CMonsterWeenie : : Tick ( )
{
CContainerWeenie : : Tick ( ) ;
Movement_Think ( ) ;
if ( m_MonsterAI )
m_MonsterAI - > Update ( ) ;
}
void CMonsterWeenie : : OnDealtDamage ( DamageEventData & damageData )
{
CWeenieObject : : OnDealtDamage ( damageData ) ;
if ( m_MonsterAI )
m_MonsterAI - > OnDealtDamage ( damageData ) ;
}
void CMonsterWeenie : : OnTookDamage ( DamageEventData & damageData )
{
CWeenieObject : : OnTookDamage ( damageData ) ;
2018-05-16 00:19:58 +01:00
if ( m_MonsterAI )
m_MonsterAI - > OnTookDamage ( damageData ) ;
}
void CMonsterWeenie : : UpdateDamageList ( DamageEventData & damageData )
{
2018-07-11 04:53:32 +00:00
if ( damageData . source & & damageData . outputDamageFinal > 0 & & damageData . damage_type ! = STAMINA_DAMAGE_TYPE & & damageData . damage_type ! = MANA_DAMAGE_TYPE )
2018-05-09 22:32:49 +01:00
{
2019-07-07 20:56:15 +00:00
uint32_t source = damageData . source - > GetID ( ) ;
std : : map < uint32_t , int > : : iterator itr = m_aDamageSources . find ( source ) ;
std : : map < uint32_t , int > : : iterator itr_high = m_aDamageSources . find ( m_highestDamageSource ) ;
2018-05-07 14:13:40 +01:00
2019-05-01 21:14:45 +00:00
if ( itr = = m_aDamageSources . end ( ) )
2018-05-09 22:32:49 +01:00
{
2019-05-01 21:14:45 +00:00
itr = m_aDamageSources . emplace ( std : : make_pair ( source , 0 ) ) . first ;
2018-05-09 22:32:49 +01:00
}
2018-05-07 14:13:40 +01:00
2019-07-07 20:56:15 +00:00
uint32_t oid = 0 ; // InqIIDQuality(PET_OWNER_IID, 0);
2019-05-12 10:54:25 -07:00
if ( damageData . source & & damageData . source - > m_Qualities . InqInstanceID ( PET_OWNER_IID , oid ) )
2019-05-01 21:14:45 +00:00
{
itr = m_aDamageSources . find ( oid ) ;
if ( itr = = m_aDamageSources . end ( ) )
{
itr = m_aDamageSources . emplace ( std : : make_pair ( oid , 0 ) ) . first ;
}
source = oid ;
}
//m_aDamageSources[source] += damageData.outputDamageFinal;
itr - > second + = damageData . outputDamageFinal ;
2018-06-25 16:13:15 +01:00
m_totalDamageTaken + = damageData . outputDamageFinal ;
2019-05-01 21:14:45 +00:00
if ( m_highestDamageSource = = 0 | | itr - > second > itr_high - > second )
2018-06-25 16:13:15 +01:00
{
m_highestDamageSource = source ;
2018-07-11 04:53:32 +00:00
if ( monster_brawl & & m_MonsterAI & & ! ( InqIntQuality ( CREATURE_TYPE_INT , 0 ) = = damageData . source - > InqIntQuality ( CREATURE_TYPE_INT , 0 ) ) )
2018-06-25 16:13:15 +01:00
{
2018-07-11 04:53:32 +00:00
m_MonsterAI - > SetNewTarget ( damageData . source ) ;
2018-06-25 16:13:15 +01:00
return ;
}
2018-07-11 04:53:32 +00:00
if ( m_MonsterAI & & m_MonsterAI - > _toleranceType ! = TolerateEverything & & damageData . source - > AsPlayer ( ) ) // TODO: maths to determine when to setnewtarget not just per attack as it would allow ping-ponging mobs
2018-06-25 16:13:15 +01:00
{
2018-07-13 16:51:42 -05:00
m_MonsterAI - > m_fAggroTime = Timer : : cur_time + 10.0f ;
2018-07-11 04:53:32 +00:00
m_MonsterAI - > SetNewTarget ( damageData . source ) ;
2018-06-25 16:13:15 +01:00
}
}
2018-07-11 04:53:32 +00:00
2018-05-09 22:32:49 +01:00
}
2018-03-29 17:01:57 -04:00
}
2018-05-07 14:13:40 +01:00
void CMonsterWeenie : : OnRegen ( STypeAttribute2nd currentAttrib , int newAmount )
{
CWeenieObject : : OnRegen ( currentAttrib , newAmount ) ;
if ( currentAttrib = = HEALTH_ATTRIBUTE_2ND )
{
2019-07-07 20:56:15 +00:00
uint32_t maxHealth = 0 ;
2018-05-07 14:13:40 +01:00
m_Qualities . InqAttribute2nd ( MAX_HEALTH_ATTRIBUTE_2ND , maxHealth , FALSE ) ;
if ( maxHealth = = newAmount )
{
// reset damage sources
m_aDamageSources . clear ( ) ;
2018-06-25 16:13:15 +01:00
m_highestDamageSource = 0 ;
m_totalDamageTaken = 0 ;
2018-07-11 04:53:32 +00:00
2018-05-07 14:13:40 +01:00
}
}
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : GivePerksForKill ( CWeenieObject * pKilled )
2018-05-07 14:13:40 +01:00
{
// Prevent CWeenieObject::GivePerksForKill from running
}
2019-07-30 02:19:05 +00:00
void CMonsterWeenie : : GiveXP ( int64_t amount , ExperienceHandlingType flags , bool showText )
{
if ( amount < = 0 )
return ;
if ( m_Qualities . GetInt ( AUGMENTATION_BONUS_XP_INT , 0 ) )
{
2019-12-19 16:07:24 -05:00
amount = uint64_t ( ( double ) amount * 1.05 ) ;
2019-07-30 02:19:05 +00:00
}
OnGivenXP ( amount , flags ) ;
uint64_t newAvailableXP = ( uint64_t ) InqInt64Quality ( AVAILABLE_EXPERIENCE_INT64 , 0 ) + amount ;
uint64_t newTotalXP = ( uint64_t ) InqInt64Quality ( TOTAL_EXPERIENCE_INT64 , 0 ) + amount ;
int currentLevel = InqIntQuality ( LEVEL_INT , 1 ) ;
uint32_t skillCredits = 0 ;
bool bLeveled = false ;
uint64_t xpToNextLevel = ExperienceSystem : : ExperienceToLevel ( currentLevel + 1 ) ;
while ( xpToNextLevel < = newTotalXP & & currentLevel < ExperienceSystem : : GetMaxLevel ( ) )
{
currentLevel + + ;
skillCredits + = ExperienceSystem : : GetCreditsForLevel ( currentLevel ) ;
bLeveled = true ;
xpToNextLevel = ExperienceSystem : : ExperienceToLevel ( currentLevel + 1 ) ;
if ( ! xpToNextLevel )
break ;
}
2019-09-18 02:53:46 +00:00
//TODO: When luminance is introduced, move this.
2019-07-30 02:19:05 +00:00
m_Qualities . SetInt64 ( AVAILABLE_EXPERIENCE_INT64 , newAvailableXP ) ;
NotifyInt64StatUpdated ( AVAILABLE_EXPERIENCE_INT64 ) ;
2019-09-18 02:53:46 +00:00
if ( currentLevel < 275 ) {
m_Qualities . SetInt64 ( TOTAL_EXPERIENCE_INT64 , newTotalXP ) ;
NotifyInt64StatUpdated ( TOTAL_EXPERIENCE_INT64 ) ;
}
2019-07-30 02:19:05 +00:00
if ( bLeveled )
{
GiveSkillCredit ( skillCredits ) ;
2019-09-03 14:18:02 +00:00
fellowship_ptr_t fs = GetFellowship ( ) ;
2019-07-30 02:19:05 +00:00
if ( fs )
{
fs - > FullUpdate ( ) ;
}
AllegianceTreeNode * node = g_pAllegianceManager - > GetTreeNode ( GetID ( ) ) ;
if ( node )
node - > _level = currentLevel ;
m_Qualities . SetInt ( LEVEL_INT , currentLevel ) ;
NotifyIntStatUpdated ( LEVEL_INT ) ;
EmitEffect ( PS_LevelUp , 1.0f ) ;
if ( currentLevel = = 275 )
{
2019-09-18 02:53:46 +00:00
m_Qualities . SetInt64 ( TOTAL_EXPERIENCE_INT64 , 191226310247 ) ;
NotifyInt64StatUpdated ( TOTAL_EXPERIENCE_INT64 ) ;
2019-07-30 02:19:05 +00:00
EmitEffect ( PS_WeddingBliss , 1.0f ) ;
}
const char * notice = csprintf (
" You are now level %s! You have %s experience points and %s skill credits available to raise skills and attributes. " ,
FormatNumberString ( currentLevel ) . c_str ( ) ,
FormatNumberString ( newAvailableXP ) . c_str ( ) ,
FormatNumberString ( InqIntQuality ( AVAILABLE_SKILL_CREDITS_INT , 0 ) ) . c_str ( ) ) ;
SendText ( notice , LTT_ADVANCEMENT ) ;
// restore vitals
if ( ! IsDead ( ) )
{
SetMaxVitals ( true ) ;
}
}
if ( showText )
{
const char * notice = csprintf (
" You've earned %s experience. " ,
FormatNumberString ( amount ) . c_str ( ) ) ;
SendText ( notice , LTT_DEFAULT ) ;
}
if ( flags & ExperienceHandlingType : : ShareWithAllegiance )
{
// let allegiance manager pass it up
g_pAllegianceManager - > HandleAllegiancePassup ( GetID ( ) , amount , true ) ;
}
std : : list < CWeenieObject * > equipment ;
Container_GetWieldedByMask ( equipment , ALL_LOC ) ;
for ( CWeenieObject * item : equipment )
{
item - > GiveXP ( amount , flags , false ) ;
}
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : OnIdentifyAttempted ( CWeenieObject * other )
2018-03-29 17:01:57 -04:00
{
if ( m_MonsterAI )
m_MonsterAI - > OnIdentifyAttempted ( other ) ;
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : OnResistSpell ( CWeenieObject * attacker )
2018-03-29 17:01:57 -04:00
{
HandleAggro ( attacker ) ;
if ( m_MonsterAI )
m_MonsterAI - > OnResistSpell ( attacker ) ;
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : OnEvadeAttack ( CWeenieObject * attacker )
2018-03-29 17:01:57 -04:00
{
HandleAggro ( attacker ) ;
if ( m_MonsterAI )
m_MonsterAI - > OnEvadeAttack ( attacker ) ;
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : HandleAggro ( CWeenieObject * attacker )
2018-03-29 17:01:57 -04:00
{
if ( m_MonsterAI )
m_MonsterAI - > HandleAggro ( attacker ) ;
}
2019-07-07 20:56:15 +00:00
bool CMonsterWeenie : : IsAttackMotion ( uint32_t motion )
2018-03-29 17:01:57 -04:00
{
switch ( ( WORD ) motion )
{
case 0x62 :
case 0x63 :
case 0x64 :
case 0x65 :
case 0x66 :
case 0x67 :
case 0x68 :
case 0x69 :
case 0x6A :
return true ;
}
return false ;
}
2019-07-07 20:56:15 +00:00
void CMonsterWeenie : : OnMotionDone ( uint32_t motion , BOOL success )
2018-03-29 17:01:57 -04:00
{
CWeenieObject : : OnMotionDone ( motion , success ) ;
if ( motion = = 0x40000011 )
{
OnDeathAnimComplete ( ) ;
}
if ( m_MotionUseData . m_MotionUseType ! = MUT_UNDEF )
{
bool bUseSuccess = success & & ! IsDead ( ) ;
if ( motion = = m_MotionUseData . m_MotionUseMotionID )
{
switch ( m_MotionUseData . m_MotionUseType )
{
case MUT_CONSUME_FOOD :
2018-11-09 13:39:05 -06:00
{
bool bConsumed = false ;
MotionUseData useData = m_MotionUseData ;
if ( bUseSuccess )
2018-03-29 17:01:57 -04:00
{
2018-11-09 13:39:05 -06:00
m_MotionUseData . Reset ( ) ; // necessary so this doesn't become infinitely recursive
DoForcedStopCompletely ( ) ;
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
CWeenieObject * pItem = FindContainedItem ( useData . m_MotionUseTarget ) ;
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
if ( pItem )
2018-03-29 17:01:57 -04:00
{
2018-11-09 13:39:05 -06:00
ReleaseContainedItemRecursive ( pItem ) ;
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
bConsumed = true ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
if ( uint32_t use_sound_did = pItem - > InqDIDQuality ( USE_SOUND_DID , 0 ) )
2018-11-09 13:39:05 -06:00
EmitSound ( use_sound_did , 1.0f ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t boost_stat = pItem - > InqIntQuality ( BOOSTER_ENUM_INT , 0 ) ;
uint32_t boost_value = pItem - > InqIntQuality ( BOOST_VALUE_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
switch ( boost_stat )
{
case HEALTH_ATTRIBUTE_2ND :
case STAMINA_ATTRIBUTE_2ND :
case MANA_ATTRIBUTE_2ND :
{
STypeAttribute2nd maxStatType = ( STypeAttribute2nd ) ( boost_stat - 1 ) ;
STypeAttribute2nd statType = ( STypeAttribute2nd ) boost_stat ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t statValue = 0 , maxStatValue = 0 ;
2018-11-09 13:39:05 -06:00
m_Qualities . InqAttribute2nd ( statType , statValue , FALSE ) ;
m_Qualities . InqAttribute2nd ( maxStatType , maxStatValue , FALSE ) ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
uint32_t newStatValue = min ( statValue + boost_value , maxStatValue ) ;
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
int statChange = newStatValue - statValue ;
if ( statChange )
2018-03-29 17:01:57 -04:00
{
2018-11-09 13:39:05 -06:00
if ( statType = = HEALTH_ATTRIBUTE_2ND )
2018-03-29 17:01:57 -04:00
{
2018-11-09 13:39:05 -06:00
AdjustHealth ( statChange ) ;
NotifyAttribute2ndStatUpdated ( statType ) ;
}
else
2018-03-29 17:01:57 -04:00
{
2018-11-09 13:39:05 -06:00
m_Qualities . SetAttribute2nd ( statType , newStatValue ) ;
NotifyAttribute2ndStatUpdated ( statType ) ;
2018-03-29 17:01:57 -04:00
}
}
2018-11-09 13:39:05 -06:00
const char * vitalName = " " ;
switch ( boost_stat )
{
case HEALTH_ATTRIBUTE_2ND : vitalName = " health " ; break ;
case STAMINA_ATTRIBUTE_2ND : vitalName = " stamina " ; break ;
case MANA_ATTRIBUTE_2ND : vitalName = " mana " ; break ;
}
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
SendText ( csprintf ( " The %s restores %d points of your %s. " , pItem - > GetName ( ) . c_str ( ) , max ( 0 , statChange ) , vitalName ) , LTT_DEFAULT ) ;
break ;
}
2018-03-29 17:01:57 -04:00
}
2018-11-09 13:39:05 -06:00
NotifyContainedItemRemoved ( pItem - > id ) ;
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
pItem - > MarkForDestroy ( ) ;
}
2018-03-29 17:01:57 -04:00
}
2018-11-09 13:39:05 -06:00
if ( ! bConsumed )
NotifyInventoryFailedEvent ( useData . m_MotionUseTarget , 0 ) ;
break ;
}
2018-03-29 17:01:57 -04:00
}
m_MotionUseData . Reset ( ) ;
}
}
}
2018-07-12 14:41:21 -07:00
CCorpseWeenie * CMonsterWeenie : : CreateCorpse ( bool visible )
2018-03-29 17:01:57 -04:00
{
if ( ! InValidCell ( ) )
return NULL ;
// spawn corpse
2018-11-09 13:39:05 -06:00
CCorpseWeenie * pCorpse = ( CCorpseWeenie * ) g_pWeenieFactory - > CreateWeenieByClassID ( W_CORPSE_CLASS ) ;
2018-03-29 17:01:57 -04:00
2019-02-10 01:03:51 +00:00
if ( m_Qualities . GetBool ( TREASURE_CORPSE_BOOL , false ) )
{
pCorpse - > m_Qualities . SetDataID ( SETUP_DID , 33558212 ) ;
pCorpse - > m_Qualities . SetDataID ( MOTION_TABLE_DID , 150995355 ) ;
pCorpse - > m_Qualities . SetFloat ( DEFAULT_SCALE_FLOAT , 0.4 ) ;
2019-12-19 16:07:24 -05:00
pCorpse - > SetName ( csprintf ( " Treasure of %s " , GetName ( ) . c_str ( ) ) ) ;
}
2019-02-10 01:03:51 +00:00
else
{
pCorpse - > CopyDIDStat ( SETUP_DID , this ) ;
2019-12-19 16:07:24 -05:00
pCorpse - > CopyFloatStat ( DEFAULT_SCALE_FLOAT , this ) ;
2019-02-10 01:03:51 +00:00
pCorpse - > SetName ( csprintf ( " Corpse of %s " , GetName ( ) . c_str ( ) ) ) ;
pCorpse - > CopyFloatStat ( TRANSLUCENCY_FLOAT , this ) ;
pCorpse - > CopyDIDStat ( MOTION_TABLE_DID , this ) ;
}
2019-12-19 16:07:24 -05:00
2018-03-29 17:01:57 -04:00
// pCorpse->CopyDIDStat(SOUND_TABLE_DID, this);
// pCorpse->CopyDIDStat(PHYSICS_EFFECT_TABLE_DID, this);
2018-07-12 14:41:21 -07:00
pCorpse - > CopyIntStat ( LEVEL_INT , this ) ; //copy the level so the treasure generator can have access to that value.
2018-03-29 17:01:57 -04:00
ObjDesc desc ;
GetObjDesc ( desc ) ;
pCorpse - > SetObjDesc ( desc ) ;
2019-02-10 01:03:51 +00:00
auto initpos = m_Position ;
2018-03-29 17:01:57 -04:00
pCorpse - > SetInitialPosition ( m_Position ) ;
pCorpse - > InitPhysicsObj ( ) ;
2018-09-21 18:33:19 -05:00
//set velocity so that corpses are affected by gravity.
pCorpse - > set_velocity ( _phys_obj - > m_velocityVector , 0 ) ;
2018-03-29 17:01:57 -04:00
pCorpse - > m_bDontClear = false ;
pCorpse - > m_Qualities . SetString ( LONG_DESC_STRING , csprintf ( " Killed by %s. " , m_DeathKillerNameForCorpse . empty ( ) ? " a mysterious source " : m_DeathKillerNameForCorpse . c_str ( ) ) ) ;
pCorpse - > m_Qualities . SetInstanceID ( KILLER_IID , m_DeathKillerIDForCorpse ) ;
pCorpse - > m_Qualities . SetInstanceID ( VICTIM_IID , GetID ( ) ) ;
pCorpse - > MakeMovementManager ( TRUE ) ;
MovementParameters params ;
params . autonomous = 0 ;
pCorpse - > last_move_was_autonomous = false ;
pCorpse - > DoMotion ( GetCommandID ( 17 ) , & params , 0 ) ;
if ( ! visible )
pCorpse - > m_Qualities . SetBool ( VISIBILITY_BOOL , false ) ;
if ( ! g_pWorld - > CreateEntity ( pCorpse ) )
2018-04-28 15:36:01 -07:00
{
SERVER_ERROR < < " Unable to create corpse of " < < GetName ( ) . c_str ( ) < < " at Landblock: " < < csprintf ( " 0x%08X " , m_Position . objcell_id ) < <
" (X, Y, Z): " < < m_Position . frame . m_origin . x < < " , " < < m_Position . frame . m_origin . y < < m_Position . frame . m_origin . z ;
2018-07-12 14:41:21 -07:00
pCorpse = NULL ;
2018-04-28 15:36:01 -07:00
}
2018-03-29 17:01:57 -04:00
m_DeathKillerIDForCorpse = 0 ;
m_DeathKillerNameForCorpse . clear ( ) ;
return pCorpse ;
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : DropAllLoot ( CCorpseWeenie * pCorpse )
2018-03-29 17:01:57 -04:00
{
}
2018-07-12 14:41:21 -07:00
void CMonsterWeenie : : GenerateDeathLoot ( CCorpseWeenie * pCorpse )
2018-03-29 17:01:57 -04:00
{
2019-07-07 20:56:15 +00:00
if ( uint32_t deathTreasureType = InqDIDQuality ( DEATH_TREASURE_TYPE_DID , 0 ) )
2018-03-29 17:01:57 -04:00
g_pWeenieFactory - > GenerateFromTypeOrWcid ( pCorpse , DestinationType : : ContainTreasure_DestinationType , deathTreasureType ) ;
2018-06-26 19:48:05 +01:00
if ( m_Qualities . _create_list )
g_pWeenieFactory - > AddFromCreateList ( pCorpse , m_Qualities . _create_list , ( DestinationType ) ( Contain_DestinationType | Treasure_DestinationType ) ) ;
2018-07-11 04:53:32 +00:00
std : : list < CWeenieObject * > removeList ;
2018-03-29 17:01:57 -04:00
2019-07-07 20:56:15 +00:00
for ( auto item : pCorpse - > m_Items )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( item - > IsDestroyedOnDeath ( ) )
2018-11-08 18:36:26 -06:00
removeList . push_back ( item ) ;
2018-03-29 17:01:57 -04:00
}
for ( auto item : removeList )
item - > Remove ( ) ;
}
void CMonsterWeenie : : OnDeathAnimComplete ( )
{
if ( ! m_bWaitingForDeathToFinish )
return ;
m_bWaitingForDeathToFinish = false ;
2018-09-14 18:46:57 -05:00
CWeenieObject * killer = g_pWorld - > FindObject ( m_DeathKillerIDForCorpse , false ) ;
2018-07-12 14:41:21 -07:00
if ( ! _IsPlayer ( ) )
{
MarkForDestroy ( ) ;
}
2018-03-29 17:01:57 -04:00
// create corpse
2018-07-12 14:41:21 -07:00
CPlayerWeenie * player = AsPlayer ( ) ;
2019-12-19 16:07:24 -05:00
if ( ! player & & ! m_Qualities . GetBool ( NO_CORPSE_BOOL , false ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
CCorpseWeenie * pCorpse = CreateCorpse ( ) ;
2018-03-29 17:01:57 -04:00
if ( pCorpse )
GenerateDeathLoot ( pCorpse ) ;
2018-09-14 18:46:57 -05:00
2018-10-07 20:31:15 -05:00
if ( pCorpse & & m_bIsRareEligible & & ! g_pTreasureFactory - > _TreasureProfile - > rareTiers . empty ( ) & & g_pConfig - > RareDropMultiplier ( ) > 0.0 )
2018-11-09 13:39:05 -06:00
{
2018-09-14 18:46:57 -05:00
if ( killer & & killer - > _IsPlayer ( ) )
g_pWeenieFactory - > GenerateRareItem ( pCorpse , killer ) ;
}
2018-03-29 17:01:57 -04:00
}
2018-04-24 02:03:00 -05:00
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
void CMonsterWeenie : : OnDeath ( uint32_t killer_id )
2018-03-29 17:01:57 -04:00
{
2018-07-28 16:55:02 +01:00
if ( m_aDamageSources . empty ( ) ) // not sure this should ever happen
2018-07-12 14:41:21 -07:00
{
2018-07-28 16:55:02 +01:00
m_highestDamageSource = killer_id ;
2018-07-12 14:41:21 -07:00
}
2019-05-01 21:14:45 +00:00
CWeenieObject : : OnDeath ( m_highestDamageSource ) ;
2018-09-14 18:46:57 -05:00
CheckRareEligible ( g_pWorld - > FindObject ( m_highestDamageSource , false ) ) ;
2018-05-07 14:13:40 +01:00
int level = InqIntQuality ( LEVEL_INT , 0 ) ;
2019-02-20 00:06:17 -06:00
int baseXPForKill = 0 ;
int baseLumForKill = 0 ;
int64_t xpForKill = 0 ;
int64_t lumForKill = 0 ;
2018-05-07 14:13:40 +01:00
if ( level < = 0 )
2019-02-20 00:06:17 -06:00
baseXPForKill = 0 ;
else if ( ! m_Qualities . InqInt ( XP_OVERRIDE_INT , baseXPForKill , 0 , FALSE ) )
baseXPForKill = ( uint32_t ) GetXPForKillLevel ( level ) ;
2018-05-07 14:13:40 +01:00
2020-04-29 00:15:00 -07:00
xpForKill = ( int64_t ) ( baseXPForKill * g_pConfig - > GetKillXPMultiplier ( ) ) ;
2018-05-07 14:13:40 +01:00
2018-12-18 17:02:31 -06:00
if ( level < = 0 )
lumForKill = 0 ;
2019-02-20 00:06:17 -06:00
else if ( m_Qualities . InqInt ( LUMINANCE_AWARD_INT , baseLumForKill , 0 , FALSE ) )
2020-04-29 00:15:00 -07:00
lumForKill = ( int64_t ) ( baseLumForKill * g_pConfig - > GetKillXPMultiplier ( ) ) ;
2018-12-18 17:02:31 -06:00
2018-05-07 14:13:40 +01:00
if ( xpForKill > 0 )
{
// hand out xp proportionally
2018-07-12 14:41:21 -07:00
for ( auto it = m_aDamageSources . begin ( ) ; it ! = m_aDamageSources . end ( ) ; + + it )
2018-05-07 14:13:40 +01:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * pSource = g_pWorld - > FindObject ( it - > first ) ;
2019-07-07 20:56:15 +00:00
//uint32_t oid = 0;// InqIIDQuality(PET_OWNER_IID, 0);
2019-05-12 10:54:25 -07:00
//if (pSource->m_Qualities.InqInstanceID(PET_OWNER_IID, oid))
//{
// pSource = g_pWorld->FindObject(oid);
//}
2019-05-01 21:14:45 +00:00
2018-07-28 16:55:02 +01:00
double dPercentage = ( double ) it - > second / m_totalDamageTaken ;
2018-05-07 14:13:40 +01:00
if ( pSource )
{
pSource - > GiveSharedXP ( dPercentage * xpForKill , false ) ;
2018-12-18 17:02:31 -06:00
if ( lumForKill > 0 )
pSource - > GiveSharedLum ( dPercentage * lumForKill , false ) ;
2018-05-07 14:13:40 +01:00
}
}
}
2018-07-28 16:55:02 +01:00
m_DeathKillerIDForCorpse = m_highestDamageSource ;
if ( ! g_pWorld - > FindObjectName ( m_highestDamageSource , m_DeathKillerNameForCorpse ) )
2018-06-17 16:27:58 -05:00
m_DeathKillerNameForCorpse = " fate " ;
2018-11-09 13:39:05 -06:00
if ( m_Qualities . _generator_registry & & m_Qualities . GetInt ( GENERATOR_DESTRUCTION_TYPE_INT , 0 ) & & m_Qualities . GetInt ( GENERATOR_DESTRUCTION_TYPE_INT , 0 ) ! = 1 )
2018-06-17 16:27:58 -05:00
{
2019-07-07 20:56:15 +00:00
for ( auto entry : m_Qualities . _generator_registry - > _registry )
2018-06-17 16:27:58 -05:00
{
2018-07-12 14:41:21 -07:00
CWeenieObject * weenie = g_pWorld - > FindObject ( entry . second . m_objectId ) ;
2018-08-04 17:24:12 -07:00
if ( weenie - > AsMonster ( ) ! = nullptr )
weenie - > AsMonster ( ) - > OnDeath ( 0 ) ;
2018-06-17 16:27:58 -05:00
}
}
2018-03-29 17:01:57 -04:00
MakeMovementManager ( TRUE ) ;
StopCompletely ( 0 ) ;
bool bHardcoreDeath = false ;
if ( g_pConfig - > HardcoreMode ( ) & & _IsPlayer ( ) )
{
2018-07-28 16:55:02 +01:00
if ( CWeenieObject * pKiller = g_pWorld - > FindObject ( m_highestDamageSource ) )
2018-03-29 17:01:57 -04:00
{
if ( ! g_pConfig - > HardcoreModePlayersOnly ( ) | | pKiller - > _IsPlayer ( ) )
{
bHardcoreDeath = true ;
}
}
}
if ( ! bHardcoreDeath )
{
MovementStruct mvs ;
MovementParameters params ;
mvs . type = RawCommand ;
mvs . motion = Motion_Dead ;
mvs . params = & params ;
params . action_stamp = + + m_wAnimSequence ;
last_move_was_autonomous = 0 ;
m_bWaitingForDeathToFinish = true ;
if ( movement_manager - > PerformMovement ( mvs ) )
{
// animation failed for some reason
OnDeathAnimComplete ( ) ;
}
else
{
Animation_Update ( ) ;
}
}
else
{
if ( ! m_DeathKillerNameForCorpse . empty ( ) )
{
g_pWorld - > BroadcastGlobal ( ServerText ( csprintf ( " %s has been defeated by %s. " , GetName ( ) . c_str ( ) , m_DeathKillerNameForCorpse . c_str ( ) ) , LTT_DEFAULT ) , PRIVATE_MSG ) ;
}
else
{
g_pWorld - > BroadcastGlobal ( ServerText ( csprintf ( " %s has been defeated. " , GetName ( ) . c_str ( ) ) , LTT_DEFAULT ) , PRIVATE_MSG ) ;
}
2018-07-12 14:41:21 -07:00
if ( CCorpseWeenie * pCorpse = CreateCorpse ( ) )
2018-03-29 17:01:57 -04:00
{
DropAllLoot ( pCorpse ) ;
}
g_pDBIO - > DeleteCharacter ( GetID ( ) ) ;
BeginLogout ( ) ;
}
}
bool CMonsterWeenie : : IsDead ( )
{
if ( m_bReviveAfterAnim )
return true ;
return CWeenieObject : : IsDead ( ) ;
}
void CMonsterWeenie : : ChangeCombatMode ( COMBAT_MODE mode , bool playerRequested )
{
2018-11-09 13:39:05 -06:00
COMBAT_MODE newCombatMode = ( COMBAT_MODE ) InqIntQuality ( COMBAT_MODE_INT , COMBAT_MODE : : NONCOMBAT_COMBAT_MODE , TRUE ) ;
2019-07-07 20:56:15 +00:00
uint32_t new_motion_style = get_minterp ( ) - > InqStyle ( ) ;
2018-03-29 17:01:57 -04:00
2019-12-19 16:07:24 -05:00
//if (_IsPlayer())
//{
switch ( mode )
2018-11-09 13:39:05 -06:00
{
2019-12-19 16:07:24 -05:00
case NONCOMBAT_COMBAT_MODE :
new_motion_style = Motion_NonCombat ;
newCombatMode = COMBAT_MODE : : NONCOMBAT_COMBAT_MODE ;
2018-11-09 13:39:05 -06:00
break ;
2018-03-29 17:01:57 -04:00
2019-12-19 16:07:24 -05:00
case MELEE_COMBAT_MODE :
2018-11-09 13:39:05 -06:00
{
2019-12-19 16:07:24 -05:00
CWeenieObject * weapon = GetWieldedMelee ( ) ;
CWeenieObject * shield = GetWieldedShield ( ) ;
if ( ! weapon )
weapon = GetWieldedTwoHanded ( ) ;
2018-11-09 13:39:05 -06:00
2019-12-19 16:07:24 -05:00
CombatStyle default_combat_style = weapon ? ( CombatStyle ) weapon - > InqIntQuality ( DEFAULT_COMBAT_STYLE_INT , Undef_CombatStyle ) : Undef_CombatStyle ;
switch ( default_combat_style )
2018-11-09 13:39:05 -06:00
{
2019-12-19 16:07:24 -05:00
case Undef_CombatStyle :
case Unarmed_CombatStyle :
new_motion_style = Motion_HandCombat ;
if ( shield & & shield - > InqIntQuality ( LOCATIONS_INT , 0 , TRUE ) ! = SHIELD_LOC )
2018-11-09 13:39:05 -06:00
new_motion_style = Motion_DualWieldCombat ;
2018-03-29 17:01:57 -04:00
2019-12-19 16:07:24 -05:00
newCombatMode = COMBAT_MODE : : MELEE_COMBAT_MODE ;
break ;
2018-03-29 17:01:57 -04:00
2019-12-19 16:07:24 -05:00
case OneHanded_CombatStyle :
{
new_motion_style = Motion_SwordCombat ;
2018-11-09 13:39:05 -06:00
2019-12-19 16:07:24 -05:00
if ( shield )
{
if ( shield - > InqIntQuality ( LOCATIONS_INT , 0 , TRUE ) ! = SHIELD_LOC )
new_motion_style = Motion_DualWieldCombat ;
else
new_motion_style = Motion_SwordShieldCombat ;
}
2018-11-09 13:39:05 -06:00
2019-12-19 16:07:24 -05:00
newCombatMode = COMBAT_MODE : : MELEE_COMBAT_MODE ;
break ;
2018-11-09 13:39:05 -06:00
}
2018-03-29 17:01:57 -04:00
2019-12-19 16:07:24 -05:00
case TwoHanded_CombatStyle :
new_motion_style = Motion_2HandedSwordCombat ;
newCombatMode = COMBAT_MODE : : MELEE_COMBAT_MODE ;
break ;
2018-11-09 13:39:05 -06:00
}
2018-03-29 17:01:57 -04:00
2018-11-09 13:39:05 -06:00
break ;
2019-12-19 16:07:24 -05:00
}
case MISSILE_COMBAT_MODE :
{
CWeenieObject * weapon = GetWieldedMissile ( ) ;
CombatStyle default_combat_style = weapon ? ( CombatStyle ) weapon - > InqIntQuality ( DEFAULT_COMBAT_STYLE_INT , Undef_CombatStyle ) : Undef_CombatStyle ;
2018-03-29 17:01:57 -04:00
2019-12-19 16:07:24 -05:00
switch ( default_combat_style )
2018-11-09 13:39:05 -06:00
{
2019-12-19 16:07:24 -05:00
case Bow_CombatStyle :
if ( CWeenieObject * ammo = GetWieldedAmmo ( ) )
{
new_motion_style = Motion_BowCombat ;
newCombatMode = COMBAT_MODE : : MISSILE_COMBAT_MODE ;
}
else
{
NotifyWeenieError ( WERROR_COMBAT_OUT_OF_AMMO ) ;
new_motion_style = Motion_NonCombat ;
newCombatMode = COMBAT_MODE : : NONCOMBAT_COMBAT_MODE ;
}
break ;
case Crossbow_CombatStyle :
if ( CWeenieObject * ammo = GetWieldedAmmo ( ) )
{
new_motion_style = Motion_CrossbowCombat ;
newCombatMode = COMBAT_MODE : : MISSILE_COMBAT_MODE ;
}
else
{
NotifyWeenieError ( WERROR_COMBAT_OUT_OF_AMMO ) ;
new_motion_style = Motion_NonCombat ;
newCombatMode = COMBAT_MODE : : NONCOMBAT_COMBAT_MODE ;
}
break ;
case ThrownWeapon_CombatStyle :
new_motion_style = Motion_ThrownWeaponCombat ;
2018-03-29 17:01:57 -04:00
newCombatMode = COMBAT_MODE : : MISSILE_COMBAT_MODE ;
2019-12-19 16:07:24 -05:00
break ;
case Atlatl_CombatStyle :
if ( CWeenieObject * ammo = GetWieldedAmmo ( ) )
{
new_motion_style = Motion_AtlatlCombat ;
newCombatMode = COMBAT_MODE : : MISSILE_COMBAT_MODE ;
}
else
{
NotifyWeenieError ( WERROR_COMBAT_OUT_OF_AMMO ) ;
new_motion_style = Motion_NonCombat ;
newCombatMode = COMBAT_MODE : : NONCOMBAT_COMBAT_MODE ;
}
break ;
2018-03-29 17:01:57 -04:00
}
break ;
}
2019-12-19 16:07:24 -05:00
case MAGIC_COMBAT_MODE :
new_motion_style = Motion_Magic ;
newCombatMode = COMBAT_MODE : : MAGIC_COMBAT_MODE ;
break ;
}
//}
2018-03-29 17:01:57 -04:00
if ( new_motion_style ! = get_minterp ( ) - > InqStyle ( ) )
{
MovementParameters params ;
get_minterp ( ) - > DoMotion ( new_motion_style , & params ) ;
_server_control_timestamp + + ;
last_move_was_autonomous = false ;
Animation_Update ( ) ;
}
m_Qualities . SetInt ( COMBAT_MODE_INT , newCombatMode ) ;
if ( newCombatMode ! = mode | | ! playerRequested )
{
NotifyIntStatUpdated ( COMBAT_MODE_INT ) ;
}
}
2019-07-07 20:56:15 +00:00
uint32_t CMonsterWeenie : : DoForcedUseMotion ( MotionUseType useType , uint32_t motion , uint32_t target , uint32_t childID , uint32_t childLoc , MovementParameters * params )
2018-03-29 17:01:57 -04:00
{
m_MotionUseData . m_MotionUseType = useType ;
m_MotionUseData . m_MotionUseMotionID = motion ;
m_MotionUseData . m_MotionUseTarget = target ;
m_MotionUseData . m_MotionUseChildID = childID ;
m_MotionUseData . m_MotionUseChildLocation = childLoc ;
return DoForcedMotion ( motion , params ) ;
}
2019-03-16 22:46:13 -07:00
//thanks lime!
2018-07-12 14:41:21 -07:00
bool CMonsterWeenie : : ClothingPrioritySorter ( const CWeenieObject * first , const CWeenieObject * second )
2018-03-29 17:01:57 -04:00
{
2019-12-19 16:07:24 -05:00
if ( ( ( CWeenieObject * ) first ) - > InqBoolQuality ( TOP_LAYER_PRIORITY_BOOL , 0 ) )
return FALSE ;
else if ( ( ( CWeenieObject * ) second ) - > InqBoolQuality ( TOP_LAYER_PRIORITY_BOOL , 0 ) )
return TRUE ;
return ( ( CWeenieObject * ) first ) - > InqIntQuality ( CLOTHING_PRIORITY_INT , 0 , TRUE ) < ( ( CWeenieObject * ) second ) - > InqIntQuality ( CLOTHING_PRIORITY_INT , 0 , TRUE ) ;
2018-03-29 17:01:57 -04:00
}
void CMonsterWeenie : : GetObjDesc ( ObjDesc & objDesc )
{
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wieldedWearable ;
2018-11-09 13:39:05 -06:00
Container_GetWieldedByMask ( wieldedWearable , ARMOR_LOC | CLOTHING_LOC ) ;
2018-03-29 17:01:57 -04:00
for ( auto wearable : wieldedWearable )
{
if ( wearable - > IsAvatarJumpsuit ( ) )
{
objDesc = wearable - > m_WornObjDesc ;
return ;
}
}
CWeenieObject : : GetObjDesc ( objDesc ) ;
2018-05-21 23:20:21 +01:00
2019-07-07 20:56:15 +00:00
uint32_t head_object_id = 0 ;
2018-05-22 00:06:53 +01:00
2018-03-29 17:01:57 -04:00
if ( m_Qualities . InqDataID ( HEAD_OBJECT_DID , head_object_id ) )
objDesc . AddAnimPartChange ( new AnimPartChange ( 16 , head_object_id ) ) ;
2019-07-07 20:56:15 +00:00
uint32_t setup_id = 0 ;
2019-01-26 23:53:53 -06:00
m_Qualities . InqDataID ( SETUP_DID , setup_id ) ;
// some heritage groups have alternate setups (undead)
// we need to get the base gender setup or clothing tables won't work
int group = 1 ;
int gender = 1 ;
if ( m_Qualities . InqInt ( HERITAGE_GROUP_INT , group ) & & m_Qualities . InqInt ( GENDER_INT , gender ) )
{
HeritageGroup_CG * heritage = CachedCharGenData - > mHeritageGroupList . lookup ( group ) ;
Sex_CG * sex = heritage - > mGenderList . lookup ( gender ) ;
//objDesc += sex->objDesc;
HairStyle_CG * hair = nullptr ;
//if (m_Qualities.InqDataID(HEAD_OBJECT_DID, head_object_id))
// hair = sex->FindHairStyle(head_object_id);
hair = sex - > FindHairStyleAltSetup ( setup_id ) ;
if ( hair )
{
//objDesc += hair->objDesc;
2019-12-19 16:07:24 -05:00
2019-01-26 23:53:53 -06:00
//if (hair->alternateSetup == setup_id)
setup_id = sex - > setup ;
}
}
2019-07-07 20:56:15 +00:00
uint32_t old_eye_texture_id , new_eye_texture_id ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . InqDataID ( DEFAULT_EYES_TEXTURE_DID , old_eye_texture_id ) & & m_Qualities . InqDataID ( EYES_TEXTURE_DID , new_eye_texture_id ) )
objDesc . AddTextureMapChange ( new TextureMapChange ( 16 , old_eye_texture_id , new_eye_texture_id ) ) ;
2019-07-07 20:56:15 +00:00
uint32_t old_nose_texture_id , new_nose_texture_id ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . InqDataID ( DEFAULT_NOSE_TEXTURE_DID , old_nose_texture_id ) & & m_Qualities . InqDataID ( NOSE_TEXTURE_DID , new_nose_texture_id ) )
objDesc . AddTextureMapChange ( new TextureMapChange ( 16 , old_nose_texture_id , new_nose_texture_id ) ) ;
2019-07-07 20:56:15 +00:00
uint32_t old_mouth_texture_id , new_mouth_texture_id ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . InqDataID ( DEFAULT_MOUTH_TEXTURE_DID , old_mouth_texture_id ) & & m_Qualities . InqDataID ( MOUTH_TEXTURE_DID , new_mouth_texture_id ) )
objDesc . AddTextureMapChange ( new TextureMapChange ( 16 , old_mouth_texture_id , new_mouth_texture_id ) ) ;
2019-07-07 20:56:15 +00:00
uint32_t skin_palette_id ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . InqDataID ( SKIN_PALETTE_DID , skin_palette_id ) )
objDesc . AddSubpalette ( new Subpalette ( skin_palette_id , 0 < < 3 , 0x18 < < 3 ) ) ;
2019-07-07 20:56:15 +00:00
uint32_t hair_palette_id ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . InqDataID ( HAIR_PALETTE_DID , hair_palette_id ) )
objDesc . AddSubpalette ( new Subpalette ( hair_palette_id , 0x18 < < 3 , 0x8 < < 3 ) ) ;
2019-07-07 20:56:15 +00:00
uint32_t eye_palette_id ;
2018-03-29 17:01:57 -04:00
if ( m_Qualities . InqDataID ( EYES_PALETTE_DID , eye_palette_id ) )
objDesc . AddSubpalette ( new Subpalette ( eye_palette_id , 0x20 < < 3 , 0x8 < < 3 ) ) ;
2019-01-04 15:55:47 -06:00
std : : list < CWeenieObject * > wieldedArmors ;
Container_GetWieldedByMask ( wieldedArmors , CLOTHING_LOC | ARMOR_LOC ) ;
wieldedArmors . sort ( ClothingPrioritySorter ) ;
2018-03-29 17:01:57 -04:00
for ( auto armor : wieldedArmors )
{
if ( armor - > IsHelm ( ) )
{
if ( ! ShowHelm ( ) )
continue ;
}
2020-02-26 17:36:19 +00:00
if ( armor - > IsCloak ( ) )
{
if ( ! ShowCloak ( ) )
continue ;
}
2019-07-07 20:56:15 +00:00
uint32_t clothing_table_id = armor - > InqDIDQuality ( CLOTHINGBASE_DID , 0 ) ;
uint32_t palette_template_key = armor - > InqIntQuality ( PALETTE_TEMPLATE_INT , 0 ) ;
2018-03-29 17:01:57 -04:00
if ( clothing_table_id & & ! armor - > IsAvatarJumpsuit ( ) )
{
ClothingTable * clothingTable = ClothingTable : : Get ( clothing_table_id ) ;
if ( clothingTable )
{
ObjDesc od ;
ShadePackage shades ( armor - > InqFloatQuality ( SHADE_FLOAT , 0.0 ) ) ;
double shadeVal ;
if ( armor - > m_Qualities . InqFloat ( SHADE2_FLOAT , shadeVal ) )
shades . _val [ 1 ] = shadeVal ;
if ( armor - > m_Qualities . InqFloat ( SHADE3_FLOAT , shadeVal ) )
shades . _val [ 2 ] = shadeVal ;
if ( armor - > m_Qualities . InqFloat ( SHADE4_FLOAT , shadeVal ) )
shades . _val [ 3 ] = shadeVal ;
2019-01-04 15:55:47 -06:00
if ( clothingTable - > BuildObjDesc ( setup_id , palette_template_key , & shades , & od ) )
objDesc + = od ;
2018-03-29 17:01:57 -04:00
ClothingTable : : Release ( clothingTable ) ;
}
}
else
{
objDesc + = armor - > m_WornObjDesc ;
}
}
}
2019-07-07 20:56:15 +00:00
uint32_t CMonsterWeenie : : OnReceiveInventoryItem ( CWeenieObject * source , CWeenieObject * item , uint32_t desired_slot )
2018-03-29 17:01:57 -04:00
{
2018-07-11 04:53:32 +00:00
if ( source ! = this )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
if ( ! InqBoolQuality ( AI_ACCEPT_EVERYTHING_BOOL , false ) )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
// Use our emote table to determine what to do with this item.
if ( m_Qualities . _emote_table )
2018-03-29 17:01:57 -04:00
{
2020-04-29 04:02:09 +00:00
PackableList < EmoteSet > * emoteCategory = m_Qualities . _emote_table - > _emote_table . lookup ( Give_EmoteCategory ) ;
2019-12-19 16:07:24 -05:00
2020-04-29 04:02:09 +00:00
if ( emoteCategory )
2019-05-20 18:02:14 +00:00
{
2020-04-29 04:02:09 +00:00
double dice = Random : : GenFloat ( 0.0 , 1.0 ) ;
double lastProbability = 1.1 ; // initialize to ensure the first check sets correctly
EmoteSet lastEmoteSet ;
// first scan all the probability entries and find the one that is just higher than the dice roll
// assumes the entries are not increasing in values, can be in any order
for ( auto & emoteSet : * emoteCategory )
2019-05-20 18:02:14 +00:00
{
2020-04-29 04:02:09 +00:00
if ( emoteSet . classID = = item - > m_Qualities . id )
{
if ( dice > = emoteSet . probability ) // ignore any that are less than the dice roll
continue ;
else
if ( emoteSet . probability < = lastProbability ) // ignore any that are greater than the current pick
{
lastProbability = emoteSet . probability ;
lastEmoteSet = emoteSet ;
}
}
2019-05-20 18:02:14 +00:00
}
2020-04-29 04:02:09 +00:00
if ( lastProbability < = 1.0 ) // double check a probability was found
2018-07-31 23:56:39 -05:00
{
2020-04-29 04:02:09 +00:00
if ( item - > InqIntQuality ( STACK_SIZE_INT , 1 ) > 1 )
2018-07-31 23:56:39 -05:00
{
2020-04-29 04:02:09 +00:00
item - > DecrementStackNum ( 1 , false ) ;
2018-07-31 23:56:39 -05:00
SimulateGiveObject ( source - > AsContainer ( ) , item ) ;
}
2020-04-29 04:02:09 +00:00
else
g_pWorld - > RemoveEntity ( item ) ;
MakeEmoteManager ( ) - > ExecuteEmoteSet ( lastEmoteSet , source - > GetID ( ) ) ;
return 0 ;
2018-07-31 23:56:39 -05:00
}
}
}
2018-03-29 17:01:57 -04:00
}
2020-04-29 01:06:18 -04:00
g_pWorld - > RemoveEntity ( item ) ;
2018-03-29 17:01:57 -04:00
return 0 ;
}
else
{
// Unless the source is ourselves, that means the item is spawning.
item - > ReleaseFromAnyWeenieParent ( false , true ) ;
item - > SetWieldedLocation ( INVENTORY_LOC : : NONE_LOC ) ;
item - > SetWeenieContainer ( GetID ( ) ) ;
item - > ReleaseFromBlock ( ) ;
return Container_InsertInventoryItem ( 0 , item , desired_slot ) ;
}
}
double CMonsterWeenie : : GetMeleeDefenseModUsingWielded ( )
{
double defenseMod = 1.0 ;
2018-11-19 12:40:53 -06:00
// we don't have an attack manager unless we are in active combat
//if (m_AttackManager)
2018-11-16 12:40:14 -06:00
//{
2018-11-19 12:40:53 -06:00
// defenseMod *= (double)m_AttackManager->GetDefenseMod();
2018-11-16 12:40:14 -06:00
//}
2018-11-19 12:40:53 -06:00
CWeenieObject * main = GetWieldedCombat ( COMBAT_USE_MELEE ) ;
CWeenieObject * left = GetWieldedCombat ( COMBAT_USE_OFFHAND ) ;
CWeenieObject * bow = GetWieldedCombat ( COMBAT_USE_MISSILE ) ;
CWeenieObject * both = GetWieldedCombat ( COMBAT_USE_TWO_HANDED ) ;
CWeenieObject * caster = GetWieldedCaster ( ) ;
if ( caster )
defenseMod = caster - > GetMeleeDefenseMod ( ) ;
else if ( bow )
defenseMod = bow - > GetMeleeDefenseMod ( ) ;
else if ( both )
defenseMod = both - > GetMeleeDefenseMod ( ) ;
else
{
// Calling the weapon::GetMeleeDefenseMod will include buffs, as will calling the base
// Here we check wether or not the main hand is empty, using
// the base defense (probably 1 + buffs) instead
defenseMod = main ? main - > GetMeleeDefenseMod ( ) : CWeenieObject : : GetMeleeDefenseMod ( ) ;
if ( left )
defenseMod = max ( defenseMod , left - > GetMeleeDefenseMod ( ) ) ;
}
2018-03-29 17:01:57 -04:00
2018-11-19 12:40:53 -06:00
std : : list < CWeenieObject * > wielded ;
2018-03-29 17:01:57 -04:00
Container_GetWieldedByMask ( wielded , ARMOR_LOC ) ;
for ( auto item : m_Wielded ) //check all armor for appropriate imbue effects
{
2018-07-12 14:41:21 -07:00
if ( item - > GetImbueEffects ( ) & MeleeDefense_ImbuedEffectType )
2018-03-29 17:01:57 -04:00
defenseMod + = 0.01 ;
}
return defenseMod ;
}
double CMonsterWeenie : : GetMissileDefenseModUsingWielded ( )
{
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wielded ;
2018-03-29 17:01:57 -04:00
Container_GetWieldedByMask ( wielded , WEAPON_LOC | HELD_LOC ) ;
double defenseMod = 1.0 ;
for ( auto item : wielded )
{
defenseMod * = item - > GetMissileDefenseMod ( ) ;
}
defenseMod * = CWeenieObject : : GetMissileDefenseMod ( ) ;
Container_GetWieldedByMask ( wielded , ARMOR_LOC ) ;
for ( auto item : m_Wielded ) //check all armor for appropriate imbue effects
{
2018-07-12 14:41:21 -07:00
if ( item - > GetImbueEffects ( ) & MissileDefense_ImbuedEffectType )
2018-03-29 17:01:57 -04:00
defenseMod + = 0.01 ;
}
return defenseMod ;
}
double CMonsterWeenie : : GetMagicDefenseModUsingWielded ( )
{
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wielded ;
2018-03-29 17:01:57 -04:00
Container_GetWieldedByMask ( wielded , WEAPON_LOC | HELD_LOC ) ;
double defenseMod = 1.0 ;
for ( auto item : wielded )
{
defenseMod * = item - > GetMagicDefenseMod ( ) ;
}
defenseMod * = CWeenieObject : : GetMagicDefenseMod ( ) ;
2018-11-09 13:39:05 -06:00
/* Container_GetWieldedByMask(wielded, ARMOR_LOC);
for ( auto item : m_Wielded ) //check all armor for appropriate imbue effects - commented out as this is checked in TryMagicResist and should be adding 1 to skill, not 1%
{
if ( item - > GetImbueEffects ( ) & MagicDefense_ImbuedEffectType )
defenseMod + = 0.01 ;
} */
2018-03-29 17:01:57 -04:00
return defenseMod ;
}
int CMonsterWeenie : : GetAttackTimeUsingWielded ( )
{
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wielded ;
2018-03-29 17:01:57 -04:00
Container_GetWieldedByMask ( wielded , WEAPON_LOC ) ;
2018-11-09 13:39:05 -06:00
2018-03-29 17:01:57 -04:00
for ( auto item : wielded )
{
return item - > GetAttackTime ( ) ;
}
return CWeenieObject : : GetAttackTime ( ) ;
}
int CMonsterWeenie : : GetAttackTime ( )
{
/*
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wielded ;
2018-03-29 17:01:57 -04:00
Container_GetWieldedByMask ( wielded , WEAPON_LOC ) ;
int totalTime = CWeenieObject : : GetAttackTime ( ) ;
for ( auto item : wielded )
{
totalTime + = item - > GetAttackTime ( ) ;
}
return totalTime ;
*/
return CWeenieObject : : GetAttackTime ( ) ;
}
2020-07-20 12:17:16 -07:00
int CMonsterWeenie : : GetAttackDamage ( bool isAssess )
2018-03-29 17:01:57 -04:00
{
/*
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wielded ;
2018-03-29 17:01:57 -04:00
Container_GetWieldedByMask ( wielded , WEAPON_LOC ) ;
int damage = CWeenieObject : : GetAttackDamage ( ) ;
for ( auto item : wielded )
{
damage + = item - > GetAttackDamage ( ) ;
}
*/
2020-07-20 12:17:16 -07:00
return CWeenieObject : : GetAttackDamage ( isAssess ) ;
2018-03-29 17:01:57 -04:00
}
float CMonsterWeenie : : GetEffectiveArmorLevel ( DamageEventData & damageData , bool bIgnoreMagicArmor )
{
2018-07-12 14:41:21 -07:00
std : : list < CWeenieObject * > wielded ;
2018-11-09 13:39:05 -06:00
Container_GetWieldedByMask ( wielded , ARMOR_LOC | CLOTHING_LOC | SHIELD_LOC ) ;
2018-03-29 17:01:57 -04:00
2018-03-31 16:00:43 -04:00
EnchantedQualityDetails buffDetails ;
2018-11-09 13:39:05 -06:00
2018-03-31 16:00:43 -04:00
//body part
GetBodyArmorEnchantmentDetails ( damageData . hitPart , damageData . damage_type , & buffDetails ) ;
2018-03-29 17:01:57 -04:00
//body
2018-03-31 16:00:43 -04:00
buffDetails . rawValue + = CWeenieObject : : GetEffectiveArmorLevel ( damageData , bIgnoreMagicArmor ) ;
2018-03-29 17:01:57 -04:00
2018-03-31 16:00:43 -04:00
//equipment
for ( auto item : wielded )
buffDetails . rawValue + = item - > GetEffectiveArmorLevel ( damageData , bIgnoreMagicArmor ) ;
2020-07-30 16:30:26 -07:00
2018-04-01 15:03:58 -04:00
if ( damageData . isArmorRending & & damageData . armorRendingMultiplier < buffDetails . valueDecreasingMultiplier )
2018-03-31 16:00:43 -04:00
buffDetails . valueDecreasingMultiplier = damageData . armorRendingMultiplier ;
2018-03-29 17:01:57 -04:00
buffDetails . CalculateEnchantedValue ( ) ;
if ( bIgnoreMagicArmor )
2018-04-02 22:46:54 -05:00
return buffDetails . rawValue ; //Take the Raw value for Hollows. Debuffs should not count.
2018-03-29 17:01:57 -04:00
else
2018-03-31 16:00:43 -04:00
return buffDetails . enchantedValue ;
2018-03-29 17:01:57 -04:00
}
2019-10-06 08:35:22 -07:00
bool CMonsterWeenie : : TryMeleeAttack ( uint32_t target_id , ATTACK_HEIGHT height , float power , uint32_t motion )
2018-03-29 17:01:57 -04:00
{
if ( IsDead ( ) )
{
NotifyAttackDone ( WERROR_DEAD ) ;
2019-10-06 08:35:22 -07:00
return true ;
2018-03-29 17:01:57 -04:00
}
if ( ! IsAttacking ( ) & & IsBusyOrInAction ( ) | | ( _blockNewAttacksUntil ! = - 1 & & _blockNewAttacksUntil > Timer : : cur_time ) )
{
NotifyAttackDone ( WERROR_ACTIONS_LOCKED ) ;
2019-10-06 08:35:22 -07:00
return true ;
2018-03-29 17:01:57 -04:00
}
2019-09-14 12:53:36 -07:00
if ( AsPlayer ( ) )
{
double last_attack_time = 0.0f ;
if ( AsPlayer ( ) - > m_Qualities . InqFloat ( ATTACK_TIMESTAMP_FLOAT , last_attack_time ) )
{
if ( last_attack_time > 0.0f ) // player has attacked since last login
{
2019-10-27 17:58:43 +00:00
const auto current_time = Timer : : cur_time ;
2019-09-14 12:53:36 -07:00
if ( last_attack_time > current_time )
{
NotifyAttackDone ( WERROR_BAD_PARAM ) ;
2019-10-06 08:35:22 -07:00
return true ;
2019-09-14 12:53:36 -07:00
}
2019-12-19 16:07:24 -05:00
2019-09-14 12:53:36 -07:00
auto dual_wield_factor = 1.0 ;
if ( get_minterp ( ) - > InqStyle ( ) = = Motion_DualWieldCombat )
dual_wield_factor = .8f ;
2019-10-06 08:35:22 -07:00
const auto attack_delta = ( ( current_time - last_attack_time ) * dual_wield_factor ) + .001 ; // floating point fudge factor
2019-09-14 12:53:36 -07:00
if ( power > attack_delta )
{
NotifyAttackDone ( WERROR_BAD_PARAM ) ;
2019-10-06 08:35:22 -07:00
return false ;
2019-09-14 12:53:36 -07:00
}
2019-12-19 16:07:24 -05:00
2019-09-14 12:53:36 -07:00
}
}
}
2018-03-29 17:01:57 -04:00
if ( ! m_AttackManager )
{
2018-07-12 14:41:21 -07:00
m_AttackManager = new AttackManager ( this ) ;
2018-03-29 17:01:57 -04:00
}
// duplicate attack
m_AttackManager - > BeginMeleeAttack ( target_id , height , power , m_MonsterAI ? m_MonsterAI - > GetChaseDistance ( ) : 15.0f , motion ) ;
2019-12-19 16:07:24 -05:00
2019-03-07 03:53:59 +00:00
m_LastAttackHeight = height ;
m_LastAttackPower = power ;
m_LastAttackTarget = target_id ;
2018-03-29 17:01:57 -04:00
// ensure there's no heartbeat animation
_last_update_pos = Timer : : cur_time ;
2019-10-06 08:35:22 -07:00
return true ;
2018-03-29 17:01:57 -04:00
}
2019-07-07 20:56:15 +00:00
void CMonsterWeenie : : TryMissileAttack ( uint32_t target_id , ATTACK_HEIGHT height , float power , uint32_t motion )
2018-03-29 17:01:57 -04:00
{
if ( IsDead ( ) )
{
//NotifyWeenieError(WERROR_DEAD);
NotifyAttackDone ( WERROR_DEAD ) ;
return ;
}
if ( ! IsAttacking ( ) & & IsBusyOrInAction ( ) | | ( _blockNewAttacksUntil ! = - 1 & & _blockNewAttacksUntil > Timer : : cur_time ) )
{
//NotifyWeenieError(WERROR_ACTIONS_LOCKED);
NotifyAttackDone ( WERROR_ACTIONS_LOCKED ) ;
return ;
}
2019-09-14 12:53:36 -07:00
if ( AsPlayer ( ) )
{
double last_attack_time = 0.0f ;
if ( AsPlayer ( ) - > m_Qualities . InqFloat ( ATTACK_TIMESTAMP_FLOAT , last_attack_time ) )
{
if ( last_attack_time > 0.0f ) // player has attacked since last login
{
2019-10-06 16:06:30 -07:00
std : : chrono : : time_point < std : : chrono : : system_clock > now = std : : chrono : : system_clock : : now ( ) ;
auto duration = now . time_since_epoch ( ) ;
auto current_time = ( double ) std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( duration ) . count ( ) / 100 ;
2019-09-14 12:53:36 -07:00
if ( last_attack_time > current_time )
{
NotifyAttackDone ( WERROR_BAD_PARAM ) ;
return ;
}
2019-10-06 16:06:30 -07:00
const auto attack_delta = ( current_time - last_attack_time ) + .001 ; ;
2019-09-14 12:53:36 -07:00
if ( power > attack_delta )
{
NotifyAttackDone ( WERROR_BAD_PARAM ) ;
return ;
}
}
}
}
2018-03-29 17:01:57 -04:00
if ( ! m_AttackManager )
2018-07-12 14:41:21 -07:00
m_AttackManager = new AttackManager ( this ) ;
2018-03-29 17:01:57 -04:00
m_AttackManager - > BeginMissileAttack ( target_id , height , power , motion ) ;
2019-03-07 03:53:59 +00:00
m_LastAttackHeight = height ;
m_LastAttackPower = power ;
m_LastAttackTarget = target_id ;
2018-03-29 17:01:57 -04:00
// ensure there's no heartbeat animation
_last_update_pos = Timer : : cur_time ;
}
BOOL CMonsterWeenie : : DoCollision ( const class ObjCollisionProfile & prof )
{
if ( prof . IsDoor ( ) & & ! AsPlayer ( ) )
{
2018-07-12 14:41:21 -07:00
if ( CWeenieObject * weenie = g_pWorld - > FindObject ( prof . id ) )
2018-03-29 17:01:57 -04:00
{
2018-07-12 14:41:21 -07:00
if ( CBaseDoor * door = weenie - > AsDoor ( ) )
2018-03-29 17:01:57 -04:00
{
if ( ! door - > IsLocked ( ) & & door - > IsClosed ( ) )
{
door - > OpenDoor ( ) ;
}
}
}
}
return CContainerWeenie : : DoCollision ( prof ) ;
2018-05-07 14:13:40 +01:00
}
2018-05-15 00:04:29 -05:00
2020-07-08 19:53:24 +00:00
int CMonsterWeenie : : AdjustHealth ( int amount , bool useRatings )
2018-05-15 00:04:29 -05:00
{
2020-07-08 19:53:24 +00:00
int adjustedAmount = CWeenieObject : : AdjustHealth ( amount , useRatings ) ;
2018-05-15 00:04:29 -05:00
2019-07-07 20:56:15 +00:00
uint32_t maxHealth = 0 ;
2018-05-15 00:04:29 -05:00
m_Qualities . InqAttribute2nd ( MAX_HEALTH_ATTRIBUTE_2ND , maxHealth , FALSE ) ;
2019-07-07 20:56:15 +00:00
uint32_t currentHealth = 0 ;
2018-05-15 00:04:29 -05:00
m_Qualities . InqAttribute2nd ( HEALTH_ATTRIBUTE_2ND , currentHealth , FALSE ) ;
if ( maxHealth = = currentHealth )
{
// reset damage sources
m_aDamageSources . clear ( ) ;
2018-06-25 16:13:15 +01:00
m_highestDamageSource = 0 ;
m_totalDamageTaken = 0 ;
2018-07-11 04:53:32 +00:00
2018-05-15 00:04:29 -05:00
}
2018-07-01 22:44:09 +01:00
return adjustedAmount ;
2018-08-16 01:21:13 +12:00
}
2018-09-14 18:46:57 -05:00
bool CMonsterWeenie : : CheckRareEligible ( CWeenieObject * highestDamageDealer )
2018-11-09 13:39:05 -06:00
{
2018-09-14 18:46:57 -05:00
if ( ! highestDamageDealer )
return false ;
if ( highestDamageDealer )
{
if ( highestDamageDealer - > _IsPlayer ( ) & & ( m_Qualities . GetInt ( LEVEL_INT , 0 ) > = highestDamageDealer - > m_Qualities . GetInt ( LEVEL_INT , 0 ) ) | | ( m_Qualities . GetInt ( LEVEL_INT , 0 ) > = 100 ) )
if ( m_Qualities . GetDID ( DEATH_TREASURE_TYPE_DID , 0 ) )
{
m_bIsRareEligible = true ;
return true ;
}
}
return false ;
2019-07-07 20:56:15 +00:00
}
2019-07-30 02:19:05 +00:00
2019-09-29 01:51:54 +00:00
void CMonsterWeenie : : SetDisplayCombatDamage ( bool show )
{
m_bGiveCombatData = show ;
}
bool CMonsterWeenie : : ShowCombatDamage ( )
{
return m_bGiveCombatData ;
}
2020-04-29 04:02:09 +00:00
bool CMonsterWeenie : : CanAcceptGive ( CWeenieObject * item )
{
if ( AsPlayer ( ) )
{
if ( AsPlayer ( ) - > GetCharacterOptions ( ) & AllowGive_CharacterOption )
return Container_CanStore ( item ) ;
}
if ( InqBoolQuality ( ALLOW_GIVE_BOOL , false ) )
{
if ( InqBoolQuality ( AI_ACCEPT_EVERYTHING_BOOL , false ) )
return true ;
if ( HasEmoteForID ( Give_EmoteCategory , item - > m_Qualities . id ) )
return true ;
}
return false ;
}
2020-05-29 01:34:33 -07:00
int CMonsterWeenie : : GetAetheriaSetCount ( int setid )
{
int retVal = 0 ;
auto sigilBlue = GetWielded ( SIGIL_ONE_LOC ) ;
if ( sigilBlue )
{
int sigilBlueSet ;
if ( sigilBlue - > m_Qualities . InqInt ( EQUIPMENT_SET_ID_INT , sigilBlueSet ) & & sigilBlueSet = = setid )
{
retVal + = sigilBlue - > GetLevel ( ) ;
}
}
auto sigilYellow = GetWielded ( SIGIL_TWO_LOC ) ;
if ( sigilYellow )
{
int sigilYellowSet ;
if ( sigilYellow - > m_Qualities . InqInt ( EQUIPMENT_SET_ID_INT , sigilYellowSet ) & & sigilYellowSet = = setid )
{
retVal + = sigilYellow - > GetLevel ( ) ;
}
}
auto sigilRed = GetWielded ( SIGIL_THREE_LOC ) ;
if ( sigilRed )
{
int sigilRedSet ;
if ( sigilRed - > m_Qualities . InqInt ( EQUIPMENT_SET_ID_INT , sigilRedSet ) & & sigilRedSet = = setid )
{
retVal + = sigilRed - > GetLevel ( ) ;
}
}
return retVal ;
}