Skip to content

Instantly share code, notes, and snippets.

@ronjunevaldoz
Created January 3, 2017 19:30
Show Gist options
  • Save ronjunevaldoz/ec8ed113391ad70385bc1fd63f23c7a8 to your computer and use it in GitHub Desktop.
Save ronjunevaldoz/ec8ed113391ad70385bc1fd63f23c7a8 to your computer and use it in GitHub Desktop.
Duel is not working, no duel menu and uanble to hit on arena
#include "stdafx.h"
#include "..\_AIInterface\ActionMover.h"
#include "Mover.h"
#include "ModelObject.h"
#include "defineText.h"
#include "defineItem.h"
#include "defineObj.h"
#include "defineSound.h"
#include "defineSkill.h"
#include "lang.h"
#include "ModelObject.h"
#include "authorization.h"
#include "CreateObj.h"
#include "eveschool.h"
extern CGuildCombat g_GuildCombatMng;
#include "..\_aiinterface\aipet.h"
#if __VER >= 9 // __PET_0410
#include "pet.h"
#endif // __PET_0410
#if __VER >= 12 // __LORD
#ifdef __WORLDSERVER
#include "slord.h"
#endif // __WORLDSERVER
#endif // __LORD
#ifdef __SYS_TICKET
#ifdef __WORLDSERVER
#include "ticket.h"
#endif // __WORLDSERVER
#endif // __SYS_TICKET
#if __VER >= 11 // __SYS_IDENTIFY
#include "randomoption.h"
#endif // __SYS_IDENTIFY
#if __VER >= 11 // __SYS_PLAYER_DATA
#include "playerdata.h"
#endif // __SYS_PLAYER_DATA
#if __VER >= 13 // __HONORABLE_TITLE // 달인
#include "honor.h"
#endif // __HONORABLE_TITLE // 달인
#ifdef __QUIZ
#include "Quiz.h"
#endif // __QUIZ
#ifdef __CLIENT
#include "..\_Common\ParticleMng.h"
#include "Resdata.h"
#include "DPClient.h"
#include "DialogMsg.h"
extern CDPClient g_DPlay;
#include "GuildRender.h"
#else // __CLIENT
#include "User.h"
#include "UserMacro.h"
#include "WorldMng.h"
#include "DPSrvr.h"
#include "DPCoreClient.h"
#include "dpdatabaseclient.h"
#include "spevent.h"
extern CUserMng g_UserMng;
extern CWorldMng g_WorldMng;
extern CDPSrvr g_DPSrvr;
extern CDPDatabaseClient g_dpDBClient;
extern CDPCoreClient g_DPCoreClient;
#endif // __CLIENT
#include "..\_AIInterface\AIInterface.h"
#include "party.h"
extern CPartyMng g_PartyMng;
#include "guild.h"
extern CGuildMng g_GuildMng;
#include "guildwar.h"
extern CGuildWarMng g_GuildWarMng;
#include "definequest.h"
#include "Ship.h"
#ifdef __WORLDSERVER
#include "User.h"
#endif
#ifdef __EVENT_MONSTER
#include "EventMonster.h"
#endif // __EVENT_MONSTER
#if __VER >= 12 // __SECRET_ROOM
#include "SecretRoom.h"
#endif // __SECRET_ROOM
#if __VER >= 12 // __NEW_ITEMCREATEMON_SERVER
#include "CreateMonster.h"
#endif // __NEW_ITEMCREATEMON_SERVER
extern BOOL CanAdd( DWORD dwGold, int nPlus );
#ifndef __VM_0820
#ifndef __MEM_TRACE
#ifdef __WORLDSERVER
#ifdef __VM_0819
CMoverPool* CMover::m_pPool = new CMoverPool( 1024, "CMover" );
#else // __VM_0819
CMoverPool* CMover::m_pPool = new CMoverPool( 1024 );
#endif // __VM_0819
#else // __WORLDSERVER
#ifdef __VM_0819
CMoverPool* CMover::m_pPool = new CMoverPool( 128, "CMover" );
#else // __VM_0819
CMoverPool* CMover::m_pPool = new CMoverPool( 128 );
#endif // __VM_0819
#endif // __WORLDSERVER
#endif // __MEM_TRACE
#endif // __VM_0820
const int MAX_DIALOGFILENAME = 32;
#ifdef __CLIENT
// 퀘스트 아이콘 확축 프로세스
BOOL CMover::m_bQuestEmoticonAdd = TRUE;
FLOAT CMover::m_fQuestEmoticonScale = 1.0f;
#if __VER >= 8 //__Y_EYE_FLASH_8
LPDIRECT3DTEXTURE9 CMover::m_pTextureEye[2][MAX_HEAD] = { 0, };
LPDIRECT3DTEXTURE9 CMover::m_pTextureEyeFlash[2][MAX_HEAD] = { 0, };
#endif //__Y_EYE_FLASH_8
#endif
#if __VER >= 11 // __SYS_COLLECTING
#include "collecting.h"
#endif
// 비스트일 때는 컴팔 안되게..
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#pragma warning ( disable : 4355 )
CMover::CMover()
#ifdef __BUFF_1107
:
m_buffs( this )
#endif // __BUFF_1107
{
Init();
}
CMover::~CMover()
{
#ifdef __CLIENT
SAFE_DELETE( m_pLadolf ); // g_Object3DMng가 파괴되기전에 부를것
#if __VER >= 8 //__CSC_VER8_5
SAFE_DELETE( m_pAngel );
#endif //__CSC_VER8_5
#ifdef __EVE_BALLOON
SAFE_DELETE( m_pBalloon );
#endif //__EVE_BALLOON
#endif //__CLIENT
#ifdef __WORLDSERVER
SAFE_DELETE( m_pNpcProperty );
#endif
#ifdef __WORLDSERVER
#if __VER >= 12 // __NEW_ITEMCREATEMON_SERVER
CCreateMonster::GetInstance()->RemoveInfo( this );
#endif // __NEW_ITEMCREATEMON_SERVER
#endif // __WORLDSERVER
CMover* pOther = m_vtInfo.GetOther();
if( IsValidObj( pOther ) )
{
if( pOther->m_vtInfo.GetOther() == this )
pOther->m_vtInfo.TradeClear();
}
#ifdef __CLIENT
m_vtInfo.VendorClose();
g_DialogMsg.ClearMessage( (CObj*)this );
#endif // __CLIENT
SAFE_DELETE( m_pActMover );
for( int i = 0; i < MAX_VENDOR_INVENTORY_TAB; i++ )
SAFE_DELETE( m_ShopInventory[ i ] );
if( GetWorld() )
{
#if !defined(__CLIENT)
#ifdef __LAYER_1021
GetWorld()->m_respawner.Increment( GetRespawn(), GetRespawnType(), m_bActiveAttack, GetLayer() );
#else // __LAYER_1021
GetWorld()->m_respawner.Increment( GetRespawn(), GetRespawnType(), m_bActiveAttack );
#endif // __LAYER_1021
#endif
}
SAFE_DELETE_ARRAY( m_aQuest );
SAFE_DELETE_ARRAY( m_aCompleteQuest );
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
SAFE_DELETE_ARRAY( m_aCheckedQuest );
#endif // __IMPROVE_QUEST_INTERFACE
#ifdef __CLIENT
m_pSfxWing = NULL;
#if __VER >= 15 // __PETVIS
m_pSfxBuffPet = NULL;
#endif
#ifdef __BS_EFFECT_LUA
CSfxModelMng::GetThis()->SubData( GetId() );
#endif //__BS_EFFECT_LUA
#endif // __CLIENT
}
void CMover::Init()
{
m_dwMotion = -1;
m_dwMotionOption = 0;
m_dwType = OT_MOVER;
m_vMarkingPos = D3DXVECTOR3( 0, 0, 0 );
m_nCount = xRandom( 128 ); // 리스폰 되는 몹마다 시작카운터를 약간씩 틀리게 해서 좀더 다양한 반응이 나오게 했다.
m_bPlayer = FALSE;
m_dwTypeFlag = 0;
m_pRide = NULL;
m_pAIInterface = NULL;
m_nHitPoint = 100;
m_nManaPoint = 100;
m_nFatiguePoint = 100;
m_vDestPos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
m_idDest = NULL_ID;
m_fArrivalRange = 0.0f;
SetSex( SEX_FEMALE );
m_dwVirtItem = II_WEA_HAN_HAND;
m_dwVirtType = VT_ITEM;
m_nHitPoint = 100;
m_nManaPoint = 100;
m_nFatiguePoint = 100;
m_dwRideItemIdx = II_RID_RID_STI_MAGIC;
m_nRemainGP = 0;
m_nDefenseMin = 0;
m_nDefenseMax = 0;
m_nJob = -1;
memset( m_szName, 0, sizeof(TCHAR) );
m_nAdjHitRate = 0;
m_nAdjParry = 0;
m_nStr = 15;
m_nSta = 15;
m_nDex = 15;
m_nInt = 15;
m_nLevel = 1;
m_nExp1 = 0;
m_nDeathExp = 0;
m_nDeathLevel = 0;
m_dwFace = 0;
m_dwSkinSet = 0;
m_dwHairMesh = 0;
m_dwHairColor = 0;
m_dwHeadMesh = 0;
#if __VER >= 12 // __MOD_TUTORIAL
m_nTutorialState = 0;
#else // __MOD_TUTORIAL
m_nFlightLv = 0;
#endif // __MOD_TUTORIAL
m_nFxp = 0;
m_szCharacterKey[ 0 ] = 0;
{
int i;
for( i = 0; i < MAX_ADJPARAMARY; i ++ ) m_adjParamAry[i] = 0;
for( i = 0; i < MAX_ADJPARAMARY; i ++ ) m_chgParamAry[i] = 0x7FFFFFFF; // 이유가 있다.
}
ClearEquipInfo();
m_vtInfo.Init( this );
#if __VER >= 11 // __SYS_POCKET
#ifdef __WORLDSERVER
m_Pocket.Init( this );
#endif // __WORLDSERVER
#endif // __SYS_POCKET
m_idPlayer = NULL_ID;
m_dwAuthorization = AUTH_GENERAL;
m_idMarkingWorld = NULL_ID;
m_dwRegionAttr = 0;
m_dwOldRegionAttr = 0;
m_bPositiveX = m_bPositiveZ = false;
m_fDestAngle = -1.0f;
m_bLeft = false;
m_bForward = true;
m_dwMode = 0;
memset( &m_CorrAction, 0, sizeof(CORR_ACTION) );
m_fWaitQueryGetPos = FALSE;
m_nCorr = 0;
m_uRemnantCorrFrm = 0;
m_fHairColorR = 1.0f;
m_fHairColorG = 1.0f;
m_fHairColorB = 1.0f;
m_dwHairColor = D3DCOLOR_COLORVALUE( 1.0f, 1.0f, 1.0f, 1.0f );
m_nQuestSize = 0;
m_aQuest = NULL;
m_aCompleteQuest = NULL;
m_nCompleteQuestSize = 0;
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
m_aCheckedQuest = NULL;
m_nCheckedQuestSize = 0;
#endif // __IMPROVE_QUEST_INTERFACE
#ifdef __WORLDSERVER
m_timerQuestLimitTime.Set( MIN( 1 ) );
m_dwPKTargetLimit = 0;
#else // __WORLDSERVER
m_nQuestEmoticonIndex = -1;
m_bShowQuestEmoticon = TRUE;
#endif // __WORLDSERVER
m_idparty = 0;
m_oaCmd = m_oaAct = OBJACT_NONE;
memset( m_nCParam, 0, sizeof(m_nCParam) );
memset( m_nAParam, 0, sizeof(m_nAParam) );
m_dwFlag = 0;
m_nAtkCnt = 0;
m_wStunCnt = 0;
#ifndef __BUFF_1107
m_SkillState.Init();
m_SkillState.SetMover( this );
#endif // __BUFF_1107
m_idAttacker = NULL_ID;
m_idTargeter = NULL_ID;
m_idTracking = NULL_ID;
m_fExpRatio = 1.0f;
m_idMurderer = NULL_ID;
m_tmActionPoint = timeGetTime();
m_nDead = 0;
#if __VER >= 8 // __S8_PK
m_dwPKTime = 0;
m_nPKValue = 0;
m_dwPKPropensity = 0;
m_dwPKExp = 0;
#else // __VER >= 8 // __S8_PK
m_nNumKill = 0; // 킬수
m_nSlaughter = 0; // 슬로터 포인트
m_dwKarmaTick = 0;
#endif // __VER >= 8 // __S8_PK
m_wDarkCover = 0;
m_idLastHitMover = NULL_ID; // this가 마지막으로 쳤던 무버아이디
m_nFame = 0; // 명성
m_nDuel = 0; // 듀얼중인가.
m_idDuelOther = NULL_ID;
m_idDuelParty = 0;
m_nFuel = -1; // 초기값은 -1이다.
m_tmAccFuel = 0; // 0이면 가속 못하는 상태.
m_fAniSpeed = 1.0f;
m_idPoisonAttacker = NULL_ID;
m_wPoisonCnt = 0;
m_tmPoisonUnit = 0;
m_wPoisonDamage = 0;
m_wDarkCnt = 0;
m_wDarkVal = 0;
m_idBleedingAttacker = NULL_ID;
m_wBleedingCnt = 0;
m_tmBleedingUnit = 0;
m_wBleedingDamage = 0;
m_nMovePattern = 0;
m_nMoveEvent = 0;
m_nMoveEventCnt = 0;
m_idGuild = 0;
m_idGuildCloak = 0;
m_bGuildBank = FALSE;
m_idWar = 0;
m_nPlusMaxHitPoint = 0;
memset( m_dwSMTime, 0, sizeof( DWORD ) * SM_MAX );
m_nAttackResistLeft = (BYTE)0xff;
m_nAttackResistRight = (BYTE)0xff;
m_nDefenseResist = (BYTE)0xff;
#ifdef __WORLDSERVER
m_bLastPK = FALSE;
m_bLastDuelParty = FALSE;
m_bGuildCombat = FALSE;
m_tGuildMember = CTime::GetCurrentTime();
m_nQuestKeeping = 0; // 길드퀘스트 클락워크 퀘스트와 관련
m_nPartyQuestKeeping = 0;
// m_idCollecter = NULL_ID;
// m_nResource = 0;
// m_nCollectOwnCnt = 0;
#endif // __WORLDSERVER
#ifdef __CLIENT
m_nDmgCnt = 0;
m_nWaterCircleCount = 0;
m_idSfxHit = 0;
m_dwReqFlag = 0;
m_pCloakTexture = NULL;
m_fDestScale = 1.0f;
m_fDestScaleSlerp = 0;
#else // CLIENT
m_nReflexDmg = 0;
#endif // not Client
m_pActMover = new CActionMover( this );
m_pActMover->SetMover( this );
m_dwTickRecovery = ::timeGetTime() + NEXT_TICK_RECOVERY;
m_dwTickRecoveryStand = ::timeGetTime() + NEXT_TICK_RECOVERYSTAND;
m_dwTickDuel = ::timeGetTime() + NEXT_TICK_DUEL;
m_dwTickEndDuel = ::timeGetTime() + NEXT_TICK_ENDDUEL;
m_nDuelState = 0;
memset( &m_Resurrection_Data, 0, sizeof(m_Resurrection_Data) );
m_bRegenItem = TRUE;
m_bActiveAttack = FALSE;
m_dwGold = 0; // 0으로 할것. -xuzhu-
for( int i = 0; i < MAX_VENDOR_INVENTORY_TAB; i++ )
m_ShopInventory[ i ] = 0;
#if __VER >= 8 // 8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
m_bPVPEnd = FALSE;
#endif // __VER >= 8
#if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans
m_nLegend = LEGEND_CLASS_NORMAL;
#endif //__LEGEND // 9차 전승시스템 Neuz, World, Trans
#if __VER >= 11 // __MA_VER11_06 // 확율스킬 효과수정 world,neuz
memset( dwRemoveSfxObj, 0, sizeof( DWORD ) * MAX_SKILLBUFF_COUNT );
#endif // __MA_VER11_06 // 확율스킬 효과수정 world,neuz
#ifdef __CLIENT
m_dwLadolfFlag = 0;
m_pLadolf = NULL;
#if __VER >= 8 //__CSC_VER8_5
m_pAngel = NULL;
m_pAngelFlag = FALSE;
m_dwAngelKind = 0;
#endif //__CSC_VER8_5
#ifdef __EVE_BALLOON
m_pBalloonFlag = FALSE;
m_pBalloon = NULL;
m_dwBalloonKind = 0;
m_fBalloonYPos = 1.0f;
m_bBalloon = TRUE;
#endif //__EVE_BALLOON
#if __VER >= 14 // __WING_ITEM
m_eWingStateFlag = FLOATING;
m_fOldLengthSq = 0.0f;
#endif // __WING_ITEM
#endif //__CLIENT
m_fCrrSpd = 0.0f;
m_dwStateMode = 0;
m_nReadyTime = 0;
m_dwUseItemId = 0;
m_bItemFind = TRUE;
m_dwTickCheer= 0;
m_nCheerPoint = 0;
m_pIADestPos = NULL;
SetEatPetId( NULL_ID );
ZeroMemory( m_tmReUseDelay, sizeof( m_tmReUseDelay ) );
#ifdef __WORLDSERVER
m_pNpcProperty = NULL;
m_dwTickCreated = 0;
#endif
m_nGuildCombatState = 0;
m_dwCtrlReadyTime = 0xffffffff;
m_dwCtrlReadyId = NULL_ID;
m_nSkillLevel = 0;
m_nSkillPoint = 0;
m_dwMotionArrive = OBJMSG_STAND;
m_SkillTimerStop = FALSE;
#if __VER >= 8 //__CSC_VER8_5
m_nAngelExp = 0; /// 엔젤 경험치
m_nAngelLevel = 0; /// 엔젤 Level
#endif // __CSC_VER8_5
#if __VER >= 8 //__Y_EYE_FLASH_8
#ifdef __CLIENT
m_tmEye[0].Set( SEC(6) );
m_tmEye[1].Set( 200 );
#endif //__CLIENT
#endif //__Y_EYE_FLASH_8
#ifdef __CLIENT
m_SkillTimer.Set(1000); //Function Key누르고 있을 경우 Skill Delay값.
#endif //__CLIENT
#if __VER >= 9 // __PET_0410
m_dwPetId = NULL_ID;
m_nHealCnt = 0;
#endif // __PET_0410
#if __VER >= 9 //__AI_0509
m_fSpeedFactor = 1.0F;
#endif // __AI_0509
#ifdef __CLIENT
m_pSfxWing = NULL;
m_dwWingTime = -1;
#if __VER >= 15 // __PETVIS
m_pSfxBuffPet = NULL;
#endif //__PETVIS
#endif //__CLIENT
#ifdef __JEFF_9_20
m_dwMute = 0;
#endif // __JEFF_9_20
#if __VER >= 13 // __HONORABLE_TITLE // 달인
m_nHonor = -1; // 달인선택
m_dwHonorCheckTime = 0; //달인 시간체크
memset( m_aHonorTitle, 0, sizeof( int ) * MAX_HONOR_TITLE );// 달인수치
m_strTitle.Empty();
#endif // __HONORABLE_TITLE // 달인
#ifdef __VTN_TIMELIMIT
m_nAccountPlayTime = -1;
#endif // __VTN_TIMELIMIT
#if __VER >= 15 // __PETVIS
m_objIdVisPet = NULL_ID;
m_dwMoverSfxId = NULL_ID;
#endif // __PETVIS
#if __VER >= 15 // __CAMPUS
m_idCampus = 0;
m_nCampusPoint = 0;
#endif // __CAMPUS
}
// AI 매시지 보냄 : 객체의 행동 패턴, 현재 상태를 매시지로 제어함
void CMover::SendAIMsg( DWORD dwMsg, DWORD dwParam1, DWORD dwParam2 )
{
if( m_pAIInterface )
m_pAIInterface->SendAIMsg( dwMsg, dwParam1, dwParam2 );
}
// AI 매시지 보냄 : 객체의 행동 패턴, 현재 상태를 매시지로 제어함
void CMover::PostAIMsg( DWORD dwMsg, DWORD dwParam1, DWORD dwParam2 )
{
if( m_pAIInterface )
m_pAIInterface->PostAIMsg( dwMsg, dwParam1, dwParam2 );
}
//raiders.2006.11.28 trade돈을 계산에 포함하던 것을 제거
BOOL CMover::AddGold( int nGold, BOOL bSend )
{
if( nGold == 0 )
return TRUE;
//#ifdef __WORLDSERVER
// if( m_vtInfo.TradeGetGold() != 0 )
// return FALSE;
//#endif // __WORLDSERVER
#ifdef __PERIN_BUY_BUG
__int64 i64Total = static_cast<__int64>( GetGold() ) + static_cast<__int64>( nGold );
if( i64Total > static_cast<__int64>( INT_MAX ) )
i64Total = static_cast<__int64>( INT_MAX );
else if( i64Total < 0 )
i64Total = 0;
SetGold( static_cast<int>( i64Total ) );
#else // __PERIN_BUY_BUG
int nTotal = GetGold() + nGold;
if( nGold > 0 )
{
if( nTotal < 0 ) // overflow?
nTotal = INT_MAX;
}
else // nGold < 0
{
if( nTotal < 0 ) // underflow?
{
//#ifdef __WORLDSERVER
// Error( "AddGold: nTotal < 0" );
//#endif // __WORLDSERVER
nTotal = 0;
// return FALSE;
}
}
SetGold( nTotal );
#endif // __PERIN_BUY_BUG
if( bSend )
{
#ifdef __WORLDSERVER
#ifdef __PERIN_BUY_BUG
g_UserMng.AddSetPointParam( this, DST_GOLD, static_cast<int>( i64Total ) );
#else // __PERIN_BUY_BUG
g_UserMng.AddSetPointParam( this, DST_GOLD, nTotal );
#endif // __PERIN_BUY_BUG
#endif // __WORLDSERVER
}
return TRUE;
}
// 이동패턴 설정.
void CMover::SetMovePattern( int nPattern )
{
m_nMovePattern = nPattern;
m_nMoveEvent = 0;
m_nMoveEventCnt = 0;
ClearDest(); // 목표는 없다.
}
// 새로운 머리색깔이 적용되기 전에 이함수를 사용해야함...
// 원본 머리색깔을 참고하기 때문...
int CMover::GetHairCost( CMover* pMover, BYTE nR, BYTE nG, BYTE nB, BYTE nHair )
{
BYTE nOrignalR = (BYTE)( pMover->m_fHairColorR * 255 );
BYTE nOrignalG = (BYTE)( pMover->m_fHairColorG * 255 );
BYTE nOrignalB = (BYTE)( pMover->m_fHairColorB * 255 );
int nHairCost = 0;
#if __VER >= 8 //__CSC_VER8_4
int nHairColorCost = 0;
if( nR != nOrignalR || nG != nOrignalG || nB != nOrignalB )
nHairColorCost = HAIRCOLOR_COST;
else
nHairColorCost = 0;
if( pMover->m_dwHairMesh+1 != nHair+1 )
nHairCost = HAIR_COST;
else
nHairCost = 0;
return (nHairCost + nHairColorCost);
#else //__CSC_VER8_4
int nHairColorCostR = 0;
int nHairColorCostG = 0;
int nHairColorCostB = 0;
if( nR >= nOrignalR )
nHairColorCostR = (nR - nOrignalR)*13;
else
nHairColorCostR = (nOrignalR - nR)*7;
if( nG >= nOrignalG )
nHairColorCostG = (nG - nOrignalG)*13;
else
nHairColorCostG = (nOrignalG - nG)*7;
if( nB >= nOrignalB )
nHairColorCostB = (nB - nOrignalB)*13;
else
nHairColorCostB = (nOrignalB - nB)*7;
if( pMover->m_dwHairMesh+1 != nHair+1 )
{
switch( nHair+1 )
{
case 1: nHairCost = 2500; break;
case 2: nHairCost = 2500; break;
case 3: nHairCost = 2500; break;
case 4: nHairCost = 2500; break;
case 5: nHairCost = 2500; break;
default: nHairCost = 4000; break;
}
}
else
{
nHairCost = 0;
}
return ( nHairColorCostR + nHairColorCostG + nHairColorCostB + nHairCost );
#endif //__CSC_VER8_4
}
#ifdef __WORLDSERVER
void CMover::SubSMMode()
{
time_t tmCur = (time_t)( CTime::GetCurrentTime().GetTime() );
for( int i = 0 ; i < SM_MAX ; ++i )
{
if( m_dwSMTime[i] > 0 )
{
if( g_AddSMMode.bSMModetime[i] ) // 절대시간
{
if( m_dwSMTime[i] < (DWORD)( tmCur ) )
{
m_dwSMTime[i] = 0;
}
}
else // 카운트
{
if( i != SM_REVIVAL )
--m_dwSMTime[i];
}
if( m_dwSMTime[i] == 0 )
{
CItemElem* pItemElemParts = NULL;
if( i == SM_RESIST_ATTACK_LEFT || i == SM_RESIST_ATTACK_RIGHT )
{
int nAttackResist;
if( i == SM_RESIST_ATTACK_LEFT )
nAttackResist = m_nAttackResistLeft;
else
nAttackResist = m_nAttackResistRight;
switch( nAttackResist )
{
case SAI79::FIRE:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_FIREASTONE;
break;
case SAI79::WATER:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_WATEILSTONE;
break;
case SAI79::WIND:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_WINDYOSTONE;
break;
case SAI79::ELECTRICITY:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_LIGHTINESTONE;
break;
case SAI79::EARTH:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_EARTHYSTONE;
break;
}
if( i == SM_RESIST_ATTACK_LEFT )
{
m_nAttackResistLeft = (BYTE)0xff;
pItemElemParts = m_Inventory.GetEquip( PARTS_LWEAPON );
}
else
{
m_nAttackResistRight = (BYTE)0xff;
pItemElemParts = m_Inventory.GetEquip( PARTS_RWEAPON );
}
}
else if( i == SM_RESIST_DEFENSE )
{
switch( m_nDefenseResist )
{
case SAI79::FIRE:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEFIREASTONE;
break;
case SAI79::WATER:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEWATEILSTONE;
break;
case SAI79::WIND:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEWINDYOSTONE;
break;
case SAI79::ELECTRICITY:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DELIGHTINESTONE;
break;
case SAI79::EARTH:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEEARTHYSTONE;
break;
}
m_nDefenseResist = (BYTE)0xff;
pItemElemParts = m_Inventory.GetEquip( PARTS_UPPER_BODY );
}
if( pItemElemParts && ( i == SM_RESIST_DEFENSE || i == SM_RESIST_ATTACK_LEFT || i == SM_RESIST_ATTACK_RIGHT ) )
{
pItemElemParts->m_nResistSMItemId = 0;
((CUser*)this)->AddCommercialElem( pItemElemParts->m_dwObjId, 0 );
}
ItemProp* aItemprop = prj.GetItemProp( g_AddSMMode.dwSMItemID[i] );
if( aItemprop )
{
if( i == SM_MAX_HP )
{
ResetDestParam( aItemprop->dwDestParam[0], aItemprop->nAdjParamVal[1], 1 );
}
else if( i == SM_MAX_HP50 )
{
ResetDestParam( aItemprop->dwDestParam[0], m_nPlusMaxHitPoint, 1 );
}
else if( i == SM_VELOCIJUMP )
{
if( aItemprop->dwDestParam1 != -1 )
ResetDestParam( aItemprop->dwDestParam1, aItemprop->nAdjParamVal1 );
if( aItemprop->dwDestParam2 != -1 )
ResetDestParam( aItemprop->dwDestParam2, aItemprop->nAdjParamVal2 );
}
#if __VER >= 12 // 12차 극단유료아이템
// 090917 mirchang - 파스킬풀 아이템 사용 기간 종료
else if( i == SM_PARTYSKILL30 || i == SM_PARTYSKILL15 || i == SM_PARTYSKILL1 )
g_DPCoreClient.SendUserPartySkill( m_idPlayer, PARTY_PARSKILL_MODE, 0, 0, 1 );
#endif // 12차 극단유료아이템
g_dpDBClient.SendLogSMItemUse( "2", (CUser*)this, NULL, aItemprop );
}
else
{
WriteLog( "%s, %d\r\n\tNo SMItem dwSMItemID[%d] : %d / Name : %s", __FILE__, __LINE__, i, g_AddSMMode.dwSMItemID[i], m_szName );
}
((CUser*)this)->AddSMMode( i, 0 );
}
}
}
}
void CMover::ClearAllSMMode()
{
time_t tmCur = (time_t)( CTime::GetCurrentTime().GetTime() );
for( int i = 0 ; i < SM_MAX ; ++i )
{
if( m_dwSMTime[i] > 0 )
{
m_dwSMTime[i] = 0;
CItemElem* pItemElemParts = NULL;
if( i == SM_RESIST_ATTACK_LEFT || i == SM_RESIST_ATTACK_RIGHT )
{
int nAttackResist;
if( i == SM_RESIST_ATTACK_LEFT )
nAttackResist = m_nAttackResistLeft;
else
nAttackResist = m_nAttackResistRight;
switch( nAttackResist )
{
case SAI79::FIRE:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_FIREASTONE;
break;
case SAI79::WATER:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_WATEILSTONE;
break;
case SAI79::WIND:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_WINDYOSTONE;
break;
case SAI79::ELECTRICITY:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_LIGHTINESTONE;
break;
case SAI79::EARTH:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_EARTHYSTONE;
break;
}
if( i == SM_RESIST_ATTACK_LEFT )
{
m_nAttackResistLeft = (BYTE)0xff;
pItemElemParts = m_Inventory.GetEquip( PARTS_LWEAPON );
}
else
{
m_nAttackResistRight = (BYTE)0xff;
pItemElemParts = m_Inventory.GetEquip( PARTS_RWEAPON );
}
}
else if( i == SM_RESIST_DEFENSE )
{
switch( m_nDefenseResist )
{
case SAI79::FIRE:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEFIREASTONE;
break;
case SAI79::WATER:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEWATEILSTONE;
break;
case SAI79::WIND:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEWINDYOSTONE;
break;
case SAI79::ELECTRICITY:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DELIGHTINESTONE;
break;
case SAI79::EARTH:
g_AddSMMode.dwSMItemID[i] = II_CHR_SYS_SCR_DEEARTHYSTONE;
break;
}
m_nDefenseResist = (BYTE)0xff;
pItemElemParts = m_Inventory.GetEquip( PARTS_UPPER_BODY );
}
if( pItemElemParts && ( i == SM_RESIST_DEFENSE || i == SM_RESIST_ATTACK_LEFT || i == SM_RESIST_ATTACK_RIGHT ) )
{
pItemElemParts->m_nResistSMItemId = 0;
((CUser*)this)->AddCommercialElem( pItemElemParts->m_dwObjId, 0 );
}
ItemProp* aItemprop = prj.GetItemProp( g_AddSMMode.dwSMItemID[i] );
if( aItemprop )
{
if( i == SM_MAX_HP )
{
ResetDestParam( aItemprop->dwDestParam[0], aItemprop->nAdjParamVal[1], 1 );
}
else if( i == SM_MAX_HP50 )
{
ResetDestParam( aItemprop->dwDestParam[0], m_nPlusMaxHitPoint, 1 );
}
else if( i == SM_VELOCIJUMP )
{
if( aItemprop->dwDestParam1 != -1 )
ResetDestParam( aItemprop->dwDestParam1, aItemprop->nAdjParamVal1 );
if( aItemprop->dwDestParam2 != -1 )
ResetDestParam( aItemprop->dwDestParam2, aItemprop->nAdjParamVal2 );
}
#if __VER >= 12 // 12차 극단유료아이템
// 090917 mirchang - 파스킬풀 아이템 사용 기간 종료
else if( i == SM_PARTYSKILL30 || i == SM_PARTYSKILL15 || i == SM_PARTYSKILL1 )
g_DPCoreClient.SendUserPartySkill( m_idPlayer, PARTY_PARSKILL_MODE, 0, 0, 1 );
#endif // 12차 극단유료아이템
g_dpDBClient.SendLogSMItemUse( "2", (CUser*)this, NULL, aItemprop );
}
else
{
WriteLog( "%s, %d\r\n\tNo SMItem dwSMItemID[%d] : %d / Name : %s", __FILE__, __LINE__, i, g_AddSMMode.dwSMItemID[i], m_szName );
}
((CUser*)this)->AddSMMode( i, 0 );
}
}
}
BOOL CMover::SetSMMode( int nType, DWORD dwTime )
{
if( g_AddSMMode.bSMModetime[nType] ) // 절대시간
{
CTime tRealtime = CTime::GetCurrentTime();
CTimeSpan ctp( 0, 0, 0, dwTime );
tRealtime += ctp;
m_dwSMTime[nType] = (time_t)( tRealtime.GetTime() );
}
else // 카운트
{
m_dwSMTime[nType] = dwTime;
}
((CUser*)this)->AddSMMode( nType, m_dwSMTime[nType] );
return TRUE;
}
#endif // __WORLDSERVER
LPCHARACTER CMover::GetCharacter()
{
return prj.GetCharacter( m_szCharacterKey );
}
#ifdef __WORLDSERVER
void CMover::SetMarkingPos()
{
m_vMarkingPos = GetPos();
m_idMarkingWorld = GetWorld()->GetID();
}
#endif
// NPC관련 프로퍼티를 초기화한다.
void CMover::InitNPCProperty()
{
#ifdef __WORLDSERVER
if( m_pNpcProperty == NULL )
m_pNpcProperty = new CNpcProperty;
#endif
}
#if defined(__WORLDSERVER)
void CMover::InitCharacter( LPCHARACTER lpCharacter )
{
if( lpCharacter )
{
#ifdef __OPT_MEM_0811
if( lpCharacter->m_nEquipNum > 0 )
m_Inventory.SetItemContainer( ITYPE_ITEM, MAX_INVENTORY, MAX_HUMAN_PARTS );
#endif // __OPT_MEM_0811
strcpy( m_szName, lpCharacter->m_strName );
for( int i = 0; i < lpCharacter->m_nEquipNum; i++ )
{
BYTE nId, nCount;
short nNum;
CItemElem itemElem;
itemElem.m_dwItemId = lpCharacter->m_adwEquip[ i ];
itemElem.m_nItemNum = 1;
m_Inventory.Add( &itemElem, &nId, &nNum, &nCount );
CItemElem* pAddItem = m_Inventory.GetAtId( nId );
m_Inventory.DoEquip( pAddItem->m_dwObjIndex, itemElem.GetProp()->dwParts );
}
m_dwHairMesh = lpCharacter->m_dwHairMesh;
m_dwHairColor = lpCharacter->m_dwHairColor;
m_dwHeadMesh = lpCharacter->m_dwHeadMesh;
AllocShopInventory( lpCharacter );
LoadDialog(); // npcproperty->LoadDialog()
#ifdef __OUTPUT_INFO_0803
prj.OutputStore( lpCharacter->m_szKey, this );
#endif // __OUTPUT_INFO_0803
}
m_nHitPoint = GetMaxHitPoint();
}
BOOL CMover::LoadDialog()
{
if( m_pNpcProperty )
{
LPCHARACTER lpCharacter = GetCharacter();
if( lpCharacter )
return m_pNpcProperty->LoadDialog( lpCharacter );
}
return FALSE;
}
#endif // __WORLDSERVER
void CMover::ProcessQuest()
{
#ifdef __WORLDSERVER
if( IsPlayer() == FALSE )
return;
BOOL bTimer = FALSE;
if( m_timerQuestLimitTime.IsTimeOut() )
{
m_timerQuestLimitTime.Reset();
bTimer = TRUE;
}
for( int i = 0; i < m_nQuestSize; i++ )
{
LPQUEST lpQuest = (LPQUEST) &m_aQuest[ i ];
if( lpQuest )
{
QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( lpQuest->m_wId );
if( pQuestProp )
{
D3DXVECTOR3 vPos = GetPos();
// 퀘스트 리전안으로 들어가면 페트롤 임무 성공 플렉 세팅
if( pQuestProp->m_dwEndCondPatrolWorld == GetWorld()->m_dwWorldID && pQuestProp->m_rectEndCondPatrol.PtInRect( CPoint( (int) vPos.x, (int) vPos.z ) ) )
{
if( lpQuest->m_bPatrol == FALSE )
{
lpQuest->m_bPatrol = TRUE;
// 여기서 클라에 매시지도 하나 보내자.
// 탐사를 완료했습니다.
// 20 마리중 2마리를 퇴치했습니다.
((CUser*)this)->AddSetQuest( lpQuest );
}
}
// 시간 제한 퀘스트 시간 카운트
if( pQuestProp->m_nEndCondLimitTime && bTimer )
{
if( lpQuest->m_wTime && !(lpQuest->m_wTime & 0x8000) )
{
lpQuest->m_wTime--;
((CUser*)this)->AddSetQuest( lpQuest );
}
}
}
else
{
//WriteError( "ProcessQuest : pQuestProp NULL이다." );
//CString string;
//string.Format( "CMover::ProcessQuest : %s의 Quest %d의 pQuestProp NULL이다.", m_szName, lpQuest->m_wId );
//OutputDebugString( string );
}
}
else
{
//WriteError( "ProcessQuest : lpQuest가 NULL이다." );
//CString string;
//string.Format( "CMover::ProcessQuest : %s의 lpQuest가 NULL이다.", m_szName );
//OutputDebugString( string );
}
}
#else // __WORLDSERVER
if( IsPlayer() )
return;
LPCHARACTER lpCharacter = GetCharacter();
if( lpCharacter )
{
CMover* pMover = GetActiveMover();
m_nQuestEmoticonIndex = -1;
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
// NPC 퀘스트 이모티콘 우선순위 변경 - 완료 > 신규 > 진행 > 근레벨
for( int i = 0; i < lpCharacter->m_awSrcQuest.GetSize() ; i++ )
{
int nQuest = lpCharacter->m_awSrcQuest.GetAt( i );
int nItem = lpCharacter->m_anSrcQuestItem.GetAt( i );
LPQUEST lpQuest = pMover->GetQuest( nQuest );
// 새로운 퀘스트일 경우
if( lpQuest == NULL && pMover->IsCompleteQuest( nQuest ) == FALSE )
{
// 내가 퀘스트 시작 조건인가?
if( __IsBeginQuestCondition( pMover, nQuest ) && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 1;
// 새로운 퀘스트가 없고 근레벨에 받을 수 있는 퀘스트가 존재한다면..
else if( m_nQuestEmoticonIndex != 1 && __IsNextLevelQuest( pMover, nQuest ) && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 4;
}
// 진행중인 퀘스트일 경우
if( lpQuest && prj.m_aPropQuest.GetAt( lpQuest->m_wId ) && pMover->IsCompleteQuest( nQuest ) == FALSE && lpQuest->m_nState != QS_END )
{
if( m_nQuestEmoticonIndex != 1 && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 2;
}
}
for( i = 0; i < lpCharacter->m_awDstQuest.GetSize(); i++ )
{
int nQuest = lpCharacter->m_awDstQuest.GetAt( i );
int nItem = lpCharacter->m_anDstQuestItem.GetAt( i );
LPQUEST lpQuest = pMover->GetQuest( nQuest );
// 퀘스트가 진행 중인 경우
if( lpQuest && prj.m_aPropQuest.GetAt( lpQuest->m_wId ) && pMover->IsCompleteQuest( nQuest ) == FALSE && lpQuest->m_nState != QS_END )
{
// 내가 퀘스트 종료 조건인가?
if( __IsEndQuestCondition( pMover, nQuest ) && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 3;
// 내가 퀘스트 종료 조건이 아니고 새로운 퀘스트가 존재하지 않으면..
else if( m_nQuestEmoticonIndex != 3 && m_nQuestEmoticonIndex != 1 && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 2;
}
}
#else // __IMPROVE_QUEST_INTERFACE
for( int i = 0; i < lpCharacter->m_awSrcQuest.GetSize() ; i++ )
{
int nQuest = lpCharacter->m_awSrcQuest.GetAt( i );
int nItem = lpCharacter->m_anSrcQuestItem.GetAt( i );
LPQUEST lpQuest = pMover->GetQuest( nQuest );
if( lpQuest == NULL && pMover->IsCompleteQuest( nQuest ) == FALSE )
{
// 내가 퀘스트 시작 조건인가?
if( __IsBeginQuestCondition( pMover, nQuest ) && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 1;
// 내가 퀘스트 시작 조건이 아닌가?
else
if( m_nQuestEmoticonIndex != 1 && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 0;
}
}
for( i = 0; i < lpCharacter->m_awDstQuest.GetSize(); i++ )
{
int nQuest = lpCharacter->m_awDstQuest.GetAt( i );
int nItem = lpCharacter->m_anDstQuestItem.GetAt( i );
LPQUEST lpQuest = pMover->GetQuest( nQuest );
// 퀘스트가 진행 중인 경우
if( lpQuest && prj.m_aPropQuest.GetAt( lpQuest->m_wId ) && pMover->IsCompleteQuest( nQuest ) == FALSE && ( lpQuest->m_nState == 0 || lpQuest->m_nState == 14 ) )
{
// 내가 퀘스트 종료 조건인가?
if( __IsEndQuestCondition( pMover, nQuest ) && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 3;
// 내가 퀘스트 종료 조건이 아닌가?
else
if( m_nQuestEmoticonIndex != 3 && ( nItem == 0 || pMover->GetItemNum( nItem ) ) )
m_nQuestEmoticonIndex = 2;
}
}
#endif // __IMPROVE_QUEST_INTERFACE
}
#endif // __WORLDSERVER
}
#ifdef __WORLDSERVER
void CMover::ProcessAbnormalState()
{
if( m_wStunCnt > 0 )
{
if( --m_wStunCnt <= 0 )
SetStun( FALSE ); // 스턴 상태 해제.
}
if( m_wDarkCover > 0 )
{
if( --m_wDarkCover <= 0 )
SetDarkCover( FALSE ); // 스턴 상태 해제.
}
if( GetAdjParam( DST_CHRSTATE ) & CHS_POISON )
{
if( IsLive() )
{
int nUnitCnt = (int)( (m_tmPoisonUnit / 1000.0f) * PROCESS_COUNT );
if( nUnitCnt <= 0 )
{
nUnitCnt = 1;
SetPoison( FALSE );
}
else
{
if( (m_nCount % nUnitCnt) == 0 ) // xx초마다 한번씩 데미지.
{
CCtrl *pAttacker = prj.GetCtrl( m_idPoisonAttacker );
if( IsValidObj( pAttacker ) && pAttacker->GetType() == OT_MOVER )
{
m_pActMover->SendDamage( AF_FORCE,
pAttacker->GetId(),
m_wPoisonDamage );
}
}
if( m_wPoisonCnt > 0 ) // 독 지속 시간동안.. SkillInfluence로 돌때는 이게 0이다
if( --m_wPoisonCnt <= 0 ) // 독 시간 다되면
SetPoison( FALSE ); // 독상태 헤제.
}
}
}
if( m_wDarkCnt > 0 ) // 암흑 지속시간동안...
{
if( --m_wDarkCnt <= 0 )
SetDark( FALSE );
}
if( GetAdjParam( DST_CHRSTATE ) & CHS_BLEEDING )
{
if( IsLive() )
{
int nUnitCnt = (int)( (m_tmBleedingUnit / 1000.0f) * PROCESS_COUNT );
if( nUnitCnt <= 0 )
{
nUnitCnt = 1;
SetBleeding( FALSE );
}
else
{
if( (m_nCount % nUnitCnt) == 0 ) // xx초마다 한번씩 데미지.
{
CCtrl *pAttacker = prj.GetCtrl( m_idBleedingAttacker );
if( IsValidObj( pAttacker ) && pAttacker->GetType() == OT_MOVER )
{
m_pActMover->SendDamage( AF_FORCE,
pAttacker->GetId(),
m_wBleedingDamage );
}
}
if( m_wBleedingCnt > 0 ) // 출혈 지속 시간동안..
if( --m_wBleedingCnt <= 0 ) // 독 시간 다되면
SetBleeding( FALSE ); // 독상태 해제.
}
}
}
#if __VER >= 9 // __PET_0410
int nHeal = GetAdjParam( DST_HEAL );
if( nHeal > 0 ) // 자동 치유 상태면,
{
if( m_nHealCnt > 0 )
m_nHealCnt--;
if( m_nHealCnt == 0 )
{
// HP가 30% 이하로 내려갔을 시, 정해진 수치만큼 HP가 채워진다. 쿨타임 6초
// if( IsLive() && GetHitPointPercent( 100 ) <= 30 )
if( IsLive() )
{
m_nHealCnt = (short)( PROCESS_COUNT * 6.0f ); // 쿨타임 6초
SetPointParam( DST_HP, nHeal );
}
}
}
#endif // __PET_0410
}
// 몬스터의 경우 정기적으로 idAttacker, m_idTargeter를 검사해서 없어진놈이면 삭제함.
void CMover::ProcessTarget()
{
if( m_idAttacker != NULL_ID || m_idTargeter != NULL_ID )
{
CMover *pAttacker = GETMOVER( m_idAttacker );
if( IsValidObj( pAttacker ) )
{
if( IsValidArea( pAttacker, 32.0f ) == FALSE )
{
m_idAttacker = NULL_ID;
}
}
else
{
m_idAttacker = NULL_ID; // 어태커가 아예 없어졌으면
}
CMover *pTargeter = GETMOVER( m_idTargeter );
if( IsValidObj( pTargeter ) )
{
if( IsValidArea( pTargeter, 32.0f ) == FALSE )
{
m_idTargeter = NULL_ID;
}
}
else
{
m_idTargeter = NULL_ID; // 타게터가 아예 없어졌으면 초기화.
}
}
}
void CMover::ProcessScript()
{
if( IsPlayer() )
return;
if( m_szCharacterKey[ 0 ] && m_pNpcProperty->IsTimeOut() )
{
m_pNpcProperty->ResetTimer();
m_pNpcProperty->RunDialog("#auto",NULL,0,GetId(),GetId(),0);
}
}
void CMover::ProcessRegenItem()
{
if( IsNPC() )
{
if( m_bRegenItem )
{
m_bRegenItem = FALSE;
//
// vender item 발생
//
//#define VENDER_DELAY (60 * 5) // 5분
LPCHARACTER pCharacter = GetCharacter();
BOOL fShop = FALSE;
if( !pCharacter )
return;
LPVENDOR_ITEM pVendor;
for( int i = 0; i < MAX_VENDOR_INVENTORY_TAB; i ++ )
{
#if __VER >= 11 // __CSC_VER11_3
if(pCharacter->m_nVenderType == 1) // 칩으로 거래하는 vender일 경우
{
if(pCharacter->m_venderItemAry2[i].GetSize())
{
fShop = TRUE;
m_ShopInventory[i]->Clear(); // m_pack을 다 없앤다.
for( int j = 0; j < pCharacter->m_venderItemAry2[i].GetSize(); j++ )
{
pVendor = (LPVENDOR_ITEM)pCharacter->m_venderItemAry2[i].GetAt(j);
CItemElem itemElem;
itemElem.m_dwItemId = pVendor->m_dwItemId;
itemElem.m_nItemNum = (short)( prj.GetItemProp( pVendor->m_dwItemId )->dwPackMax );
itemElem.m_nHitPoint = prj.GetItemProp( pVendor->m_dwItemId )->dwEndurance;
if( (int)itemElem.GetChipCost() < 1 )
Error( "chip cost < 1 : npc = %s, item = %d", pCharacter->m_szKey, pVendor->m_dwItemId );
else
m_ShopInventory[i]->Add( &itemElem );
}
}
}
else
{
#endif //__CSC_VER11_3
if( pCharacter->m_venderItemAry[i].GetSize() )
{
fShop = TRUE;
{
m_ShopInventory[i]->Clear(); // m_pack을 다 없앤다.
ItemProp* apItemProp[MAX_VENDOR_INVENTORY];
int cbSize = 0;
// generate
for( int j = 0; j < pCharacter->m_venderItemAry[i].GetSize(); j++ )
{
pVendor = (LPVENDOR_ITEM)pCharacter->m_venderItemAry[i].GetAt(j);
GenerateVendorItem( apItemProp, &cbSize, MAX_VENDOR_INVENTORY, pVendor );
}
// sort
for( j = 0; j < cbSize - 1; j++ )
{
for( int k = j + 1; k < cbSize; k++ )
{
if( ( apItemProp[k]->dwItemKind1 < apItemProp[j]->dwItemKind1 ) ||
( apItemProp[k]->dwItemKind1 == apItemProp[j]->dwItemKind1 && apItemProp[k]->dwItemRare < apItemProp[j]->dwItemRare ) )
{
ItemProp* ptmp = apItemProp[j];
apItemProp[j] = apItemProp[k];
apItemProp[k] = ptmp;
}
}
}
// add
for( j = 0; j < cbSize; j++ )
{
CItemElem itemElem;
itemElem.m_dwItemId = apItemProp[j]->dwID;
itemElem.m_nItemNum = (short)( apItemProp[j]->dwPackMax );
itemElem.m_nHitPoint = apItemProp[j]->dwEndurance;
if( m_ShopInventory[i]->Add( &itemElem ) == FALSE )
break;
}
}
}
#if __VER >= 11 // __CSC_VER11_3
}
#endif //__CSC_VER11_3
}
if( fShop )
g_UserMng.AddVendor( this );
}
}
}
#endif // __WORLDSERVER
CModel* CMover::LoadModel( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwType, DWORD dwIndex )
{
if( m_dwIndex == MI_FEMALE || m_dwIndex == MI_MALE )
return prj.m_modelMng.LoadModel( pd3dDevice, dwType, dwIndex, TRUE );
return prj.m_modelMng.LoadModel( pd3dDevice, dwType, dwIndex );
}
// 이 함수를 실행하기 전에 인덱스와 타입이 먼저 세팅되어 있어야한다.
void CMover::InitProp( BOOL bInitAI )
{
MoverProp* pProp = GetProp();
if( pProp == NULL )
{
Error( "CMover::InitProp - GetProp(%d) return NULL \n", GetIndex() );
ASSERT( 0 );
return;
}
if( m_szName[0] == '\0' )
_tcscpy( m_szName, pProp->szName );
#ifdef __WORLDSERVER
if( bInitAI )
SetAIInterface( pProp->dwAI );
#else
UNUSED_ALWAYS( bInitAI );
#endif
m_dwBelligerence = pProp->dwBelligerence;
#ifdef __OPT_MEM_0811
if( IsPlayer() )
{
m_Inventory.SetItemContainer( ITYPE_ITEM, MAX_INVENTORY, MAX_HUMAN_PARTS );
m_Pocket.Avail( 0 );
}
#else // __OPT_MEM_0811
m_Inventory.SetItemContainer( ITYPE_ITEM, MAX_INVENTORY, MAX_HUMAN_PARTS );
#endif // __OPT_MEM_0811
m_nSlot = 0;
m_bBank = FALSE;
for( int k = 0 ; k < 3 ; ++k )
{
if( IsPlayer() )
m_Bank[k].SetItemContainer( ITYPE_ITEM, MAX_BANK ) ;
m_dwGoldBank[k] = 0;
m_idPlayerBank[k] = 0;
}
ZeroMemory( m_ShopInventory, sizeof( m_ShopInventory ) );
ZeroMemory( m_aJobSkill, sizeof( m_aJobSkill ) );
ZeroMemory( m_tmReUseDelay, sizeof( m_tmReUseDelay ) );
// 잡스킬 초기화
for( int i = 0; i < MAX_SKILL_JOB; i++ )
{
m_aJobSkill[ i ].dwSkill = NULL_ID;
}
if( m_nJob != -1 )
{
ItemProp** apSkillProp = prj.m_aJobSkill[ m_nJob ];
int nJobNum = prj.m_aJobSkillNum[ m_nJob ];
LPSKILL lpSkill;
for( i = 0; i < nJobNum; i++ )
{
ItemProp* pSkillProp = apSkillProp[ i ];
lpSkill = &m_aJobSkill[ i ];
lpSkill->dwSkill = pSkillProp->dwID;
}
}
// 기본 능력치 초기화
m_nLevel = pProp->dwLevel;
if( m_nLevel < 1 )
m_nLevel = 1;
if( IsPlayer() )
{
if( m_nJob != -1 )
{
m_nHitPoint = GetMaxHitPoint();
m_nManaPoint = GetMaxManaPoint();
m_nFatiguePoint = GetMaxFatiguePoint();
}
else
{
m_nHitPoint = 1;
m_nManaPoint = 1;
m_nFatiguePoint = 1;
}
m_pActMover->m_fSpeed = pProp->fSpeed;
}
else
{
m_nStr = pProp->dwStr;
m_nSta = pProp->dwSta;
m_nDex = pProp->dwDex;
m_nInt = pProp->dwInt;
m_nHitPoint = GetMaxHitPoint();
m_nManaPoint = pProp->dwAddMp;
m_nFatiguePoint = GetMaxFatiguePoint();
}
UpdateParam();
m_dwVirtItem = pProp->dwAtk1; // dwVirtItem은 앞으로 dwAtk1으로 쓴다.
if( m_bPlayer == FALSE && pProp->dwFlying == 1 ) // 비행형 몬스터인가?
m_dwTypeFlag |= OBJTYPE_FLYING;
//#ifdef __WORLDSERVER
// m_nResource = pProp->dwMaterialAmount; // 자원량.
//#endif
if( IsPlayer() )
{
m_aQuest = new QUEST[ MAX_QUEST ];
m_aCompleteQuest = new WORD[ MAX_COMPLETE_QUEST ];
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
m_aCheckedQuest = new WORD[ MAX_CHECKED_QUEST ];
#endif // __IMPROVE_QUEST_INTERFACE
}
}
void CMover::InitLevel( int nJob, LONG nLevel, BOOL bGamma )
{
#ifdef __WORLDSERVER
// 운영자 명령으로 레벨업 하는곳임
MoverProp* pProp = GetProp();
if( pProp )
{
// 방랑자 스킬 값 가지고 있기.
int nJobSkillBuf[MAX_JOB_SKILL];
int nJobSkillLevelBuf[MAX_JOB_SKILL];
for( int i = 0 ; i < MAX_JOB_SKILL ; ++i )
{
nJobSkillBuf[ i ] = m_aJobSkill[ i ].dwSkill;
nJobSkillLevelBuf[ i ] = m_aJobSkill[ i ].dwLevel;
}
ZeroMemory( m_aJobSkill, sizeof( m_aJobSkill ) );
LPSKILL lpSkill;
// 잡스킬 초기화
for( i = 0; i < MAX_SKILL_JOB; i++ )
{
m_aJobSkill[ i ].dwSkill = NULL_ID;
m_aJobSkill[ i ].dwLevel = 0;
}
// 1. 방랑자 스킬은 그냥 지급
m_nJob = JOB_VAGRANT;
ItemProp** apSkillProp = prj.m_aJobSkill[ m_nJob ];
int nJobNum = prj.m_aJobSkillNum[ m_nJob ];
for( i = 0; i < nJobNum; i++ )
{
ItemProp* pSkillProp = apSkillProp[ i ];
lpSkill = &m_aJobSkill[ i ];
lpSkill->dwSkill = pSkillProp->dwID;
}
// 2. 기본 능력치 초기화
m_nLevel = 1;
m_nStr = m_nSta = m_nDex = m_nInt = 15;
m_nRemainGP = 0;
m_nSkillLevel = 0;
m_nSkillPoint = 0;
// 3. LP, GP, 직업
for( i = 1 ; i < nLevel ; i++ )
{
m_nLevel = i + 1;
m_nRemainGP += prj.m_aExpCharacter[ m_nLevel ].dwLPPoint;
#if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans
if( nJob >= MAX_PROFESSIONAL && i > 59 )
m_nRemainGP++;
if( nJob < MAX_PROFESSIONAL )
{
if( ( i + 1 ) == MAX_JOB_LEVEL )
{
if( nJob < MAX_EXPERT )
{
AddChangeJob( nJob );
}
else
{
if( nJob % 2 != 0 )
{
AddChangeJob( ( nJob - 5 ) / 2 );
}
else
{
AddChangeJob( ( nJob - 4 ) / 2 );
}
}
}
else
if( ( i + 1 ) == MAX_JOB_LEVEL + MAX_EXP_LEVEL )
{
AddChangeJob( nJob );
}
}
else
{
if( ( i + 1 ) == MAX_JOB_LEVEL )
{
if( nJob < MAX_MASTER )
{
if( nJob % 2 != 0 )
{
AddChangeJob( ( nJob - 15 ) / 2 );
}
else
{
AddChangeJob( ( nJob - 14 ) / 2 );
}
}
else
{
if( nJob % 2 != 0 )
{
AddChangeJob( ( nJob - 23 ) / 2 );
}
else
{
AddChangeJob( ( nJob - 22 ) / 2 );
}
}
}
else
if( ( i + 1 ) == MAX_JOB_LEVEL + MAX_EXP_LEVEL )
{
if( nJob < MAX_MASTER )
{
AddChangeJob( nJob - 10 );
AddChangeJob( nJob );
}
else
{
AddChangeJob( nJob - 18 );
AddChangeJob( nJob - 8);
AddChangeJob( nJob );
}
}
}
#else //__LEGEND // 10차 전승시스템 Neuz, World, Trans
if( ( i + 1 ) == MAX_JOB_LEVEL )
{
if( nJob < MAX_EXPERT )
{
AddChangeJob( nJob );
}
else
{
if( nJob % 2 != 0 )
{
AddChangeJob( ( nJob - 5 ) / 2 );
}
else
{
AddChangeJob( ( nJob - 4 ) / 2 );
}
}
}
else
if( ( i + 1 ) == MAX_JOB_LEVEL + MAX_EXP_LEVEL )
{
AddChangeJob( nJob );
}
#endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans
}
int nPoint = 0;
if( m_nLevel <= 20 )
nPoint = 2 * m_nLevel - 2;
else if( m_nLevel <= 40 )
nPoint = 3 * m_nLevel - 22;
else if( m_nLevel <= 60 )
nPoint = 4 * m_nLevel - 62;
else if( m_nLevel <= 80 )
nPoint = 5 * m_nLevel - 122;
else if( m_nLevel <= 100 )
nPoint = 6 * m_nLevel - 202;
else
nPoint = 7 * m_nLevel - 302;
if( m_nJob == JOB_MERCENARY )
nPoint += 40;
else if( m_nJob == JOB_ACROBAT )
nPoint += 50;
else if( m_nJob == JOB_ASSIST )
nPoint += 60;
else if( m_nJob == JOB_MAGICIAN )
nPoint += 90;
else if( m_nJob == JOB_KNIGHT || m_nJob == JOB_BLADE )
nPoint += 120;
else if( m_nJob == JOB_JESTER || m_nJob == JOB_RANGER )
nPoint += 150;
else if( m_nJob == JOB_RINGMASTER )
nPoint += 160;
else if( m_nJob == JOB_BILLPOSTER || m_nJob == JOB_PSYCHIKEEPER )
nPoint += 180;
else if( m_nJob == JOB_ELEMENTOR )
nPoint += 390;
m_nSkillLevel = m_nSkillPoint = nPoint;
SetJobLevel( nLevel, nJob );
m_nDeathLevel = nLevel;
#if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans
if(IsMaster())
{
int dwTmpSkLevel = 1;//60, 72, 84, 96, 108
if( nLevel > 59 && nLevel < 72 )
dwTmpSkLevel = 1;
else if( nLevel > 71 && nLevel < 84 )
dwTmpSkLevel = 2;
else if( nLevel > 83 && nLevel < 96 )
dwTmpSkLevel = 3;
else if( nLevel > 95 && nLevel < 108 )
dwTmpSkLevel = 4;
else if( nLevel > 107 && nLevel < 120 )
dwTmpSkLevel = 5;
for( i = 0; i < MAX_SKILL_JOB; i++ )
{
LPSKILL lpSkill = &(m_aJobSkill[i]);
if( lpSkill && lpSkill->dwSkill != NULL_ID )
{
ItemProp* pSkillProp = prj.GetSkillProp( lpSkill->dwSkill );
if( pSkillProp == NULL )
continue;
if( pSkillProp->dwItemKind1 != JTYPE_MASTER)
continue;
lpSkill->dwLevel = dwTmpSkLevel;
}
}
}
else if(IsHero())
{
for( i = 0; i < MAX_SKILL_JOB; i++ )
{
LPSKILL lpSkill = &(m_aJobSkill[i]);
if( lpSkill && lpSkill->dwSkill != NULL_ID )
{
ItemProp* pSkillProp = prj.GetSkillProp( lpSkill->dwSkill );
if( pSkillProp == NULL )
continue;
if( pSkillProp->dwItemKind1 != JTYPE_MASTER)
continue;
lpSkill->dwLevel = 5;
}
}
}
#endif // __LEGEND // 10차 전승시스템 Neuz, World, Trans
if( bGamma )
{
m_nExp1 = 0;
}
if( m_nLevel >= 20 )
SetFlightLv( 1 );
else
SetFlightLv( 0 );
( (CUser*)this )->AddSetChangeJob( nJob );
g_UserMng.AddNearSetChangeJob( this, nJob, &((CUser*)this)->m_aJobSkill[MAX_JOB_SKILL] );
// #ifdef __S_RECOMMEND_EVE
// if( g_eLocal.GetState( EVE_RECOMMEND ) && IsPlayer() )
// g_dpDBClient.SendRecommend( (CUser*)this, nJob );
// #endif // __S_RECOMMEND_EVE
#if __VER >= 11 // __SYS_PLAYER_DATA
g_dpDBClient.SendUpdatePlayerData( (CUser*)this );
#else // __SYS_PLAYER_DATA
g_DPCoreClient.SendPartyMemberJob( (CUser*)this );
g_DPCoreClient.SendFriendChangeJob( (CUser*)this );
if( m_idGuild != 0 )
g_DPCoreClient.SendGuildChangeJobLevel( (CUser*)this );
#endif // __SYS_PLAYER_DATA
SetHitPoint( GetMaxHitPoint() );
SetManaPoint( GetMaxManaPoint() );
SetFatiguePoint( GetMaxFatiguePoint() );
g_UserMng.AddSetLevel( this, (WORD)m_nLevel );
( (CUser*)this )->AddSetGrowthLearningPoint( m_nRemainGP );
( (CUser*)this )->AddSetExperience( GetExp1(), (WORD)m_nLevel, m_nSkillPoint, m_nSkillLevel );
( (CUser*)this )->m_playTaskBar.InitTaskBarShorcutKind( SHORTCUT_SKILL );
( (CUser*)this )->AddTaskBar();
((CUser*)this)->AddSetState( m_nStr, m_nSta, m_nDex, m_nInt, m_nRemainGP );
#if __VER >= 13 // __HONORABLE_TITLE // 달인
((CUser*)this)->CheckHonorStat();
((CUser*)this)->AddHonorListAck();
g_UserMng.AddHonorTitleChange( this, m_nHonor);
#endif // __HONORABLE_TITLE // 달인
}
#endif // __WORLDSERVER
}
int CMover::SetLevel( int nSetLevel )
{
#ifdef __WORLDSERVER
#if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans
m_nLevel = nSetLevel;
m_nExp1 = 0;
m_nDeathExp = GetExp1();
m_nDeathLevel = nSetLevel - 1;
( (CUser *)this )->AddSetExperience( GetExp1(), (WORD)m_nLevel, m_nSkillPoint, m_nSkillLevel, m_nDeathExp, (WORD)m_nDeathLevel ); // 해당유저에게 exp1,exp2변경된 정보를 보냄.
g_UserMng.AddSetLevel( this, (WORD)m_nLevel );
g_dpDBClient.SendLogLevelUp( this, 1 ); // 레벨업 로그
#endif//__LEGEND // 9차 전승시스템 Neuz, World, Trans
#endif
return 0;
}
int CMover::AddGPPoint( int nAddGPPoint )
{
#ifdef __WORLDSERVER
#if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans
m_nRemainGP += nAddGPPoint;
( (CUser*)this )->AddSetGrowthLearningPoint( m_nRemainGP ); // pUser에게 GP변동된것을 보냄.
g_dpDBClient.SendLogLevelUp( this, 1 ); // 레벨업 로그
#endif//__LEGEND // 9차 전승시스템 Neuz, World, Trans
#endif
return 0;
}
BOOL CMover::InitSkillExp()
{
for( int i = 0 ; i < MAX_SKILL_JOB ; ++i )
{
LPSKILL pSkill = &m_aJobSkill[ i ];
if( pSkill != NULL && pSkill->dwSkill != NULL_ID )
{
ItemProp* pSkillProp = prj.GetSkillProp( pSkill->dwSkill );
if( pSkillProp == NULL )
return FALSE;
#if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans
if( 0 < pSkill->dwLevel && pSkillProp->dwItemKind1 != JTYPE_MASTER && pSkillProp->dwItemKind1 != JTYPE_HERO )
{
m_nSkillPoint += ( pSkill->dwLevel * prj.GetSkillPoint( pSkillProp ) );
pSkill->dwLevel = 0;
}
#else //__LEGEND // 9차 전승시스템 Neuz, World, Trans
if( 0 < pSkill->dwLevel )
m_nSkillPoint += ( pSkill->dwLevel * prj.GetSkillPoint( pSkillProp ) );
pSkill->dwLevel = 0;
#endif //__LEGEND // 9차 전승시스템 Neuz, World, Trans
}
}
#if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans
int nMaxPoint = 1280; // 최대인 JOB_ELEMENTOR 꺼로 설정함
if( m_nJob == JOB_KNIGHT || m_nJob == JOB_BLADE || m_nJob == JOB_KNIGHT_MASTER || m_nJob == JOB_BLADE_MASTER || m_nJob == JOB_KNIGHT_HERO || m_nJob == JOB_BLADE_HERO )
nMaxPoint = 870;
else if( m_nJob == JOB_JESTER || m_nJob == JOB_RANGER || m_nJob == JOB_JESTER_MASTER || m_nJob == JOB_RANGER_MASTER || m_nJob == JOB_JESTER_HERO || m_nJob == JOB_RANGER_HERO )
nMaxPoint = 910;
else if( m_nJob == JOB_RINGMASTER || m_nJob == JOB_RINGMASTER_MASTER || m_nJob == JOB_RINGMASTER_HERO )
nMaxPoint = 902;
else if( m_nJob == JOB_BILLPOSTER || m_nJob == JOB_PSYCHIKEEPER || m_nJob == JOB_BILLPOSTER_MASTER || m_nJob == JOB_PSYCHIKEEPER_MASTER || m_nJob == JOB_BILLPOSTER_HERO || m_nJob == JOB_PSYCHIKEEPER_HERO )
nMaxPoint = 950;
if( m_nSkillPoint > nMaxPoint)
m_nSkillPoint = nMaxPoint;
#endif //__LEGEND // 9차 전승시스템 Neuz, World, Trans
#ifdef __WORLDSERVER
( (CUser*)this )->m_playTaskBar.InitTaskBarShorcutKind( SHORTCUT_SKILL );
( (CUser*)this )->AddTaskBar();
#endif //__WORLDSERVER
return TRUE;
}
#ifdef __CLIENT
int CMover::GetCurrentMaxSkillPoint()
{
int nCurrentMaxSkillPoint = m_nSkillPoint;
for( int i = 0 ; i < MAX_SKILL_JOB ; ++i )
{
LPSKILL pSkill = &m_aJobSkill[ i ];
if( pSkill != NULL && pSkill->dwSkill != NULL_ID )
{
ItemProp* pSkillProp = prj.GetSkillProp( pSkill->dwSkill );
if( pSkillProp != NULL )
{
if( 0 < pSkill->dwLevel && pSkillProp->dwItemKind1 != JTYPE_MASTER && pSkillProp->dwItemKind1 != JTYPE_HERO )
nCurrentMaxSkillPoint += ( pSkill->dwLevel * prj.GetSkillPoint( pSkillProp ) );
}
}
}
int nMaxPoint = 1280; // 최대인 JOB_ELEMENTOR 꺼로 설정함
if( m_nJob == JOB_KNIGHT || m_nJob == JOB_BLADE || m_nJob == JOB_KNIGHT_MASTER || m_nJob == JOB_BLADE_MASTER || m_nJob == JOB_KNIGHT_HERO || m_nJob == JOB_BLADE_HERO )
nMaxPoint = 870;
else if( m_nJob == JOB_JESTER || m_nJob == JOB_RANGER || m_nJob == JOB_JESTER_MASTER || m_nJob == JOB_RANGER_MASTER || m_nJob == JOB_JESTER_HERO || m_nJob == JOB_RANGER_HERO )
nMaxPoint = 910;
else if( m_nJob == JOB_RINGMASTER || m_nJob == JOB_RINGMASTER_MASTER || m_nJob == JOB_RINGMASTER_HERO )
nMaxPoint = 902;
else if( m_nJob == JOB_BILLPOSTER || m_nJob == JOB_PSYCHIKEEPER || m_nJob == JOB_BILLPOSTER_MASTER || m_nJob == JOB_PSYCHIKEEPER_MASTER || m_nJob == JOB_BILLPOSTER_HERO || m_nJob == JOB_PSYCHIKEEPER_HERO )
nMaxPoint = 950;
if( nCurrentMaxSkillPoint > nMaxPoint)
nCurrentMaxSkillPoint = nMaxPoint;
return nCurrentMaxSkillPoint;
}
#if __VER >= 15 // __PETVIS
//버프펫 이펙트
void CMover::SetSfxBuffPet( const DWORD idEffect )
{
if( m_pSfxBuffPet )
{
g_WorldMng.Get()->RemoveObj( m_pSfxBuffPet );
m_pSfxBuffPet = NULL;
}
if( NULL_ID != idEffect )
m_pSfxBuffPet = CreateSfx( g_Neuz.m_pd3dDevice, idEffect, GetPos(), GetId(), GetPos(), GetId(), -1 );
}
#endif //__PETVIS
#endif //__CLIENT
void CMover::ReState()
{
#ifdef __WORLDSERVER
m_nStr = m_nSta = m_nDex = m_nInt = 15;
m_nRemainGP = 0;
int nLevelFor = m_nLevel;
if( m_nLevel < m_nDeathLevel )
nLevelFor = m_nDeathLevel;
#if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans
for( int i = 1 ; i < nLevelFor ; i++ )
{
m_nRemainGP += prj.m_aExpCharacter[ i + 1 ].dwLPPoint;
if( ( IsMaster() || IsHero() ) && i > 59 )
m_nRemainGP++;
if( IsHero() && i == MAX_LEVEL)
m_nRemainGP+=12;
}
#else //__LEGEND // 9차 전승시스템 Neuz, World, Trans
for( int i = 1 ; i < nLevelFor ; i++ )
m_nRemainGP += prj.m_aExpCharacter[ i + 1 ].dwLPPoint;
#endif //__LEGEND // 9차 전승시스템 Neuz, World, Trans
SetHitPoint( GetMaxHitPoint() );
SetManaPoint( GetMaxManaPoint() );
SetFatiguePoint( GetMaxFatiguePoint() );
((CUser*)this)->AddSetState( m_nStr, m_nSta, m_nDex, m_nInt, m_nRemainGP );
#if __VER >= 13 // __HONORABLE_TITLE // 달인
((CUser*)this)->CheckHonorStat();
((CUser*)this)->AddHonorListAck();
g_UserMng.AddHonorTitleChange( this, m_nHonor);
#endif // __HONORABLE_TITLE // 달인
#endif // __WORLDSERVER
}
#ifdef __S_ADD_RESTATE
void CMover::ReStateOne( int nKind )
{
#ifdef __WORLDSERVER
int nAdd = 0;
switch( nKind )
{
case 0: // Str
{
nAdd = m_nStr - 15;
m_nStr = 15;
}
break;
case 1: // Sta
{
nAdd = m_nSta - 15;
m_nSta = 15;
}
break;
case 2: // Dex
{
nAdd = m_nDex - 15;
m_nDex = 15;
}
break;
case 3: // Int
{
nAdd = m_nInt - 15;
m_nInt = 15;
}
break;
}
m_nRemainGP += nAdd;
SetHitPoint( GetMaxHitPoint() );
SetManaPoint( GetMaxManaPoint() );
SetFatiguePoint( GetMaxFatiguePoint() );
((CUser*)this)->AddSetState( m_nStr, m_nSta, m_nDex, m_nInt, m_nRemainGP );
#if __VER >= 13 // __HONORABLE_TITLE // 달인
((CUser*)this)->CheckHonorStat();
((CUser*)this)->AddHonorListAck();
g_UserMng.AddHonorTitleChange( this, m_nHonor);
#endif // __HONORABLE_TITLE // 달인
#endif // __WORLDSERVER
}
#endif // __S_ADD_RESTATE
#ifdef __ADD_RESTATE_LOW
void CMover::ReStateOneLow( int nKind )
{
#ifdef __WORLDSERVER
int nAdd = 0;
switch( nKind )
{
case 0: // Str
{
if( m_nStr >= RESTATE_LOW + 15 )
{
nAdd = RESTATE_LOW;
m_nStr -= RESTATE_LOW;
}
else
{
nAdd = m_nStr - 15;
m_nStr = 15;
}
}
break;
case 1: // Sta
{
if( m_nSta >= RESTATE_LOW + 15 )
{
nAdd = RESTATE_LOW;
m_nSta -= RESTATE_LOW;
}
else
{
nAdd = m_nSta - 15;
m_nSta = 15;
}
}
break;
case 2: // Dex
{
if( m_nDex >= RESTATE_LOW + 15 )
{
nAdd = RESTATE_LOW;
m_nDex -= RESTATE_LOW;
}
else
{
nAdd = m_nDex - 15;
m_nDex = 15;
}
}
break;
case 3: // Int
{
if( m_nInt >= RESTATE_LOW + 15 )
{
nAdd = RESTATE_LOW;
m_nInt -= RESTATE_LOW;
}
else
{
nAdd = m_nInt - 15;
m_nInt = 15;
}
}
break;
}
m_nRemainGP += nAdd;
SetHitPoint( GetMaxHitPoint() );
SetManaPoint( GetMaxManaPoint() );
SetFatiguePoint( GetMaxFatiguePoint() );
((CUser*)this)->AddSetState( m_nStr, m_nSta, m_nDex, m_nInt, m_nRemainGP );
#if __VER >= 13 // __HONORABLE_TITLE // 달인
((CUser*)this)->CheckHonorStat();
((CUser*)this)->AddHonorListAck();
g_UserMng.AddHonorTitleChange( this, m_nHonor);
#endif // __HONORABLE_TITLE // 달인
#endif // __WORLDSERVER
}
#endif // __ADD_RESTATE_LOW
#ifdef __WORLDSERVER
BOOL CMover::ReplaceInspection( REGIONELEM* pPortkey )
{
BOOL bResult = TRUE;
if( bResult != FALSE && pPortkey->m_uItemId != 0xffffffff )
{
int nCount = GetItemNum( pPortkey->m_uItemId );
if( (DWORD)( nCount ) <= pPortkey->m_uiItemCount )
{
bResult = TRUE;
}
else
{
bResult = FALSE;
}
TRACE( "ReplaceInspection Item %d Count %d/%d Inspection %d \n", pPortkey->m_uItemId, nCount, pPortkey->m_uiItemCount, bResult );
}
if( bResult != FALSE && pPortkey->m_uiMinLevel != 0xffffffff )
{
if( pPortkey->m_uiMinLevel <= (UINT)( m_nLevel ) && (UINT)( m_nLevel ) <= pPortkey->m_uiMaxLevel)
{
bResult = TRUE;
}
else
{
bResult = FALSE;
}
TRACE( "ReplaceInspection Level (%d~%d) %d Inspection %d \n", pPortkey->m_uiMinLevel, pPortkey->m_uiMaxLevel, m_nLevel, bResult );
}
if( bResult != FALSE && pPortkey->m_iQuest != 0xffffffff )
{
LPQUEST pCurQuest = GetQuest( pPortkey->m_iQuest );
if( pCurQuest && ( pPortkey->m_iQuestFlag == 0 || pPortkey->m_iQuestFlag == pCurQuest->m_nState ) )
bResult = TRUE;
else
bResult = FALSE;
TRACE( "ReplaceInspection Quest %d Flag %d/%d Inspection %d \n", pPortkey->m_iQuest, pPortkey->m_iQuestFlag, pCurQuest->m_nState, bResult );
}
if( bResult != FALSE && pPortkey->m_iJob != 0xffffffff )
{
if( pPortkey->m_iJob == m_nJob )
bResult = TRUE;
else
bResult = FALSE;
TRACE( "ReplaceInspection Job %d/%d Inspection %d \n", pPortkey->m_iJob, m_nJob, bResult );
}
if( bResult != FALSE && pPortkey->m_iGender != 0xffffffff )
{
if( pPortkey->m_iGender == GetSex() )
bResult = TRUE;
else
bResult = FALSE;
TRACE( "ReplaceInspection Gender %d/%d Inspection %d \n", pPortkey->m_iGender, GetSex(), bResult );
}
if( bResult != FALSE && pPortkey->m_bCheckParty != FALSE )
{
CParty* pParty = g_PartyMng.GetParty( m_idparty );
if( pParty != NULL && pParty->IsMember( m_idPlayer ) )
bResult = TRUE;
else
bResult = FALSE;
TRACE( "ReplaceInspection Party Inspection %d \n", bResult );
}
if( bResult != FALSE && pPortkey->m_bCheckGuild != FALSE )
{
CGuild* pGuild = g_GuildMng.GetGuild( m_idGuild );
if( pGuild && pGuild->IsMember( m_idPlayer ) )
bResult = TRUE;
else
bResult = FALSE;
TRACE( "ReplaceInspection Guild Inspection %d \n", bResult );
}
#if __VER < 14 // __INSTANCE_DUNGEON // 상위 함수인 ProcessRegion()에서 처리
if( bResult != FALSE && IsFly() )
{
bResult = FALSE;
}
#endif // __INSTANCE_DUNGEON
return bResult;
}
// default type = REPLACE_NORMAL
#ifdef __LAYER_1015
BOOL CMover::Replace( u_long uIdofMulti, DWORD dwWorldID, D3DXVECTOR3 & vPos, REPLACE_TYPE type, int nLayer )
#else // __LAYER_1015
BOOL CMover::Replace( u_long uIdofMulti, DWORD dwWorldID, D3DXVECTOR3 & vPos, REPLACE_TYPE type )
#endif // __LAYER_1015
{
CWorld* pWorld = GetWorld();
if( !pWorld )
return FALSE;
if( dwWorldID == 0 || dwWorldID == NULL_ID )
return FALSE;
#ifdef __LAYER_1015
CWorld* pTargetWorld = g_WorldMng.GetWorld( dwWorldID );
if( !pTargetWorld || !pTargetWorld->m_linkMap.GetLinkMap( nLayer ) )
{
Error( "Layer not found" );
return FALSE;
}
#endif // __LAYER_1015
// 조건검사
if( type == REPLACE_NORMAL )
{
if( IsAuthHigher( AUTH_GAMEMASTER ) == FALSE && IsFly() )
return FALSE;
}
// 이동을 멈춘다.
ClearDest();
SendActMsg( OBJMSG_ACC_STOP );
SendActMsg( OBJMSG_STOP_TURN );
SendActMsg( OBJMSG_STAND );
#if __VER >= 11 // __SYS_COLLECTING
if( IsCollecting() )
StopCollecting();
#endif // __SYS_COLLECTING
#if __VER >= 15 // __REACTIVATE_EATPET
if( HasActivatedEatPet() )
InactivateEatPet();
#endif // __REACTIVATE_EATPET
LPREPLACEOBJ lpReplaceObj = NULL;
for( int i = 0; i < pWorld->m_cbModifyLink; i++ )
{
if( pWorld->m_apModifyLink[i] == this )
{
pWorld->m_apModifyLink[i] = NULL;
m_vRemoval = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
break;
}
}
for( i = 0; i < pWorld->m_cbReplaceObj; i++ )
{
if( pWorld->m_aReplaceObj[i].pObj == this )
{
lpReplaceObj = &pWorld->m_aReplaceObj[i];
break;
}
}
if( lpReplaceObj == NULL )
{
ASSERT( pWorld->m_cbReplaceObj < MAX_REPLACEOBJ );
lpReplaceObj = &pWorld->m_aReplaceObj[pWorld->m_cbReplaceObj++];
lpReplaceObj->pObj = this;
}
lpReplaceObj->dwWorldID = dwWorldID;
lpReplaceObj->vPos = vPos;
lpReplaceObj->uIdofMulti = uIdofMulti;
#ifdef __LAYER_1015
lpReplaceObj->nLayer = nLayer;
#endif // __LAYER_1015
#if __VER >= 14 // __INSTANCE_DUNGEON
if( IsPlayer() )
{
if( CInstanceDungeonHelper::GetInstance()->IsInstanceDungeon( pWorld->GetID() )
&& !CInstanceDungeonHelper::GetInstance()->IsInstanceDungeon( dwWorldID ) )
//입장 인원수를 감소시킨다.
CInstanceDungeonHelper::GetInstance()->LeaveDungeon( static_cast<CUser*>( this ), pWorld->GetID() );
}
#endif // __INSTANCE_DUNGEON
return TRUE;
}
BOOL CMover::CreateItem( CItemBase* pItemBase, BYTE* pnId, short* pnNum, BYTE nCount )
{
if( pItemBase->m_dwItemId == 0 )
return FALSE;
CItemElem* pItemElem = (CItemElem*)pItemBase;
if( pItemElem->m_nHitPoint == -1 )
{
ItemProp* pItemProp = pItemElem->GetProp();
if( pItemProp )
pItemElem->m_nHitPoint = pItemProp->dwEndurance;
else
pItemElem->m_nHitPoint = 0;
}
if( pItemBase->GetSerialNumber() == 0 )
pItemBase->SetSerialNumber();
BOOL fSuccess;
if( nCount == 0 )
{
BYTE anId[MAX_INVENTORY];
short anNum[MAX_INVENTORY];
fSuccess = m_Inventory.Add( (CItemElem*)pItemBase, anId, anNum, &nCount );
if( fSuccess && IsPlayer() )
{
( (CUser*)this )->AddCreateItem( pItemBase, anId, anNum, nCount );
}
if( pnId != NULL )
memcpy( pnId, anId, sizeof(BYTE) * nCount );
if( pnNum != NULL )
memcpy( pnNum, anNum, sizeof(short) * nCount );
}
else
{
CItemElem* pItemElem = (CItemElem*)pItemBase;
CItemElem itemElem;
itemElem = *pItemElem;
for( int i = 0; i < nCount; i++ )
{
itemElem.m_nItemNum = pnNum[i];
m_Inventory.SetAtId( pnId[i], &itemElem );
}
if( IsPlayer() )
( (CUser*)this )->AddCreateItem( pItemBase, pnId, pnNum, nCount );
fSuccess = TRUE;
}
return fSuccess;
}
void CMover::RemoveItem( BYTE nId, short nNum )
{
CItemBase* pItemBase = GetItemId( nId );
if( pItemBase )
UpdateItem( nId, UI_NUM, ( (CItemElem*)pItemBase )->m_nItemNum - nNum );
}
// IK3로 삭제하기 예) IK3_CLOAK
void CMover::RemoveItemIK3( DWORD dwItemKind3 )
{
int nSize = m_Inventory.GetMax();
for( int i = 0 ; i < nSize; i++ )
{
CItemElem* pItemElem = m_Inventory.GetAtId( i );
if( IsUsableItem( pItemElem ) && pItemElem->GetProp()->dwItemKind3 == dwItemKind3 )
{
if( pItemElem->GetProp()->dwItemKind3 == IK3_CLOAK && pItemElem->m_idGuild == 0 )
continue;
if( m_Inventory.IsEquip( pItemElem->m_dwObjId ) )
{
if( DoEquip( pItemElem, FALSE ) )
{
g_UserMng.AddDoEquip( this, -1, pItemElem, FALSE );
UpdateItem( i, UI_NUM, 0 ); // remove
}
else
{
// 인벤 full이고, 장착상태이면 제거할 수 없다.
// WriteError( "RemoveItemIK3->DoEquip : %s %d, User = %s, Item = %d %d %d",
// __FILE__, __LINE__, GetName(), pItemElem->m_dwObjId, pItemElem->GetProp()->dwItemKind3, dwItemKind3 );
}
}
else
{
UpdateItem( i, UI_NUM, 0 ); // remove
}
}
}
}
void CMover::RemoveVendorItem( CHAR chTab, BYTE nId, short nNum )
{
short num;
CItemElem* pItemElem = m_ShopInventory[chTab]->GetAtId( nId );
if( pItemElem )
{
if( ( num = pItemElem->m_nItemNum - nNum ) > 0 )
pItemElem->m_nItemNum = num;
else
m_ShopInventory[chTab]->RemoveAtId( nId );
g_UserMng.AddUpdateVendor( this, chTab, nId, num );
}
}
#endif // __WORLDSERVER
void CMover::UpdateItemBank( int nSlot, BYTE nId, CHAR cParam, DWORD dwValue )
{
CItemBase* pItemBase = GetItemBankId( nSlot, nId );
if( pItemBase )
{
switch( cParam )
{
case UI_NUM:
{
if( dwValue == 0 )
{
RemoveItemBankId( nSlot, nId );
}
else
{
( (CItemElem*)pItemBase )->m_nItemNum = (short)( dwValue );
}
break;
}
default:
break;
}
}
#ifdef __WORLDSERVER
if( IsPlayer() )
( (CUser*)this )->AddUpdateBankItem( nSlot, nId, cParam, dwValue );
#endif
}
#ifdef __WORLDSERVER
// 인벤토리내에서 1개 아이템을 떨어트린다.
int CMover::DoDropItemRandom( BOOL bExcludeEquip, CMover* pAttacker, BOOL bOnlyEquip )
{
int i, nMax, nRealMax, nDropCnt;
CItemElem* pItemElem;
CItemElem *pElemBuff[ MAX_INVENTORY + MAX_EQUIPMENT ] = { NULL, };
nRealMax = nDropCnt = 0;
nMax = m_Inventory.GetMax();
for( i = 0; i < nMax; ++i ) // 인벤 갯수만큼 돌면서 아이템이 있는칸만 포인터를 뽑아놓는다.
{
pItemElem = m_Inventory.GetAtId( i );
if( pItemElem == NULL )
continue;
if( pItemElem->IsQuest() ) // 퀘스트 아이템 제외
continue;
if( pItemElem->IsCharged() ) // 유료 상품아이템 제외
continue;
#if __VER >= 8 // __S8_PK
if( pItemElem->IsEatPet()
#if __VER >= 9 // __PET_0410
|| IsUsing( pItemElem )
#endif // __PET_0410
)
continue;
#else // __VER >= 8 // __S8_PK
if( HasActivatedEatPet() && pItemElem->IsEatPet() )
continue;
#endif // __VER >= 8 // __S8_PK
if( pItemElem->IsBinds() )
continue;
if( bOnlyEquip )
{
if( m_Inventory.IsEquip( pItemElem->m_dwObjId ) ) // 장착된 아이템 제외
pElemBuff[ nRealMax++ ] = pItemElem;
}
else
{
if( bExcludeEquip && m_Inventory.IsEquip( pItemElem->m_dwObjId ) ) // 장착된 아이템 제외
continue;
pElemBuff[ nRealMax++ ] = pItemElem;
}
}
while( nRealMax ) // 검색대상 아이템이 더이상 없을경우 끝.
{
int nIdx = xRandom( nRealMax );
pItemElem = pElemBuff[ nIdx ]; // 아이템 리스트에서 랜덤으로 하나를 뽑아옴
int nPartBuf = -1;
#if __VER >= 8 // __S8_PK
CItemElem* pItemElemLWepon = m_Inventory.GetEquip( PARTS_LWEAPON );
CItemElem* pItemElemRWepon = m_Inventory.GetEquip( PARTS_RWEAPON );
if( pItemElem == pItemElemLWepon )
nPartBuf = PARTS_LWEAPON;
else if( pItemElem == pItemElemRWepon )
nPartBuf = PARTS_RWEAPON;
#endif // __VER >= 8 // __S8_PK
if( m_Inventory.IsEquip( pItemElem->m_dwObjId ) ) // 장착하고 있으면 벗김
{
if( DoEquip( pItemElem, FALSE, nPartBuf ) )
g_UserMng.AddDoEquip( this, nPartBuf, pItemElem, FALSE );
}
CItem* pItem = DropItem( pItemElem->m_dwObjId, 0, GetPos(), TRUE );
if( pItem )
{
UNUSED_ALWAYS( pAttacker );
return 1;
}
// drop에 실패한 아이템이라도 리스트에서 빼주자.
for( int j = nIdx; j < nRealMax-1; j ++ ) // 앞으로 한칸씩 땡김.
pElemBuff[j] = pElemBuff[j+1];
nRealMax --; // 하나를 떨어트렸으니 버퍼의 크기를 하나 줄임
}
return 0;
}
#endif // __WORLDSERVER
CItem *CMover::_DropItemNPC( DWORD dwItemType, DWORD dwID, short nDropNum, const D3DXVECTOR3 &vPos )
{
#ifdef __WORLDSERVER
if( IsInvalidObj(this) )
return NULL;
CWorld *pWorld = GetWorld();
if( pWorld == NULL )
return NULL;
CItemBase* pItemBase = GetItemId( dwID );
if( NULL == pItemBase )
return NULL;
short nNum = 1;
nNum = ((CItemElem*)pItemBase)->m_nItemNum;
if( m_Inventory.IsEquip( pItemBase->m_dwObjId ) )
return NULL;
if( nDropNum == 0 )
nDropNum = nNum;
else if( nNum - (int)nDropNum < 0 )
return NULL;
CItem* pItem = new CItem;
pItem->m_pItemBase = new CItemElem;
*((CItemElem*)pItem->m_pItemBase) = *((CItemElem*)pItemBase);
((CItemElem*)pItem->m_pItemBase)->m_nItemNum = nDropNum;
if( pItemBase->m_dwItemId == 0 )
Error( "_DropItemNPC SetIndex: %s \n", GetName() );
pItem->SetIndex( D3DDEVICE, pItemBase->m_dwItemId );
if( pItem->m_pModel )
{
D3DXVECTOR3 v = vPos;
v.y += ( pItem->m_pModel->m_vMax.y - pItem->m_pModel->m_vMin.y ) / 2.0f;
pItem->SetPos( v );
pItem->SetAngle( (float)( xRandom( 360 ) ) );
pItem->m_dwDropTime = timeGetTime(); // 떨어트렸을때의 시간.
pWorld->ADDOBJ( (CObj*)pItem, TRUE, GetLayer() );
RemoveItem( (BYTE)( dwID ), nDropNum );
return pItem;
}
else
{
SAFE_DELETE( pItem );
}
#endif // WORLDSERVER
return NULL;
}
// 아이템을 떨굴 수 있는가? PK - PK를 당한 경우는 TRUE
BOOL CMover::IsDropableState( BOOL bPK )
{
if( IsInvalidObj(this) )
return FALSE;
#ifdef __WORLDSERVER
CWorld *pWorld = GetWorld();
if( pWorld == NULL )
return FALSE;
if( m_pActMover->m_bGround == 0 || m_pActMover->IsFly() ) // 날고있는 중이거나 공중에 떠있는상태에선 일단 못떨어트리게 하자.
{
if( bPK == FALSE ) // PK당한 경우가 아닐경우만 떨군다.
{
((CUser*)this)->AddDefinedText( TID_GAME_FLIGHTDROP, "" );
return FALSE;
}
}
if( m_vtInfo.GetOtherID() != NULL_ID ) // 트레이드중일땐 일단 못떨어트리게 하자
{
((CUser*)this)->AddDefinedText( TID_GAME_TRADELIMITITEM, "" );
return FALSE;
}
if( m_vtInfo.VendorIsVendor() )
return FALSE;
if( IsMode( ITEM_MODE ) )
return FALSE;
#endif // __WORLDSERVER
return TRUE;
}
// 인벤의 아이템을 바닥에 내려놓을때 사용한다.
// dwType, dwID의 아이템을 vPos에 떨어트린다.
// bPK == YES면 플레이어가 PK당해서 떨어트린 아이템이다.
CItem* CMover::DropItem( DWORD dwID, short nDropNum, const D3DXVECTOR3 &vPos, BOOL bPK )
{
#ifdef __WORLDSERVER
if( IsPlayer() == FALSE )
return _DropItemNPC( 0, dwID, nDropNum, vPos ); // 몹이 떨어뜨릴땐 이걸사용.
CItemBase* pItemBase = GetItemId( dwID );
if( IsDropable( (CItemElem*)pItemBase, bPK ) == FALSE )
return NULL;
short nNum = ((CItemElem*)pItemBase)->m_nItemNum;
if( nDropNum == 0 )
nDropNum = nNum;
else if( nDropNum > nNum )
return NULL;
CItem* pItem = new CItem;
pItem->m_pItemBase = new CItemElem;
*( (CItemElem*)pItem->m_pItemBase ) = *( (CItemElem*)pItemBase );
( (CItemElem*)pItem->m_pItemBase )->m_nItemNum = nDropNum;
if( pItemBase->IsQuest() )
pItem->m_idHolder = m_idPlayer;
if( ( (CItemElem*)pItemBase )->IsLogable() )
{
LogItemInfo aLogItem;
aLogItem.Action = "D";
aLogItem.SendName = GetName();
aLogItem.RecvName = "GROUND";
aLogItem.WorldId = GetWorld()->GetID();
aLogItem.Gold = aLogItem.Gold2 = GetGold();
g_DPSrvr.OnLogItem( aLogItem, ( (CItemElem*)pItemBase ), nDropNum );
}
pItem->SetIndex( D3DDEVICE, pItemBase->m_dwItemId );
if( pItem->m_pModel )
{
D3DXVECTOR3 v = vPos;
v.y += ( pItem->m_pModel->m_vMax.y - pItem->m_pModel->m_vMin.y ) / 2.0f;
pItem->SetPos( v );
pItem->SetAngle( (float)( xRandom( 360 ) ) );
pItem->m_dwDropTime = timeGetTime(); // 떨어트렸을때의 시간.
UNUSED_ALWAYS( bPK );
GetWorld()->ADDOBJ( (CObj*)pItem, TRUE, GetLayer() );
RemoveItem( (BYTE)( dwID ), nDropNum );
return pItem;
}
else
{
SAFE_DELETE( pItem );
}
#endif // WORLDSERVER
return NULL;
}
// TODO_OPTIMIZE: 좌표가 변경될 때 호출되게한다. ( rect를 트리구조로 갖고 찾게 하는 것도 좋겠다.)
REGIONELEM* CMover::UpdateRegionAttr()
{
REGIONELEM* pPortkey = NULL;
const DWORD dwCheck = ( RA_SAFETY | RA_PENALTY_PK | RA_PK | RA_FIGHT ) ;
D3DXVECTOR3 vPos = GetPos();
POINT pt = { (LONG)( vPos.x ), (LONG)( vPos.z ) };
LPREGIONELEM lpRegionElem;
int nSize = GetWorld()->m_aRegion.GetSize();
DWORD dwRegionAttr = 0;
for( int i = 0; i < nSize; i++ )
{
lpRegionElem = GetWorld()->m_aRegion.GetAt( i );
if( lpRegionElem->m_rect.PtInRect( pt ) )
{
dwRegionAttr |= lpRegionElem->m_dwAttribute;
if( lpRegionElem->m_dwIdTeleWorld != WI_WORLD_NONE )
pPortkey = lpRegionElem;
}
}
if( dwRegionAttr & dwCheck )
{
m_dwOldRegionAttr = m_dwRegionAttr;
m_dwRegionAttr = dwRegionAttr;
}
else
{
m_dwOldRegionAttr = m_dwRegionAttr;
m_dwRegionAttr = GetWorld()->m_nPKMode;;
}
return pPortkey;
}
//다른 지역으로 이동했는지 검사 ( 평화 지역, 페널티 피케이 지역, 프리 피케이 지역 )
BOOL CMover::IsRegionMove( DWORD dwOldAttr, DWORD dwRegionAttr )
{
if( ( dwOldAttr & RA_SAFETY ) == RA_SAFETY )
{
if( ( dwRegionAttr & RA_SAFETY ) != RA_SAFETY )
{
return TRUE;
}
}
else if( ( dwOldAttr & RA_PENALTY_PK ) == RA_PENALTY_PK )
{
if( ( dwRegionAttr & RA_PENALTY_PK ) != RA_PENALTY_PK )
{
return TRUE;
}
}
else if( ( dwOldAttr & RA_PK ) == RA_PK )
{
if( ( dwRegionAttr & RA_PK ) != RA_PK )
{
return TRUE;
}
}
else if( ( dwOldAttr & RA_FIGHT ) == RA_FIGHT )
{
if( ( dwRegionAttr & RA_FIGHT ) != RA_FIGHT )
{
return TRUE;
}
}
return FALSE;
}
DWORD CMover::GetPKPVPRegionAttr()
{
if( IsRegionAttr( RA_FIGHT ) )
return RA_FIGHT;
else if( IsRegionAttr( RA_PENALTY_PK ) )
return RA_PENALTY_PK;
else if( IsRegionAttr( RA_PK ) )
return RA_PK;
else
return RA_SAFETY;
}
void CMover::SetStateMode( DWORD dwMode, BYTE nFlag )
{
m_dwStateMode |= dwMode;
#ifdef __WORLDSERVER
g_UserMng.AddStateMode( ((CUser*)this), nFlag );
#endif // __WORLDSERVER
}
void CMover::SetStateNotMode( DWORD dwMode, BYTE nFlag )
{
m_dwStateMode &= (~dwMode);
#ifdef __WORLDSERVER
g_UserMng.AddStateMode( ((CUser*)this), nFlag );
#endif // __WORLDSERVER
}
BOOL CMover::IsUseItemReadyTime( ItemProp* pItemProp, OBJID dwObjItemId )
{
if( m_Inventory.IsEquip( dwObjItemId ) )
{
return TRUE;
}
if( pItemProp->dwParts == PARTS_RIDE )
{
CWorld* pWorld = GetWorld();
if( pWorld == NULL )
return FALSE;
int nLimitLv = pItemProp->dwFlightLimit;
if( nLimitLv == NULL_ID )
nLimitLv = 1;
#ifdef __NOLIMIT_RIDE_ITEM
if( pItemProp->dwID == II_RID_RID_STI_MAGIC01 )
nLimitLv = 0;
#endif // __NOLIMIT_RIDE_ITEM
if( GetFlightLv() < nLimitLv ) // 비행레벨이 안되면 못탄다.
{
PrintString( this, TID_GAME_USEAIRCRAFT ); // 서있어야 사용할수 있습니다
return FALSE;
}
int nAttr = pWorld->GetHeightAttribute( GetPos().x, GetPos().z );
if( !pWorld->m_bFly || nAttr == HATTR_NOFLY ) // 비행금지구역입니다.
{
PrintString( this, TID_ERROR_NOFLY );
return FALSE;
}
}
if( pItemProp->dwSkillReadyType != 0 &&
pItemProp->dwSkillReadyType != 0xffffffff )
{
if( m_vtInfo.IsVendorOpen() ) // 개인상점 중에는 못탄다
{
return FALSE;
}
else if( IsStateMode( STATE_BASEMOTION_MODE ) ) // 이미 시전중이면 메세지 처리
{
PrintString( this, TID_PK_BLINK_LIMIT ); // 시전중에는 사용할수 없습니다
return FALSE;
}
else if( m_pActMover->IsState( OBJSTA_STAND ) == FALSE ) // 서있는 상태가 아니면 메세지 처리
{
PrintString( this, TID_PK_STAND_LIMIT ); // 서있어야 사용할수 있습니다
return FALSE;
}
else if( IsFly() )
{
#ifdef __CLIENT
g_WndMng.PutString( prj.GetText( TID_PK_FLIGHT_NOUSE ), NULL, prj.GetTextColor( TID_PK_FLIGHT_NOUSE ) );
#endif // __CLINET
return FALSE;
}
}
return TRUE;
}
void CMover::ProcessRegion()
{
if( FALSE == IsPlayer() )
return;
REGIONELEM* pPortkey = NULL;
if( IsPosChanged() )
{
pPortkey = UpdateRegionAttr();
SetPosChanged( FALSE );
}
#ifdef __WORLDSERVER
//#if __VER < 8 // 8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
if( IsRegionMove( m_dwOldRegionAttr, m_dwRegionAttr ) )
{
if( m_nDuel == 1 )
{
CMover *pDuelOther = prj.GetMover( m_idDuelOther );
if( IsValidObj( pDuelOther ) )
{
pDuelOther->DuelResult( this );
pDuelOther->ClearDuel();
( (CUser*)pDuelOther )->AddSetDuel( pDuelOther );
ClearDuel();
( (CUser*)this )->AddSetDuel( this );
}
}
else if( m_nDuel == 2 )
{
CParty* pParty = g_PartyMng.GetParty( m_idparty );
if( pParty && pParty->IsLeader( m_idPlayer ) )
{
CParty* pParty2 = g_PartyMng.GetParty( m_idDuelParty );
if( pParty2 )
{
CUser* pWinner = (CUser*)pParty2->GetLeader();
if( pWinner )
pWinner->DuelResult( this );
}
}
}
}
//#endif // __VER < 8
if( pPortkey )
{
#if __VER >= 14 // __INSTANCE_DUNGEON
if( IsFly() ) // ReplaceInspection() 에 있는 것을 밖으로 꺼내왔다.
return;
if( CInstanceDungeonHelper::GetInstance()->IsInstanceDungeon( pPortkey->m_dwIdTeleWorld ) )
{
if( !CInstanceDungeonHelper::GetInstance()->IsInstanceDungeon( static_cast<CUser*>( this )->GetWorld()->GetID() ) )
CInstanceDungeonHelper::GetInstance()->EnteranceDungeon( static_cast<CUser*>( this ), pPortkey->m_dwIdTeleWorld );
else
REPLACE( g_uIdofMulti, pPortkey->m_dwIdTeleWorld, pPortkey->m_vTeleWorld, REPLACE_NORMAL, static_cast<CUser*>( this )->GetLayer() );
return;
}
#endif // __INSTANCE_DUNGEON
if( ReplaceInspection( pPortkey ) == FALSE )
return;
REPLACE( g_uIdofMulti, pPortkey->m_dwIdTeleWorld, pPortkey->m_vTeleWorld, REPLACE_NORMAL, nTempLayer );
}
#endif // __WORLDSERVER
}
BOOL CMover::Read( CFileIO* pFile )
{
CObj::Read( pFile );
char szDialogFile[MAX_DIALOGFILENAME];
DWORD dwExtraFlag = 0;
pFile->Read( m_szName, sizeof( m_szName ) );
pFile->Read( szDialogFile, sizeof( szDialogFile ) );
pFile->Read( m_szCharacterKey, sizeof( m_szCharacterKey ) );
pFile->Read( &m_dwBelligerence, sizeof( m_dwBelligerence ) );
pFile->Read( &dwExtraFlag, sizeof( dwExtraFlag ) );
UpdateParam();
#if defined(__WORLDSERVER)
InitCharacter( GetCharacter() );
#endif
return TRUE;
}
CItemElem* CMover::GetLWeaponItem()
{
return GetWeaponItem( PARTS_LWEAPON );
}
CItemElem* CMover::GetWeaponItem( int nParts )
{
if( IsPlayer() )
return (CItemElem*)m_Inventory.GetEquip( nParts );
return NULL;
}
ItemProp* CMover::GetActiveHandItemProp( int nParts )
{
if( IsPlayer() )
{
#ifdef __CLIENT
if( IsActiveMover() )
{
CItemElem* pItemElem = (CItemElem*)m_Inventory.GetEquip( nParts );
if( pItemElem )
return pItemElem->GetProp();
return prj.GetItemProp( II_WEA_HAN_HAND );
}
else // 클라이언트에서는 타 캐릭터는 m_adwEquipment에 dwObjId가 아닌 dwItemId를 가지고 있다.
{
DWORD dwWeaponId = m_aEquipInfo[nParts].dwId;
if( dwWeaponId != NULL_ID )
return prj.GetItemProp( dwWeaponId );
return prj.GetItemProp( II_WEA_HAN_HAND );
}
#else // __CLIENT
CItemElem* pItemElem = (CItemElem*)m_Inventory.GetEquip( nParts );
if( pItemElem )
return pItemElem->GetProp();
return prj.GetItemProp( II_WEA_HAN_HAND );
#endif // __CLIENT
}
// virt는 NPC들이 사용하는 가상 아이템 또는 플레이어가 무기를 장착하지 않았을 때 사용할 아이템이다.
// 이것을 설정하여 몹의 사용할 아이템을 결정한다.
// 그 아이템은 주로 무기나, 스킬을 의미할 것이며, 주로 공격용으로 사용될 것이다.
if( m_dwVirtItem != NULL_ID )
{
if( m_dwVirtType == VT_ITEM )
return prj.GetItemProp( m_dwVirtItem );
if( m_dwVirtType == VT_SKILL )
return prj.GetSkillProp( m_dwVirtItem );
}
return NULL;
}
ItemProp* CMover::GetTransyItem( ItemProp* pItemProp, BOOL bCheck, LPCTSTR lpszFileName )
{
ItemProp* pItemPropChange = NULL;
CString szMsg;
int nCount = 0;
BOOL bSetIteFirst = FALSE;
if( pItemProp && ( pItemProp->dwItemKind2 == IK2_ARMOR || pItemProp->dwItemKind2 == IK2_ARMORETC )
&& ( pItemProp->dwItemSex == SEX_MALE || pItemProp->dwItemSex == SEX_FEMALE ) )
{
for( int j = 0; j < prj.m_aPropItem.GetSize(); j++ )
{
BOOL bSetIteSecond = FALSE;
ItemProp* pItemProp1 = prj.GetItemProp( j );
if( pItemProp1 && pItemProp->dwID != pItemProp1->dwID
&& ( pItemProp1->dwItemKind2 == IK2_ARMOR || pItemProp1->dwItemKind2 == IK2_ARMORETC )
&& ( pItemProp1->dwItemSex == SEX_MALE || pItemProp1->dwItemSex == SEX_FEMALE )
&& pItemProp->dwItemSex != pItemProp1->dwItemSex )
{
if( pItemProp->dwItemKind1 == pItemProp1->dwItemKind1 && pItemProp->dwItemKind2 == pItemProp1->dwItemKind2 && pItemProp->dwItemKind3 == pItemProp1->dwItemKind3
&& pItemProp->dwItemJob == pItemProp1->dwItemJob && pItemProp->dwHanded == pItemProp1->dwHanded && pItemProp->dwParts == pItemProp1->dwParts
&& pItemProp->dwItemLV == pItemProp1->dwItemLV //&& pItemProp->dwCost == pItemProp1->dwCost//&& pItemProp->dwItemRare == pItemProp1->dwItemRare
&& pItemProp->dwAbilityMin == pItemProp1->dwAbilityMin && pItemProp->dwAbilityMax == pItemProp1->dwAbilityMax && pItemProp->fAttackSpeed == pItemProp1->fAttackSpeed
)
{
if( CSetItemFinder::GetInstance()->GetSetItemByItemId( pItemProp->dwID ) )
bSetIteFirst = TRUE;
if( CSetItemFinder::GetInstance()->GetSetItemByItemId( pItemProp1->dwID ) )
bSetIteSecond = TRUE;
// 같은 종류 인지? ( 세트? 일반? )
if( bSetIteFirst == bSetIteSecond )
{
pItemPropChange = pItemProp1;
++nCount;
if( bCheck )
{
if( 0 < nCount )
szMsg.Format( "%s -> %s (%d)", pItemProp->szName, pItemProp1->szName, nCount );
else
szMsg.Format( "%s -> %s", pItemProp->szName, pItemProp1->szName );
FILEOUT( lpszFileName, szMsg );
}
else
{
break;
}
}
}
}
}
if( bCheck && nCount == 0 )
{
szMsg.Format( "%s -> %s", pItemProp->szName, "NULL" );
FILEOUT( lpszFileName, szMsg );
}
}
return pItemPropChange;
}
CItemElem* CMover::GetEquipItem( int nParts )
{
return (CItemElem*)m_Inventory.GetEquip( nParts );
}
ItemProp* CMover::GetEquipItemProp( CItemContainer<CItemElem>* pInventory, PEQUIP_INFO pEquipInfo, int nParts )
{
ItemProp *pItemProp = NULL;
#if 1
if( pInventory == NULL )
{
if( pEquipInfo[nParts].dwId != NULL_ID )
pItemProp = prj.GetItemProp( pEquipInfo[nParts].dwId );
} else
{
CItemElem *pItemElem = pInventory->GetEquip( nParts );
if( pItemElem )
pItemProp = pItemElem->GetProp();
}
#endif
return pItemProp;
}
// 쌍칼모드 인가.
// 양손에 쌍칼을 들고 있나.
BOOL CMover::IsDualWeapon()
{
#ifdef __CLIENT
if( IsActiveMover() )
#else
if( IsPlayer() )
#endif
{
CItemElem *pItemElemR = m_Inventory.GetEquip( PARTS_RWEAPON );
CItemElem *pItemElemL = m_Inventory.GetEquip( PARTS_LWEAPON );
if( pItemElemR && pItemElemL )
return TRUE;
else
return FALSE;
} else
{
if( m_aEquipInfo[PARTS_RWEAPON].dwId != NULL_ID && m_aEquipInfo[PARTS_LWEAPON].dwId != NULL_ID )
return TRUE;
else
return FALSE;
}
return FALSE;
}
void CMover::ProcessAniSpeed()
{
if( IsPlayer() )
{
switch( m_pActMover->GetState() & OBJSTA_ATK_ALL )
{
case OBJSTA_ATK1:
case OBJSTA_ATK2:
case OBJSTA_ATK3:
case OBJSTA_ATK4:
case OBJSTA_ATK_MAGIC1:
case OBJSTA_ATK_RANGE1:
m_fAniSpeed = GetAttackSpeed();
break;
case OBJSTA_ATK_CASTING1:
case OBJSTA_ATK_CASTING2:
case OBJSTA_ATK_MAGICSKILL:
m_fAniSpeed = GetCastingAniSpeed();
break;
default:
{
#if __VER < 9 // __AI_0509
int nSpeed = GetAdjParam( DST_SPEED );
if( nSpeed > 0 && (m_pActMover->GetState() == OBJSTA_FMOVE) )
m_fAniSpeed = 1.5f; // 퀵스탭이고 전진중이면 에니속도 증가
else
if( nSpeed < 0 && (m_pActMover->GetState() == OBJSTA_FMOVE) )
m_fAniSpeed = 0.7f; //
else
m_fAniSpeed = 1.0f; // 보통은 기본 속도.
#else // __AI_0509
m_fAniSpeed = 1.0f; // 보통은 기본 속도.
#endif // __AI_0509
}
}
}
else
{
#if __VER < 9 // __AI_0509
if( GetAdjParam( DST_CHRSTATE ) & CHS_SLOW )
m_fAniSpeed = 0.5f;
else
m_fAniSpeed = 1.0f;
MoverProp* pMoverProp = GetProp();
if( pMoverProp->dwAI == AII_PET )
{
switch( m_pActMover->GetState() )
{
case OBJSTA_FMOVE:
m_fAniSpeed = 3.0f;
break;
default:
m_fAniSpeed = 1.0f;
}
}
#else // __AI_0509
m_fAniSpeed = 1.0f;
#endif // __AI_0509
}
}
#ifdef __CLIENT
void CMover::ProcessScaleSlerp()
{
if( m_fDestScaleSlerp > 0 ) // 줄어 들어야 하는 상태다.
{
MoverProp* pMoverProp = GetProp();
if( pMoverProp )
{
D3DXVECTOR3 vScale = GetScale();
if( pMoverProp->dwClass != RANK_MATERIAL && pMoverProp->dwClass != RANK_SUPER && pMoverProp->dwClass != RANK_MIDBOSS )
{
LPCTSTR szErr = Error( "CMover::Process : 자원몹이 아닌데 들어왔다.%s %f, %f, %f %f %f", GetName(), m_fDestScaleSlerp, m_fDestScale, vScale.x, vScale.y, vScale.z );
ADDERRORMSG( szErr );
m_fDestScaleSlerp = 0;
}
else
{
D3DXVECTOR3 vDestScale = D3DXVECTOR3( m_fDestScale, m_fDestScale, m_fDestScale );
D3DXVec3Lerp( &vScale, &vDestScale, &vScale, m_fDestScaleSlerp );
SetScale( vScale );
m_fDestScaleSlerp -= 0.001f;
}
}
}
}
void CMover::ProcessWaterCircle( const D3DXVECTOR3& vPosTemp, const D3DXVECTOR3& vPos )
{
if( !IsMode( TRANSPARENT_MODE ) )
{
LPWATERHEIGHT pWaterHeight = GetWorld()->GetWaterHeight( GetPos() );
#if __VER >= 14 // __WATER_EXT
if(pWaterHeight && (pWaterHeight->byWaterTexture & (byte)(~MASK_WATERFRAME)) == WTYPE_WATER)
#else //__WATER_EXT
if( pWaterHeight && pWaterHeight->byWaterTexture == WTYPE_WATER )
#endif //__WATER_EXT
{
FLOAT fHeight = (FLOAT)pWaterHeight->byWaterHeight;
if( vPosTemp.y > fHeight && vPos.y <= fHeight && m_pActMover->IsActJump() )
{
CreateSfx( g_Neuz.m_pd3dDevice, XI_GEN_WATERCROWN01, D3DXVECTOR3( vPos.x, fHeight, vPos.z ) );
}
if( vPos != vPosTemp && vPos.y < fHeight && vPos.y > ( fHeight - 1.5f ) && m_nWaterCircleCount > 7 )
{
CreateSfx( g_Neuz.m_pd3dDevice, XI_GEN_WATERCIRCLE01, D3DXVECTOR3( vPos.x, fHeight + .01f, vPos.z) );
m_nWaterCircleCount = 0;
}
}
m_nWaterCircleCount++;
}
}
// 플레이어들이 뛸때 사운드소리를 낸다...콜라에서 사운드지정으로 플레이하는것이 아님.
// 임시적으로 히트포인트를 사운드 플레이 시점으로 사용함...
void CMover::ProcessWalkSound()
{
if( IsPlayer() && !( IsMode( TRANSPARENT_MODE ) ) )
{
#ifdef __Y_INTERFACE_VER3
if( m_pActMover->GetMoveState() & OBJSTA_FMOVE || m_pActMover->GetMoveState() & OBJSTA_LMOVE || m_pActMover->GetMoveState() & OBJSTA_RMOVE )
#else //__Y_INTERFACE_VER3
if( m_pActMover->GetMoveState() & OBJSTA_FMOVE )
#endif //__Y_INTERFACE_VER3
{
CModelObject* pModel = (CModelObject*)m_pModel;
if( pModel->IsAttrHit() )
{
PLAYSND( SND_WALK_LANDSOFT, &GetPos() );
}
}
}
}
void CMover::ProcessDustSFX()
{
if( ! ( IsMode( TRANSPARENT_MODE ) ) ) // 투명상태가 아닐때만 렌더.
{
CModelObject* pModel = (CModelObject*)m_pModel;
MOTION_ATTR* pAttr = pModel->IsAttrSound();
if( IsPlayer() && pAttr && pAttr->m_nSndID > 0 ) // 효과음 속성이 있다면 플레이, pause상태면 사운드 출력 안함
{
if( m_pActMover->IsActJump() )
CreateSfx( g_Neuz.m_pd3dDevice, XI_NAT_DUST_JUMP, GetPos() );
else
if( m_pActMover->IsRun() && !m_pActMover->IsActAttack() )
CreateSfx( g_Neuz.m_pd3dDevice, XI_NAT_DUST_RUN, GetPos() );
}
}
}
// 기타 처리
void CMover::ProcessETC()
{
int nAbilityOption = GetSetItemClient();
if( nAbilityOption >= 3 && !(m_dwFlag & MVRF_SETITEMSFX))
{
m_dwFlag |= MVRF_SETITEMSFX;
CreateAbilityOption_SetItemSFX( nAbilityOption );
}
CModelObject* pModel = (CModelObject*)m_pModel;
if( pModel->m_SparkInfo.m_bUsed )
{
if( pModel->m_SparkInfo.m_nCnt != 0 )
{
pModel->m_SparkInfo.m_fLerp -= 0.05f;
if( pModel->m_SparkInfo.m_fLerp < 0.0f )
{
pModel->m_SparkInfo.m_bUsed = FALSE;
}
}
pModel->m_SparkInfo.m_nCnt++;
}
if( (m_nCount & 131071) == 0 ) // 30분마다
{
if( xRandom(100) > 50 )
{
ItemProp* pItemProp = NULL;
if( IsActiveMover() )
{
CItemElem* pItemElem = GetEquipItem( PARTS_HAT );
if( pItemElem )
pItemProp = pItemElem->GetProp();
}
else
{
DWORD dwId = m_aEquipInfo[PARTS_HAT].dwId;
O3D_ELEMENT* pElement = NULL;
if( dwId != NULL_ID )
pItemProp = prj.GetItemProp( dwId );
}
if( pItemProp )
{
if( GetSex() == SEX_MALE )
{
if( pItemProp->dwID == II_ARM_M_CHR_DARKVADER01HAT )
{
char szFormat[128] = {0};
sprintf( szFormat, "/s %s", prj.GetText(TID_GAME_FATHER) );
g_DPlay.SendChat( szFormat );
}
}
else
{
if( pItemProp->dwID == II_ARM_F_CHR_DARKVADER01HAT )
{
char szFormat[128] = {0};
sprintf( szFormat, "/s %s", prj.GetText(TID_GAME_MOTHER) );
g_DPlay.SendChat( szFormat );
}
}
}
}
}
// 길드컴뱃 맵이라면...부하를 줄이기 위해 상태에 따라 랜더링을 금지한다.
if( GetWorld() && GetWorld()->GetID() == WI_WORLD_GUILDWAR )
{
CWndWorld *pWndWorld = (CWndWorld *)g_WndMng.m_pWndWorld;
if( IsPlayer() && g_pPlayer && pWndWorld )
{
BOOL bFlag = FALSE;
int nActivePlayer = pWndWorld->IsGCStatusPlayerWar( g_pPlayer->m_idPlayer );
int nPlayer = pWndWorld->IsGCStatusPlayerWar( m_idPlayer );
// 액티브(주인공)이 전쟁중이면
if( nActivePlayer == 1 )
{
// 전쟁중이 아닌애들은 랜더금지
if( nPlayer != 1 )
{
bFlag = TRUE;
}
}
else
// 액티브(주인공)이 대기중이면
if( nActivePlayer == 0 )
{
// 일반인들은 랜더금지
if( nPlayer == -1 )
{
bFlag = TRUE;
}
}
if( bFlag )
{
m_dwMode |= GCWAR_NOT_CLICK_MODE;
m_dwMode |= GCWAR_RENDER_SKIP_MODE;
}
else
{
m_dwMode &= ~GCWAR_NOT_CLICK_MODE;
m_dwMode &= ~GCWAR_RENDER_SKIP_MODE;
}
}
}
else
{
m_dwMode &= ~GCWAR_NOT_CLICK_MODE;
m_dwMode &= ~GCWAR_RENDER_SKIP_MODE;
}
#ifdef __QUIZ
if( GetWorld() && GetWorld()->GetID() == WI_WORLD_QUIZ )
{
CWndWorld *pWndWorld = (CWndWorld *)g_WndMng.m_pWndWorld;
if( IsPlayer() && CQuiz::GetInstance()->GetZoneType( this ) != CQuiz::ZONE_QUIZ && pWndWorld )
m_dwMode |= QUIZ_RENDER_SKIP_MODE;
else
m_dwMode &= ~QUIZ_RENDER_SKIP_MODE;
}
else
m_dwMode &= ~QUIZ_RENDER_SKIP_MODE;
#endif // __QUIZ
}
extern void CreateFlyParticle( CMover *pMover, float fAngX, int nType );
#endif // __CLIENT
void CMover::ProcessIAObjLink( D3DXVECTOR3& vPos )
{
if( GetIAObjLink() )
{
D3DXMATRIX mLocal, mTrans, mRot, mWorld, *pmWorldIA;
D3DXMatrixTranslation( &mTrans, vPos.x, vPos.y, vPos.z );
D3DXMatrixRotationY( &mRot, D3DXToRadian( -GetAngle() ) );
mWorld = m_matScale;
pmWorldIA = GetIAObjLink()->GetMatrixWorldPtr();
D3DXMatrixMultiply( &mWorld, &mWorld, &mRot );
D3DXMatrixMultiply( &mWorld, &mWorld, &mTrans );
D3DXMatrixMultiply( &mLocal, &mWorld, GetIAObjLink()->GetInvTM() ); // IA오브젝트로부터의 로컬 행렬.
D3DXMatrixMultiply( &mWorld, &mLocal, pmWorldIA );
vPos.x = mWorld._41;
vPos.y = mWorld._42;
vPos.z = mWorld._43;
D3DXQUATERNION qRot;
D3DXVECTOR3 vYPW;
D3DXQuaternionRotationMatrix( &qRot, &mWorld );
QuaternionRotationToYPW( qRot, vYPW );
FLOAT fAngNew = -D3DXToDegree(vYPW.y);
SetAngle( fAngNew );
}
}
void CMover::ProcessActionPoint()
{
// 3초마다 액션포인트 자동 상승.
if( (int)(g_tmCurrent - m_tmActionPoint) > (1000 * 3) )
{
FLOAT fTime = (g_tmCurrent - m_tmActionPoint) / 1000.0f; // 지나간 시간을 소수점 단위로 환산.
fTime /= 3.0f; // 3초마다 갱신이므로.
if( fTime < 0 ) fTime = 0;
#ifdef __WORLDSERVER
((CUser*)this)->m_playTaskBar.m_nActionPoint += (int)(fTime * 2.0f);
if( ((CUser*)this)->m_playTaskBar.m_nActionPoint > 100 )
((CUser*)this)->m_playTaskBar.m_nActionPoint = 100;
if( m_nDuel == 1 ) // 플레이어가 / 듀얼중일때.
{
CMover *pDstDuel = prj.GetMover( m_idDuelOther );
if( IsInvalidObj(pDstDuel) ) // 듀얼상대가 없어졌으면.
{
( (CUser*)this )->AddDuelCancel( NULL_ID );
ClearDuel();
}
}
#else
if( IsActiveMover() )
{
g_WndMng.m_pWndTaskBar->m_nActionPoint += (int)(fTime * 2.0f);
if( g_WndMng.m_pWndTaskBar->m_nActionPoint > 100 )
g_WndMng.m_pWndTaskBar->m_nActionPoint = 100;
g_Neuz.m_NeuzEnemy.CheckInvalid();
}
#endif // CLIENT
m_tmActionPoint = g_tmCurrent;
}
}
//
//
//
#ifdef __WORLDSERVER
#include "GlobalTime.h"
extern float r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
extern BOOL g_bProfiling;
class CProfileSample
{
public:
CStopwatch& m_stopWatch;
float& m_fValue;
CProfileSample( CStopwatch& stopWatch, float& value ) : m_stopWatch( stopWatch ), m_fValue( value )
{
if( g_bProfiling )
stopWatch.PlayEx();
}
~CProfileSample()
{
if( g_bProfiling )
m_fValue += m_stopWatch.StopEx();
}
};
#ifdef __PROFILE_RUN
#define PROFILE( stopWatch, value ) ((void)0);
#else
#define PROFILE( stopWatch, value ) CProfileSample __sample( stopWatch, value )
#endif
#else
#define PROFILE( stopWatch, value ) ((void)0);
#endif
#ifdef __WORLDSERVER
#define CF_SEC 15
#else // __WORLDSERVER
#define CF_SEC 63
#endif // __WORLDSERVER
void CMover::Process()
{
_PROFILE("CMover::Process()");
if( IsDelete() )
return;
CModelObject* pModel = (CModelObject*)m_pModel;
D3DXVECTOR3 vPos, vPosTemp;
BOOL bCollision;
#if defined(__WORLDSERVER) && !defined(__PROFILE_RUN)
CStopwatch sw;
#endif
#ifdef __WORLDSERVER
if( m_2pc.size() == 0 && m_dwAIInterface != AII_PET )
return;
#endif // __WORLDSERVER
#ifdef __CLIENT
#if __VER >= 12 // __UPDATE_OPT
//if(IsPlayer())
//{
O3D_ELEMENT* pMask = pModel->GetParts(PARTS_MASK);
if(pMask)
{
if(IsOptionRenderMask() )
pModel->SetEffectOff(PARTS_MASK, XE_HIDE);
else
pModel->SetEffect(PARTS_MASK, XE_HIDE);
}
//}
#endif
#endif // __CLIENT
// 변수 조정
#ifdef __CLIENT
if( m_nCorr > 0 )
--m_nCorr;
if( m_nDmgCnt > 0 )
--m_nDmgCnt;
#else
if( m_nDead > 0 )
--m_nDead;
#endif
#ifdef __CLIENT
if( IsNPC() && IsFlyingNPC() ) // 비행몹은 파티클 생성
CreateFlyParticle( this, GetAngleX(), 0 );
ProcessScaleSlerp();
Interpolate();
#if __VER >= 14 // __WING_ITEM
if( m_pRide && m_pRide->m_pBone )
{
WingMotionSetting( pModel );
}
#endif // __WING_ITEM
#if __VER >= 14 // __WING_ITEM
if( m_pRide )
m_pRide->FrameMove( NULL, GetRideFrameSpeed() );
#else // __WING_ITEM
if( m_pRide )
m_pRide->FrameMove();
#endif // __WING_ITEM
if( m_pLadolf )
m_pLadolf->FrameMove();
#if __VER >= 8 //__CSC_VER8_5
if( IsPlayer() && HasBuffByIk3( IK3_ANGEL_BUFF ) )
{
if( m_pAngel == NULL )
{
m_pAngel = new CModelObject;
m_pAngel->InitDeviceObjects( g_Neuz.m_pd3dDevice );
#ifdef __BUFF_1107
IBuff* pBuff = m_buffs.GetBuffByIk3( IK3_ANGEL_BUFF );
ItemProp* pItemProp = NULL;
if( pBuff )
pItemProp = pBuff->GetProp();
if( pItemProp )
#else // __BUFF_1107
LPSKILLINFLUENCE itemskill = m_SkillState.GetItemBuf(IK3_ANGEL_BUFF);
ItemProp *pItemProp = prj.GetItemProp( itemskill->wID );
if( itemskill && pItemProp )
#endif // __BUFF_1107
{
switch(pItemProp->dwSfxElemental)
{
case ELEMENTAL_ANGEL_BLUE: m_dwAngelKind = 13; break;
case ELEMENTAL_ANGEL_RED: m_dwAngelKind = 16; break;
case ELEMENTAL_ANGEL_WHITE: m_dwAngelKind = 19; break;
case ELEMENTAL_ANGEL_GREEN: m_dwAngelKind = 22; break;
}
CString textFile;
textFile.Format("%s.chr", pItemProp->szTextFileName);
m_pAngel->LoadBone( textFile );
textFile.Format("%s.o3d", pItemProp->szTextFileName);
m_pAngel->LoadElement( textFile, 0 );
textFile.Format("%s_stand01.ani", pItemProp->szTextFileName);
m_pAngel->LoadMotion( textFile );
m_AngelPos = GetPos();
m_AngelWorldM = m_matWorld;
D3DXMATRIX mScal;
D3DXMatrixScaling( &mScal, 0.2f, 0.2f, 0.2f );
m_AngelWorldM = mScal * m_matRotation;
m_AngelPos.x += 1.0f;
m_AngelWorldM._41 = m_AngelPos.x;
m_AngelWorldM._42 = m_AngelPos.y + 1.0f;
m_AngelWorldM._43 = m_AngelPos.z;
m_pAngelFlag = TRUE;
}
}
}
else
{
m_pAngelFlag = FALSE;
if( m_pAngel )
{
SAFE_DELETE(m_pAngel);
m_pAngel = NULL;
}
}
if( m_pAngel )
{
m_pAngel->FrameMove();
AngelMoveProcess();
}
#endif //__CSC_VER8_5
#ifdef __EVE_BALLOON
#if __VER >= 14 // __BALLOON_CODE_IMPROVEMENT
if( IsPlayer() != FALSE && HasBuffByIk3( IK3_BALLOON ) != FALSE )
#else // __BALLOON_CODE_IMPROVEMENT
if( IsPlayer() && (HasBuff( BUFF_ITEM, II_SYS_SYS_EVE_BALLOON )
|| HasBuff( BUFF_ITEM, II_SYS_SYS_EVE_BALLOON01 )
|| HasBuff( BUFF_ITEM, II_SYS_SYS_EVE_BALLOON02 )
|| HasBuff( BUFF_ITEM, II_SYS_SYS_EVE_BALLOON_01 )
|| HasBuff( BUFF_ITEM, II_SYS_SYS_EVE_BALLOON01_01 )
|| HasBuff( BUFF_ITEM, II_SYS_SYS_EVE_BALLOON02_01 )
) )
#endif // __BALLOON_CODE_IMPROVEMENT
{
if( m_pBalloon == NULL )
{
m_pBalloon = new CModelObject;
m_pBalloon->InitDeviceObjects( g_Neuz.m_pd3dDevice );
#ifdef __BUFF_1107
#if __VER >= 14 // __BALLOON_CODE_IMPROVEMENT
IBuff* pBuff = m_buffs.GetBuffByIk3( IK3_BALLOON );
if( pBuff != NULL )
{
ItemProp *pItemProp = pBuff->GetProp();
#else // __BALLOON_CODE_IMPROVEMENT
IBuff* pBuff = NULL;
for( MAPBUFF::iterator i = m_buffs.m_mapBuffs.begin(); i != m_buffs.m_mapBuffs.end(); ++i )
{
IBuff* ptr = i->second;
if( ptr->GetId() == II_SYS_SYS_EVE_BALLOON
|| ptr->GetId() == II_SYS_SYS_EVE_BALLOON01
|| ptr->GetId() == II_SYS_SYS_EVE_BALLOON02
|| ptr->GetId() == II_SYS_SYS_EVE_BALLOON_01
|| ptr->GetId() == II_SYS_SYS_EVE_BALLOON01_01
|| ptr->GetId() == II_SYS_SYS_EVE_BALLOON02_01
)
pBuff = ptr;
}
if( pBuff )
{
ItemProp *pItemProp = pBuff->GetProp();
#endif // __BALLOON_CODE_IMPROVEMENT
#else // __BUFF_1107
LPSKILLINFLUENCE itemskill;
for( int i=0; i<MAX_SKILLINFLUENCE; i++)
{
LPSKILLINFLUENCE pSkill = m_SkillState.Get(i);
if( pSkill->wID == II_SYS_SYS_EVE_BALLOON
|| pSkill->wID == II_SYS_SYS_EVE_BALLOON01
|| pSkill->wID == II_SYS_SYS_EVE_BALLOON02
|| pSkill->wID == II_SYS_SYS_EVE_BALLOON_01
|| pSkill->wID == II_SYS_SYS_EVE_BALLOON01_01
|| pSkill->wID == II_SYS_SYS_EVE_BALLOON02_01
)
itemskill = pSkill;
}
if(itemskill)
{
ItemProp *pItemProp = prj.GetItemProp( itemskill->wID );
#endif // __BUFF_1107
if( pItemProp )
{
#if __VER >= 14 // __BALLOON_CODE_IMPROVEMENT
TCHAR szModelName[ MAX_PATH ];
prj.m_modelMng.MakeModelName( szModelName, OT_ITEM, pItemProp->dwID );
m_pBalloon->LoadElement( szModelName, 0 );
#else // __BALLOON_CODE_IMPROVEMENT
CString textFile;
textFile.Format("%s.o3d", pItemProp->szTextFileName);
m_pBalloon->LoadElement( textFile, 0 );
#endif // __BALLOON_CODE_IMPROVEMENT
m_BalloonPos = GetPos();
m_BalloonWorldM = m_matWorld;
D3DXMATRIX mScal;
D3DXMatrixScaling( &mScal, 1.5f, 1.5f, 1.5f );
m_BalloonWorldM = mScal;// * m_matRotation;
m_BalloonPos.x += 1.0f;
m_BalloonWorldM._41 = m_BalloonPos.x;
m_BalloonWorldM._42 = m_BalloonPos.y + 1.0f;
m_BalloonWorldM._43 = m_BalloonPos.z;
m_pBalloonFlag = TRUE;
}
}
}
}
else
{
m_pBalloonFlag = FALSE;
if( m_pBalloon )
{
SAFE_DELETE(m_pBalloon);
m_pBalloon = NULL;
m_fBalloonYPos = 1.0f;
}
}
if( m_pBalloon )
{
m_pBalloon->FrameMove();
BalloonMoveProcess();
}
#endif //__EVE_BALLOON
if( g_tmCurrent - m_dwWingTime > 1100 )
{
if(HasBuff( BUFF_ITEM, II_CHR_MAG_TRI_ANGELWING ) || HasBuff( BUFF_ITEM, II_SYS_SYS_EVE_WINGS ))
{
if(m_pSfxWing == NULL)
m_pSfxWing = CreateSfx( D3DDEVICE, XI_NAT_WINGANGEL01, GetPos(), GetId(), D3DXVECTOR3(0,0,0), NULL_ID, -1 );
}
else
{
if(m_pSfxWing != NULL)
{
m_pSfxWing->Delete();
m_pSfxWing = NULL;
}
}
m_dwWingTime = g_tmCurrent;
}
#endif // __CLIENT
// 1초 1회 사용자 처리
if( IsPlayer() )
{
#ifdef __MAP_SECURITY
#ifdef __CLIENT
if( IsActiveMover() && ( ( m_nCount & 31 ) == 0 ) )
g_WorldMng.CheckMapKey();
#endif // __CLIENT
#endif // __MAP_SECURITY
if( ( m_nCount & CF_SEC ) == 0 )
{
#if __VER >= 9 // __PET_0410
ProcessPet();
#endif // __PET_0410
#if __VER >= 11 // __SYS_COLLECTING
#ifdef __WORLDSERVER
ProcessCollecting();
( (CUser*)this )->m_Pocket.ProcessExpiring();
#else // ProcessCollecting
if( IsActiveMover() )
ProcessCollecting();
#endif // ProcessCollecting
#endif // __SYS_COLLECTING
#ifdef __JEFF_9_20
if( m_dwMute > 0 )
m_dwMute--;
#endif // __JEFF_9_20
}
}
if( ( m_nCount & CF_SEC ) == 0 )
{
PROFILE( sw, r1 );
ProcessBuff();
}
{
PROFILE( sw, r2 );
ProcessMove();
}
{
PROFILE( sw, r3 );
ProcessAI(); // 1회 이동하면 ProcessAI가 반드시 호출되어야 한다.
}
vPosTemp = vPos = GetPos();
{
PROFILE( sw, r4 );
m_pActMover->ProcessPreAction(); // 현재 행동 상태에 따라 적절한 모션을 처리함
ProcessAniSpeed(); // 공속 애니메이션 속도 조절.
}
{
PROFILE( sw, r5 );
#ifdef __X15
for( int i = 0; i < 4; ++i )
#endif
{
ProcessMovePattern();
m_pActMover->ProcessAction( &vPos );
#ifdef __CLIENT
ProcessWalkSound();
#endif //__CLIENT
if( IsAnimate() )
{
#if __VER >= 9 //__AI_0509
FLOAT fFactor = 1.0F;
if( !( IsPlayer() && IsFly() ) && ( m_pActMover->IsState( OBJSTA_FMOVE ) || m_pActMover->IsState( OBJSTA_TURN_ALL ) ) )
{
int nMaxFrame = pModel->GetMaxFrame();
FLOAT fSpeed = GetSpeed( m_pActMover->m_fSpeed );
// FLOAT fMaxWidth = pModel->GetMaxWidth();
// FLOAT fMaxHeight = pModel->GetMaxHeight();
MoverProp* pProp = GetProp();
if( IsNPC() )
{
switch( pProp->dwAI )
{
case AII_MONSTER:
case AII_PET:
case AII_EGG:
{
fFactor = fSpeed * nMaxFrame / 1.1F;
break;
}
}
}
else
fFactor = fSpeed * nMaxFrame / 2.2F;
if( fabs( pProp->fFrame - 0.0F ) < 0.000001F ) // 0이면 무시
fFactor = 1.0F;
else if( pProp->dwFlying == 1 )
fFactor = 1.0F;
else
fFactor *= pProp->fFrame;
if( fabs( fFactor - 0.0F ) < 0.000001F ) // fFactor가 0이면 기본 값
fFactor = 1.0F;
}
pModel->FrameMove( &vPos, m_fAniSpeed * fFactor ); // 애니메이션 프레임 증가
#else // __AI_0509
pModel->FrameMove( &vPos, m_fAniSpeed ); // 애니메이션 프레임 증가
#endif // __AI_0509
#ifdef __CLIENT
ProcessDustSFX();
#endif // CLIENT
}
} // for( 4 )
if( m_nAtkCnt > 0 ) // 공격행위를 하고난 이후는 카운트가 계속 증가 한다.
++m_nAtkCnt;
}
/*
#ifdef __CLIENT
if(this == g_pPlayer)
{
int n = 0;
}
#endif*/
{
PROFILE( sw, r6 );
bCollision = m_pActMover->ProcessCollision( &vPos ); // 이동성분 더하기 & 충돌처리.
}
#ifdef __CLIENT
ProcessWaterCircle( vPosTemp, vPos ); // 수면 효과 - 투명이 아닐때만 출력
#endif
{
PROFILE( sw, r7 );
ProcessIAObjLink( vPos );
}
{
PROFILE( sw, r8 );
#ifdef __CLIENT
if( GetWorld()->GetLandscape( vPos ) )
#endif
{
SetPos( vPos );
if( bCollision )
OnActCollision();
}
}
{
PROFILE( sw, r9 );
ProcessRegion();
ProcessQuest();
#ifdef __WORLDSERVER
ProcessDeleteRespawn();
#endif // __WORLDSERVER
}
#ifdef __WORLDSERVER
{
PROFILE( sw, r10 );
ProcessRegenItem();
ProcessScript();
}
#endif // __WORLDSERVER
{
PROFILE( sw, r11 );
#ifdef __WORLDSERVER
ProcessRecovery(); // 히트포인트, 마나포인트, 피로포인트 회복 하기 일단은 플레이어만 자동으로 찬다.
ProcessAbnormalState();
if( IsNPC() )
{
// if( m_nCollectOwnCnt > 0 )
// --m_nCollectOwnCnt;
if( (m_nCount & 127) == 0 ) // 약 8초만에 한번씩
{
ProcessTarget();
ProcInstantBanker();
ProcInstantGC();
}
}
#endif // __WORLDSERVER
if( IsPlayer() && IsLive() )
ProcessActionPoint();
}
#ifdef __WORLDSERVER
ProcessSFXDamage();
#endif // __WORLDSERVER
#if defined(__CLIENT)
ProcessETC();
ProcessEyeFlash();
#if __VER >= 15 // __PETVIS
if( NULL_ID != m_dwMoverSfxId && !m_pSfxBuffPet ) //gmpbigsun: buffpet effect
SetSfxBuffPet( m_dwMoverSfxId );
#endif
#endif //defined(__CLIENT)
++m_nCount; // 무버가 범용으로 쓰는 순차적 카운터. 생성자 외엔 0으로 초기화 하지 말것.
}
#ifdef __CLIENT
#if __VER >= 8 //__CSC_VER8_5
void CMover::AngelMoveProcess()
{
if( m_pAngelFlag && m_pAngel != NULL )
{
D3DXVECTOR3 vDist = GetPos() - m_AngelPos;
FLOAT fDistSq = D3DXVec3LengthSq( &vDist );
if(fDistSq > 100.0f * 100.0f) //Teleport등 거리가 멀어질 경우 다시 생성하도록 함.
{
if(m_pAngel)
SAFE_DELETE(m_pAngel);
m_pAngel = NULL;
m_pAngelFlag = FALSE;
return;
}
if( fDistSq > 1.0f * 1.0f )
{
D3DXVECTOR3 vf1 = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vf2 = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
D3DXVECTOR3 vf3;
FLOAT fSerp = fDistSq / 10.0f;
D3DXVec3Lerp( &vf3, &vf1, &vf2, fSerp );
FLOAT fSpeed = 0.0f;
m_AngelWorldM = m_matWorld;
D3DXMATRIX mScal;
D3DXMatrixScaling( &mScal, 0.2f, 0.2f, 0.2f );
m_AngelWorldM = mScal * m_matRotation;
D3DXVec3Normalize( &vDist, &vDist );
fSpeed = GetSpeed( m_pActMover->m_fSpeed ) * vf3.x;
vDist = vDist * fSpeed;
m_AngelPos.x += vDist.x;
m_AngelPos.y += vDist.y;
m_AngelPos.z += vDist.z;
m_AngelWorldM._41 = m_AngelPos.x;
m_AngelWorldM._42 = m_AngelPos.y + 1.0f;
m_AngelWorldM._43 = m_AngelPos.z;
}
CreateAngelParticle( m_AngelPos );
}
}
#endif //__CSC_VER8_5
#ifdef __EVE_BALLOON
void CMover::BalloonMoveProcess()
{
if( m_pBalloonFlag && m_pBalloon != NULL )
{
D3DXVECTOR3 vDist = GetPos() - m_BalloonPos;
FLOAT fDistSq = D3DXVec3LengthSq( &vDist );
D3DXMATRIX mScal, mRot;
if(fDistSq > 100.0f * 100.0f) //Teleport등 거리가 멀어질 경우 다시 생성하도록 함.
{
if(m_pBalloon)
SAFE_DELETE(m_pBalloon);
m_pBalloon = NULL;
m_pBalloonFlag = FALSE;
return;
}
if( fDistSq > 1.0f * 1.0f )
{
D3DXVECTOR3 vf1 = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vf2 = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
D3DXVECTOR3 vf3;
FLOAT fSerp = fDistSq / 10.0f;
D3DXVec3Lerp( &vf3, &vf1, &vf2, fSerp );
FLOAT fSpeed = 0.0f;
m_BalloonWorldM = m_matWorld;
D3DXMatrixScaling( &mScal, 1.5f, 1.5f, 1.5f );
m_BalloonWorldM = mScal;// * m_matRotation;
D3DXVec3Normalize( &vDist, &vDist );
fSpeed = GetSpeed( m_pActMover->m_fSpeed ) * vf3.x;
vDist = vDist * fSpeed;
m_BalloonPos.x += vDist.x;
m_BalloonPos.y += vDist.y;
m_BalloonPos.z += vDist.z;
m_BalloonWorldM._41 = m_BalloonPos.x;
m_BalloonWorldM._42 = m_BalloonPos.y + m_fBalloonYPos;
m_BalloonWorldM._43 = m_BalloonPos.z;
if( m_bBalloon == TRUE )
{
m_fBalloonYPos += 0.006f;
if( m_fBalloonYPos > 1.5 )
m_bBalloon = FALSE;
}
else
{
m_fBalloonYPos -= 0.006f;
if( m_fBalloonYPos < 0.5 )
m_bBalloon = TRUE;
}
}
else
{
m_BalloonWorldM = m_matWorld;
D3DXMATRIX mScal;
D3DXMatrixScaling( &mScal, 1.5f, 1.5f, 1.5f );
m_BalloonWorldM = mScal;// * m_matRotation;
m_BalloonWorldM._41 = m_BalloonPos.x;
m_BalloonWorldM._42 = m_BalloonPos.y + m_fBalloonYPos;
m_BalloonWorldM._43 = m_BalloonPos.z;
if( m_bBalloon == TRUE )
{
m_fBalloonYPos += 0.002f;
if( m_fBalloonYPos > 1.3 )
m_bBalloon = FALSE;
}
else
{
m_fBalloonYPos -= 0.002f;
if( m_fBalloonYPos < 0.7 )
m_bBalloon = TRUE;
}
}
D3DXMatrixRotationY(&mRot,timeGetTime()/3000.0f);
m_BalloonWorldM = mRot * m_BalloonWorldM;
}
}
#endif //__EVE_BALLOON
void CMover::InitInterpolation()
{
m_vScrPos = GetPos();
m_fScrAngle = GetAngle();
m_fScrAngleX = GetAngleX();
#if __VER >= 9 //__AI_0509
m_vOldRotate = D3DXVECTOR3( 0.0F, 0.0F, 0.0F );
#endif // __AI_0509
D3DXMatrixTranslation( &m_matTrans, m_vScrPos.x, m_vScrPos.y, m_vScrPos.z );
D3DXMATRIX matRotX;
D3DXMatrixRotationX( &matRotX, D3DXToRadian( m_fScrAngleX ) );
m_matRotation *= matRotX;
D3DXMatrixRotationYawPitchRoll( &m_matRotation, D3DXToRadian( -m_fScrAngle ), D3DXToRadian( -m_fScrAngleX ), 0 );
SetUpdateMatrix( TRUE );
}
void CMover::Interpolate()
{
D3DXVECTOR3 vPos;
float fAngle, fAngleX;
vPos = GetPos();
fAngle = GetAngle();
fAngleX = GetAngleX();
if( TRUE == IsActiveObj() )
{
// pos
if( fabs( vPos.x - m_vScrPos.x ) > 0.001 || fabs( vPos.y - m_vScrPos.y ) > 0.001 || fabs( vPos.z - m_vScrPos.z ) > 0.001 ) // dif
{
m_vScrPos = vPos;
D3DXMatrixTranslation( &m_matTrans, m_vScrPos.x, m_vScrPos.y, m_vScrPos.z );
SetUpdateMatrix( TRUE );
}
// angle
if( fabs( fAngle - m_fScrAngle ) > 0.001 || fabs( fAngleX - m_fScrAngleX ) > 0.001 )
{
m_fScrAngle = fAngle;
D3DXMatrixRotationY( &m_matRotation, D3DXToRadian( -m_fScrAngle ) );
m_fScrAngleX = fAngleX;
D3DXMATRIX matRotX;
D3DXMatrixRotationX( &matRotX, D3DXToRadian( m_fScrAngleX ) );
m_matRotation *= matRotX;
D3DXMatrixRotationYawPitchRoll( &m_matRotation, D3DXToRadian( -m_fScrAngle ), D3DXToRadian( -m_fScrAngleX ), 0 );
SetUpdateMatrix( TRUE );
}
}
else
{
float d;
// pos
if( fabs( vPos.x - m_vScrPos.x ) > 0.001 || fabs( vPos.y - m_vScrPos.y ) > 0.001 || fabs( vPos.z - m_vScrPos.z ) > 0.001 ) // dif
{
D3DXVECTOR3 v = vPos - m_vScrPos;
d = D3DXVec3LengthSq( &v );
if( d > 0.001 )
m_vScrPos += v / 8;
else
m_vScrPos = vPos;
D3DXMatrixTranslation( &m_matTrans, m_vScrPos.x, m_vScrPos.y, m_vScrPos.z );
SetUpdateMatrix( TRUE );
}
// angle
if( fabs( fAngle - m_fScrAngle ) > 0.001 || fabs( fAngleX - m_fScrAngleX ) > 0.001 )
{
d = fAngle - m_fScrAngle;
if( fabs( d ) < 4 )
m_fScrAngle = fAngle;
if( d < -180 )
d += 360;
else if( d > 180 )
d -= 360;
m_fScrAngle += d / 8;
if( m_fScrAngle > 360 )
m_fScrAngle -= 360;
else if( m_fScrAngle < 0 )
m_fScrAngle += 360;
D3DXMatrixRotationY( &m_matRotation, D3DXToRadian( -m_fScrAngle ) );
m_fScrAngleX = fAngleX;
if( m_fScrAngleX > 45 )
m_fScrAngleX = 45;
else if( m_fScrAngleX < -45 )
m_fScrAngleX = -45;
D3DXMATRIX matRotX;
D3DXMatrixRotationX( &matRotX, D3DXToRadian( m_fScrAngleX ) );
m_matRotation *= matRotX;
D3DXMatrixRotationYawPitchRoll( &m_matRotation, D3DXToRadian( -m_fScrAngle ), D3DXToRadian( -m_fScrAngleX ), 0 );
#if __VER >= 9 //__AI_0509
if( 0 ) //if( GetProp()->dwOrthograde == 0 && fabs( m_pWorld->GetLandHeight( m_vScrPos ) - m_vScrPos.y ) < 0.1F )
{
D3DXVECTOR3 vScrPos = m_vScrPos;
D3DXVECTOR3 vec3Tri[3];
GetWorld()->GetLandTri( vScrPos.x, vScrPos.z, vec3Tri );
D3DXVECTOR3 vVector1 = vec3Tri[2] - vec3Tri[0];
D3DXVECTOR3 vVector2 = vec3Tri[1] - vec3Tri[0];
D3DXVECTOR3 vNormal;
D3DXVec3Cross( &vNormal, &vVector1, &vVector2);
D3DXVec3Normalize( &vNormal, &vNormal );
D3DXVECTOR3 v3Up = D3DXVECTOR3( 0.0f, -1.0f, 0.0f );
D3DXVECTOR3 v3Cross;
FLOAT fDot;
FLOAT fTheta;
D3DXVec3Cross( &v3Cross, &v3Up, &vNormal );
fDot = D3DXVec3Dot( &v3Up, &vNormal );
fTheta = acos( fDot );
D3DXQUATERNION qDirMap;
D3DXQuaternionRotationAxis( &qDirMap, &v3Cross, fTheta );
D3DXVECTOR3 vYPW;
QuaternionRotationToYPW( qDirMap, vYPW );
D3DXVECTOR3 vRotate;
vRotate.x = D3DXToDegree(vYPW.x);
vRotate.y = D3DXToDegree(vYPW.y);
vRotate.z = D3DXToDegree(vYPW.z);
d = vRotate.x - m_vOldRotate.x;
if( d < -180 )
d += 360;
else if( d > 180 )
d -= 360;
// if( d > 0.5F )
vRotate.x = m_vOldRotate.x + d / 4.0F;
if( vRotate.x > 360 )
vRotate.x -= 360;
else if( vRotate.x < 0 )
vRotate.x += 360;
d = vRotate.z - m_vOldRotate.z;
if( d < -180 )
d += 360;
else if( d > 180 )
d -= 360;
// if( d > 0.5F )
vRotate.z = m_vOldRotate.z + d / 4.0F;
if( vRotate.z > 360 )
vRotate.z -= 360;
else if( vRotate.z < 0 )
vRotate.z += 360;
d = vRotate.y - m_vOldRotate.y;
if( d < -180 )
d += 360;
else if( d > 180 )
d -= 360;
// if( d > 0.5F )
vRotate.y = m_vOldRotate.y + d / 4.0F;
if( vRotate.y > 360 )
vRotate.y -= 360;
else if( vRotate.y < 0 )
vRotate.y += 360;
m_vOldRotate = vRotate;
D3DXMATRIX matRotLand;
D3DXMatrixRotationYawPitchRoll( &matRotLand, D3DXToRadian( vRotate.y ), D3DXToRadian( vRotate.x ), D3DXToRadian( vRotate.z ) );
m_matRotation *= matRotLand;
}
#endif // __AI_0509
SetUpdateMatrix( TRUE );
}
}
}
void CMover::CreateAbilityOption_SetItemSFX( int nAbilityOption )
{
DWORD dwSfx = 0;
// nAbilityOption = 4;
switch( nAbilityOption )
{
case 3: dwSfx = XI_GEN_ITEM_SETITEM03; break;
case 4: dwSfx = XI_GEN_ITEM_SETITEM04; break;
case 5: dwSfx = XI_GEN_ITEM_SETITEM05; break;
case 6: dwSfx = XI_GEN_ITEM_SETITEM06; break;
case 7: dwSfx = XI_GEN_ITEM_SETITEM07; break;
case 8: dwSfx = XI_GEN_ITEM_SETITEM08; break;
case 9: dwSfx = XI_GEN_ITEM_SETITEM09; break;
case 10: dwSfx = XI_GEN_ITEM_SETITEM10; break;
}
CSfxPartsLinkShoulder* pSfx = NULL;
D3DXVECTOR3 v3Scal = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
if( nAbilityOption == 3 )
{
// 어깨
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 0;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 1;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
}
/*
else
if( nAbilityOption == 4 )
{
// 몸통
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 6;
pSfx->SetScale(D3DXVECTOR3( 2.2f, 2.2f, 2.2f ));
}
*/
else
if( nAbilityOption == 4 )
{
// 몸통
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 6;
pSfx->SetScale(D3DXVECTOR3( 3.0f, 3.0f, 3.0f ));
pSfx->m_nOldAbilityOption = nAbilityOption;
}
else
if( nAbilityOption == 5 )
{
// 어깨
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 0;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 1;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 어깨, 팔목 중간
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 4;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 5;
pSfx->m_nOldAbilityOption = nAbilityOption;
}
else
if( nAbilityOption == 6 )
{
// 어깨
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 0;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 1;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 어깨, 팔목 중간
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 4;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 5;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 팔목
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 2;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 3;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
}
else
if( nAbilityOption == 7 )
{
// 어깨
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 0;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 1;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 어깨, 팔목 중간
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 4;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 5;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 팔목
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 2;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 3;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 손
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 8;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 9;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
}
else
if( nAbilityOption == 8 )
{
// 어깨
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 0;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 1;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 어깨, 팔목 중간
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 4;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 5;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 팔목
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 2;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 3;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 손
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 8;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 9;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, XI_SETIEM_EFFECTHAND, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 9;
pSfx->m_v3Offset.y = 0.2f;
pSfx->m_nOldAbilityOption = nAbilityOption;
}
else
if( nAbilityOption == 9 )
{
// 어깨
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 0;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 1;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 어깨, 팔목 중간
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 4;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 5;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 팔목
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 2;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 3;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 손
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 8;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 9;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 발
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 26;
pSfx->SetScale(D3DXVECTOR3( 1.5f, 1.5f, 1.5f ));
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 29;
pSfx->SetScale(D3DXVECTOR3( 1.5f, 1.5f, 1.5f ));
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, XI_SETIEM_EFFECTHAND, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 9;
pSfx->m_v3Offset.y = 0.2f;
pSfx->m_nOldAbilityOption = nAbilityOption;
}
else
if( nAbilityOption == 10 )
{
// 어깨
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 0;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 1;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 어깨, 팔목 중간
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 4;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 5;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 몸통
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 6;
pSfx->SetScale(D3DXVECTOR3( 3.0f, 4.5f, 3.0f ));
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 7;
pSfx->SetScale(D3DXVECTOR3( 3.0f, 3.0f, 3.0f ));
pSfx->m_nOldAbilityOption = nAbilityOption;
// 손
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 8;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 9;
pSfx->m_v3Offset.y = 0.1f;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 팔목
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 2;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 3;
pSfx->m_nOldAbilityOption = nAbilityOption;
// 발
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 26;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, dwSfx, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 29;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, XI_SETIEM_EFFECTHAND, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 8;
pSfx->m_v3Offset.y = 0.2f;
pSfx->m_nOldAbilityOption = nAbilityOption;
pSfx = (CSfxPartsLinkShoulder*)CreateSfx( D3DDEVICE, XI_SETIEM_EFFECTHAND, GetPos(), GetId(), GetPos(), GetId(), -1 );
pSfx->m_nPartsLink = 9;
pSfx->m_v3Offset.y = 0.2f;
pSfx->m_nOldAbilityOption = nAbilityOption;
}
}
#endif //__CLIENT
//int nItemKind, int nItemKind2, int nNumMax, int nUniqueMin, int nUniqueMax, int nTotalNum, CAnim* pAnimParent, int nMaterialCount )
void CMover::GenerateVendorItem( ItemProp** apItemProp, int* pcbSize, int nMax, LPVENDOR_ITEM pVendor )
{
CPtrArray* pItemKindAry = prj.GetItemKindAry( pVendor->m_nItemkind3 );
ItemProp* pItemProp = NULL;
int cbSizeOld = *pcbSize;
ASSERT( pVendor->m_nUniqueMin >= 0 );
ASSERT( pVendor->m_nUniqueMax >= 0 );
if( *pcbSize >= nMax )
return;
int nMinIdx = -1, nMaxIdx = -1;
for( int j = pVendor->m_nUniqueMin; j <= pVendor->m_nUniqueMax; j++ )
{
nMinIdx = prj.GetMinIdx( pVendor->m_nItemkind3, j );
if( nMinIdx != -1 )
break;
}
for( j = pVendor->m_nUniqueMax; j >= pVendor->m_nUniqueMin; j-- )
{
nMaxIdx = prj.GetMaxIdx( pVendor->m_nItemkind3, j );
if( nMaxIdx != -1 )
break;
}
if( nMinIdx < 0 )
{
WriteError( "VENDORITEM//%s//%d-%d//%d", GetName(), pVendor->m_nUniqueMin, pVendor->m_nUniqueMax, pVendor->m_nItemkind3 );
return;
}
for( int k = nMinIdx; k <= nMaxIdx; k++ )
{
pItemProp = (ItemProp*)pItemKindAry->GetAt( k );
if( ( NULL == pItemProp ) ||
( pItemProp->dwShopAble == (DWORD)-1 ) ||
( pVendor->m_nItemJob != -1 && (DWORD)pItemProp->dwItemJob != pVendor->m_nItemJob ) )
continue;
if( *pcbSize >= nMax )
break;
apItemProp[*pcbSize] = pItemProp;
(*pcbSize)++;
}
}
void CMover::EnforcedGhostCorr()
{
if( m_CorrAction.fValid == TRUE && ( m_uRemnantCorrFrm - 1 ) == 0 ) {
if( m_CorrAction.dwStateFlag & OBJSTAF_FLY ) {
ActionForceSet2( m_CorrAction.v, m_CorrAction.vd, m_CorrAction.f, m_CorrAction.fAngleX,
m_CorrAction.fAccPower, m_CorrAction.fTurnAngle,
m_CorrAction.dwState, m_CorrAction.dwStateFlag,
m_CorrAction.dwMotion, m_CorrAction.nMotionEx,
m_CorrAction.nLoop, m_CorrAction.dwMotionOption );
}
else {
ActionForceSet( m_CorrAction.v, m_CorrAction.vd, m_CorrAction.f, m_CorrAction.dwState,
m_CorrAction.dwStateFlag, m_CorrAction.dwMotion, m_CorrAction.nMotionEx,
m_CorrAction.nLoop, m_CorrAction.dwMotionOption );
}
memset( &m_CorrAction, 0, sizeof(CORR_ACTION) );
}
}
void CMover::ApproachGhostAngle()
{
if( m_fDestAngle > -0.001f )
{
float f = m_pActMover->IsFly() ? 0.601f : 4.001f;
if( fabs( GetAngle() - m_fDestAngle ) < f )
{
if( m_CorrAction.fValid == FALSE )
{
SetAngle( m_fDestAngle );
ClearDestAngle();
SendActMsg( OBJMSG_STOP_TURN );
}
else
{
ClearDestAngle();
if( (m_CorrAction.dwStateFlag & OBJSTAF_FLY) == 0 )
{
ActionForceSet( m_CorrAction.v, m_CorrAction.vd, m_CorrAction.f, m_CorrAction.dwState,
m_CorrAction.dwStateFlag, m_CorrAction.dwMotion, m_CorrAction.nMotionEx,
m_CorrAction.nLoop, m_CorrAction.dwMotionOption );
}
memset( &m_CorrAction, 0, sizeof(CORR_ACTION) );
}
}
else
{
f = m_pActMover->IsFly() ? 0.6f * 100.0f : 0.0f;
if( m_bLeft )
SendActMsg( OBJMSG_LTURN, (int)f );
else
SendActMsg( OBJMSG_RTURN, (int)f );
}
}
}
// 목표 위치에 도착했을 경우 호출됨
void CMover::OnArrive( DWORD dwParam1, DWORD dwParam2 )
{
#ifdef __WORLDSERVER
if( IsPlayer() )
((CUser* )this)->OnMsgArrival( dwParam1 ); // dwParam1 - pickup대상
else
PostAIMsg( AIMSG_ARRIVAL, dwParam1, dwParam2 );
#endif // __WORLDSERVER
}
void CMover::OnArriveAtPos()
{
if( m_CorrAction.fValid == FALSE )
{
SendActMsg( m_dwMotionArrive );
OnArrive( NULL_ID, 1 );
}
else {
if( m_CorrAction.fHalf )
{
HalfForceSet( m_CorrAction.v, m_CorrAction.vd,
m_CorrAction.f, m_CorrAction.fAngleX,
m_CorrAction.fAccPower, m_CorrAction.fTurnAngle );
}
else
{
if( m_CorrAction.dwStateFlag & OBJSTAF_FLY ) {
ActionForceSet2( m_CorrAction.v, m_CorrAction.vd, m_CorrAction.f, m_CorrAction.fAngleX,
m_CorrAction.fAccPower, m_CorrAction.fTurnAngle,
m_CorrAction.dwState, m_CorrAction.dwStateFlag,
m_CorrAction.dwMotion, m_CorrAction.nMotionEx,
m_CorrAction.nLoop, m_CorrAction.dwMotionOption );
}
else {
ActionForceSet( m_CorrAction.v, m_CorrAction.vd, m_CorrAction.f, m_CorrAction.dwState,
m_CorrAction.dwStateFlag, m_CorrAction.dwMotion, m_CorrAction.nMotionEx,
m_CorrAction.nLoop, m_CorrAction.dwMotionOption );
}
}
memset( &m_CorrAction, 0, sizeof(CORR_ACTION) );
}
ClearDestPos();
}
BOOL CMover::AddItem( CItemBase* pItemBase )
{
return m_Inventory.Add( (CItemElem*)pItemBase );
}
BOOL CMover::AddItemBank( int nSlot, CItemElem* pItemElem )
{
return m_Bank[nSlot].Add( pItemElem );
}
CItemBase* CMover::GetItemId( DWORD dwId )
{
return m_Inventory.GetAtId( dwId );
}
CItemBase* CMover::GetItemBankId( int nSlot, DWORD dwId )
{
CItemBase* pItemBase = NULL;
pItemBase = m_Bank[nSlot].GetAtId( dwId );
return pItemBase;
}
void CMover::RemoveItemId( DWORD dwId )
{
if( m_Inventory.IsEquip( dwId ) )
DoEquip( (CItemElem*)m_Inventory.GetAtId( dwId ), FALSE ); // 실패할 경우, 장착 해제 효과가 나타나지 않으므로 고려가 필요함.
m_Inventory.RemoveAtId( dwId );
}
void CMover::SetKeeptimeInven( DWORD dwItemId, DWORD dwTime )
{
int nSize = m_Inventory.GetMax();
for( int i = 0 ; i < nSize; i++ )
{
CItemElem* pItemElem = m_Inventory.GetAtId( i );
if( pItemElem->GetProp()->dwID == dwItemId )
{
SetKeeptimeItem( pItemElem, dwTime );
}
}
}
void CMover::SetKeeptimeBank( DWORD dwItemId, DWORD dwTime )
{
int nSize = m_Bank[m_nSlot].GetMax();
for( int i = 0 ; i < nSize; i++ )
{
CItemElem* pItemElem = m_Bank[m_nSlot].GetAtId( i );
if( pItemElem->GetProp()->dwID == dwItemId )
{
SetKeeptimeItem( pItemElem, dwTime );
}
}
}
void CMover::SetKeeptimeItem( CItemElem* pItemElem, DWORD dwTime )
{
pItemElem->m_dwKeepTime = dwTime;
}
void CMover::RemoveItemBankId( int nSlot, DWORD dwId )
{
m_Bank[nSlot].RemoveAtId( dwId );
}
#ifdef __CLIENT
void CMover::DialogOut( LPCTSTR lpszText )
{
g_DialogMsg.AddMessage( this, lpszText, 0xffffffff );
}
#endif
// bSWDForce대신에 Option을 써서 비트로 사용하자.
// 0x01 : 검광
// 0x02 : 고정모션(+100안하는..)
// 0x04 : Motion Transition 사용하지 않음.
BOOL CMover::SetMotion( DWORD dwMotion, int nLoop, DWORD dwOption )
{
CModelObject* pModel = (CModelObject*)m_pModel;
DWORD dwOrigMotion = dwMotion;
ItemProp* pItemProp = GetActiveHandItemProp();
if( m_pActMover->IsStateFlag( OBJSTAF_COMBAT ) && (dwOption & MOP_FIXED) == 0 )
{
#if defined(__CLIENT)
if( pItemProp == NULL )
{
if( IsPlayer() )
{
LPCTSTR szErr = Error( "CMover::SetMotion : Player %s %d %d", GetName(), IsActiveMover(), m_aEquipInfo[PARTS_RWEAPON].dwId );
ADDERRORMSG( szErr );
}
else
{
LPCTSTR szErr = Error( "CMover::SetMotion : NPC %s %d", GetName(), m_dwVirtItem );
ADDERRORMSG( szErr );
}
return FALSE;
}
#endif // __CLIENT
// 몹일 경우 dwItemKind3는 virtual 아이템이다.
// 플레이어는 무기 종류에 따라서 모션을 결정하지만, 몹은 virtual 아이템에서 모션을 결정한다.
int nIndex = GetIndex();
if( !IsPlayer() || ( IsPlayer() &&
( nIndex == MI_MALE ||
nIndex == MI_FEMALE ||
nIndex == MI_CROWNIBLIS ||
nIndex == MI_CROWNSHADE ||
nIndex == MI_CROWNBUBBLE ||
nIndex == MI_DWARPETMAS ) ) )
{
BOOL bMasterPlayer = FALSE;
if( nIndex == MI_CROWNIBLIS || nIndex == MI_CROWNSHADE || nIndex == MI_CROWNBUBBLE || nIndex == MI_DWARPETMAS )
bMasterPlayer = TRUE;
if( IsDualWeapon() && !bMasterPlayer )
{
dwMotion += 900; // 이도류는 무슨 무기를 들었든 간에 이도류 동작이 된다.
}
else
{
BOOL bHanded = ( pItemProp->dwHanded == HD_TWO ) ? TRUE : FALSE; // 투핸드냐 원핸드냐?
switch( pItemProp->dwItemKind3 )
{
case IK3_YOYO:
if( !bMasterPlayer ) dwMotion += MTI_STAND_14;
else dwMotion += 200;
break;
case IK3_BOW:
if( !bMasterPlayer ) dwMotion += MTI_STAND_13;
else dwMotion += 200;
break;
case IK3_SWD:
if( bHanded ) dwMotion += 800;
else dwMotion += 200;
break;
case IK3_AXE:
if( bHanded ) dwMotion += 800;
else dwMotion += 500;
break;
case IK3_WAND:
#if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans
if( GetJob() == JOB_PSYCHIKEEPER || GetJob() == JOB_PSYCHIKEEPER_MASTER || GetJob() == JOB_PSYCHIKEEPER_HERO ) dwMotion += MTI_STAND_11;
#else //__LEGEND // 9차 전승시스템 Neuz, World, Trans
if( GetJob() == JOB_PSYCHIKEEPER ) dwMotion += MTI_STAND_11;
#endif //__LEGEND // 9차 전승시스템 Neuz, World, Trans
else dwMotion += MTI_STAND_02;
break;
case IK3_CHEERSTICK: dwMotion += 400; break;
case IK3_STAFF:
dwMotion += MTI_STAND_05;
break;
case IK3_KNUCKLEHAMMER: dwMotion += 700; break;
default:
if( IsPlayer() ) dwMotion += 200;
break;
}
}
}
}
if( m_dwMotion == dwOrigMotion && m_dwMotionOption == dwOption ) // 같은 모션을 하라고 했는데...
{
if( nLoop == ANILOOP_LOOP ) return FALSE; // 루핑모드 이면 걍 리턴
if( pModel->m_bEndFrame == FALSE ) // 아직 애니메이션중일때는
return FALSE; // 취소.
if( pModel->m_bEndFrame && nLoop == ANILOOP_CONT ) // 애니메이션이 끝난상태고 지속모드면 마지막 프레임으로 지속
return FALSE;
}
#ifdef _DEBUG
if( dwOrigMotion == MTI_WALK )
{
int a = 0;
}
#endif
prj.m_modelMng.LoadMotion( m_pModel, m_dwType, m_dwIndex, dwMotion );
m_dwMotion = dwOrigMotion; // +100 하지 않은 값을 저장하자.
m_dwMotionOption = dwOption;
pModel->m_bEndFrame = FALSE;
pModel->SetLoop( nLoop );
// 눈 사람 애니메이션 안하는 Mover에서 생기는 문제 때문에 예외처리.
if(m_pModel && m_pModel->m_pModelElem && (m_pModel->m_pModelElem->m_dwIndex == MI_NPC_SNOWMAN01 || m_pModel->m_pModelElem->m_dwIndex == MI_NPC_SNOWMAN02))
dwOption |= MOP_NO_TRANS;
if( dwOption & MOP_NO_TRANS ) pModel->SetMotionBlending( FALSE );
else pModel->SetMotionBlending( TRUE );
if( dwOption & MOP_SWDFORCE )
{
if( IsPlayer() )
{
int nOption = 0;
DWORD dwColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
if( IsActiveMover() )
{
CItemElem *pItemElem = GetWeaponItem();
if( pItemElem )
nOption = pItemElem->GetAbilityOption();
}
else
{
// 타 플레이어는 페이크아이템이므로 여기서에서 값을 빼온다.
nOption = m_aEquipInfo[PARTS_RWEAPON].nOption & 0xFF;
}
if( nOption == 10 )
dwColor = D3DCOLOR_ARGB( 255, 255, 0, 0 );
else if( nOption == 9 )
dwColor = D3DCOLOR_ARGB( 255, 255, 150, 0 );
else if( nOption >= 7 )
dwColor = D3DCOLOR_ARGB( 255, 198, 0, 255 );
else if( nOption >= 5 )
dwColor = D3DCOLOR_ARGB( 255, 123, 82, 255 );
else if( nOption >= 3)
dwColor = D3DCOLOR_ARGB( 255, 129, 221, 251 );
else if( nOption >= 1 )
dwColor = D3DCOLOR_ARGB( 255, 201, 251, 190 );
else
dwColor = D3DCOLOR_ARGB( 255, 255, 255, 255 );
pModel->MakeSWDForce( PARTS_RWEAPON, pItemProp->dwItemKind3, (dwOption & MOP_HITSLOW) ? TRUE : FALSE, dwColor, m_fAniSpeed );
pModel->MakeSWDForce( PARTS_LWEAPON, pItemProp->dwItemKind3, (dwOption & MOP_HITSLOW) ? TRUE : FALSE, dwColor, m_fAniSpeed );
}
}
else
{
if( pModel->m_pForce )
pModel->m_pForce->Clear();
if( pModel->m_pForce2 )
pModel->m_pForce2->Clear();
}
return TRUE;
}
BOOL CMover::InitMotion(DWORD dwMotion)
{
prj.m_modelMng.LoadMotion( m_pModel, m_dwType, m_dwIndex, dwMotion );
m_dwMotion = dwMotion;
return TRUE;
}
//적의 숫자를 구한다.
int CMover::GetEnemyCount()
{
int nCount = 0;
nCount = m_idEnemies.size();
return nCount;
}
OBJID CMover::GetMaxEnemyHitID()
{
OBJID objId = NULL_ID;
int nHitPoint = 0;
for( SET_OBJID::iterator i = m_idEnemies.begin(); i != m_idEnemies.end(); ++i )
{
HIT_INFO info = (*i).second;
if( nHitPoint < info.nHit )
{
objId = (*i).first;
nHitPoint = info.nHit;
}
}
return objId;
}
int CMover::GetEnemyHit( OBJID objid, DWORD* pdwTick )
{
int nHit = 0;
DWORD dwTick = 0;
SET_OBJID::iterator i = m_idEnemies.find( objid );
if( i != m_idEnemies.end() )
{
HIT_INFO info = (*i).second;
nHit = info.nHit;
dwTick = info.dwTick;
}
if( pdwTick )
*pdwTick = dwTick;
return nHit;
}
// 마지막으로 때린 시각을 리턴한다.
DWORD CMover::AddEnemy( OBJID objid, int nHit )
{
DWORD dwLast = 0;
SET_OBJID::iterator i = m_idEnemies.find( objid );
if( i == m_idEnemies.end() )
{
HIT_INFO info;
info.nHit = nHit;
info.dwTick = GetTickCount();
m_idEnemies.insert( make_pair(objid, info) );
}
else
{
HIT_INFO& info = (*i).second;
dwLast = info.dwTick;
info.dwTick = GetTickCount();
info.nHit += nHit;
}
return dwLast;
}
void CMover::RemoveEnemy( OBJID objid )
{
SET_OBJID::iterator i = m_idEnemies.find( objid );
if( i != m_idEnemies.end() )
{
if( m_pActMover->GetObjHit() == objid )
m_pActMover->SetObjHit( NULL_ID );
#ifdef __WORLDSERVER
PostAIMsg( AIMSG_DSTDIE, objid );
#endif
if( GetDestId() == objid )
{
ClearDestObj();
SendActMsg( OBJMSG_STAND );
}
#ifdef __WORLDSERVER
#if __VER < 8 // __S8_PK
// PK세션을 종료시키기 위해서 플레이어간의 적대관계 종료를 보낸다.
if( IsPlayer() )
{
CUser* pEnemy = prj.GetUser( objid );
if( IsValidObj( pEnemy ) && (GetTickCount() - i->second.dwTick) <= MIN(1) )
{
((CUser*)this)->UpdatePlayerEnemy( DEL_PLAYER_ENEMY, objid );
pEnemy->UpdatePlayerEnemy( DEL_PLAYER_ENEMY, GetId() );
}
}
#endif // __VER < 8 // __S8_PK
#endif // __WORLDSERVER
m_idEnemies.erase( i );
}
}
void CMover::RemoveAllEnemies()
{
vector<OBJID> adwEnemy;
for( SET_OBJID::iterator it = m_idEnemies.begin(); it != m_idEnemies.end(); ++it )
adwEnemy.push_back( it->first );
m_idEnemies.clear();
CMover* pEnemy;
while( adwEnemy.size() > 0 )
{
OBJID objid = adwEnemy.back();
pEnemy = prj.GetMover( objid );
if( IsValidObj( (CObj*)pEnemy ) )
pEnemy->RemoveEnemy( GetId() );
adwEnemy.pop_back();
}
adwEnemy.clear();
/*
int nSizeofEnemies = 0;
OBJID idEnemies[1024];
for( SET_OBJID::iterator i = m_idEnemies.begin(); i != m_idEnemies.end(); ++i )
{
idEnemies[nSizeofEnemies++] = (*i).first;
if( nSizeofEnemies >= 1024 )
break;
}
m_idEnemies.clear();
CMover* pEnemy;
for( int j = 0; j < nSizeofEnemies; j++ )
{
pEnemy = prj.GetMover( idEnemies[j] );
if( IsValidObj( (CObj*)pEnemy ) )
pEnemy->RemoveEnemy( GetId() );
}
*/
}
//
// this를 죽게 만드는 명령. - 외부에서 직접 호출해서 죽이기만 할때도 쓸수있다.
// Attacker는 NULL일 수도 있다. 어느지역가면 걍 뒤지는 경우.
int CMover::DoDie( CCtrl *pAttackCtrl, DWORD dwMsg )
{
#ifdef __WORLDSERVER
if( IsPlayer() && m_nDead )
{
Error( "CMover::DoDie : %s 죽은 후 5초이내 또죽었다. 두번죽은듯?", GetName() );
return 0;
}
// 클라이언트는 이쪽으로 오지 않음.
BOOL bBehavior = FALSE;
CMover *pAttacker = NULL;
if( pAttackCtrl && pAttackCtrl->GetType() == OT_MOVER ) // 어태커가 무버라면 무버 포인터 만들어 둔다.
pAttacker = (CMover *)pAttackCtrl;
m_bLastPK = FALSE;
if( pAttacker && pAttacker != this && pAttacker->IsPlayer() ) // 자살한게 아니고, 플레이어에게 죽었냐 아니냐.
{
PVP_MODE mode = GetPVPCase( pAttacker );
if( mode == PVP_MODE_PK ) // PK경우
{
#ifdef __JEFF_11_4
#endif // __JEFF_11_4
if( g_eLocal.GetState( EVE_PKCOST )
#ifdef __JEFF_11_4
&& GetWorld()->IsArena() == FALSE
#endif // __JEFF_11_4
)
m_bLastPK = FALSE; // 경험치 다운
else
m_bLastPK = TRUE; // 경험치 다운 없음
}
else
m_bLastPK = TRUE; // 경험치 다운 없음
m_bGuildCombat = FALSE;
if( GetWorld()->GetID() == WI_WORLD_GUILDWAR && g_GuildCombatMng.m_nState != CGuildCombat::CLOSE_STATE )
m_bGuildCombat = TRUE;
#if __VER >= 11 // __GUILD_COMBAT_1TO1
if( g_GuildCombat1to1Mng.IsPossibleUser( (CUser*)this ) )
m_bGuildCombat = TRUE;
#endif // __GUILD_COMBAT_1TO1
#if __VER >= 13 // __HONORABLE_TITLE // 달인
if(IsNPC())
{
((CUser*)pAttacker)->SetHonorAdd(GetIndex(),HI_HUNT_MONSTER);
}
#endif // __HONORABLE_TITLE // 달인
}
m_nAtkCnt = 0; // 죽고 난 후에는 어택카운트를 클리어 해서 빗자루를 탈 수 있게하자.
if( IsPlayer() )
{
if( IsStateMode( STATE_BASEMOTION_MODE ) )
{
SetStateNotMode( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_OFF );
m_nReadyTime = 0;
m_dwUseItemId = 0;
}
SetStun( FALSE ); // 플레이어만 부활후에 스턴 안걸려 있도록 풀어줌.
SetPoison( FALSE );
SetDark( FALSE );
SetBleeding( FALSE );
}
BOOL fValid = IsValidObj( this );
if( IsPlayer() && m_pActMover->IsFly() ) // 날고있는 중에 죽었으면
UnequipRide();
SendActMsg( OBJMSG_STOP );
SendActMsg( OBJMSG_DIE, dwMsg, (int)pAttacker );
// 플레이어인 내가 죽었으면 내가 타겟으로 잡고있던넘을 풀어줌. 로그아웃 같은거 할때도 마찬가지 처리를 해야함.
if( IsPlayer() )
{
CMover *pLastHit = prj.GetMover( m_idLastHitMover );
if( IsValidObj( pLastHit ) )
{
if( pLastHit->m_idAttacker == GetId() ) // pLastHit의 공격자가 나로 설정되어 있을때만 풀어줌,.
pLastHit->m_idAttacker = NULL_ID;
if( pLastHit->m_idTargeter == GetId() )
pLastHit->m_idTargeter = NULL_ID;
}
// 유저가 죽었을때만 로그 남김
if( fValid )
{
g_dpDBClient.SendLogPlayDeath( this, pAttacker );
#if __VER >= 9 // __PET_0410
// 캐릭터간의 전투로 인한 모든 캐릭터의 사망 시 펫은 사망하지 않는다. // 0723
if( IsValidObj( pAttacker ) == FALSE || pAttacker->IsNPC() )
// if( m_bLastPK == FALSE && m_bGuildCombat == FALSE )
{
// 캐릭터 사망 시 소환중인 펫도 사망
CPet* pPet = GetPet();
if( pPet && pPet->GetLevel() != PL_EGG ) // 펫 '알'은 사망하지 않도록 설정 // 0723
{
CItemElem* pItemElem = GetPetItem();
int nLife = (int)pPet->GetLife();
if( --nLife >= 0 )
{
// 생명이 0 이상이면, 부활
pPet->SetLife( nLife );
pPet->SetEnergy( CPetProperty::GetInstance()->GetMaxEnergy( pPet->GetLevel() ) );
// pPet->SetExp( 0 );
g_dpDBClient.CalluspPetLog( m_idPlayer, pItemElem->GetSerialNumber(), 0, PETLOGTYPE_DEATH, pPet );
}
else
{
pPet->SetLife( 0 );
pPet->SetEnergy( 0 );
pPet->SetExp( 0 );
pItemElem->SetFlag( CItemElem::expired );
UpdateItem( (BYTE)( pItemElem->m_dwObjId ), UI_FLAG, MAKELONG( pItemElem->m_dwObjIndex, pItemElem->m_byFlag ) );
g_dpDBClient.CalluspPetLog( m_idPlayer, pItemElem->GetSerialNumber(), 0, PETLOGTYPE_DEATH, pPet );
}
PetRelease();
( (CUser*)this )->AddPetState( pItemElem->m_dwObjId , pPet->GetLife(), pPet->GetEnergy(), pPet->GetExp() );
}
}
#endif // __PET_0410
}
// 듀얼중 플레이어의 경우
// 리더인지 판단해서 듀얼을 취소시키고
// 양 파티원들에게 결과를 통보함.
}
if( bBehavior ) {
g_UserMng.AddMoverBehavior2
( this, GetPos(), m_pActMover->m_vDelta, GetAngle(), GetAngleX(), m_pActMover->m_fAccPower, m_pActMover->m_fTurnAngle,
m_pActMover->GetState(), m_pActMover->GetStateFlag(), m_dwMotion, m_pActMover->m_nMotionEx, m_pModel->m_nLoop, m_dwMotionOption,
g_TickCount.GetTickCount(), TRUE );
}
if( fValid )
{
// g_DPCoreClient.SendMoverDeath( this, pAttacker, dwMsg );
g_UserMng.AddMoverDeath( this, pAttacker, dwMsg );
RemoveAllEnemies(); // pAttacker->SendAIMsg( AIMSG_DSTDIE, GetId() );
} // fValid
if( pAttacker )
pAttacker->m_pActMover->SetObjHit( NULL_ID );
// 타겟을 죽인후 AI에서 타겟을 클리어함.
if( IsValidObj(pAttacker) && pAttacker->IsNPC() )
{
pAttacker->SendAIMsg( AIMSG_INIT_TARGETCLEAR ); // 공격자는 타겟을 클리어하고 대기모드로 돌아감.
}
// 몬스터를 죽이면 몬스터가 퀘스트가 요구하는 것인지 판단해서 킬 카운트 증가
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
if( IsPlayer() == FALSE && pAttacker && pAttacker->IsPlayer() )
{
for( int i = 0; i < pAttacker->m_nQuestSize; i++ )
{
LPQUEST lpQuest = (LPQUEST) &pAttacker->m_aQuest[ i ];
if( !lpQuest ) continue;
QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( lpQuest->m_wId );
if( !pQuestProp ) continue;
for( int j = 0; j < 2; ++j )
{
// 진행 중인 퀘스트의 종료 조건과 같은 NPC인가?
if( pQuestProp->m_nEndCondKillNPCIdx[ j ] != GetIndex() ) continue;
// 극단 퀘스트인 경우
if( pQuestProp->m_nBeginCondParty == 2 )
{
CParty* pParty = g_PartyMng.GetParty( pAttacker->m_idparty );
// 극단원중에 해당 퀘스트를 진행하고 있으면..
if( pParty && pParty->IsMember( pAttacker->m_idPlayer ) )
{
for( int k = 0; k < pParty->GetSizeofMember(); ++k )
{
PartyMember* pPartyMember = &pParty->m_aMember[k];
CMover* pMember = prj.GetUserByID( pPartyMember->m_uPlayerId );
if( IsValidObj( pMember ) && IsValidArea( pMember, 64.0f ) )
{
LPQUEST pMemberQuest = pMember->GetQuest( lpQuest->m_wId );
if( pMemberQuest && pMemberQuest->m_nKillNPCNum[j] < pQuestProp->m_nEndCondKillNPCNum[j] )
{
++pMemberQuest->m_nKillNPCNum[j];
( (CUser*)pMember )->AddSetQuest( pMemberQuest );
}
}
}
}
}
else
if( lpQuest->m_nKillNPCNum[ j ] < pQuestProp->m_nEndCondKillNPCNum[ j ] )
{
++lpQuest->m_nKillNPCNum[ j ];
( (CUser*)pAttacker )->AddSetQuest( lpQuest );
}
}
}
}
#else // __IMPROVE_QUEST_INTERFACE
if( IsPlayer() == FALSE && pAttacker && pAttacker->IsPlayer() )
{
for( int i = 0; i < pAttacker->m_nQuestSize; i++ )
{
LPQUEST lpQuest = (LPQUEST) &pAttacker->m_aQuest[ i ];
if( lpQuest )
{
QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( lpQuest->m_wId );
if( pQuestProp )
{
for( int i = 0; i < 2; i++ )
{
// 진행 중인 퀘스트의 종료 조건과 같은 NPC인가?
if( pQuestProp->m_nEndCondKillNPCIdx[ i ] == GetIndex() )
{
if( lpQuest->m_nKillNPCNum[ i ] < pQuestProp->m_nEndCondKillNPCNum[ i ] )
{
lpQuest->m_nKillNPCNum[ i ]++; // 그렇다면 킬 넘버
((CUser*)pAttacker)->AddSetQuest( lpQuest );
}
}
}
}
else
{
}
}
else
{
}
}
}
#endif // __IMPROVE_QUEST_INTERFACE
#else // WORLDSERVER
#ifndef __CLIENT
CMover *pAttacker = NULL;
if( pAttackCtrl && pAttackCtrl->GetType() == OT_MOVER ) // 어태커가 무버라면 무버 포인터 만들어 둔다.
pAttacker = (CMover *)pAttackCtrl;
SendActMsg( OBJMSG_DIE, dwMsg, (int)pAttacker );
#endif
#endif // not WORLDSERVER
#if defined(__WORLDSERVER)
if( GetType() == OT_MOVER )
{
RemoveCommonBuffs();
g_UserMng.AddRemoveAllSkillInfluence( this );
}
if( m_nGuildCombatState )
{
if( pAttacker && pAttacker->IsPlayer() && GetWorld() )
GetWorld()->OnDie( this, pAttacker );
}
#if __VER >= 12 // __SECRET_ROOM
if( CSecretRoomMng::GetInstance()->IsInTheSecretRoom( this ) )
{
if( IsNPC() && pAttacker->IsPlayer() )
CSecretRoomMng::GetInstance()->SetSecretRoomKill( GetWorld()->GetID(), GetProp()->dwID );
if( IsPlayer() && CSecretRoomMng::GetInstance()->IsGuildMaster( (CUser*)this ) )
CSecretRoomMng::GetInstance()->SetFailGuild( (CUser*)this );
}
#endif // __SECRET_ROOM
#if __VER >= 12 // __NEW_ITEMCREATEMON_SERVER
if( IsNPC() )
CCreateMonster::GetInstance()->SetState( GetId(), 'D' );
#endif // __NEW_ITEMCREATEMON_SERVER
#if __VER >= 14 // __INSTANCE_DUNGEON
if( CInstanceDungeonHelper::GetInstance()->IsInstanceDungeon( GetWorld()->GetID() ) )
{
if( !IsPlayer() && pAttacker->IsPlayer() )
CInstanceDungeonHelper::GetInstance()->SetInstanceDungeonKill( GetWorld()->GetID(), static_cast<DWORD>( this->GetLayer() ), GetProp()->dwID );
}
#endif // __INSTANCE_DUNGEON
#ifdef __EVENTLUA_SPAWN
if( IsNPC() )
prj.m_EventLua.RemoveSpawnedMonster( GetId() );
#endif // __EVENTLUA_SPAWN
#endif //__WORLDSERVER
return 1;
}
#if __VER >= 8 // 8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
void CMover::EndPVP(int nPVPHP)
{
if(m_bPVPEnd)
m_bPVPEnd = FALSE;
else
SetPointParam( DST_HP, nPVPHP ); // 2007/11 수정(HP 비동기 문제)
//m_nHitPoint = nPVPHP;
}
//
// 듀얼끝난뒤 처리
void CMover::DoPVPEnd( CCtrl *pAttackCtrl, bool bWinner , DWORD dwMsg )
{
#ifdef __WORLDSERVER
CMover *pAttacker = NULL;
if( pAttackCtrl && pAttackCtrl->GetType() == OT_MOVER ) // 무버라면 무버 포인터 만들어 둔다.
pAttacker = (CMover *)pAttackCtrl;
else
return;
if( IsPlayer() )
{
if( IsStateMode( STATE_BASEMOTION_MODE ) )
{
SetStateNotMode( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_OFF );
m_nReadyTime = 0;
m_dwUseItemId = 0;
}
}
SendActMsg( OBJMSG_STOP );
pAttacker->SendActMsg( OBJMSG_STOP );
m_nDead = PROCESS_COUNT * 3; // 듀얼 후 3초간은 무적
pAttacker->m_nDead = PROCESS_COUNT * 3; // 듀얼 후 3초간은 무적
// 플레이어인 내가 타겟으로 잡고있던넘을 풀어줌.
if( IsPlayer() )
{
CMover *pLastHit = prj.GetMover( m_idLastHitMover );
if( IsValidObj( pLastHit ) )
{
if( pLastHit->m_idAttacker == GetId() ) // pLastHit의 공격자가 나로 설정되어 있을때만 풀어줌,.
pLastHit->m_idAttacker = NULL_ID;
if( pLastHit->m_idTargeter == GetId() )
pLastHit->m_idTargeter = NULL_ID;
}
}
m_bPVPEnd = TRUE;
if( pAttacker )
{
pAttacker->m_pActMover->SetObjHit( NULL_ID );
}
#endif //__WORLDSERVER
}
#endif // __VER >= 8
#ifdef __WORLDSERVER
#if __VER < 8 // __S8_PK
int CMover::ChangeSlaughter( CHANGE_SLAUGHTER_TYPE type, CMover* pDefender, int nSetCarmaPoint )
{
int nVal = 0;
switch( type )
{
case CHANGE_SLAUGHTER_KILL: // PK에 의한 Slaughter 변경
nVal = IncSlaughterPoint( pDefender );
break;
case CHANGE_SLAUGHTER_ATTACK: // PK시도에 의한 Slaughter 변경
nVal = IncSlaughterPoint2( pDefender );
break;
case CHANGE_SLAUGHTER_RECOVERY:
if( m_nSlaughter < 0 )
{
m_nSlaughter += 1;
nVal = 1;
}
break;
case CHANGE_SLAUGHTER_SET:
{
nVal = nSetCarmaPoint - m_nSlaughter;
m_nSlaughter = nSetCarmaPoint;
}
break;
}
if( nVal > 0 )
((CUser*)this)->AddDefinedText( TID_GAME_GETPKPOINT, "%d", nVal ); // xxx 슬로터 포인트를 얻었다
else if( nVal < 0 )
((CUser*)this)->AddDefinedText( TID_GAME_DECPKPOINT, "%d", -nVal ); // xxx 슬로터 포인트가 감소했다.
if( nVal )
{
// 슬로터 포인트의 변화가 있었으면 갱신시킴.
g_UserMng.AddSetSlaughterPoint( this, m_nSlaughter, m_nNumKill ); // 어태커 주위 클라에 슬로터포인트 증가를 알림.
if( pDefender ) // 전투에 의함
g_dpDBClient.SendLogPkPvp( this, pDefender, nVal, 'P' );
}
return nVal;
}
// 카르마 등급을 한단계 올린다.
void CMover::UpgradeKarma()
{
KarmaProp* pProp = prj.GetKarmaProp( m_nSlaughter );
int nGrade = pProp->nGrade + 1;
pProp = prj.GetKarmaPropByGrade( nGrade );
ChangeSlaughter( CHANGE_SLAUGHTER_SET, NULL, pProp->nKarmaPoint );
}
#endif // __VER < 8 // __S8_PK
int CMover::SubPK( CMover *pAttacker, int nReflect )
{
if( !g_eLocal.GetState( EVE_PK )
#ifdef __JEFF_11_4
|| GetWorld()->IsArena()
#endif // __JEFF_11_4
)
return 1;
#if __VER >= 8 // __S8_PK
if( GetWorld()->GetID() == WI_WORLD_GUILDWAR && g_GuildCombatMng.m_nState != CGuildCombat::CLOSE_STATE )
return 1;
if( pAttacker->GetWorld()->GetID() == WI_WORLD_GUILDWAR && g_GuildCombatMng.m_nState != CGuildCombat::CLOSE_STATE )
return 1;
#if __VER >= 11 // __GUILD_COMBAT_1TO1
if( g_GuildCombat1to1Mng.IsPossibleUser( (CUser*)this ) && g_GuildCombat1to1Mng.IsPossibleUser( (CUser*)pAttacker ) )
return 1;
#endif // __GUILD_COMBAT_1TO1
if( g_eLocal.GetState( EVE_PKCOST )
#ifdef __JEFF_11_4
&& GetWorld()->IsArena() == FALSE
#endif // __JEFF_11_4
)
{
if( IsPlayer() && IsChaotic() )
{
#if !defined(__INTERNALSERVER)
if( m_dwAuthorization < AUTH_HELPER )
#endif
{
// 아이템 드롭
// - 인벤 드롭( 장착부터 드롭하면 안됨 - 인벤공간이 부족하여 드롭할수 없음 )
CHAO_PROPENSITY Propensity = prj.GetPropensityPenalty( GetPKPropensity() );
int nInvenDrop = xRandom( Propensity.nInvenDorpMin, Propensity.nInvenDorpMax + 1 );
for( int i=0; i < nInvenDrop; ++i )
{
if( DoDropItemRandom( TRUE, pAttacker ) == 0 )
break;
}
// - 장착 드롭
int nEquipDrop = xRandom( Propensity.nEquipDorpMin, Propensity.nEquipDorpMax + 1 );
for( i=0; i < nEquipDrop; ++i )
{
if( DoDropItemRandom( FALSE, pAttacker, TRUE ) == 0 )
break;
}
}
}
}
if( !pAttacker->IsPlayer() || IsNPC() )
return 1;
BOOL bAdd = FALSE;
if( pAttacker->IsChaotic() ) // 카오상태
{
if( !IsChaotic() )
bAdd = TRUE;
}
else // 핑크상태, 힌색상태
{
if( !(IsChaotic() || IsPKPink()) )
bAdd = TRUE;
}
/// 카오수치, 성향을 올려줌
if( bAdd && nReflect == 0
&& pAttacker != this ) // chipi_081119 지속형 데미지 스킬 받고 재접하면 자살되어 카오되는 문제 수정...
{
if( IsPlayer() && pAttacker->IsPlayer() )
{
if( !pAttacker->IsChaotic() )
((CUser*)pAttacker)->AddPlaySound( SND_PC_CHAOS );
CString szSendMsg;
szSendMsg.Format( prj.GetText(TID_GAME_PK_DEFENDER) , pAttacker->GetName() );
((CUser*)this)->AddText( szSendMsg );
szSendMsg.Format( prj.GetText(TID_GAME_PK_ATTACKER) , GetName() );
((CUser*)pAttacker)->AddText( szSendMsg );
}
pAttacker->SetPKValue( pAttacker->GetPKValue() + 1 );
((CUser*)pAttacker)->AddPKValue();
pAttacker->SetPKPropensity( pAttacker->GetPKPropensity() + NextPKPropensity( pAttacker->GetPKValue() ) );
g_UserMng.AddPKPropensity( pAttacker );
g_dpDBClient.SendLogPkPvp( pAttacker, this, 0, 'P' );
#if __VER >= 13 // __HONORABLE_TITLE // 달인
#ifndef __MAINSERVER
if(!pAttacker->IsPlayer())
FILEOUT( "..\\HonorError.txt", "subpk()AddHonorListAck()\n" );
#endif // __MAINSERVER
((CUser*)pAttacker)->SetHonorAdd(HS_PK_COUNT,HI_COUNT_CHECK);
#endif // __HONORABLE_TITLE // 달인
}
#else // __VER >= 8 // __S8_PK
BOOL bChaotic = IsChaotic();
m_idMurderer = pAttacker->m_idPlayer; // 날 마지막으로 죽인놈의 플레이어아이디를 저장해둠.
pAttacker->m_nNumKill++; // 킬수 증가
((CUser*)this)->AddDefinedText( TID_GAME_PKDEAD, "\"%s\"", pAttacker->m_szName ); // ??에게 죽음을 당하였습니다.
int nGap = abs( this->GetLevel() - pAttacker->GetLevel() );
if( nGap >= 80 )
ChangeFame( this ); // 80 이상일 차이 날 경우, 예외적으로 명성치 증감
// 보상금 떨구기를 요청한다.
CWorld* pWorld = GetWorld();
if( pWorld )
{
//"%s님이 현상범 %s를 잡아 현상금 %s페냐를 얻었습니다."
char szFormat[256];
strcpy( szFormat, pAttacker->GetName() );
strcat( szFormat, prj.GetText( TID_PK_REWARDNOTICE ) );
g_DPCoreClient.SendWCWantedReward( m_idPlayer, pAttacker->m_idPlayer, szFormat, pWorld->GetID(), GetPos() );
}
if( g_eLocal.GetState( EVE_PKCOST )
#ifdef __JEFF_11_4
&& ( pWorld && pWorld->IsArena() == FALSE )
#endif // __JEFF_11_4
)
{
if( bChaotic )
{
#if !defined(__INTERNALSERVER)
if( m_dwAuthorization < AUTH_HELPER )
#endif
{
// 페냐드롭
KarmaProp* pProp = prj.GetKarmaProp( m_nSlaughter );
float fRate = pProp->nDropGoldPercent / 100.0f;
int nGold = GetGold() * fRate;
if( nGold > 0 )
DropGold( nGold , GetPos(), TRUE );
// 아이템 드롭
for( int i=0; i<pProp->nDropItem; ++i )
{
BOOL bExcludeEquip = ( i == 0 ); // 1개 이하의 경우, 장착 아이템은 떨구지 않는다.
if( xRandom( 100 ) < pProp->nDropPercent )
{
if( DoDropItemRandom( bExcludeEquip, pAttacker ) == 0 )
break;
}
}
}
}
}
//pAttacker의 slaughter값을 변경시킨다.
pAttacker->ChangeSlaughter( CHANGE_SLAUGHTER_KILL, this );
// 준카오 유저는 PK로 사망 당할 경우, 카르마 등급이 한 단계 올라간다.
if( GetSlaughterGrade() == SLAUGHTER_SEMI_CHAOTIC )
UpgradeKarma();
#endif // __VER >= 8 // __S8_PK
return 1;
}
int CMover::SubDuel( CMover *pAttacker )
{
if( m_nDuel )
pAttacker->DuelResult( this ); // 듀얼후 결과 처리.
return 1;
}
int CMover::SubWar( CMover *pAttacker )
{
#ifdef __WORLDSERVER
// 길드전 가능한 서버인가.
if( g_eLocal.GetState( EVE_GUILDWAR ) == 0 )
return 0;
// 나랑 다른길드인가(동맹인경우는 이걸로 안된다.)
if( m_idGuild == pAttacker->m_idGuild )
return 0;
// 적대길드원에게 죽었다.
g_DPCoreClient.SendWarDead( m_idPlayer );
#endif // __WORLDSERVER
return 1;
}
PVP_MODE CMover::GetPVPCase( CMover *pAttacker )
{
BOOL bPKEnable = FALSE;
if( g_eLocal.GetState( EVE_18 ) == 1 ) // 18세 서버
bPKEnable = TRUE;
if( bPKEnable == FALSE ||
pAttacker == NULL ||
pAttacker->IsNPC() || // 죽인놈이 NPC면 걍 리턴.
IsNPC() ) // 죽은놈이 NPC면 걍리턴
return PVP_MODE_NONE;
// 이건 사람대 사람의 싸움이다!
if( m_idWar && pAttacker->m_idWar == m_idWar ) // 나랑 같은 전쟁에 참가중인 놈인가.
{
return PVP_MODE_GUILDWAR;
}
if( m_nDuel == 0 || m_nDuelState == 300 ) // PK
{
/* if( GetTickCount() < m_dwPKTargetLimit ) // PK선공불가시간동안에는 선공이 안됨
{
return PVP_MODE_NONE;
} */ // mirchang 100114 듀얼중 타 유저에게 PK당한경우 경험치 하락이 되지 않는다. 내가 카오일 경우 카오수치만 떨어지기 때문에 악용의 소지가 있음..
return PVP_MODE_PK;
}
else //듀얼 상황.
{
return PVP_MODE_DUEL;
}
}
// this가 죽고 난후 PVP(PK, 듀얼, 길드전)처리
void CMover::SubPVP( CMover *pAttacker, int nReflect )
{
if( m_nDuel == 1 )
{
if( GetId() != pAttacker->m_idDuelOther )
{
CUser* pOther = prj.GetUser( m_idDuelOther );
if( IsValidObj( (CObj*)pOther ) )
{
pOther->AddDuelCancel( pOther->m_idDuelOther );
pOther->ClearDuel();
}
( (CUser*)this )->AddDuelCancel( m_idDuelOther );
ClearDuel();
//return; // mirchang 100114 듀얼 중 다른 유저에게 PK를 당한경우 SubPK() 로 가도록..
}
}
else if( m_nDuel == 2 )
{
if( m_idDuelParty != pAttacker->m_idparty || pAttacker->m_nDuelState == 300 )
{
CParty *pLoseParty = g_PartyMng.GetParty( m_idparty );
if( pLoseParty && pLoseParty->IsLeader( m_idPlayer ) )
{
g_DPCoreClient.SendSetPartyDuel( m_idDuelParty, pLoseParty->m_uPartyId, FALSE );
CParty* pParty2 = g_PartyMng.GetParty( m_idDuelParty );
if( pParty2 )
pParty2->DoDuelPartyCancel( pLoseParty );
pLoseParty->DoDuelPartyCancel( pParty2 );
}
}
}
PVP_MODE mode = GetPVPCase( pAttacker );
switch( mode )
{
case PVP_MODE_GUILDWAR:
SubWar( pAttacker );
break;
#if __VER >= 8 // __S8_PK
case PVP_MODE_NONE:
#endif // __VER >= 8 // __S8_PK
case PVP_MODE_PK:
SubPK( pAttacker, nReflect ); // PK의 서브루틴.
break;
case PVP_MODE_DUEL:
SubDuel( pAttacker );
break;
}
}
void CMover::AddPartyMemberExperience( CUser * pUser, EXPINTEGER nExp, int nFxp )
{
if( nFxp ) // 비행경험치가 0인경우는 아무 처리도 안해도 된다.
{
if( pUser->AddFxp( nFxp ) )
{
// 비행레벨업!
g_UserMng.AddSetFlightLevel( pUser, pUser->GetFlightLv() );
} else
{
// 레벨업하지 않고 경험치만 올라감.
// 로그 남길것.
}
pUser->AddSetFxp( pUser->m_nFxp, pUser->GetFlightLv() ); // 당사자에게 비행경험치/레벨을 보냄.
}
if( nExp > prj.m_aExpCharacter[pUser->m_nLevel].nLimitExp )
nExp = prj.m_aExpCharacter[pUser->m_nLevel].nLimitExp;
if( pUser->AddExperience( nExp, TRUE, TRUE, TRUE ) )
pUser->LevelUpSetting();
else
pUser->ExpUpSetting();
pUser->AddSetExperience( pUser->GetExp1(), (WORD)pUser->m_nLevel, pUser->m_nSkillPoint, pUser->m_nSkillLevel );
}
// this가 죽은무버다.
// this를 중심으로 반경 fRange 이내에 있는 사람들에게 경험치를 분배한다.
void CMover::SubAroundExp( CMover *pAttacker, float fRange )
{
#if 1
#define MAX_AROUND_USER 512
D3DXVECTOR3 vPos = GetPos();
D3DXVECTOR3 vDist;
FLOAT fDistSq;
CUser *pUser;
CUser *pList[ MAX_AROUND_USER ], **ptr;
int nMaxList = 0;
int i;
TRACE( "보스몹 죽임 %s\n", pAttacker->GetName() );
fRange *= fRange; // Sq 버전으로 바꿈.
memset( pList, 0, sizeof(pList) );
ptr = pList;
// 반경내에 있는 유저를 추려냄.
FOR_VISIBILITYRANGE( this )
{
pUser = USERPTR;
vDist = vPos - pUser->GetPos();
fDistSq = D3DXVec3LengthSq( &vDist ); // 죽은넘과 유저사이의 거리Sq를 구함
if( fDistSq <= fRange ) // 반경 fRange 미터 이내에 있는 사람은
{
*ptr++ = pUser;
nMaxList ++;
}
}
NEXT_VISIBILITYRANGE( this )
if( nMaxList == 0 )
{
Error( "CMover::SubAroundExp %s주위에 유저가 없다. ", GetName() );
return;
}
EXPINTEGER nExp = GetProp()->nExpValue / (EXPINTEGER)nMaxList; // 1인당 얼마씩 배분되야 하는가.
// 추려낸 유저들에게 경험치를 줌.
ptr = pList;
for( i = 0; i < nMaxList; i ++ )
{
pUser = *ptr++;
if( nExp > prj.m_aExpCharacter[pUser->m_nLevel].nLimitExp )
nExp = prj.m_aExpCharacter[pUser->m_nLevel].nLimitExp;
if( pUser->AddExperience( nExp, TRUE, TRUE, TRUE ) )
{
// 레벨업 됐다.
g_UserMng.AddSetLevel( pUser, (WORD)pUser->m_nLevel ); // pUser의 주위사람에게 pUser가 레벨이 올랐다는걸 보냄.
((CUser*)pUser)->AddSetGrowthLearningPoint( pUser->m_nRemainGP ); // pUser에게 GP변동된것을 보냄.
g_dpDBClient.SendLogLevelUp( pUser, 1 ); // 레벨업 로그
#if __VER >= 11 // __SYS_PLAYER_DATA
g_dpDBClient.SendUpdatePlayerData( pUser );
#else // __SYS_PLAYER_DATA
if( 0 < pUser->GetPartyId() )
g_DPCoreClient.SendPartyMemberLevel( pUser );
if( pUser->m_idGuild != 0 )
g_DPCoreClient.SendGuildChangeJobLevel( (CUser*)pUser );
#endif // __SYS_PLAYER_DATA
}
else
{
// 레벨업 안되고 겸치만 올랐다.
// 레벨 5이상일때는 경험치 업을 로그_레벨업 테이블에 로그를 남긴다
// 경험치 20% 단위로 로그를 남김
#ifdef __EXP_ANGELEXP_LOG
int nNextExpLog = (int)(pUser->m_nExpLog/20 + 1) * 20;
int nExpPercent = (int)( GetExp1() * 100 / GetMaxExp1() );
if( nExpPercent >= nNextExpLog )
{
pUser->m_nExpLog = nExpPercent;
g_dpDBClient.SendLogLevelUp( this, 5 );
}
#else // __EXP_ANGELEXP_LOG
int iLogExp = GetExp1() * 100 / GetMaxExp1();
iLogExp /= 20;
if( pUser->GetLevel() > 5 ) // 레벨 5이상
{
if( ( 20 * ( iLogExp + 1 ) ) <= ( pUser->GetExp1() * 100 / pUser->GetMaxExp1() ) )
g_dpDBClient.SendLogLevelUp( pUser, 5 );
}
#endif // __EXP_ANGELEXP_LOG
}
// pUser에게 경험치 바뀐걸 보냄
((CUser*)pUser)->AddSetExperience( pUser->GetExp1(), (WORD)pUser->m_nLevel, pUser->m_nSkillPoint, pUser->m_nSkillLevel );
}
#endif // 0
}
void CMover::AddKillRecovery()
{
if( IsPlayer() == FALSE ) return; // this(Attacker)가 몬스터면 처리안함.
int nHPPoint = GetParam( DST_KILL_HP, 0 );
int nMPPoint = GetParam( DST_KILL_MP, 0 );
int nFPPoint = GetParam( DST_KILL_FP, 0 );
BOOL bSfx = FALSE;
if( nHPPoint )
{
int nHP = GetPointParam( DST_HP );
int nHPMax = GetMaxPoint( DST_HP );
if( nHP + nHPPoint >= nHPMax ) // 포인트 더했을때 오바되는걸 처리.
nHP = nHPMax;
else
nHP = nHP + nHPPoint;
SetPointParam( DST_HP, nHP );
bSfx = TRUE;
}
if( nMPPoint )
{
int nMP = GetPointParam( DST_MP );
int nMPMax = GetMaxPoint( DST_MP );
if( nMP + nMPPoint >= nMPMax ) // 포인트 더했을때 오바되는걸 처리.
nMP = nMPMax;
else
nMP = nMP + nMPPoint;
SetPointParam( DST_MP, nMP );
bSfx = TRUE;
}
if( nFPPoint )
{
int nFP = GetPointParam( DST_FP );
int nFPMax = GetMaxPoint( DST_FP );
if( nFP + nFPPoint >= nFPMax ) // 포인트 더했을때 오바되는걸 처리.
nFP = nFPMax;
else
nFP = nFP + nFPPoint;
SetPointParam( DST_FP, nFP );
bSfx = TRUE;
}
if( bSfx )
g_UserMng.AddCreateSfxObj( this, XI_KILL_RECOVERY );
}
// pDead를 죽인후 경험치 처리
int CMover::SubExperience( CMover *pDead )
{
if( IsPlayer() == FALSE ) return 0; // this(Attacker)가 몬스터면 처리안함.
if( pDead->IsPlayer() ) return 0; // 죽은넘이 플레이어면 경험치 처리할일이 없음.
MoverProp* pMoverProp = pDead->GetProp();
ASSERT( pMoverProp );
#ifdef __WORLDSERVER
EXPFLOAT fExpValue = 0;
float fFxpValue = 0.0f;
#ifdef __S1108_BACK_END_SYSTEM
// fExpValue = pMoverProp->nExpValue * static_cast<EXPFLOAT>( prj.m_fMonsterExpRate ) * static_cast<EXPFLOAT>( pMoverProp->m_fExp_Rate );
// fFxpValue = pMoverProp->nFxpValue * prj.m_fMonsterExpRate * pMoverProp->m_fExp_Rate;
fExpValue = pMoverProp->nExpValue * static_cast<EXPFLOAT>( pMoverProp->m_fExp_Rate );
fFxpValue = pMoverProp->nFxpValue * pMoverProp->m_fExp_Rate;
#else // __S1108_BACK_END_SYSTEM
// fExpValue = pMoverProp->nExpValue * static_cast<EXPFLOAT>( prj.m_fMonsterExpRate );
// fFxpValue = pMoverProp->nFxpValue * prj.m_fMonsterExpRate;
fExpValue = pMoverProp->nExpValue;
fFxpValue = pMoverProp->nFxpValue;
#endif // __S1108_BACK_END_SYSTEM
#else // __WORLDSERVER
EXPFLOAT fExpValue = static_cast<EXPFLOAT>( pMoverProp->nExpValue );
float fFxpValue = pMoverProp->nFxpValue;
#endif // __WORLDSERVER
if( IsAuthHigher( AUTH_ADMINISTRATOR ) ) // 운영자 계정일때
{
if( IsMode( MODE_EXPUP_STOP ) ) // 경험치 상승 금지 상태면
fExpValue = 0; // 경험치값 0
}
AddExperienceKillMember( pDead, fExpValue, pMoverProp, fFxpValue );
return 1;
}
BOOL CMover::IsValidArea( CMover* pMover, float fLength )
{
float fDist;
D3DXVECTOR3 vDist;
if( IsValidObj( (CObj*)this) && IsValidObj( (CObj*)pMover ) && GetWorld() == pMover->GetWorld()/*2008.04.11 동맵 검사 추가*/
#ifdef __LAYER_1015
&& GetLayer() == pMover->GetLayer() // 2008.12.26 레이어 검사
#endif // __LAYER_1015
)
{
vDist = pMover->GetPos() - GetPos();
fDist = D3DXVec3LengthSq( &vDist );
if( fDist < fLength * fLength )
{
return TRUE;
}
}
return FALSE;
}
BOOL CMover::GetPartyMemberFind( CParty* pParty, CUser* apMember[], int* nTotalLevel, int* nMaxLevel10, int* nMaxLevel, int* nMemberSize )
{
CUser* pUsertmp = NULL;
D3DXVECTOR3 vDist;
for( int i = 0 ; i < pParty->m_nSizeofMember ; i++ )
{
pUsertmp = g_UserMng.GetUserByPlayerID( pParty->m_aMember[i].m_uPlayerId );
if( IsValidArea( (CMover*)pUsertmp, 64.0f ) )
{
apMember[(*nMemberSize)++] = pUsertmp;
(*nTotalLevel) += pUsertmp->GetLevel();
if( (*nMaxLevel10) < pUsertmp->GetLevel() )
{
(*nMaxLevel) = (*nMaxLevel10) = pUsertmp->GetLevel();
}
}
}
if( 0 < (*nMaxLevel10) - 20 )
{
(*nMaxLevel10) -= 20;
}
else
{
(*nMaxLevel10) = 0;
}
if( (*nMemberSize) == 0 || (*nTotalLevel) == 0 )
{
return FALSE;
}
return TRUE;
}
void CMover::AddExperienceKillMember( CMover *pDead, EXPFLOAT fExpValue, MoverProp* pMoverProp, float fFxpValue )
{
vector<OBJID> adwEnemy;
vector<int> anHitPoint;
DWORD dwMaxEnemyHit = 0;
for( SET_OBJID::iterator it = pDead->m_idEnemies.begin(); it != pDead->m_idEnemies.end(); ++it )
{
adwEnemy.push_back( (*it).first );
anHitPoint.push_back( (*it).second.nHit );
dwMaxEnemyHit += (*it).second.nHit;
}
if( adwEnemy.size() > 1024 )
{
Error( "CMover::AddExperienceKillMember - enemy size is too big" );
}
if( dwMaxEnemyHit == 0 ) //
return;
for( DWORD j = 0; j < adwEnemy.size(); j++ )
{
if( adwEnemy[j] == 0 ) // 무시
continue;
CMover* pEnemy = prj.GetMover( adwEnemy[j] );
if( IsValidObj( pEnemy ) && pDead->IsValidArea( pEnemy, 64.0f ) && pEnemy->IsPlayer() ) // 플레이어, 범위 검사
{
DWORD dwHitPointParty = 0;
CParty* pParty = g_PartyMng.GetParty( pEnemy->m_idparty );
if( pParty && pParty->IsMember( pEnemy->m_idPlayer ) )
{
dwHitPointParty = anHitPoint[j];
for( DWORD k = j + 1 ; k < adwEnemy.size(); k++ )
{
if( adwEnemy[k] == 0 )
continue; // 중복 처리 스킵
CMover* pEnemy2 = prj.GetMover( adwEnemy[k] );
if( IsValidObj( pEnemy2 ) && pDead->IsValidArea( pEnemy2, 64.0f ) && pEnemy2->IsPlayer() ) // 플레이어, 범위 검사
{
if( pEnemy->m_idparty == pEnemy2->m_idparty && pParty->IsMember( pEnemy2->m_idPlayer ) ) // 같은 파티 삭제 대상
{
dwHitPointParty += anHitPoint[k];
adwEnemy[k] = 0; // 중복 처리 방지
}
}
else
{
adwEnemy[k] = 0; // 삭제 대상
}
}
}
if( dwHitPointParty > 0 )
anHitPoint[j] = dwHitPointParty;
float fExpValuePerson = (float)( fExpValue * ( float( anHitPoint[j] ) / float( dwMaxEnemyHit ) ) );
if( dwHitPointParty ) // 극단 경험치 분배
{
int nTotalLevel = 0;
int nMaxLevel10 = 0;
int nMaxLevel = 0;
int nMemberSize = 0;
CUser* apMember[MAX_PTMEMBER_SIZE];
memset( apMember, 0, sizeof(apMember) );
// 1. 주변 멤버 검사
if( pEnemy->GetPartyMemberFind( pParty, apMember, &nTotalLevel, &nMaxLevel10, &nMaxLevel, &nMemberSize ) == FALSE )
break;
#if __VER >= 14 // __PCBANG
fExpValuePerson *= CPCBang::GetInstance()->GetPartyExpFactor( apMember, nMemberSize );
#endif // __PCBANG
if( 1 < nMemberSize ) // 파티원가 같이 있음 // 파티원들 경험치 주기
pEnemy->AddExperienceParty( pDead, fExpValuePerson, pMoverProp, fFxpValue, pParty, apMember, &nTotalLevel, &nMaxLevel10, &nMaxLevel, &nMemberSize );
else // 혼자서 싸운것으로 처리.
pEnemy->AddExperienceSolo( fExpValuePerson, pMoverProp, fFxpValue, TRUE );
}
else
{
#if __VER >= 14 // __PCBANG
if( IsPlayer() )
fExpValuePerson *= CPCBang::GetInstance()->GetExpFactor( static_cast<CUser*>( this ) );
#endif // __PCBANG
pEnemy->AddExperienceSolo( fExpValuePerson, pMoverProp, fFxpValue, FALSE );
}
}
}
}
void CMover::AddExperienceSolo( EXPFLOAT fExpValue, MoverProp* pMoverProp, float fFxpValue, BOOL bParty )
{
if( g_eLocal.GetState( EVE_EVENT0214 ) && !bParty ) // 발렌타인 이벤트 중 솔로 플레이 시 경험치 1.5배
fExpValue *= static_cast<EXPFLOAT>( 1.5f );
#if __VER < 8 // 8차 스킬경험치다운변경
// 죽음 이후 상태라면 경험치를 150%준다.
if( IsAfterDeath() )
fExpValue *= static_cast<EXPFLOAT>( 1.5f );
#endif // __VER < 8
#if __VER < 9 // __S_9_ADD
//#ifdef __VCRITICAL
// 크리티칼률 조정. 내 HP가 CRITICAL_BERSERK_HP%보다 적으면 적용
int nHitPercent = GetHitPointPercent( 100 );
if( nHitPercent < CRITICAL_BERSERK_HP )
{
// CRITICAL_BERSERK_HP : ( fExpValue * 0.2 ) = nHitPercent : x
// 30 : ( 1000 * 0.2 ) = 0 : x
if( nHitPercent <= 10 )
fExpValue *= 1.2f;
else
fExpValue += ( fExpValue * .2f ) - ( ( fExpValue * .2f ) * nHitPercent / CRITICAL_BERSERK_HP );
}
//#endif
#endif // __S_9_ADD
// 레벨에 따라 경험치를 준다. 렙이 나보다 낮을경우 70 %, 나보다 높을경우 130 %
int dw_Level = GetLevel() - (int)pMoverProp->dwLevel;
if( dw_Level > 0 )
{
if( 1 == dw_Level || dw_Level == 2 ) // 1~2 차이
{
fExpValue *= static_cast<EXPFLOAT>( 0.7f );
fFxpValue *= 0.7f;
}
else if( 3 == dw_Level || dw_Level == 4 ) // 3~4 차이
{
fExpValue *= static_cast<EXPFLOAT>( 0.4f );
fFxpValue *= 0.4f;
}
else // 5이상 차이
{
fExpValue *= static_cast<EXPFLOAT>( 0.1f );
fFxpValue *= 0.1f;
}
}
EXPINTEGER iLogExp = GetExp1() * 100 / GetMaxExp1();
iLogExp /= 20;
if( fExpValue > static_cast<EXPFLOAT>( prj.m_aExpCharacter[m_nLevel].nLimitExp ) )
fExpValue = static_cast<EXPFLOAT>( prj.m_aExpCharacter[m_nLevel].nLimitExp );
// 올릴 비행경험치가 없다면 실행안해도 된다.
if( fFxpValue )
{
if( AddFxp( (int)fFxpValue ) )
{
#ifdef __WORLDSERVER
g_UserMng.AddSetFlightLevel( this, GetFlightLv() );
#endif // __WORLDSERVER
}
else
{
// 비행경험치 획득 로그 넣을것!
}
#ifdef __WORLDSERVER
( (CUser*)this )->AddSetFxp( m_nFxp, GetFlightLv() );
#endif // __WORLDSERVER
}
TRACE("Name : %s 얻어지는 : %I64d ", this->GetName(), static_cast<EXPINTEGER>( fExpValue ) );
TRACE(" 레벨업에 필요한:%I64d\n", prj.m_aExpCharacter[m_nLevel+1].nExp1 - m_nExp1 );
if( AddExperience( static_cast<EXPINTEGER>( fExpValue ), TRUE, TRUE, TRUE ) ) // lv up
# ifdef __WORLDSERVER
((CUser*)this)->LevelUpSetting();
# endif // __WORLDSERVER
else
# ifdef __WORLDSERVER
((CUser*)this)->ExpUpSetting();
# endif // __WORLDSERVER
# ifdef __WORLDSERVER
( (CUser*)this )->AddSetExperience( GetExp1(), (WORD)m_nLevel, m_nSkillPoint, m_nSkillLevel );
# endif // __WORLDSERVER
}
void CMover::AddExperienceParty( CMover *pDead, EXPFLOAT fExpValue, MoverProp* pMoverProp, float fFxpValue, CParty* pParty, CUser* apMember[], int* nTotalLevel, int* nMaxLevel10, int* nMaxLevel, int* nMemberSize )
{
// 죽이넘 주변의 파티원들중 최고 레벨 파티원으로 경험치를 감소 시킴
float fFactor = GetExperienceReduceFactor( (int)pMoverProp->dwLevel, *nMaxLevel );
fExpValue *= static_cast<EXPFLOAT>( fFactor );
fFxpValue *= fFactor;
// 몬스터 레벨과 극단총레벨이 5이상 몬스터레벨이 적으면 경험치와 포인트가 안올라감
pParty->GetPoint( (*nTotalLevel), (*nMemberSize), pDead->GetLevel() );
if( pParty->m_nKindTroup ) // 순회극단
{
switch( pParty->m_nTroupsShareExp ) // 경험치 분배 방식
{
case 1 : // 기여분배
{
AddExperiencePartyContribution( pDead, apMember, pParty, fExpValue, fFxpValue, (*nMemberSize), (*nMaxLevel10) );
}
break;
case 2 : // 동일분배
{
// 아직 기획이 미정 적용안됨
}
break;
default: // 기본 분배(레벨분배)
{
AddExperiencePartyLevel( apMember, pParty, fExpValue, fFxpValue, (*nMemberSize), (*nMaxLevel10) );
}
break;
}
}
else // 단막극단
{
// 단막극단은 순회극단의 레벨 분배와 같다
AddExperiencePartyLevel( apMember, pParty, fExpValue, fFxpValue, (*nMemberSize), (*nMaxLevel10) );
}
}
// 극단시 기여분배
void CMover::AddExperiencePartyContribution( CMover *pDead, CUser* apMember[], CParty* pParty, EXPFLOAT fExpValue, float fFxpValue, int nMemberSize, int nMaxLevel10 )
{
// 획득한 경험치 = 자신의 타격에 의한 경험치 + 보너스 경험치 + 옵션 (몬스터경험치 * 파티원중 때린놈들 / 100 )
// 보너스 경험치 = ( 몬스터 경험치 * 0.15) *( 극단 인원 -1 ) * ((자신의레벨의 제곱)/( 파티원 각각의 레벨의 제곱의 합))
EXPINTEGER nMemberExp;
int nAttackMember = 0;
float fMaxMemberLevel = 0.0f;
for( int i = 0 ; i < nMemberSize ; i++ )
{
float fContribution = 0;
int nHit = pDead->GetEnemyHit( apMember[i]->GetId() );
if( nHit )
{
++nAttackMember;
}
fMaxMemberLevel += ((float)apMember[i]->GetLevel() * (float)apMember[i]->GetLevel());
}
float fAddExp = 0.0f; // 보너스 경험치
fAddExp = (float)( ( fExpValue * 0.2f ) * ( pParty->m_nSizeofMember - 1 ) );
float fFullParty = 0.0f; // 풀파티 보너스 경험치
if( nMemberSize == MAX_PTMEMBER_SIZE_SPECIAL )
{
fFullParty = (float)( ( fExpValue * 0.1f ) );
}
float fOptionExp = 0.0f; // 옵션 경험치
if( 1 < nAttackMember )
{
fOptionExp = (float)( (fExpValue * (float)nAttackMember / 100.0f ) );
}
TRACE("GetExp(Contribution) : %s -> %f\n ", pParty->m_sParty, fExpValue );
for( i = 0 ; i < nMemberSize ; i++ )
{
float fContribution = 0;
int nHit = pDead->GetEnemyHit( apMember[i]->GetId() );
if( nHit )
{
fContribution = (float)nHit * 100 / (float)pDead->GetMaxHitPoint();
if( 100 < fContribution )
{
fContribution = 100.0f;
}
if( nMaxLevel10 < apMember[i]->GetLevel() )
{
nMemberExp = static_cast<EXPINTEGER>( ( fExpValue * ( fContribution / 100.0f ) ) + ( fAddExp * ( ((float)apMember[i]->GetLevel() * (float)apMember[i]->GetLevel()) / fMaxMemberLevel ) ) + fOptionExp + fFullParty );
#if __VER < 8 // 8차 스킬경험치다운변경
// 죽은후 경험치 더주기
if( apMember[i]->IsAfterDeath() )
nMemberExp *= static_cast<EXPFLOAT>( 1.5f );
#endif // __VER < 8
#if __VER < 9 // __S_9_ADD
// HP가 적을때 경험치 더주기
int nHitPercent = apMember[i]->GetHitPointPercent( 100 );
if( nHitPercent < CRITICAL_BERSERK_HP )
{
if( nHitPercent <= 10 )
nMemberExp *= 1.2f;
else
nMemberExp += ( nMemberExp * .2f ) - ( ( nMemberExp * .2f ) * nHitPercent / CRITICAL_BERSERK_HP );
}
#endif // __S_9_ADD
TRACE("GetExp(Contribution) : %s -> %I64d\n ", apMember[i]->GetName(), static_cast<EXPINTEGER>( nMemberExp ) );
AddPartyMemberExperience( apMember[i], nMemberExp, 0 );
}
}
else // 한대도 안때렸으면 보너스 경치와 옵션 경치와 풀파티보너스경치 만 준다
{
if( nMaxLevel10 < apMember[i]->GetLevel() )
{
nMemberExp = static_cast<EXPINTEGER>( ( fAddExp * ( ((float)apMember[i]->GetLevel() * (float)apMember[i]->GetLevel()) / fMaxMemberLevel ) ) + fOptionExp + fFullParty );
#if __VER < 8 // 8차 스킬경험치다운변경
// 죽은후 경험치 더주기
if( apMember[i]->IsAfterDeath() )
nMemberExp *= static_cast<EXPFLOAT>( 1.5f );
#endif // __VER < 8
#if __VER < 9 // __S_9_ADD
// HP가 적을때 경험치 더주기
int nHitPercent = apMember[i]->GetHitPointPercent( 100 );
if( nHitPercent < CRITICAL_BERSERK_HP )
{
if( nHitPercent <= 10 )
nMemberExp *= 1.2f;
else
nMemberExp += ( nMemberExp * .2f ) - ( ( nMemberExp * .2f ) * nHitPercent / CRITICAL_BERSERK_HP );
}
#endif // __S_9_ADD
TRACE("GetExp(Contribution) : %s -> %I64d\n ", apMember[i]->GetName(), static_cast<EXPINTEGER>( nMemberExp ) );
AddPartyMemberExperience( apMember[i], nMemberExp, 0 );
}
}
}
}
void CMover::AddExperiencePartyLevel( CUser* apMember[], CParty* pParty, EXPFLOAT fExpValue, float fFxpValue, int nMemberSize, int nMaxLevel10 )
{
EXPINTEGER nMemberExp;
// int nMemberFxp;
float fMaxMemberLevel = 0.0f;
for( int i = 0 ; i < nMemberSize ; i++ )
{
fMaxMemberLevel += ((float)apMember[i]->GetLevel() * (float)apMember[i]->GetLevel());
}
float fAddExp = 0.0f;
fAddExp = (float)( ( fExpValue * 0.2f ) * ( nMemberSize - 1 ) );
TRACE("GetExp(Level) : %s -> %f\n ", pParty->m_sParty, fExpValue );
for( i = 0 ; i < nMemberSize ; i++ )
{
if( nMaxLevel10 < apMember[i]->GetLevel() )
{
//[ 몬스터의 경험치 + {(몬스터 경험치 * 0.15) * (극단 인원 - 1)} * (자신의 레벨의 제곱/모든 파티원 레벨 제곱의 합) ]
nMemberExp = static_cast<EXPINTEGER>( ( ( fExpValue + fAddExp ) * ( ((float)apMember[i]->GetLevel() * (float)apMember[i]->GetLevel()) / fMaxMemberLevel ) ) ); //+ fFullAddExp );
#if __VER < 8 // 8차 스킬경험치다운변경
// 죽은후 경험치 더주기
if( apMember[i]->IsAfterDeath() )
nMemberExp *= static_cast<EXPFLOAT>( 1.5f );
#endif // __VER < 8
#if __VER < 9 // __S_9_ADD
// HP가 적을때 경험치 더주기
int nHitPercent = apMember[i]->GetHitPointPercent( 100 );
if( nHitPercent < CRITICAL_BERSERK_HP )
{
if( nHitPercent <= 10 )
nMemberExp *= 1.2f;
else
nMemberExp += ( nMemberExp * .2f ) - ( ( nMemberExp * .2f ) * nHitPercent / CRITICAL_BERSERK_HP );
}
#endif // __S_9_ADD
AddPartyMemberExperience( apMember[i], nMemberExp, 0 );
TRACE("GetExp(Level) : %s -> %I64d\n ", apMember[i]->GetName(), static_cast<EXPINTEGER>( nMemberExp ) );
}
}
}
// 경험치 감소값을 리턴: 대상과 주변의 파티원들중 최고 레벨 파티원의 차이를 바탕으로 ...
float CMover::GetExperienceReduceFactor( int nLevel, int nMaxLevel )
{
float fFactor = 1.0f;
int nDelta = nMaxLevel - nLevel;
if( nDelta > 0 )
{
nDelta = min( nDelta, 9 ); // 최대 9
if( ::GetLanguage() == LANG_KOR )
{
float fFactors[10] = { 0.7f, 0.7f, 0.7f, 0.4f, 0.4f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f };
return fFactors[ nDelta ];
}
else
{
float fFactors[10] = { 0.8f, 0.8f, 0.6f, 0.35f, 0.2f, 0.12f, 0.08f, 0.04f, 0.02f, 0.01f };
return fFactors[ nDelta ];
}
}
return fFactor;
}
#endif // __WORLDSERVER not client
// 서버에서도 사용되는 신버전.
BOOL CMover::IsAttackAble( CObj *pObj )
{
#if __VER >= 8 //__Y_FLAG_SKILL_BUFF
if( HasBuffByIk3(IK3_TEXT_DISGUISE) )
return FALSE;
#endif //__Y_FLAG_SKILL_BUFF
BOOL bAble = FALSE;
CWorld* pWorld = GetWorld();
if( pObj )
{
if( IsStateMode( STATE_BASEMOTION_MODE ) )
{
#ifdef __CLIENT
g_DPlay.SendStateModeCancel( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_CANCEL );
#else
SetStateNotMode( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_CANCEL );
m_nReadyTime = 0;
m_dwUseItemId = 0;
#endif
return FALSE;
}
if( pObj->GetType() == OT_MOVER )
{
#ifdef __CLIENT
CMover *pMover = (CMover *)pObj;
if( pMover->IsPlayer() )
{
if( g_eLocal.GetState( EVE_18 ) )
{
if( IsPVPTarget( pMover ) ) // pvp
{
if( m_nDuelState == 1 && !IsFly() && !pMover->IsFly() )
bAble = TRUE;
}
else if( IsWarTarget( pMover ) ) // war
bAble = TRUE;
else if( IsSchoolTarget( pMover ) ) // event
bAble = TRUE;
#ifdef __JEFF_11_4
else if( IsArenaTarget( pMover ) )
bAble = TRUE;
#endif // __JEFF_11_4
else // pk
{
bAble = IsPKAttackAble( pMover );
if( bAble )
( (CWndWorld *)g_WndMng.m_pWndWorld )->SetLastTarget( pMover->GetId() );
}
}
/*#if __VER >= 8 // 8차 듀얼 061226 ma
if( IsPVPTarget( pMover ) ) // pvp
{
if( m_nDuelState == 1 && !IsFly() && !pMover->IsFly() )
bAble = TRUE;
}
#endif // __VER >= 8 // 8차 듀얼 061226 ma*/
if( g_eLocal.GetState( EVE_GUILDCOMBAT ) )
{
if( pWorld->GetID() == WI_WORLD_GUILDWAR )
{
if( IsGuildCombatTarget( pMover ) ) // GuildCombat
bAble = TRUE;
}
}
#if __VER >= 11 // __GUILD_COMBAT_1TO1
if( g_eLocal.GetState( EVE_GUILDCOMBAT1TO1 ) )
{
if( g_GuildCombat1to1Mng.IsPossibleMover( pMover ) && IsGuildCombatTarget( pMover ) )
bAble = TRUE;
}
#endif // __GUILD_COMBAT_1TO1
}
else
{
bAble = IsAttackAbleNPC( pMover );
}
#else // __CLIENT
if( GetHitType( (CMover *)pObj, TRUE, 0 ) == HITTYPE_FAIL )
bAble = FALSE;
else
bAble = TRUE;
#endif // __CLIENT
}
else
{
// no mover
bAble = TRUE;
}
#ifdef __CLIENT
if( !bAble )
( (CWndWorld *)g_WndMng.m_pWndWorld )->m_bAutoAttack = FALSE;
#endif
}
return bAble;
}
BOOL CMover::IsAttackAbleNPC( CMover* pNPC )
{
#if __VER >= 8 //__Y_FLAG_SKILL_BUFF
if( HasBuffByIk3(IK3_TEXT_DISGUISE) )
return FALSE;
#endif //__Y_FLAG_SKILL_BUFF
BOOL bAble = TRUE;
if( pNPC->IsDie() ) // 이미 죽은넘은 포커스 해제시키고 더이상 실행하지 않음.
{
#ifdef __CLIENT
g_WorldMng()->SetObjFocus( NULL );
#else
if( IsPlayer() )
((CUser *)this)->AddSetTarget( NULL_ID );
#endif
bAble = FALSE;
}
else
{
MoverProp *pMoverProp = pNPC->GetProp();
if( pMoverProp->bKillable == 0 )
return FALSE; // 공격이불가능한 NPC는 무조건 공격못함.
// 평화적이면 못때림.
if( pNPC->IsPeaceful() == TRUE ) // 평화적인넘은 공격 안됨
{
bAble = FALSE;
}
else
{
if( pMoverProp->dwClass == RANK_GUARD ) // 가드일때만 성향을 비교한다.
{
if( pMoverProp->nChaotic < 0 && IsChaotic() == TRUE ) // 성향이 서로 같으면 공격못함.
bAble = FALSE;
else if( pMoverProp->nChaotic > 0 && IsChaotic() == FALSE ) // 성향이 서로 같으면 공격못함.
bAble = FALSE;
}
if( m_pActMover->IsFly() && pMoverProp->dwFlying == 0 ) // 공격자가 비행중이고 타겟이 비행몹이 아니면
bAble = FALSE;
else if( m_pActMover->IsFly() == FALSE && pMoverProp->dwFlying == 1 ) // 공격자 지상 / 타겟 비행몹
bAble = FALSE;
}
}
#ifdef __CLIENT
if( bAble == TRUE )
if( GetAsyncKeyState(VK_CONTROL) & 0x8000 ) // NPC에게 공격키를 누르고 있을때 클릭하면 자동공격.
((CWndWorld *)g_WndMng.m_pWndWorld)->m_bAutoAttack = TRUE;
#endif // Client
return bAble;
}
#ifdef __CLIENT
BOOL CMover::IsPKAttackAble( CMover* pMover )
{
#ifdef __JEFF_11_4
if( IsArenaTarget( pMover ) )
return TRUE;
#endif // __JEFF_11_4
if( !g_eLocal.GetState( EVE_PK ) )
return FALSE;
return IsPKInspection( pMover );
}
BOOL CMover::IsPKInspection( CMover* pOther )
{
#if __VER < 8 // __S8_PK
if( g_Party.IsMember( pOther->m_idPlayer ) )
return FALSE;
if( m_idGuild > 0 && m_idGuild == pOther->m_idGuild )
return FALSE;
#endif // __VER >= 8 // __S8_PK
DWORD dwRegionAttr = GetPKPVPRegionAttr();
BOOL bAble = TRUE;
int nAttackerPK, nDefenderPK;
nAttackerPK = nDefenderPK = 0;
if( nAttackerPK = IsPKPVPInspectionBase( dwRegionAttr, FALSE ) )
bAble = FALSE;
if( nDefenderPK = pOther->IsPKPVPInspectionBase( dwRegionAttr, FALSE ) )
bAble = FALSE;
#if __VER >= 8 // __S8_PK
if( bAble == FALSE && ( pOther->IsChaotic() || (GetAsyncKeyState(VK_CONTROL) & 0x8000)) )
{
if(GetWorld() && GetWorld()->GetID() == WI_WORLD_GUILDWAR && IsGuildCombatTarget( pOther ) ) // 길드대전 중인 유저에게는 메세지가 안나오게 하자
nAttackerPK = nDefenderPK = 9;
#if __VER >= 11 // __GUILD_COMBAT_1TO1
else if( g_GuildCombat1to1Mng.IsPossibleMover( this ) )
nAttackerPK = nDefenderPK = 9;
#endif // __GUILD_COMBAT_1TO1
else if(!IsFly() && !pOther->IsFly())
{
CWndWorld* pWndWorld = (CWndWorld*)g_WndMng.GetWndBase( APP_WORLD );
if( pWndWorld && pWndWorld->m_bLButtonDown && !pWndWorld->m_bLButtonDowned )
{
if( nAttackerPK == 1 || nDefenderPK == 1 )
g_WndMng.PutString( prj.GetText(TID_GMAE_PK_NOT_AREA), NULL, prj.GetTextColor(TID_GMAE_PK_NOT_AREA) );
else if( nAttackerPK == 5 )
g_WndMng.PutString( prj.GetText(TID_GAME_PK_LIMIT_LEVEL0), NULL, prj.GetTextColor(TID_GAME_PK_LIMIT_LEVEL0) );
else if( nDefenderPK == 5 )
g_WndMng.PutString( prj.GetText(TID_GAME_PK_LIMIT_LEVEL1), NULL, prj.GetTextColor(TID_GAME_PK_LIMIT_LEVEL1) );
}
}
}
#endif // __VER >= 8 // __S8_PK
if( bAble )
{
if( pOther->m_vtInfo.IsVendorOpen() )
{
if( IsForceAttack() )
{
;
}
else if( !( g_Neuz.m_NeuzEnemy.IsPKing( pOther->GetId() ) ) )
bAble = FALSE;
}
else
{
if( dwRegionAttr == RA_PENALTY_PK )
{
if( IsForceAttack() )
{
;
}
#if __VER >= 8 // __S8_PK
else if( !pOther->IsChaotic() )
{
bAble = FALSE;
}
#else // __VER >= 8 // __S8_PK
else if( !( IsMode( FREEPK_MODE ) || ( g_Neuz.m_NeuzEnemy.IsPKing( pOther->GetId() ) ) || pOther->IsChaotic() ) )
{
bAble = FALSE;
}
#endif // __VER >= 8 // __S8_PK
}
}
}
return bAble;
}
#endif // CLIENT
#ifdef __WORLDSERVER
BOOL CMover::IsPVPInspection( CMover* pMover, int nFlag )
{
int nError = 0;
DWORD dwAttr = GetPKPVPRegionAttr();
#if __VER >= 8 // 8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
DWORD dwWorldIDtmp = 0;
DWORD dwDestWorldIDtmp = 1;
if( GetWorld() && pMover->GetWorld() )
{
dwWorldIDtmp = GetWorld()->GetID();
dwDestWorldIDtmp = pMover->GetWorld()->GetID();
}
#endif // __VER >= 8
switch( nFlag )
{
case 1: // 개인 PVP
{
// 1
if( abs( GetLevel() - pMover->GetLevel() ) >= 30 ) // 레벨 30이상 나는것
{
((CUser*)this)->AddDefinedText( TID_PK_LEVEL_GAP, "" ); // 레벨이 30이상 차이가 나면 PVP를 할수 없습니다
return FALSE;
}
// 1 // 2 // 3 // 4 // 5
#if __VER >= 8 // 8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
if( ( nError = IsPVPInspectionBase( dwAttr,dwDestWorldIDtmp ) ) == 0 )
{
nError = pMover->IsPVPInspectionBase( dwAttr ,dwWorldIDtmp);
}
#else // __VER >= 8
if( ( nError = IsPKPVPInspectionBase( dwAttr ) ) == 0 )
{
nError = pMover->IsPKPVPInspectionBase( dwAttr );
}
#endif // __VER >= 8
if( nError != 0 )
{
switch( nError )
{
case 1:
((CUser*)this)->AddDefinedText( TID_PK_SAFETY_NO, "" ); // 안전영역에서는 PVP할수 없습니다
break;
case 2:
((CUser*)this)->AddDefinedText( TID_PK_SAME_NO, "" ); // 같은영역에 있어야 PVP를 할수 있습니다
break;
case 3:
((CUser*)this)->AddDefinedText( TID_PK_CHANGEJOB_NO, "" ); // 1차전직 이후에 PVP를 할수 있습니다
break;
}
return FALSE;
}
return TRUE;
}
case 2: // 극단 PVP
{
CParty* pSrc = g_PartyMng.GetParty( m_idparty );
CParty* pDest = g_PartyMng.GetParty( pMover->m_idparty );
if( pSrc && pDest )
{
DWORD dwTick = GetTickCount();
u_long anPlayer[MAX_PTMEMBER_SIZE*2];
int nSize = 0;
for( int i = 0; i < pSrc->GetSizeofMember(); i++ )
anPlayer[nSize++] = pSrc->GetPlayerId( i );
for( i = 0; i < pDest->GetSizeofMember(); i++ )
anPlayer[nSize++] = pDest->GetPlayerId( i );
CUser* pLeaderSrc = (CUser*)pSrc->GetLeader();
CUser* pLeaderDest = (CUser*)pDest->GetLeader();
if( IsValidObj( (CObj*)pLeaderSrc ) && IsValidObj( (CObj*)pLeaderDest ) )
{
if( abs( pLeaderSrc->GetLevel() - pLeaderDest->GetLevel() ) >= 30 )
{
((CUser*)this)->AddDefinedText( TID_PK_LEVEL_GAP, "" ); // 레벨이 30이상 차이가 나면 PVP를 할수 없습니다
return FALSE;
}
}
else
{
//
return FALSE;
}
for( i = 0; i < nSize; i++ )
{
CUser* pPlayer = g_UserMng.GetUserByPlayerID( anPlayer[i] );
if( IsValidObj( (CObj*)pPlayer ) )
{
#if __VER >= 8 // 8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
if( ( nError = pPlayer->IsPVPInspectionBase( dwAttr,dwWorldIDtmp ) ) )
#else // __VER >= 8
if( ( nError = pPlayer->IsPKPVPInspectionBase( dwAttr ) ) )
#endif // __VER >= 8
{
if( nError != 0 )
{
switch( nError )
{
case 1:
((CUser*)this)->AddDefinedText( TID_PK_SAFETY_NO, "" ); // 안전영역에서는 PVP할수 없습니다
break;
case 2:
((CUser*)this)->AddDefinedText( TID_PK_SAME_NO, "" ); // 같은영역에 있어야 PVP를 할수 있습니다
break;
case 3:
((CUser*)this)->AddDefinedText( TID_PK_CHANGEJOB_NO, "" ); // 1차전직 이후에 PVP를 할수 있습니다
break;
}
return FALSE;
}
}
}
}
return TRUE;
}
return FALSE;
}
}
return TRUE;
}
#endif // __WORLDSERVER
int CMover::IsPKPVPInspectionBase( DWORD dwRegionAttr, BOOL bPVP )
{
DWORD dwAttr = GetPKPVPRegionAttr();
if( dwRegionAttr == RA_SAFETY ) // 안전지역 검사
return 1;
if( dwRegionAttr != dwAttr ) // 같은지역에 있는지 검사
return 2;
#ifdef __CLIENT
if( GetAsyncKeyState( VK_MENU ) & 0x8000 )
return 9;
#endif // __CLIENT
if( bPVP && (dwAttr == RA_FIGHT || dwAttr != RA_PK) ) // PVP나 Penalty 지역이면 검사
{
if( IsBaseJob() )
return 3;
}
#if __VER >= 8 // __S8_PK
if( !bPVP && GetLevel() <= prj.m_PKSetting.nLimitLevel ) // PK
return 5;
#endif // __VER >= 8 // __S8_PK
if( bPVP )
{
if( m_nDuelState != 0 )
return 9;
}
if( IsFly() )
return 1;
if( m_idWar > 0 )
return 1;
return 0;
}
//8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
#if __VER >= 8 // 8차 듀얼존에 관계없이 PVP가능하게함 Neuz, World
int CMover::IsPVPInspectionBase( DWORD dwRegionAttr,DWORD dwWorldID, BOOL bPVP )
{
#ifdef __CLIENT
if( GetAsyncKeyState( VK_MENU ) & 0x8000 )
return 9;
#endif // __CLIENT
if( IsBaseJob() )
return 3;
if( bPVP )
{
if( m_nDuelState != 0 )
return 9;
}
if(GetWorld() && GetWorld()->GetID() == WI_WORLD_GUILDWAR)
return 10;
if(GetWorld() && GetWorld()->GetID() != dwWorldID)
return 2;
if( IsFly() )
return 1;
if( m_idWar > 0 )
return 1;
#ifdef __QUIZ
if( GetWorld() && GetWorld()->GetID() == WI_WORLD_QUIZ )
return 1;
#endif // __QUIZ
return 0;
}
#endif // __VER >= 8
BOOL CMover::SubPKPVPInspectionBase( CMover* pMover, CMover* pMover1, DWORD dwPKAttr, int nFlag )
{
if( IsBaseJob() ) // 전직을 안햇음
{
#ifdef __CLIENT
g_WndMng.PutString( prj.GetText( TID_PK_CHANGEJOB_NO ), NULL, prj.GetTextColor( TID_PK_CHANGEJOB_NO ) );
#endif // __CLIENT
#ifdef __WORLDSERVER
((CUser*)this)->AddDefinedText( TID_PK_CHANGEJOB_NO, "" ); // 1차전직 이후에 PVP를 할수 있습니다
if( IsValidObj( pMover ) )
((CUser*)pMover)->AddDefinedText( TID_PK_CHANGEJOB_NO, "" ); // 1차전직 이후에 PVP를 할수 있습니다
#endif // __WORLDSERVER
// pMover->PrintString( pMover1, TID_GAME_PVP_LOWLEVEL2 );
return FALSE;
}
if( IsFly() ) // 날고 있음
{
#ifdef __CLIENT
g_WndMng.PutString( prj.GetText( TID_PK_NOFLIGHT_DURING ), NULL, prj.GetTextColor( TID_PK_NOFLIGHT_DURING ) ); // 비행중이면 듀얼을 할수 없습니다
#endif // __CLIENT
#ifdef __WORLDSERVER
((CUser*)this)->AddDefinedText( TID_PK_NOFLIGHT_DURING, "" ); // 비행중이면 듀얼을 할수 없습니다
if( IsValidObj( pMover ) )
((CUser*)pMover)->AddDefinedText( TID_PK_NOFLIGHT_DURING, "" ); // 비행중이면 듀얼을 할수 없습니다
#endif // __WORLDSERVER
// pMover->PrintString( pMover1, TID_GAME_PVP_LOWLEVEL2 );
return FALSE;
}
#ifdef __WORLDSERVER
if( m_idWar ) // 전쟁중엔 듀얼, PK 못함.
{
if( g_eLocal.GetState( EVE_GUILDWAR ) )
{
pMover->PrintString( pMover1, TID_GAME_GUILDWARERRORDUEL ); // 전쟁중엔 듀얼 못함다.
return FALSE;
}
}
else
{
if( m_nDuelState != 0 )
{
return FALSE;
}
}
#endif __WORLDSERVER
if( IsRegionAttr( dwPKAttr ) == FALSE ) // 같은 지역에 있는지 확인
{
#ifdef __CLIENT
g_WndMng.PutString( prj.GetText( TID_PK_SAME_NO ), NULL, prj.GetTextColor( TID_PK_SAME_NO ) );
#endif // __CLIENT
#ifdef __WORLDSERVER
((CUser*)this)->AddDefinedText( TID_PK_SAME_NO, "" ); // 같은영역에 있어야 PVP를 할수 있습니다
if( IsValidObj( pMover ) )
((CUser*)pMover)->AddDefinedText( TID_PK_SAME_NO, "" ); // 같은영역에 있어야 PVP를 할수 있습니다
#endif // __WORLDSERVER
// pMover->PrintString( pMover1, TID_GAME_PVP_SAFEZONENOATTACK ); //g_WndMng.PutString( prj.GetText( TID_GAME_PVP_SAFEZONENOATTACK ), NULL, prj.GetTextColor( TID_GAME_PVP_SAFEZONENOATTACK ) );
return FALSE;
}
return TRUE;
}
void CMover::PrintString( CMover* pMover, DWORD dwId )
{
#ifdef __CLIENT
g_WndMng.PutString( prj.GetText( dwId ), NULL, prj.GetTextColor( dwId ) );
#endif // __CLIENT
#ifdef __WORLDSERVER
((CUser*)this)->AddDefinedText( dwId, "" );
if( IsValidObj( pMover ) )
((CUser*)pMover)->AddDefinedText( dwId, "" );
#endif // __WORLDSERVER
}
// this는 공격자
// this가 pTarget을 스틸하려는지 검사.
// pTarget은 반드시 IsValid 체크를 하고 넘어와야 한다.
#ifdef __WORLDSERVER
int CMover::IsSteal( CMover *pTarget )
{
if( IsNPC() || ::GetLanguage() == LANG_JAP )
return 0; // 공격자가 NPC면 스틸 체크대상 아님.
if( ::GetLanguage() == LANG_THA && pTarget->GetIndex() == MI_MRPUMPKIN5 ) // 태국의 경우 괴수 미스터펌킨은 스틸이 허용됨.
return 0;
if( pTarget->GetIndex() == MI_DEMIAN5 || pTarget->GetIndex() == MI_KEAKOON5 || pTarget->GetIndex() == MI_MUFFRIN5 )
return 0; // 얘들은 이벤트몹이므로 아무나 스틸 가능
// 플레이어만 여기로 들어온다.
#if __VER >= 8 // __S8_PK
if( pTarget->IsNPC() ) // 공격자:플레이어, 맞는자:NPC
#else // __VER >= 8 // __S8_PK
if( pTarget->IsNPC() || (pTarget->IsPlayer() && pTarget->IsChaotic() == FALSE) ) // 공격자:플레이어, 맞는자:NPC 혹은 착한사람. (슬로터는 다구리당해도 된다).
#endif // __VER >= 8 // __S8_PK
{
BOOL bStealCheck = TRUE;
if( pTarget->m_idTargeter == NULL_ID )
{
return 0; //타겟을를 누군가가 찜한 흔적이 없으면 스틸아님.
}
CMover *pOtherPlayer = prj.GetMover( pTarget->m_idTargeter ); // pTarget를 찜한 다른 유저.
if( IsValidObj(pOtherPlayer) )
{
// 공격자가 파티가 있고 pTarget를 때렸던 사람이 같은 파티면 스틸이 아니다.
if( m_idparty && (pOtherPlayer->m_idparty == m_idparty) )
bStealCheck = FALSE;
if( m_idWar && m_idGuild && (pOtherPlayer->m_idGuild == m_idGuild) ) // 전쟁중에 나랑같은 길드끼리 치는건 스틸이 아니다.
bStealCheck = FALSE;
if( g_eLocal.GetState( EVE_SCHOOL ) )
bStealCheck = FALSE;
if( pTarget->GetProp()->dwClass == RANK_SUPER ) // 보스몹은 스틸없음.
bStealCheck = FALSE;
} else
bStealCheck = FALSE; // pTarget를 때렸던 유저가 유효하지 않으면 스틸이 아니다.
if( bStealCheck &&
pTarget->m_idTargeter != NULL_ID && pTarget->m_idTargeter != GetId()) // pTarget를 찜한놈이 있고 그게 현재공격자가 아니라면 스틸.
{
((CUser*)this)->AddDefinedText( TID_GAME_PRIORITYMOB, "" ); // 몬스터가 다른캐릭터랑 전투중임다.
return 1; // 스틸.
}
}
return 0; // 스틸이 아님.
}
//
// 죽었을때 경험치 깎는 부분.
//
void CMover::GetDieDecExp( int nLevel, FLOAT& fRate, FLOAT& fDecExp, BOOL& bPxpClear, BOOL& bLvDown )
{
#if __VER >= 8
bPxpClear = FALSE;
// HP회복수치(%)
DWORD veci = 0;
for( veci = 0 ; veci < prj.m_vecRevivalPenalty.size() ; ++veci )
{
if( veci == 0 && nLevel <= prj.m_vecRevivalPenalty[veci].nLevel )
break;
if( veci != 0 && prj.m_vecRevivalPenalty[veci-1].nLevel < nLevel && nLevel <= prj.m_vecRevivalPenalty[veci].nLevel )
break;
}
if( prj.m_vecRevivalPenalty.size() <= veci )
{
veci = prj.m_vecRevivalPenalty.size()-1;
}
fRate = (float)prj.m_vecRevivalPenalty[veci].nValue / 10000.0f;
// 경험치다운(%)
for( veci = 0 ; veci < prj.m_vecDecExpPenalty.size() ; ++veci )
{
if( veci == 0 && nLevel <= prj.m_vecDecExpPenalty[veci].nLevel )
break;
if( veci != 0 && prj.m_vecDecExpPenalty[veci-1].nLevel < nLevel && nLevel <= prj.m_vecDecExpPenalty[veci].nLevel )
break;
}
if( prj.m_vecDecExpPenalty.size() <= veci )
{
veci = prj.m_vecDecExpPenalty.size()-1;
}
fDecExp = (float)prj.m_vecDecExpPenalty[veci].nValue / 10000.0f;
// 레벨다운(유/무)
for( veci = 0 ; veci < prj.m_vecLevelDownPenalty.size() ; ++veci )
{
if( veci == 0 && nLevel <= prj.m_vecLevelDownPenalty[veci].nLevel )
break;
if( veci != 0 && prj.m_vecLevelDownPenalty[veci-1].nLevel < nLevel && nLevel <= prj.m_vecLevelDownPenalty[veci].nLevel )
break;
}
if( prj.m_vecLevelDownPenalty.size() <= veci )
{
veci = prj.m_vecLevelDownPenalty.size()-1;
}
bLvDown = (prj.m_vecLevelDownPenalty[veci].nValue)? TRUE : FALSE;
#else // __VER >= 8
if( nLevel == 1 ) { fRate = 0.8f; fDecExp = 0.0f ; bPxpClear = FALSE; bLvDown = FALSE; }
else if( nLevel == 2 ) { fRate = 0.6f; fDecExp = 0.0f ; bPxpClear = FALSE; bLvDown = FALSE; }
else if( nLevel <= 5 ) { fRate = 0.5f; fDecExp = 0.0f ; bPxpClear = FALSE; bLvDown = FALSE; }
else if( nLevel <= 10 ) { fRate = 0.4f; fDecExp = 0.0f ; bPxpClear = TRUE ; bLvDown = FALSE; }
else if( nLevel <= 15 ) { fRate = 0.3f; fDecExp = 0.02f; bPxpClear = TRUE ; bLvDown = FALSE; }
else { fRate = 0.3f; fDecExp = 0.03f; bPxpClear = TRUE ; bLvDown = TRUE; }
#endif // __VER >= 8
}
#if __VER >= 8 // __S8_PK
void CMover::GetDieDecExpRate( FLOAT& fDecExp, DWORD dwDestParam, BOOL bResurrection )
{
// 로드스타/라이트로 부활한것은 경험치 하락.
if( dwDestParam != 0 )
{
FLOAT fAddDec = (float)(100 - dwDestParam) / 100.0f;
fDecExp = fDecExp - (fDecExp * fAddDec);
}
if( IsChaotic() && ( IsSMMode( SM_REVIVAL ) || bResurrection ) )
fDecExp = fDecExp * 0.9f;
else if( IsSMMode( SM_REVIVAL ) )
fDecExp = 0.0f;
}
#else // __VER >= 8 // __S8_PK
void CMover::GetDieDecExpRate( FLOAT& fDecExp, DWORD dwDestParam, int nSlaughter )
{
// 로드스타/라이트로 부활한것은 경험치 하락.
if( dwDestParam != 0 )
{
FLOAT fAddDec = (float)(100 - dwDestParam) / 100.0f;
fDecExp = fDecExp - (fDecExp * fAddDec);
}
// 카르마 등급은 기존의 사망시 경험치 하락에도 영향을 미친다.
KarmaProp* pProp = prj.GetKarmaProp( nSlaughter );
if( pProp )
{
//fDecExp = ( fDecExp * (1.0f + ( 30.0f / 100.0f) ));
fDecExp = ( fDecExp * (1.0f + ( (float)pProp->nSubtractExpRate / 100.0f) ));
}
}
#endif // __VER >= 8 // __S8_PK
#if __VER >= 8 // __S8_PK
float CMover::SubDieDecExp( BOOL bTransfer, DWORD dwDestParam, BOOL bResurrection )
#else // __VER >= 8 // __S8_PK
float CMover::SubDieDecExp( BOOL bTransfer, DWORD dwDestParam )
#endif // __VER >= 8 // __S8_PK
{
if( IsNPC() )
return 0.0f;
float fRate = 0.1f, fDecExp = 0.0f;
BOOL bPxpClear = FALSE, bLvDown = FALSE;
int nLevel = GetLevel();
GetDieDecExp( nLevel, fRate, fDecExp, bPxpClear, bLvDown );
if( m_bLastPK ) // 무조건 경험치 안깍는다...
return fRate;
if( m_bGuildCombat )
return fRate;
if( m_bLastDuelParty )
{
m_bLastDuelParty = FALSE;
return fRate;
}
#if __VER >= 8 // __CSC_VER8_5
#if __VER < 12 // __ANGEL_NODIE
( (CUser*)this )->RemoveAngel();
#endif // __ANGEL_NODIE
#endif // __CSC_VER8_5
//#if __VER < 8
bLvDown = FALSE; // 사망 시 경험치 하락으로 인한 레벨 하락 막기
//#endif // __VER < 8
if( fDecExp )
{
if( IsAfterDeath() == FALSE )
{
m_nDeathExp = m_nExp1; // 현재 경험치를 죽었을 때 경험치에 기록
m_nDeathLevel = m_nLevel; // 현재 레벨 기록
}
#if __VER >= 8 // __S8_PK
GetDieDecExpRate( fDecExp, dwDestParam, bResurrection );
#else // __VER >= 8 // __S8_PK
GetDieDecExpRate( fDecExp, dwDestParam, m_nSlaughter );
#endif // __VER >= 8 // __S8_PK
#if __VER >= 8 // __S8_PK
if( bResurrection == FALSE && IsSMMode( SM_REVIVAL ) )
((CUser*)this)->SetSMMode( SM_REVIVAL, 0 );
bLvDown = DecExperiencePercent( fDecExp, bPxpClear, bLvDown );
#else // __VER >= 8 // __S8_PK
if( IsSMMode( SM_REVIVAL ) )
((CUser*)this)->SetSMMode( SM_REVIVAL, 0 );
else
bLvDown = DecExperiencePercent( fDecExp, bPxpClear, bLvDown );
#endif // __VER >= 8 // __S8_PK
if( bTransfer )
{
if( bLvDown ) // 레벨 다운이 되었는가?
{
g_UserMng.AddSetLevel( this, (WORD)m_nLevel ); // this이외의 주변에 레벨변경정보를 보냄.
((CUser *)this)->AddSetGrowthLearningPoint( m_nRemainGP ); // 해당유저에게 GP변경정보를 보냄.
}
else
( (CUser *)this )->AddSetExperience( GetExp1(), (WORD)m_nLevel, m_nSkillPoint, m_nSkillLevel, m_nDeathExp, (WORD)m_nDeathLevel ); // 해당유저에게 exp1,exp2변경된 정보를 보냄.
}
}
return fRate; // 부활할때 얼마의 HP를 회복할꺼냐.
}
#endif // WORLDSERVER
BOOL CMover::DropItemByDied( CMover* pAttacker )
{
BOOL bResult;
OBJID objid = GetMaxEnemyHitID();
if( objid != NULL_ID )
{
CMover* pMover = prj.GetMover( objid );
if( IsValidObj( pMover ) )
bResult = DropItem( pMover );
else
objid = NULL_ID;
}
if( objid == NULL_ID )
bResult = DropItem( pAttacker );
return bResult;
}
// 몹이 죽어서 아이템을 드랍할때 사용
// 클라는 이쪽으로 안들어온다.
// 죽어서 물건을 떨어트리는넘이 this다.
BOOL CMover::DropItem( CMover* pAttacker )
{
MoverProp* lpMoverProp = GetProp();
#ifdef __WORLDSERVER
if( pAttacker->IsPlayer() && IsNPC() )
{
#ifdef __VTN_TIMELIMIT
// mulcom BEGIN100315 베트남 시간 제한
if( ::GetLanguage() == LANG_VTN )
{
if( pAttacker->m_nAccountPlayTime > MIN( 300 ) )
{
return TRUE;
}
}
// mulcom END100315 베트남 시간 제한
#endif // __VTN_TIMELIMIT
if( !lpMoverProp )
return FALSE;
if( m_nQuestKeeping > 0 )
{
CGuildQuestProcessor* pProcessor = CGuildQuestProcessor::GetInstance();
GUILDQUESTELEM* pElem = pProcessor->GetGuildQuest( m_nQuestKeeping );
if( pElem && pElem->objidWormon == GetId() )
{
CGuild* pGuild = pAttacker->GetGuild();
if( pGuild )
{
pGuild->SetQuest( pElem->nId, pElem->ns );
g_dpDBClient.SendUpdateGuildQuest( pGuild->m_idGuild, pElem->nId, pElem->ns );
pElem->nProcess = GQP_GETITEM;
pElem->dwEndTime = GetTickCount() + MIN( 20 );
pElem->ns = pElem->nf = 0;
pElem->nState = 0;
pElem->objidWormon = NULL_ID;
}
}
}
if( m_nPartyQuestKeeping > 0 )
{
CPartyQuestProcessor* pProcessor = CPartyQuestProcessor::GetInstance();
PARTYQUESTELEM* pElem = pProcessor->GetPartyQuest( m_nPartyQuestKeeping );
if( pElem && pElem->objidWormon == GetId() )
{
CParty* pParty = g_PartyMng.GetParty( pAttacker->m_idparty );
if( pParty )
{
pElem->nProcess = PQP_GETITEM;
pElem->dwEndTime = GetTickCount() + MIN( 20 );
pElem->ns = pElem->nf = 0;
pElem->nState = 0;
pElem->objidWormon = NULL_ID;
pProcessor->SendQuestLimitTime( PQP_GETITEM, MIN( 20 ), pAttacker->m_idparty );
}
}
}
if( ( pAttacker->m_nLevel - (int)lpMoverProp->dwLevel ) < 10 )
{
int nNum = 0;
CEventItem* pEventItem = CEventGeneric::GetInstance()->GetItem( &nNum );
while( pEventItem )
{
#ifdef __BUGFIX_0326
if( lpMoverProp->dwFlying ) //
{
CItemElem itemElem;
itemElem.m_dwItemId = pEventItem->m_dwItemId;
itemElem.m_nItemNum = nNum;
itemElem.SetSerialNumber();
if( pAttacker->CreateItem( &itemElem ) == TRUE )
{
ItemProp* pItemProp = itemElem.GetProp();
if( pItemProp )
( (CUser*)pAttacker )->AddDefinedText( TID_GAME_REAPITEM, "\"%s\"", pItemProp->szName );
}
}
else
#endif // __BUGFIX_0326
{
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = pEventItem->m_dwItemId;
pItemElem->m_nItemNum = nNum;
pItemElem->m_nHitPoint = -1;
pItemElem->SetSerialNumber();
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
pItem->m_idOwn = pAttacker->GetId();
pItem->m_dwDropTime = timeGetTime();
pItem->m_bDropMob = TRUE;
pItem->SetIndex( D3DDEVICE, pItem->m_pItemBase->m_dwItemId );
D3DXVECTOR3 vPos = GetPos();
vPos.x += ( xRandomF(2.0f) - 1.0f );
vPos.z += ( xRandomF(2.0f) - 1.0f );
vPos.y = GetPos().y;
pItem->SetPos( vPos );
GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
}
pEventItem = CEventGeneric::GetInstance()->GetItem( &nNum );
}
#if __VER >= 9 // __EVENTLUA
map<DWORD, int> mapItemList = prj.m_EventLua.GetItem( lpMoverProp->dwLevel );
for( map<DWORD, int>::iterator it=mapItemList.begin(); it!=mapItemList.end(); it++ )
{
#ifdef __BUGFIX_0326
if( lpMoverProp->dwFlying ) //
{
CItemElem itemElem;
itemElem.m_dwItemId = it->first;
itemElem.m_nItemNum = it->second;
itemElem.SetSerialNumber();
if( pAttacker->CreateItem( &itemElem ) == TRUE )
{
ItemProp* pItemProp = itemElem.GetProp();
if( pItemProp )
( (CUser*)pAttacker )->AddDefinedText( TID_GAME_REAPITEM, "\"%s\"", pItemProp->szName );
}
}
else
#endif // __BUGFIX_0326
{
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = it->first;
pItemElem->m_nItemNum = it->second;
pItemElem->m_nHitPoint = -1;
pItemElem->SetSerialNumber();
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
pItem->m_idOwn = pAttacker->GetId();
pItem->m_dwDropTime = timeGetTime();
pItem->m_bDropMob = TRUE;
pItem->SetIndex( D3DDEVICE, pItem->m_pItemBase->m_dwItemId );
D3DXVECTOR3 vPos = GetPos();
vPos.x += ( xRandomF(2.0f) - 1.0f );
vPos.z += ( xRandomF(2.0f) - 1.0f );
vPos.y = GetPos().y;
pItem->SetPos( vPos );
GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
}
}
#endif // __EVENTLUA
}
QUESTITEM* pQuestItem;
short nNum;
u_long uSizeOfQuestItem = lpMoverProp->m_QuestItemGenerator.GetSize();
for( u_long i = 0; i < uSizeOfQuestItem; i++ )
{
pQuestItem = lpMoverProp->m_QuestItemGenerator.GetAt( i );
LPQUEST lpQuest = pAttacker->GetQuest( pQuestItem->dwQuest );
if( lpQuest && lpQuest->m_nState == pQuestItem->dwState )
{
DWORD dwProbability = pQuestItem->dwProbability;
if( pQuestItem->dwQuest == QUEST_VALENTINE || pQuestItem->dwQuest == QUEST_WHITEDAY )
{
float f;
int d = pAttacker->m_nLevel - (int)lpMoverProp->dwLevel;
if( d <= 1 ) f = 1.0f;
else if( d <= 2 ) f = 0.8f;
else if( d <= 4 ) f = 0.6f;
else if( d <= 7 ) f = 0.3f;
else f = 0.1f;
dwProbability = (DWORD)( dwProbability * f );
}
if( xRandom( 3000000000 ) <= dwProbability )
{
if( pQuestItem->dwNumber == 0 )
Error( "CMover::DropItem : %s의 quest item drop %d번째의 dwNumber가 0", GetName(), i );
nNum = (short)( xRandom( pQuestItem->dwNumber ) + 1 );
if( pQuestItem->dwIndex == 0 )
{
WriteLog( "%s, %d\r\n\t%s", __FILE__, __LINE__, lpMoverProp->szName );
break;
}
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
CParty* pParty = g_PartyMng.GetParty( pAttacker->m_idparty );
if( pParty && pParty->IsMember( pAttacker->m_idPlayer ) ) // party
{
for( int j = 0; j < pParty->GetSizeofMember(); ++j )
{
PartyMember* pPartyMember = &pParty->m_aMember[j];
CMover* pMember = prj.GetUserByID( pPartyMember->m_uPlayerId );
if( !IsValidObj( pMember ) || !IsValidArea( pMember, 64.0f ) )
continue;
LPQUEST pMemberQuest = pMember->GetQuest( pQuestItem->dwQuest );
if( pMemberQuest && pMemberQuest->m_nState == pQuestItem->dwState )
{
BYTE nId;
CItemElem itemElem;
itemElem.m_dwItemId = pQuestItem->dwIndex;
itemElem.m_nItemNum = nNum;
itemElem.m_nHitPoint = -1;
if( pMember->CreateItem( &itemElem, &nId ) == FALSE )
{
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = pQuestItem->dwIndex;
pItemElem->m_nItemNum = nNum;
ItemProp* pItemProp = pItemElem->GetProp();
if( pItemProp )
pItemElem->m_nHitPoint = pItemProp->dwEndurance;
pItemElem->SetSerialNumber();
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
if( pItemElem->m_dwItemId == 0 )
Error("DropItem:1st %s\n", GetName() );
pItem->SetIndex( D3DDEVICE, pItemElem->m_dwItemId );
pItem->SetPos( pMember->GetPos() );
pItem->SetAngle( (float)( xRandom( 360 ) ) );
pItem->m_idHolder = pMember->m_idPlayer;
pItem->m_dwDropTime = timeGetTime();
pMember->GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
}
else
{
( (CUser*)pMember )->AddDefinedText( TID_EVE_REAPITEM, "\"%s\"", prj.GetItemProp( pQuestItem->dwIndex )->szName );
CItemBase* pItemBase = pMember->GetItemId( nId );
if( pItemBase )
{
CItemElem* pItemElem = (CItemElem*)pItemBase;
LogItemInfo aLogItem;
aLogItem.Action = "Q";
aLogItem.SendName = pMember->m_szName;
aLogItem.RecvName = "QUEST";
aLogItem.WorldId = pMember->GetWorld()->GetID();
aLogItem.Gold = aLogItem.Gold2 = pMember->GetGold();
g_DPSrvr.OnLogItem( aLogItem, pItemElem, pItemElem->m_nItemNum );
}
}
}
}
}
else // solo
{
BYTE nId;
CItemElem itemElem;
itemElem.m_dwItemId = pQuestItem->dwIndex;
itemElem.m_nItemNum = nNum;
itemElem.m_nHitPoint = -1;
if( pAttacker->CreateItem( &itemElem, &nId ) == FALSE )
{
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = pQuestItem->dwIndex;
pItemElem->m_nItemNum = nNum;
ItemProp* pItemProp = pItemElem->GetProp();
if( pItemProp )
pItemElem->m_nHitPoint = pItemProp->dwEndurance;
pItemElem->SetSerialNumber();
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
if( pItemElem->m_dwItemId == 0 )
Error("DropItem:1st %s\n", GetName() );
pItem->SetIndex( D3DDEVICE, pItemElem->m_dwItemId );
pItem->SetPos( pAttacker->GetPos() );
pItem->SetAngle( (float)( xRandom( 360 ) ) );
pItem->m_idHolder = pAttacker->m_idPlayer;
pItem->m_dwDropTime = timeGetTime();
pAttacker->GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
}
else
{
( (CUser*)pAttacker )->AddDefinedText( TID_EVE_REAPITEM, "\"%s\"", prj.GetItemProp( pQuestItem->dwIndex )->szName );
CItemBase* pItemBase = pAttacker->GetItemId( nId );
if( pItemBase )
{
CItemElem* pItemElem = (CItemElem*)pItemBase;
LogItemInfo aLogItem;
aLogItem.Action = "Q";
aLogItem.SendName = pAttacker->m_szName;
aLogItem.RecvName = "QUEST";
aLogItem.WorldId = pAttacker->GetWorld()->GetID();
aLogItem.Gold = aLogItem.Gold2 = pAttacker->GetGold();
g_DPSrvr.OnLogItem( aLogItem, pItemElem, pItemElem->m_nItemNum );
}
}
}
#else // __IMPROVE_QUEST_INTERFACE
int nMemberSize = 0;
CMover* pMember;
CMover* apMember[MAX_PTMEMBER_SIZE];
// 1
CParty* pParty = g_PartyMng.GetParty( pAttacker->m_idparty );
if( pParty && pParty->IsMember( pAttacker->m_idPlayer ) )
{
int nPartyMemberSize = pParty->GetSizeofMember();
for( int j = 0; j < nPartyMemberSize; j++ )
{
PartyMember* pPartyMember = &pParty->m_aMember[j];
pMember = prj.GetUserByID( pPartyMember->m_uPlayerId );
if( IsValidObj( pMember ) && IsNearPC( pMember->GetId() ) )
{
LPQUEST pMemberQuest = pMember->GetQuest( pQuestItem->dwQuest );
if( pMemberQuest && pMemberQuest->m_nState == pQuestItem->dwState )
apMember[nMemberSize++] = pMember;
}
}
}
// 3
// 4
CMover* pTakeMover;
if( nMemberSize > 0 )
pTakeMover = apMember[xRandom( nMemberSize )];
else
pTakeMover = pAttacker;
BYTE nId;
CItemElem itemElem;
itemElem.m_dwItemId = pQuestItem->dwIndex;
itemElem.m_nItemNum = nNum;
itemElem.m_nHitPoint = -1;
if( pTakeMover->CreateItem( &itemElem, &nId ) == FALSE )
{
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = pQuestItem->dwIndex;
pItemElem->m_nItemNum = nNum;
ItemProp* pItemProp = pItemElem->GetProp();
if( pItemProp )
pItemElem->m_nHitPoint = pItemProp->dwEndurance;
pItemElem->SetSerialNumber();
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
if( pItemElem->m_dwItemId == 0 ) Error("DropItem:1st %s\n", GetName() );
pItem->SetIndex( D3DDEVICE, pItemElem->m_dwItemId );
pItem->SetPos( pTakeMover->GetPos() );
pItem->SetAngle( xRandom( 360 ) );
pItem->m_idHolder = pTakeMover->m_idPlayer;
pItem->m_dwDropTime = timeGetTime();
pTakeMover->GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
}
else
{
( (CUser*)pTakeMover )->AddDefinedText( TID_EVE_REAPITEM, "\"%s\"", prj.GetItemProp( pQuestItem->dwIndex )->szName );
// 퀘스트 아이템 로그
CItemBase* pItemBase = pTakeMover->GetItemId( nId );
if( pItemBase )
{
CItemElem* pItemElem = (CItemElem*)pItemBase;
LogItemInfo aLogItem;
aLogItem.Action = "Q";
aLogItem.SendName = pTakeMover->m_szName;
aLogItem.RecvName = "QUEST";
aLogItem.WorldId = pTakeMover->GetWorld()->GetID();
aLogItem.Gold = aLogItem.Gold2 = pTakeMover->GetGold();
g_DPSrvr.OnLogItem( aLogItem, pItemElem, pItemElem->m_nItemNum );
}
}
#endif // __IMPROVE_QUEST_INTERFACE
}
}
}
int nloop = 1;
BOOL bUnique = FALSE;
if( pAttacker->m_idparty ) // 내가 파티에 참여 여부
{
CParty* pParty = g_PartyMng.GetParty( pAttacker->m_idparty );
if( pParty )
{
// 순회극단이며 링크어택중이며 단장만 데미지를 높여준다
if( pParty->m_nKindTroup == 1 )
{
if( pParty->m_nModeTime[PARTY_GIFTBOX_MODE] || pParty->m_nModeTime[PARTY_FORTUNECIRCLE_MODE] )
{
#if __VER >= 12 // __PARSKILL1001 //12차 파스킬 아이템 수정 world,core,neuz
if( pParty->m_nModeTime[PARTY_PARSKILL_MODE] )
{
if( pParty->m_nModeTime[PARTY_GIFTBOX_MODE] )
nloop = 2;
if( pParty->m_nModeTime[PARTY_FORTUNECIRCLE_MODE] )
bUnique = TRUE;
}
else
{
CUser* pLeader = g_UserMng.GetUserByPlayerID( pParty->m_aMember[0].m_uPlayerId );
if( IsValidObj( (CObj*)pLeader )/* && pLeader->IsNearPC( (CUser*)pAttacker ) && IsOrigin()*/ )
{
if( pLeader->IsValidArea( pAttacker, 255.0f ) )
{
if( pParty->m_nModeTime[PARTY_GIFTBOX_MODE] )
nloop = 2;
if( pParty->m_nModeTime[PARTY_FORTUNECIRCLE_MODE] )
bUnique = TRUE;
}
}
}
#else //__PARSKILL1001 //12차 파스킬 아이템 수정 world,core,neuz
// 여기서 단장주위를 검색하여 주위이면 할수 잇게 함
CUser* pLeader = g_UserMng.GetUserByPlayerID( pParty->m_aMember[0].m_uPlayerId );
if( IsValidObj( (CObj*)pLeader )/* && pLeader->IsNearPC( (CUser*)pAttacker ) && IsOrigin()*/ )
{
if( pLeader->IsSMMode( SM_PARTYSKILL1 ) || pLeader->IsSMMode( SM_PARTYSKILL15 ) || pLeader->IsSMMode( SM_PARTYSKILL30 ) ) // 여기서 유료 아이템 사용중인지 확인
{
if( pParty->m_nModeTime[PARTY_GIFTBOX_MODE] )
{
nloop = 2;
}
if( pParty->m_nModeTime[PARTY_FORTUNECIRCLE_MODE] )
{
bUnique = TRUE;
}
}
else
{
if( pLeader->IsValidArea( pAttacker, 255.0f ) )
{
if( pParty->m_nModeTime[PARTY_GIFTBOX_MODE] )
{
nloop = 2;
}
if( pParty->m_nModeTime[PARTY_FORTUNECIRCLE_MODE] )
{
bUnique = TRUE;
}
}
}
}
#endif //__PARSKILL1001 //12차 파스킬 아이템 수정 world,core,neuz
}
}
}
}
#if __VER >= 9 // __II_SYS_SYS_SCR_GET
if( pAttacker->HasBuff( BUFF_ITEM, II_SYS_SYS_SCR_GET01 ) )
nloop += 1;
if( pAttacker->HasBuff( BUFF_ITEM, II_SYS_SYS_SCR_GET02 ) )
nloop += 2;
#endif // __II_SYS_SYS_SCR_GET
#ifdef __DST_GIFTBOX
nloop += pAttacker->GetAdjParam( DST_GIFTBOX );
#endif // __DST_GIFTBOX
D3DXVECTOR3 vPos; // 드랍될 위치.
#ifdef __EVENT_MONSTER
// 이벤트 몬스터는 설정에 따라 한번만 드랍한다.
if( CEventMonster::GetInstance()->SetEventMonster( lpMoverProp->dwID ) )
if( !CEventMonster::GetInstance()->IsGiftBoxAble() )
nloop = 1;
#endif // __EVENT_MONSTER
for( int k = 0 ; k < nloop ; k++ )
{
// 아이템 드롭 확률
int nProbability = 100, nPenyaRate = 100;
BOOL bAdjDropRate = TRUE; // 일반적으론 레벨차에 의한 드랍률저하가 이뤄진다.
if( GetIndex() == MI_CLOCKWORK1 ) //레벨차에의한 드랍률저하가 없다.
bAdjDropRate = FALSE;
if( GetIndex() == MI_DEMIAN5 || GetIndex() == MI_KEAKOON5 || GetIndex() == MI_MUFFRIN5 )
bAdjDropRate = FALSE; // 이벤트몹들도 레벨차에의한 드랍률 저하가 없다.
#ifdef __EVENT_MONSTER
if( CEventMonster::GetInstance()->SetEventMonster( lpMoverProp->dwID ) )
bAdjDropRate = FALSE;
#endif // __EVENT_MONSTER
#ifdef __EVENTLUA_SPAWN
if( prj.m_EventLua.IsEventSpawnMonster( lpMoverProp->dwID ) )
bAdjDropRate = FALSE;
#endif // __EVENTLUA_SPAWN
if( bAdjDropRate )
{
int d = pAttacker->m_nLevel - (int)lpMoverProp->dwLevel;
if( d <= 1 ) { nProbability = 100; nPenyaRate = 100; }
else if( d <= 2 ) { nProbability = 80; nPenyaRate = 100; }
else if( d <= 4 ) { nProbability = 60; nPenyaRate = 80; }
else if( d <= 7 ) { nProbability = 30; nPenyaRate = 65; }
else { nProbability = 10; nPenyaRate = 50; }
}
FLOAT fItemDropRate = nProbability * GetItemDropRateFactor( pAttacker );
if( xRandom( 100 ) < fItemDropRate ) // 아이템을 드롭할지 말지 결정. 레벨차가 많이 나면 아예 떨어트리지 않는다.
{
int nSize = lpMoverProp->m_DropItemGenerator.GetSize();
int nNumber = 0;
DROPITEM* lpDropItem;
for( int i = 0; i < nSize; i++ )
{
if( ( lpDropItem = lpMoverProp->m_DropItemGenerator.GetAt( i, bUnique, GetPieceItemDropRateFactor( pAttacker ) ) ) != NULL )
{
if( lpDropItem->dtType == DROPTYPE_NORMAL )
{
DWORD dwNum = lpDropItem->dwNumber;
if( dwNum == (DWORD)-1 )
dwNum = 1;
if( lpMoverProp->dwFlying )
{
CItemElem itemElem;
itemElem.m_dwItemId = lpDropItem->dwIndex;
itemElem.m_nItemNum = (short)( xRandom( dwNum ) + 1 );
itemElem.SetAbilityOption( lpDropItem->dwLevel );
if( pAttacker->CreateItem( &itemElem ) == TRUE )
{ // log
ItemProp* pItemProp = itemElem.GetProp();
if( pItemProp )
{
( (CUser*)pAttacker )->AddDefinedText( TID_GAME_REAPITEM, "\"%s\"", pItemProp->szName );
if( pItemProp->dwItemKind1 == IK1_WEAPON || pItemProp->dwItemKind1 == IK1_ARMOR || ( pItemProp->dwItemKind1 == IK1_GENERAL && pItemProp->dwItemKind2 == IK2_JEWELRY ) )
{
switch( pItemProp->nLog )
{
case 1: g_dpDBClient.SendLogUniqueItem2( pAttacker, itemElem.GetProp(), itemElem.GetAbilityOption() ); break;
case 2: g_dpDBClient.SendLogUniqueItem2( pAttacker, itemElem.GetProp(), 200 ); break;
case 3: g_dpDBClient.SendLogUniqueItem2( pAttacker, itemElem.GetProp(), 100 ); break;
}
}
}
if( lpDropItem->dwNumber != (DWORD)-1 )
nNumber++;
if( (DWORD)( nNumber ) >= lpMoverProp->m_DropItemGenerator.m_dwMax )
break;
}
continue;
}
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = lpDropItem->dwIndex;
pItemElem->m_nItemNum = (short)( xRandom( dwNum ) + 1 );
ItemProp* pItemProp = pItemElem->GetProp();
if( pItemProp )
{
pItemElem->m_nHitPoint = pItemProp->dwEndurance;
pItemElem->SetRandomOpt( CRandomOptItemGen::GetInstance()->GenRandomOptItem( lpMoverProp->dwLevel, (FLOAT)nProbability / 100.0f, pItemProp, lpMoverProp->dwClass ) );
}
pItemElem->SetAbilityOption( lpDropItem->dwLevel ); // 추가 능력치 +1, +2 같은거.
pItemElem->SetSerialNumber();
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
BOOL bJJim = TRUE; // 주인이 있다는걸 표시해야하는 템인가.
if( lpMoverProp->dwClass == RANK_SUPER ) // 보스몹이 드롭한 아이템은 아무나 먹을수 있다.
bJJim = FALSE;
if( GetIndex() == MI_DEMIAN5 || GetIndex() == MI_KEAKOON5 || GetIndex() == MI_MUFFRIN5 )
bJJim = FALSE; // 얘들은 이벤트몹이므로 찜안해놔도 된다. 아무나 먹을수 있음
if( bJJim )
{
pItem->m_idOwn = pAttacker->GetId(); // 이 아이템의 소유가 pAttacker(어태커)꺼란걸 표시.
pItem->m_dwDropTime = timeGetTime(); // 드랍 했을당시의 시간을 기록함.
}
pItem->m_bDropMob = TRUE; // 몹이 죽어서 떨군 돈은 표시를 해둠.
if( pItem->m_pItemBase->m_dwItemId == 0 ) Error("DropItem:2nd %s\n", GetName() );
pItem->SetIndex( D3DDEVICE, pItem->m_pItemBase->m_dwItemId );
vPos = GetPos();
vPos.x += ( xRandomF(2.0f) - 1.0f );
vPos.z += ( xRandomF(2.0f) - 1.0f );
vPos.y = GetPos().y;
#ifdef __EVENT_MONSTER
// 이벤트 몬스터가 드랍한 아이템은 몬스터의 ID를 기억한다(펫이 못 줍게...)
if( CEventMonster::GetInstance()->SetEventMonster( lpMoverProp->dwID ) )
{
// 이벤트 몬스터는 무조건 선점권을 갖는다.
pItem->m_idOwn = pAttacker->GetId();
pItem->m_dwDropTime = timeGetTime();
pItem->m_IdEventMonster = lpMoverProp->dwID;
float fItemDropRange = CEventMonster::GetInstance()->GetItemDropRange();
vPos = GetPos();
vPos.x += ( xRandomF( fItemDropRange ) - (fItemDropRange / 2.0f) );
vPos.z += ( xRandomF( fItemDropRange ) - (fItemDropRange / 2.0f) );
}
#endif // __EVENT_MONSTER
pItem->SetPos( vPos );
GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
if( lpDropItem->dwNumber != (DWORD)-1 )
nNumber++;
if( pItemProp->dwItemKind1 == IK1_WEAPON || pItemProp->dwItemKind1 == IK1_ARMOR || ( pItemProp->dwItemKind1 == IK1_GENERAL && pItemProp->dwItemKind2 == IK2_JEWELRY ) )
{
switch( pItemProp->nLog )
{
case 1: g_dpDBClient.SendLogUniqueItem( pAttacker, pItem, pItemElem->GetAbilityOption() ); // 일반 아이템 +아이템
break;
case 2: g_dpDBClient.SendLogUniqueItem( pAttacker, pItem, 200 ); // 이펙트 아이템
break;
case 3: g_dpDBClient.SendLogUniqueItem( pAttacker, pItem, 100 ); // 유니크 아이템
break;
}
}
if( nNumber == lpMoverProp->m_DropItemGenerator.m_dwMax )
break;
} else
// 돈은 무조건떨어져야 한다.
if( lpDropItem->dtType == DROPTYPE_SEED && k == 0 )
{
int nSeedID = 0;
int nNumGold = lpDropItem->dwNumber + xRandom( lpDropItem->dwNumber2 - lpDropItem->dwNumber ); // Number ~ Number2 사이의 랜덤값.
nNumGold = nNumGold * nPenyaRate / 100;
#ifdef __S1108_BACK_END_SYSTEM
nNumGold = (int)( nNumGold * prj.m_fGoldDropRate * lpMoverProp->m_fPenya_Rate );
if( nNumGold == 0 )
continue;
#else // __S1108_BACK_END_SYSTEM
nNumGold *= prj.m_fGoldDropRate;
#endif // __S1108_BACK_END_SYSTEM
#if __VER >= 9 // __EVENTLUA
nNumGold = (int)( nNumGold * prj.m_EventLua.GetGoldDropFactor() );
#endif // __EVENTLUA
if( lpMoverProp->dwFlying )
{
if( CanAdd( pAttacker->GetGold(), nNumGold ) )
{
pAttacker->AddGold( nNumGold );
( (CUser*)pAttacker )->AddGoldText( nNumGold );
}
}
else
{
// 돈액수에 따라 어떤모양의 시드를 사용할지 결정한다.
if( nNumGold <= (int)( prj.GetItemProp( II_GOLD_SEED1 )->dwAbilityMax ) )
nSeedID = II_GOLD_SEED1;
else if( nNumGold <= (int)( prj.GetItemProp( II_GOLD_SEED2 )->dwAbilityMax ) )
nSeedID = II_GOLD_SEED2;
else if( nNumGold <= (int)( prj.GetItemProp( II_GOLD_SEED3 )->dwAbilityMax ) )
nSeedID = II_GOLD_SEED3;
else
nSeedID = II_GOLD_SEED4;
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = nSeedID;
pItemElem->m_nItemNum = nNumGold; // 돈액수
pItemElem->m_nHitPoint = nNumGold;
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
BOOL bJJim = TRUE;
if( lpMoverProp->dwClass == RANK_SUPER ) // 보스몹이 드롭한 아이템은 아무나 먹을수 있다.
bJJim = FALSE;
if( GetIndex() == MI_DEMIAN5 || GetIndex() == MI_KEAKOON5 || GetIndex() == MI_MUFFRIN5 )
bJJim = FALSE; // 얘들은 이벤트몹이므로 찜안해놔도 된다. 아무나 먹을수 있음
if( bJJim )
{
pItem->m_idOwn = pAttacker->GetId(); // 이 아이템의 소유가 pAttacker(어태커)꺼란걸 표시.
pItem->m_dwDropTime = timeGetTime(); // 드랍 했을당시의 시간을 기록함.
}
pItem->m_bDropMob = TRUE; // 몹이 죽어서 떨군 돈은 표시를 해둠.
if( pItem->m_pItemBase->m_dwItemId == 0 ) Error("DropItem: 3rd %s\n", GetName() );
pItem->SetIndex( D3DDEVICE, pItem->m_pItemBase->m_dwItemId );
vPos = GetPos();
vPos.x += ( xRandomF(2.0f) - 1.0f );
vPos.z += ( xRandomF(2.0f) - 1.0f );
#ifdef __EVENT_MONSTER
// 이벤트 몬스터가 드랍한 아이템은 몬스터의 ID를 기억한다(펫이 못 줍게...)
if( CEventMonster::GetInstance()->SetEventMonster( lpMoverProp->dwID ) )
{
// 이벤트 몬스터는 무조건 선점권을 갖는다.
pItem->m_idOwn = pAttacker->GetId();
pItem->m_dwDropTime = timeGetTime();
pItem->m_IdEventMonster = lpMoverProp->dwID;
float fItemDropRange = CEventMonster::GetInstance()->GetItemDropRange();
vPos = GetPos();
vPos.x += ( xRandomF( fItemDropRange ) - (fItemDropRange / 2.0f) );
vPos.z += ( xRandomF( fItemDropRange ) - (fItemDropRange / 2.0f));
}
#endif // __EVENT_MONSTER
pItem->SetPos( vPos );
GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
}
} // DROPTYPE_SEED
} // if
//////////////
// 여기까지 for-loop안내려오고 continue하는 수도 있으니까 여기다 코드 넣지 말것.
///////////
} // for nSize
nSize = lpMoverProp->m_DropKindGenerator.GetSize();
DROPKIND* pDropKind;
CPtrArray* pItemKindAry;
int nAbilityOption; //, nDropLuck;
BOOL bDrop = FALSE;
for( i = 0; i < nSize; i++ )
{
bDrop = FALSE;
pDropKind = lpMoverProp->m_DropKindGenerator.GetAt( i );
pItemKindAry = prj.GetItemKindAry( pDropKind->dwIK3 );
int nMinIdx = -1, nMaxIdx = -1;
for( int j = pDropKind->nMinUniq; j <= pDropKind->nMaxUniq; j++ )
{
nMinIdx = prj.GetMinIdx( pDropKind->dwIK3, j );
if( nMinIdx != -1 )
break;
}
for( j = pDropKind->nMaxUniq; j >= pDropKind->nMinUniq; j-- )
{
nMaxIdx = prj.GetMaxIdx( pDropKind->dwIK3, j );
if( nMaxIdx != -1 )
break;
}
if( nMinIdx < 0 || nMaxIdx < 0 )
{
#ifdef __INTERNALSERVER
WriteLog( "dropkind, 1, dwIndex = %d, nIndex = %d", lpMoverProp->dwID, i );
#endif // __INTERNALSERVER
continue;
}
ItemProp* pItemProp = (ItemProp*)pItemKindAry->GetAt( nMinIdx + xRandom( nMaxIdx - nMinIdx + 1 ) );
if( NULL == pItemProp )
{
#ifdef __INTERNALSERVER
WriteLog( "dropkind, 2, dwIndex = %d, nIndex = %d", lpMoverProp->dwID, i );
#endif // __INTERNALSERVER
continue;
}
nAbilityOption = xRandom( 11 ); // 0 ~ 10
DWORD dwAdjRand;
for( int k = nAbilityOption; k >= 0; k-- )
{
DWORD dwPrabability = (DWORD)( prj.m_adwExpDropLuck[( pItemProp->dwItemLV > 120? 119: pItemProp->dwItemLV-1 )][k]
* ( (float)lpMoverProp->dwCorrectionValue / 100.0f ) );
dwAdjRand = xRandom( 3000000000 );
if( bUnique && dwPrabability <= 10000000 )
dwAdjRand /= 2;
if( dwAdjRand < dwPrabability )
{
if( lpMoverProp->dwFlying )
{
CItemElem itemElem;
itemElem.m_dwItemId = pItemProp->dwID;
itemElem.m_nItemNum = 1;
itemElem.SetAbilityOption( k );
itemElem.SetRandomOpt( CRandomOptItemGen::GetInstance()->GenRandomOptItem( lpMoverProp->dwLevel, (FLOAT)nProbability / 100.0f, pItemProp, lpMoverProp->dwClass ) );
if( pAttacker->CreateItem( &itemElem ) == TRUE )
{ // log
( (CUser*)pAttacker )->AddDefinedText( TID_GAME_REAPITEM, "\"%s\"", pItemProp->szName );
if( pItemProp->dwItemKind1 == IK1_WEAPON || pItemProp->dwItemKind1 == IK1_ARMOR || ( pItemProp->dwItemKind1 == IK1_GENERAL && pItemProp->dwItemKind2 == IK2_JEWELRY ) )
{
switch( pItemProp->nLog )
{
case 1: g_dpDBClient.SendLogUniqueItem2( pAttacker, itemElem.GetProp(), itemElem.GetAbilityOption() ); break;
case 2: g_dpDBClient.SendLogUniqueItem2( pAttacker, itemElem.GetProp(), 200 ); break;
case 3: g_dpDBClient.SendLogUniqueItem2( pAttacker, itemElem.GetProp(), 100 ); break;
}
}
break;
}
}
CItemElem* pItemElem = new CItemElem;
pItemElem->m_dwItemId = pItemProp->dwID;
pItemElem->m_nItemNum = 1;
pItemElem->m_nHitPoint = pItemProp->dwEndurance;
pItemElem->SetAbilityOption( k );
pItemElem->SetRandomOpt( CRandomOptItemGen::GetInstance()->GenRandomOptItem( lpMoverProp->dwLevel, (FLOAT)nProbability / 100.0f, pItemProp, lpMoverProp->dwClass ) );
pItemElem->SetSerialNumber();
CItem* pItem = new CItem;
pItem->m_pItemBase = pItemElem;
BOOL bJJim = TRUE;
if( lpMoverProp->dwClass == RANK_SUPER ) // 보스몹이 드롭한 아이템은 아무나 먹을수 있다.
bJJim = FALSE;
if( GetIndex() == MI_DEMIAN5 || GetIndex() == MI_KEAKOON5 || GetIndex() == MI_MUFFRIN5 )
bJJim = FALSE; // 얘들은 이벤트몹이므로 찜안해놔도 된다. 아무나 먹을수 있음
if( bJJim )
{
pItem->m_idOwn = pAttacker->GetId();
pItem->m_dwDropTime = timeGetTime();
}
pItem->m_bDropMob = TRUE;
#ifdef __EVENT_MONSTER
if( CEventMonster::GetInstance()->SetEventMonster( lpMoverProp->dwID ) )
{
// 이벤트 몬스터는 무조건 선점권을 갖는다.
pItem->m_idOwn = pAttacker->GetId();
pItem->m_dwDropTime = timeGetTime();
pItem->m_IdEventMonster = lpMoverProp->dwID;
}
#endif // __EVENT_MONSTER
if( pItem->m_pItemBase->m_dwItemId == 0 ) Error("DropItem: 4th %s\n", GetName() );
pItem->SetIndex( D3DDEVICE, pItem->m_pItemBase->m_dwItemId );
pItem->SetPos( GetPos() );
GetWorld()->ADDOBJ( pItem, TRUE, GetLayer() );
bDrop = TRUE;
if( pItemProp->dwItemKind1 == IK1_WEAPON || pItemProp->dwItemKind1 == IK1_ARMOR || ( pItemProp->dwItemKind1 == IK1_GENERAL && pItemProp->dwItemKind2 == IK2_JEWELRY ) )
{
switch( pItemProp->nLog )
{
case 1: g_dpDBClient.SendLogUniqueItem( pAttacker, pItem, pItemElem->GetAbilityOption() ); break;
case 2: g_dpDBClient.SendLogUniqueItem( pAttacker, pItem, 200 ); break;
case 3: g_dpDBClient.SendLogUniqueItem( pAttacker, pItem, 100 ); break;
}
}
break;
}
}
if( GetProp()->dwClass == RANK_SUPER )
{
if( bDrop ) // KIND아이템을 하나 떨어트렸다면
break; // 더이상 떨어트리지 않고 종료.
}
} // for( i = 0; i < nSize; i++ )
} // if( xRandom( 100 ) < fItemDropRate )
} // for( int k = 0 ; k < nloop ; k++ )
}
if( IsNPC() ) // 몹이 죽었을때..
{
MoverProp* pMoverProp = GetProp();
if( pMoverProp->m_nLoot == 2 ) // 2아 d옵션. 아이템 먹고 뱉기까지 하는 옵션.
{
int nSize = m_Inventory.GetSize();
int i;
CItemElem *pElem = NULL;
for( i = 0; i < nSize; i ++ )
{
pElem = m_Inventory.GetAt( i );
if( pElem )
{
D3DXVECTOR3 vPos = GetPos();
#ifdef __WORLDSERVER
vPos.x += ( xRandomF(2.0f) - 1.0f );
vPos.z += ( xRandomF(2.0f) - 1.0f );
#endif
CItem *pItem = DropItem( i, pElem->m_nItemNum, vPos, FALSE );
pItem->m_idOwn = pAttacker->GetId();
pItem->m_dwDropTime = timeGetTime();
}
}
}
}
#endif // __WORLDSERVER
return TRUE;
}
// this오브젝트에다 찜한사람(JJimer -_-;;;) 의 아이디를 박아둬서
// this가 찜당했다는걸 표시.
void CMover::SetJJim( CMover *pJJimer )
{
if( ::GetLanguage() == LANG_THA ) // 태국의 경우
if( GetIndex() == MI_MRPUMPKIN5 ) // 괴수 미스터펌킨은
return; // 스틸이 허용됨.
if( GetProp()->dwClass == RANK_SUPER ) // 슈퍼몹은 스틸 허용.
return;
#ifdef __EVENT_MONSTER
// 이벤트 몬스터는 스틸 허용
if( CEventMonster::GetInstance()->IsEventMonster( GetProp()->dwID ) )
return;
#endif // __EVENT_MONSTER
// 찜한넘은 사람 / 찜당한넘은 NPC일때만.
if( pJJimer->IsPlayer() && IsNPC() ) //this != pJJimer ) // 찜한사람이 사람일경우만 적용./ 자기자신을 찜할순 없다.
{
m_idTargeter = pJJimer->GetId();
}
}
CGuild* CMover::GetGuild()
{
#ifdef __WORLDSERVER
// locked
CGuild* pGuild = g_GuildMng.GetGuild( m_idGuild );
if( pGuild && pGuild->IsMember( m_idPlayer ) )
return pGuild;
return NULL;
#else // __WORLDSERVER
#ifdef __CLIENT
if( m_idGuild > 0 && CMover::GetActiveMover() &&
m_idGuild == CMover::GetActiveMover()->m_idGuild )
{
CGuild* pGuild = g_GuildMng.GetGuild( m_idGuild );
if( pGuild && pGuild->IsMember( m_idPlayer ) )
return pGuild;
return NULL;
}
else
{
return g_GuildMng.GetGuild( m_idGuild );
}
#endif // __CLIENT
#endif // __WORLDSERVER
}
CGuildWar* CMover::GetWar()
{
return g_GuildWarMng.GetWar(m_idWar);
}
#ifdef __WORLDSERVER
// HP, MP, FP회복을 처리한다.
void CMover::ProcessRecovery()
{
if( IsPlayer() == FALSE || IsDie() )
return;
DWORD dwCurTick = g_tmCurrent;
#if __VER < 8 // __S8_PK
// 일정시간마다 카르마 회복
KarmaProp* pProp = prj.GetKarmaProp( m_nSlaughter );
if( pProp->dwKarmaRecoverPoint )
{
if( m_dwKarmaTick == 0 )
{
m_dwKarmaTick = dwCurTick + pProp->dwKarmaRecoverPoint * 1000;
}
else if( dwCurTick > m_dwKarmaTick )
{
m_dwKarmaTick = 0;
ChangeSlaughter( CHANGE_SLAUGHTER_RECOVERY, NULL );
}
}
#endif // __VER < 8 // __S8_PK
if( dwCurTick > m_dwTickDuel ) // 두얼 시작후 1초에 3, 2, 1, Fight
{
if( 100 <= m_nDuelState && m_nDuelState < 200 ) // 100 ~ 200 은 듀얼 시작후 시작 타임
{
--m_nDuelState;
if( 100 == m_nDuelState ) // 마지막 Fight 메세지를 보냄
{
m_nDuelState = 1; // 듀얼 중이라고 세팅
if( m_nDuel == 1 )
{
CMover *pDuelOther = prj.GetMover( m_idDuelOther );
if( pDuelOther )
{
((CUser*)this)->AddDuelStart( pDuelOther->m_idPlayer, 1 ); // Fight
((CUser*)this)->AddDuelCount( 0 );
}
}
else if( m_nDuel == 2 )
{
CParty* pParty = g_PartyMng.GetParty( m_idDuelParty ); // 신청자의 파티꺼냄
if( pParty )
{
LPCSTR pszPartyName;
if( pParty->m_nKindTroup ) // 순회극단
pszPartyName = pParty->m_sParty;
else // 단막극단
#if __VER >= 11 // __SYS_PLAYER_DATA
pszPartyName = CPlayerDataCenter::GetInstance()->GetPlayerString( pParty->GetPlayerId( 0 ) );
#else // __SYS_PLAYER_DATA
pszPartyName = prj.GetPlayerString( pParty->GetPlayerId( 0 ) );
#endif // __SYS_PLAYER_DATA
if( !pszPartyName )
{
Error( "Error Party PVP 2" );
}
else
{
int j;
OBJID pDstMember[ MAX_PTMEMBER_SIZE ];
memset( pDstMember, 0xff, sizeof(pDstMember) );
CMover *pMember2;
for( j = 0; j < pParty->m_nSizeofMember; j ++ )
{
pMember2 = (CMover *)g_UserMng.GetUserByPlayerID( pParty->m_aMember[j].m_uPlayerId );
if( IsValidObj(pMember2) )
pDstMember[j] = pMember2->GetId();
}
// 상대 파티에 대한 정보를 우리멤버들에게 보냄
((CUser *)this)->AddDuelPartyStart( pszPartyName, pParty->m_nSizeofMember, pDstMember, pParty->m_uPartyId, 1 ); // 상대방 멤버의 ID를 다보낸다. 2값으로
((CUser*)this)->AddDuelCount( 0 );
}
}
}
}
else
{
((CUser*)this)->AddDuelCount( m_nDuelState - 100 );
}
}
m_dwTickDuel = dwCurTick + NEXT_TICK_DUEL;
}
if( m_nDuel != 0 && dwCurTick > m_dwTickEndDuel )
{
// 듀얼취소 3분동안 교전이 없었음
if( m_nDuel == 1 )
{
CMover *pDuelOther = prj.GetMover( m_idDuelOther );
if( pDuelOther )
{
pDuelOther->ClearDuel();
( (CUser*)pDuelOther )->AddSetDuel( pDuelOther );
ClearDuel();
( (CUser*)this )->AddSetDuel( this );
}
}
else if( m_nDuel == 2 )
{
CParty* pParty = g_PartyMng.GetParty( m_idparty );
if( pParty && pParty->IsLeader( m_idPlayer ) )
{
u_long uidDuelParty = m_idDuelParty;
CMover *pMember;
CParty* pParty2 = g_PartyMng.GetParty( uidDuelParty );
for( int k = 0 ; k < pParty->m_nSizeofMember ; ++k )
{
pMember = (CMover *)g_UserMng.GetUserByPlayerID( pParty->m_aMember[k].m_uPlayerId );
if( IsValidObj( pMember ) )
{
if( pParty2 )
{
pParty2->DoDuelPartyCancel( pParty );
}
else
{
pParty->DoDuelPartyCancel( NULL );
Error( "CMover::ProcessRecovery : 파티멤버 %s의 정보이상. %d %d", pMember->GetName(), pMember->m_idDuelParty, uidDuelParty );
}
}
}
if( pParty2 )
{
for( int k = 0 ; k < pParty2->m_nSizeofMember ; ++k )
{
pMember = (CMover *)g_UserMng.GetUserByPlayerID( pParty2->m_aMember[k].m_uPlayerId );
if( IsValidObj( pMember ) )
{
pParty->DoDuelPartyCancel( pParty2 );
}
}
}
g_DPCoreClient.SendSetPartyDuel( m_idparty, uidDuelParty, FALSE );
}
}
}
if( m_pActMover->IsSit() )
{
// 앉아있을 때
float fRecovery = 1.0f;
if( dwCurTick <= m_dwTickRecovery )
return;
m_dwTickRecovery = dwCurTick + NEXT_TICK_RECOVERY;
// 파티 PARTY_STRETCHING_MODE일 때
CParty* pParty = g_PartyMng.GetParty( m_idparty );
if( pParty && pParty->IsMember( m_idPlayer ) )
{
if( pParty->m_nKindTroup == 1 && pParty->m_nModeTime[PARTY_STRETCHING_MODE] )
{
#if __VER >= 12 // __PARSKILL1001 //12차 파스킬 아이템 수정 world,core,neuz
BOOL nMItem = FALSE;
CUser* pLeader = g_UserMng.GetUserByPlayerID( pParty->m_aMember[0].m_uPlayerId );
if( pParty->m_nModeTime[PARTY_PARSKILL_MODE] )
{
nMItem = TRUE;
}
else
{
if( IsValidObj( (CObj*)pLeader ) )
{
if( IsValidArea( pLeader, 255.0f ) )
nMItem = TRUE;
}
}
if( nMItem )
{
if( IsValidObj( pLeader ) && ( pLeader->GetJob() == JOB_ASSIST || pLeader->GetJob() == JOB_RINGMASTER || pLeader->GetJob() == JOB_BILLPOSTER ) )
fRecovery = 1.8f;
else
fRecovery = 1.5f;
}
#else //__PARSKILL1001 //12차 파스킬 아이템 수정 world,core,neuz
CUser* pLeader = g_UserMng.GetUserByPlayerID( pParty->m_aMember[0].m_uPlayerId );
if( IsValidObj( (CObj*)pLeader ) )
{
BOOL nMItem = FALSE;
if( pLeader->IsSMMode( SM_PARTYSKILL1 ) || pLeader->IsSMMode( SM_PARTYSKILL15 ) || pLeader->IsSMMode( SM_PARTYSKILL30 ) ) // 여기서 유료 아이템 사용중인지 확인
{
nMItem = TRUE;
}
else
{
if( IsValidArea( pLeader, 255.0f ) )
{
nMItem = TRUE;
}
}
if( nMItem )
{
if( pLeader->GetJob() == JOB_ASSIST || pLeader->GetJob() == JOB_RINGMASTER || pLeader->GetJob() == JOB_BILLPOSTER )
fRecovery = 1.8f;
else
fRecovery = 1.5f;
}
}
#endif //__PARSKILL1001 //12차 파스킬 아이템 수정 world,core,neuz
}
}
else
{
m_idparty = 0;
}
IncHitPoint( (int)( GetHPRecovery() * fRecovery ) );
IncManaPoint( (int)( GetMPRecovery() * fRecovery ) );
IncFatiguePoint( (int)( GetFPRecovery() * fRecovery ) );
}
else
{
// 서있을 때
m_dwTickRecovery = dwCurTick + NEXT_TICK_RECOVERY; // 앉아있기 회복을 막는다.
//if( m_pActMover->IsActAttack() == FALSE )
if( IsAttackMode() == FALSE ) // IsActAttack은 공격동작일 때만, IsAttackMode는 전투중
{
// 어택상태가 아닐때만 일정시간마다 피찬다.
if( dwCurTick > m_dwTickRecoveryStand )
{
m_dwTickRecoveryStand = dwCurTick + NEXT_TICK_RECOVERYSTAND;
#if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans
if( ! (GetAdjParam( DST_CHRSTATE ) & CHS_SETSTONE) )
#endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans
{
IncHitPoint( GetHPRecovery() );
IncManaPoint( GetMPRecovery() );
IncFatiguePoint( GetFPRecovery() );
}
}
}
else
{
// 어택 상태일 때는 계속 시간을 리셋한다.
m_dwTickRecoveryStand = dwCurTick + NEXT_TICK_RECOVERYSTAND;
}
}
}
#endif // __WORLDSERVER
void CMover::AllocShopInventory( LPCHARACTER pCharacter )
{
if( IsVendorNPC() )
{
m_ShopInventory[ 0 ] = new CItemContainer< CItemElem >; m_ShopInventory[ 0 ]->SetItemContainer( ITYPE_ITEM, MAX_VENDOR_INVENTORY );
m_ShopInventory[ 1 ] = new CItemContainer< CItemElem >; m_ShopInventory[ 1 ]->SetItemContainer( ITYPE_ITEM, MAX_VENDOR_INVENTORY );
m_ShopInventory[ 2 ] = new CItemContainer< CItemElem >; m_ShopInventory[ 2 ]->SetItemContainer( ITYPE_ITEM, MAX_VENDOR_INVENTORY );
m_ShopInventory[ 3 ] = new CItemContainer< CItemElem >; m_ShopInventory[ 3 ]->SetItemContainer( ITYPE_ITEM, MAX_VENDOR_INVENTORY );
}
}
BOOL CMover::IsVendorNPC()
{
LPCHARACTER pCharacter = GetCharacter();
if( !pCharacter )
return FALSE;
for( int i = 0; i < MAX_VENDOR_INVENTORY_TAB; i++ )
{
if( pCharacter->m_venderItemAry[i].GetSize() )
return TRUE;
}
#if __VER >= 11 // __CSC_VER11_3
if(pCharacter->m_nVenderType == 1)
for( int i = 0; i < MAX_VENDOR_INVENTORY_TAB; i++ )
{
if( pCharacter->m_venderItemAry2[i].GetSize() )
return TRUE;
}
#endif //__CSC_VER11_3
return FALSE;
}
#ifdef __CLIENT
BOOL CMover::EndMotion()
{
if( !m_pActMover->IsActAttack() &&
!m_pActMover->IsActDamage() &&
!m_pActMover->IsActJump() &&
!m_pActMover->IsFly() &&
!m_pActMover->IsDie() &&
!m_pActMover->IsSit() )
{
SetAngle( GetDegree(GetWorld()->GetCamera()->m_vPos, GetPos()) ); // 목표쪽으로 몸을 돌림.
SetMotion( MTI_LOGOUT, ANILOOP_CONT, MOP_FIXED );
return TRUE;
}
return FALSE;
}
#endif //__CLIENT
BOOL CMover::IsBullet( ItemProp* pItemProp )
{
// 필요총알종류가 지정되어 있다면
if( pItemProp->dwLinkKindBullet != NULL_ID )
{
DWORD dwTip = TID_TIP_NEEDSKILLITEM;
if( pItemProp->dwItemKind3 == IK3_BOW || pItemProp->dwLinkKind == IK3_BOW )
{
dwTip = TID_TIP_NEEDSATTACKITEM;
}
ItemProp *pProp = GetActiveHandItemProp( PARTS_BULLET );
if( pProp )
{
if( pProp->dwItemKind2 != pItemProp->dwLinkKindBullet ) // 필요총알종류랑 다른걸 장착하고 있으면 에러
{
#ifdef __CLIENT
g_WndMng.PutString( prj.GetText( dwTip ), NULL, prj.GetTextColor( dwTip ) );
( (CWndWorld *)g_WndMng.m_pWndWorld )->m_bAutoAttack = FALSE;
#endif // __CLIENT
#ifdef __WORLDSERVER
((CUser*)this)->AddDefinedText( dwTip, "" );
#endif // __WORLDSERVER
return FALSE;
}
} else
{ // 총알(?)이 없어도 에러
#ifdef __CLIENT
g_WndMng.PutString( prj.GetText( dwTip ), NULL, prj.GetTextColor( dwTip ) );
#endif // __CLIENT
#ifdef __WORLDSERVER
((CUser*)this)->AddDefinedText( dwTip, "" );
#endif // __WORLDSERVER
return FALSE;
}
}
return TRUE;
}
#ifdef __WORLDSERVER
// 화살을 nCount대로 삭제
// 화살을 장착되어 있는것을 소모했을시 자동으로 같은 화살을 장착
// 같은 화살인지 체크
void CMover::ArrowDown( int nCount )
{
if( IsNPC() ) return;
CItemElem* pItemElem = m_Inventory.GetEquip( PARTS_BULLET ); // 장착되어 있는 화살 아이템 꺼냄
if( pItemElem )
{
// 장착되어 있는것 모두 소진 되었음. 장착되어 있는 아이템 삭제후
// 인벤토리에서 같은 화살이 있으면 그것을 사용하게 해줌
DWORD dwItemId = pItemElem->m_dwItemId;
BOOL bDoEquip = FALSE;
for( int i = 0 ; i < 100 && 0 < nCount ; i++ ) // 혹 100번은 안나오겠지?
{ // 아이템 사용이 4개인데 아이템 1개짜리가 4개일때 루프가 돌음
BOOL bGetItem = FALSE;
if( pItemElem->m_nItemNum <= nCount )
{
nCount -= pItemElem->m_nItemNum;
pItemElem->m_nItemNum = 0;
bGetItem = TRUE;
}
else
{
pItemElem->m_nItemNum -= nCount;
nCount = 0;
}
UpdateItem( (BYTE)( pItemElem->m_dwObjId ), UI_NUM, pItemElem->m_nItemNum );
if( bGetItem )
{
bDoEquip = FALSE;
pItemElem = m_Inventory.GetAtItemId( dwItemId );
if( pItemElem == NULL )
{
break;
}
bDoEquip = TRUE;
}
}
if( bDoEquip )
{
if( TRUE == DoEquip( pItemElem, TRUE, pItemElem->GetProp()->dwParts ) )
{
g_UserMng.AddDoEquip( this, pItemElem->GetProp()->dwParts, pItemElem, TRUE );
}
}
}
}
#endif // __WORLDSERVER
void CMover::ClearDuel()
{
m_nDuel = 0;
m_idDuelOther = NULL_ID;
m_nDuelState = 0;
m_dwTickEndDuel = ::timeGetTime() + NEXT_TICK_ENDDUEL; // 3 min
SetPKTargetLimit( 10 ); // PK선공을 못하게 막게함
}
void CMover::ClearDuelParty()
{
m_nDuel = 0;
m_idDuelParty = 0;
m_nDuelState = 0;
m_dwTickEndDuel = ::timeGetTime() + NEXT_TICK_ENDDUEL; // 3 min
SetPKTargetLimit( 10 ); // PK선공을 못하게 막게함
}
void CMover::SetPKTargetLimit( int nSec )
{
#if defined( __WORLDSERVER )
m_dwPKTargetLimit = GetTickCount() + SEC( nSec );
#endif // defined( __WORLDSERVER )
}
#if defined(__WORLDSERVER)
BOOL CMover::IsItemRedyTime( ItemProp* pItemProp, OBJID dwObjid, BOOL bItemFind )
{
if( pItemProp->dwSkillReadyType != 0 &&
pItemProp->dwSkillReadyType != 0xffffffff )
{
#if __VER >= 15 // __IMPROVE_SYSTEM_VER15
if( pItemProp->dwItemKind2 == IK2_RIDING )
{
if( HasActivatedEatPet() || HasActivatedSystemPet() || HasPet() )
{
( (CUser*)this )->AddDefinedText( TID_GAME_CANNOT_FLY_WITH_PET );
return FALSE;
}
}
#endif // __IMPROVE_SYSTEM_VER15
// 라이드를 장착을 하려면 프로퍼티에 있는값을 참조하여 시전을 해야함
if( IsStateMode( STATE_BASEMOTION_MODE ) )
{
if( m_nReadyTime != 0 ) // 시전중
{
( (CUser*)this )->AddDefinedText(TID_PK_BLINK_LIMIT, "" ); // 시전중에는 사용할수 없습니다
return FALSE;
}
else // 시전이 완료된 시점
{
SetStateNotMode( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_OFF );
}
}
else // 시전 ™V팅
{
#if __VER >= 9 // __S_9_ADD
if( pItemProp->dwItemKind2 == IK2_BLINKWING && m_pActMover->IsSit() )
{
( (CUser*)this )->AddDefinedText(TID_GAME_NOTSIT_BLINK, "" );
return FALSE;
}
#endif // __S_9_ADD
m_nReadyTime = timeGetTime() + pItemProp->dwSkillReadyType;
m_dwUseItemId = dwObjid;
m_bItemFind = bItemFind;
SetStateMode( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_ON );
return FALSE;
}
}
return TRUE;
}
#endif // __WORLDSERVER
#ifdef __CLIENT
CSfx* CMover::CreateSfxArrow( DWORD dwSfxObjArrow, DWORD dwSfxObjHit, D3DXVECTOR3 vPosDest, int idTarget )
{
CSfx* pSfx = NULL;
// 화살은 왼손에 연결...
D3DXVECTOR3 vPos;
CModelObject *pModel = (CModelObject *)m_pModel;
pModel->GetHandPos( &vPos, PARTS_LWEAPON, GetMatrixWorld() ); // 주먹 월드좌표 구함
pSfx = CreateSfx( D3DDEVICE, dwSfxObjArrow, vPos, GetId(), vPosDest , idTarget );
if( dwSfxObjHit != NULL_ID )
{
if( pSfx )
{
((CSfxShoot*)pSfx)->m_dwSfxHit = dwSfxObjHit;
}
}
return pSfx;
}
#endif
BOOL CMover::IsAfterDeath()
{
if( m_nDeathLevel > m_nLevel )
return TRUE;
if( m_nDeathLevel == m_nLevel )
{
#if __VER >= 8
if( m_nExp1 == 0 )
return TRUE;
#endif // __VER >= 8
if( m_nDeathExp > m_nExp1 )
return TRUE;
}
return FALSE;
}
int CMover::GetSetItem( CItemElem* pItemElem )
{
static DWORD adwParts[4] = { PARTS_UPPER_BODY, PARTS_HAND, PARTS_FOOT, PARTS_CAP };
if( !pItemElem )
{
pItemElem = GetEquipItem( PARTS_UPPER_BODY );
}
else
{
if( !IsSetItemPart( pItemElem->GetProp()->dwParts ) )
return 0;
}
if( !pItemElem )
return 0;
if( pItemElem->IsFlag( CItemElem::expired ) )
return 0;
int nAbilityOption = pItemElem->GetAbilityOption();
DWORD dwParts = pItemElem->GetProp()->dwParts;
for( int i = 0; i < 4; i++ )
{
if( dwParts != adwParts[i] )
{
pItemElem = GetEquipItem( adwParts[i] );
if( pItemElem && !pItemElem->IsFlag( CItemElem::expired ) )
{
if( nAbilityOption > pItemElem->GetAbilityOption() )
nAbilityOption = pItemElem->GetAbilityOption();
continue;
}
return 0;
}
}
return nAbilityOption;
}
int CMover::GetSetItemParts(DWORD dwParts)
{
CItemElem* pItemElem = NULL;
ItemProp * pItemProp = NULL;
pItemElem = GetEquipItem( dwParts );
int nAbilityOption = 0;
if( pItemElem )
{
nAbilityOption = pItemElem->GetAbilityOption();
} else
{
if( IsActiveMover() )
return 0;
nAbilityOption = (m_aEquipInfo[dwParts].nOption & 0xFF );
}
return nAbilityOption;
}
int CMover::GetSetItemClient()
{
static DWORD adwParts[4] = { PARTS_UPPER_BODY, PARTS_HAND, PARTS_FOOT, PARTS_CAP };
int nAbilityOption = 10;
for( int i = 0; i < 4; i++ )
{
int nValue = GetSetItemParts( adwParts[i] );
if( nValue == 0 )
return 0;
if( nAbilityOption > nValue )
nAbilityOption = nValue;
}
return nAbilityOption;
}
BOOL CMover::IsSetItemPart( DWORD dwParts )
{
switch( dwParts )
{
case PARTS_UPPER_BODY:
case PARTS_HAND:
case PARTS_FOOT:
case PARTS_CAP:
return TRUE;
}
return FALSE;
}
void CMover::SetSetItemAvail( int nAbilityOption )
{
PSETITEMAVAIL pSetItemAvail = prj.GetSetItemAvail( nAbilityOption );
if( pSetItemAvail )
{
// OutputDebugString( "SetSetItemAvail" );
if( pSetItemAvail->nHitRate != 0 )
SetDestParam( DST_ADJ_HITRATE, pSetItemAvail->nHitRate, NULL_CHGPARAM );
if( pSetItemAvail->nBlock != 0 )
{
SetDestParam( DST_BLOCK_RANGE, pSetItemAvail->nBlock, NULL_CHGPARAM );
SetDestParam( DST_BLOCK_MELEE, pSetItemAvail->nBlock, NULL_CHGPARAM );
}
if( pSetItemAvail->nMaxHitPointRate != 0 )
SetDestParam( DST_HP_MAX_RATE, pSetItemAvail->nMaxHitPointRate, NULL_CHGPARAM );
if( pSetItemAvail->nAddMagic != 0 )
SetDestParam( DST_ADDMAGIC, pSetItemAvail->nAddMagic, NULL_CHGPARAM );
if( pSetItemAvail->nAdded != 0 )
{
SetDestParam( DST_STR, pSetItemAvail->nAdded, NULL_CHGPARAM );
SetDestParam( DST_DEX, pSetItemAvail->nAdded, NULL_CHGPARAM );
SetDestParam( DST_INT, pSetItemAvail->nAdded, NULL_CHGPARAM );
SetDestParam( DST_STA, pSetItemAvail->nAdded, NULL_CHGPARAM );
}
}
}
void CMover::ResetSetItemAvail( int nAbilityOption )
{
PSETITEMAVAIL pSetItemAvail = prj.GetSetItemAvail( nAbilityOption );
if( pSetItemAvail )
{
// OutputDebugString( "ResetSetItemAvail" );
if( pSetItemAvail->nHitRate != 0 )
ResetDestParam( DST_ADJ_HITRATE, pSetItemAvail->nHitRate, TRUE );
if( pSetItemAvail->nBlock != 0 )
{
ResetDestParam( DST_BLOCK_RANGE, pSetItemAvail->nBlock, TRUE );
ResetDestParam( DST_BLOCK_MELEE, pSetItemAvail->nBlock, TRUE );
}
if( pSetItemAvail->nMaxHitPointRate != 0 )
ResetDestParam( DST_HP_MAX_RATE, pSetItemAvail->nMaxHitPointRate, TRUE );
if( pSetItemAvail->nAddMagic != 0 )
ResetDestParam( DST_ADDMAGIC, pSetItemAvail->nAddMagic, TRUE );
if( pSetItemAvail->nAdded != 0 )
{
ResetDestParam( DST_STR, pSetItemAvail->nAdded, TRUE );
ResetDestParam( DST_DEX, pSetItemAvail->nAdded, TRUE );
ResetDestParam( DST_INT, pSetItemAvail->nAdded, TRUE );
ResetDestParam( DST_STA, pSetItemAvail->nAdded, TRUE );
}
}
}
void CMover::DestParamPiercingAvail( CItemElem* pItemElem, BOOL bSET )
{
#if __VER >= 12 // __EXT_PIERCING
if( !pItemElem->IsPierceAble() )
#else // __EXT_PIERCING
if( pItemElem->GetProp()->dwItemKind3 != IK3_SUIT )
#endif // __EXT_PIERCING
return;
PIERCINGAVAIL piercingAvail;
memset( &piercingAvail, 0, sizeof(piercingAvail) );
pItemElem->GetPiercingAvail( &piercingAvail );
for( int i = 0; i < piercingAvail.nSize; i++ )
{
if( bSET )
SetDestParam( piercingAvail.anDstParam[i], piercingAvail.anAdjParam[i], NULL_CHGPARAM );
else
ResetDestParam( piercingAvail.anDstParam[i], piercingAvail.anAdjParam[i], TRUE );
}
}
BOOL CMover::Pierce( CItemElem *pSuit, DWORD dwItemId )
{
for( int i = 0; i < pSuit->GetPiercingSize(); i++ )
{
if( pSuit->GetPiercingItem( i ) == 0 )
{
//pSuit->SetPiercingItem( i, dwItemId ); - 중복 실행
UpdateItem( (BYTE)( pSuit->m_dwObjId ), UI_PIERCING, MAKELONG( i, dwItemId ) );
return TRUE;
}
}
return FALSE;
}
#ifdef __WORLDSERVER
void CMover::CheckTickCheer()
{
if( m_nCheerPoint >= MAX_CHEERPOINT )
return;
DWORD dwTickCount = GetTickCount();
if( dwTickCount > m_dwTickCheer )
SetCheerParam( m_nCheerPoint + 1, dwTickCount, TICK_CHEERPOINT );
}
#endif // __WORLDSERVER
void CMover::SetCheerParam( int nCheerPoint, DWORD dwTickCount, DWORD dwRest )
{
#ifdef __WORLDSERVER // chipi_080411
BOOL bAdd = FALSE;
if( m_nCheerPoint < nCheerPoint )
bAdd = TRUE;
#endif // __WORLDSERVER
m_nCheerPoint = nCheerPoint;
m_dwTickCheer = dwTickCount + dwRest;
#ifdef __WORLDSERVER
( (CUser*)this )->AddSetCheerParam( nCheerPoint, dwRest, /* chipi_080411 */ bAdd );
#endif // __WORLDSERVER
}
BOOL CMover::NoDisguise( LPDIRECT3DDEVICE9 pd3dDevice )
{
#ifdef __CLIENT
// 이미 사람 모양이므로 해제 처리 할 필요 없음.
if( GetIndex() == MI_MALE || GetIndex() == MI_FEMALE )
return FALSE;
// 기존 모델 파괴
DWORD dwIndex = (GetSex() == SEX_MALE ? MI_MALE : MI_FEMALE);
SetIndex( pd3dDevice, dwIndex, FALSE, FALSE );
#endif //__CLIENT
return TRUE;
}
BOOL CMover::Disguise( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwMoverIndex )
{
#ifdef __CLIENT
return SetIndex( pd3dDevice, dwMoverIndex );
#endif // __CLIENT
return TRUE;
}
BOOL CMover::SetIndex( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwMoverIndex, BOOL bInitProp, BOOL bDestParam )
{
MoverProp* pMoverProp = prj.GetMoverProp( dwMoverIndex );
if( pMoverProp == NULL )
{
Error( "CMover.SetIndex: property not found: %d", dwMoverIndex );
return FALSE;
}
// 기존 모델 파괴
if( m_pModel && m_pModel->IsAniable() )
SAFE_DELETE( m_pModel );
SetTypeIndex( pd3dDevice, OT_MOVER, dwMoverIndex, bInitProp );//
m_dwMotion = -1;
SetMotion( MTI_STAND );
// 이런건 프로퍼티를 이용하는게 좋다.
if( m_bPlayer )
// 플레이어일 경우에만 장착을 적용. 일반 npc에 장착을 적용하면 여러가지 조건 검사 끝에 직업,
// 능력 등등에 따라서 오히려 장비가 탈착될 수도 있기 때문에, 아예 적용을 하지 않는다.
// 어차피 RedoEquip는 시각적인 것이므로, 구지 안해도 Inventory 차원에서 장착은 되어 있다.
{
if( dwMoverIndex == MI_MALE || dwMoverIndex == MI_FEMALE )
{
#if defined( __CLIENT )
RedoEquip( !IsActiveMover(), bDestParam );
#else
RedoEquip( FALSE );
#endif
SetHairColor( m_dwHairColor );
}
}
ResetScale();
UpdateLocalMatrix();
return TRUE;
}
BOOL CMover::IsDisguise()
{
if( IsPlayer() )
{
return ( GetIndex() != MI_MALE && GetIndex() != MI_FEMALE );
}
return FALSE;
}
LPCTSTR CMover::GetName( BOOL bNickname )
{
if( !bNickname )
return (LPCTSTR)m_szName;
if( m_dwAuthorization >= AUTH_GAMEMASTER && ( GetIndex() == MI_CROWNIBLIS || GetIndex() == MI_CROWNSHADE || GetIndex() == MI_CROWNBUBBLE ) )
{
MoverProp* pMoverProp = GetProp();
if( pMoverProp )
return (LPCTSTR)pMoverProp->szName;
}
return (LPCTSTR)m_szName;
}
void CMover::SetDestParamSetItem( CItemElem* pItemElem )
{
ITEMAVAIL itemAvail;
memset( &itemAvail, 0, sizeof(itemAvail) );
if( pItemElem && !pItemElem->IsFlag( CItemElem::expired ) )
{
CSetItem* pSetItem = CSetItemFinder::GetInstance()->GetSetItemByItemId( pItemElem->m_dwItemId );
if( pSetItem )
{
int nEquiped = GetEquipedSetItemNumber( pSetItem );
pSetItem->GetItemAvail( &itemAvail, nEquiped, FALSE );
}
}
else
{
map<CSetItem*, int> mapSetItem;
map<CSetItem*, int>::iterator i;
for( int nParts = 0; nParts < MAX_HUMAN_PARTS; nParts++ )
{
pItemElem = GetEquipItem( nParts );
if( pItemElem && !pItemElem->IsFlag( CItemElem::expired ) )
{
CSetItem* pSetItem = CSetItemFinder::GetInstance()->GetSetItemByItemId( pItemElem->m_dwItemId );
if( pSetItem )
{
i = mapSetItem.find( pSetItem );
if( i != mapSetItem.end() )
i->second++;
else
mapSetItem.insert( map<CSetItem*, int>::value_type( pSetItem, 1 ) );
}
}
}
for( i = mapSetItem.begin(); i != mapSetItem.end(); ++i )
{
CSetItem* pSetItem = i->first;
int nEquiped = i->second;
pSetItem->GetItemAvail( &itemAvail, nEquiped, TRUE );
}
}
for( int i = 0; i < itemAvail.nSize; i++ )
SetDestParam( itemAvail.anDstParam[i], itemAvail.anAdjParam[i], NULL_CHGPARAM );
}
void CMover::ResetDestParamSetItem( CItemElem* pItemElem )
{
if( pItemElem && !pItemElem->IsFlag( CItemElem::expired ) )
{
CSetItem* pSetItem = CSetItemFinder::GetInstance()->GetSetItemByItemId( pItemElem->m_dwItemId );
if( pSetItem )
{
ITEMAVAIL itemAvail;
memset( &itemAvail, 0, sizeof(itemAvail) );
int nEquiped = GetEquipedSetItemNumber( pSetItem );
pSetItem->GetItemAvail( &itemAvail, nEquiped + 1, FALSE );
for( int i = 0; i < itemAvail.nSize; i++ )
ResetDestParam( itemAvail.anDstParam[i], itemAvail.anAdjParam[i], TRUE );
}
}
}
int CMover::GetEquipedSetItemNumber( CSetItem* pSetItem )
{
int nEquiped = 0;
for( int i = 0; i < pSetItem->m_nElemSize; i++ )
{
CItemElem* pItemElem = GetEquipItem( pSetItem->m_anParts[i] );
if( pItemElem && pItemElem->m_dwItemId == pSetItem->m_adwItemId[i] && !pItemElem->IsFlag( CItemElem::expired ) )
nEquiped++;
}
return nEquiped;
}
void CMover::GetEquipedSetItem( int nSetItemId, BOOL* pbEquiped, int* pnEquip )
{
*pnEquip = 0;
// memset( pbEquiped, 0, sizeof(BYTE) * MAX_HUMAN_PARTS );
CSetItem* pSetItem = CSetItemFinder::GetInstance()->GetSetItem( nSetItemId );
if( pSetItem )
{
for( int i = 0; i < pSetItem->m_nElemSize; i++ )
{
CItemElem* pItemElem = GetEquipItem( pSetItem->m_anParts[i] );
if( pItemElem && pItemElem->m_dwItemId == pSetItem->m_adwItemId[i] && !pItemElem->IsFlag( CItemElem::expired ) )
{
pbEquiped[i] = TRUE;
(*pnEquip)++;
}
}
}
}
void CMover::SetDestParamRandomOptOrigin( CItemElem* pItemElem )
{
if( pItemElem->GetRandomOpt() > 0 )
{
PRANDOMOPTITEM pRandomOptItem = CRandomOptItemGen::GetInstance()->GetRandomOptItem( pItemElem->GetRandomOpt() );
if( pRandomOptItem )
{
for( int i = 0; i < pRandomOptItem->ia.nSize; i++ )
SetDestParam( pRandomOptItem->ia.anDstParam[i], pRandomOptItem->ia.anAdjParam[i], NULL_CHGPARAM );
}
}
}
void CMover::SetDestParamRandomOptExtension( CItemElem* pItemElem )
{
#if __VER >= 11 // __SYS_IDENTIFY
int cbOption = g_xRandomOptionProperty->GetRandomOptionSize( pItemElem->GetRandomOptItemId() );
for( int i = 0; i < cbOption; i++ )
{
int nDst, nAdj;
if( g_xRandomOptionProperty->GetParam( pItemElem->GetRandomOptItemId(), i, &nDst, &nAdj ) )
SetDestParam( nDst, nAdj, NULL_CHGPARAM );
}
#endif // __SYS_IDENTIFY
}
void CMover::SetDestParamRandomOpt( CItemElem* pItemElem )
{
SetDestParamRandomOptOrigin( pItemElem );
SetDestParamRandomOptExtension( pItemElem );
}
void CMover::ResetDestParamRandomOptOrigin( CItemElem* pItemElem )
{
if( pItemElem->GetRandomOpt() > 0 )
{
PRANDOMOPTITEM pRandomOptItem = CRandomOptItemGen::GetInstance()->GetRandomOptItem( pItemElem->GetRandomOpt() );
if( pRandomOptItem )
{
for( int i = 0; i < pRandomOptItem->ia.nSize; i++ )
ResetDestParam( pRandomOptItem->ia.anDstParam[i], pRandomOptItem->ia.anAdjParam[i], TRUE );
}
}
}
void CMover::ResetDestParamRandomOptExtension( CItemElem* pItemElem )
{
#if __VER >= 11 // __SYS_IDENTIFY
int cbOption = g_xRandomOptionProperty->GetRandomOptionSize( pItemElem->GetRandomOptItemId() );
for( int i = 0; i < cbOption; i++ )
{
int nDst, nAdj;
if( g_xRandomOptionProperty->GetParam( pItemElem->GetRandomOptItemId(), i, &nDst, &nAdj ) )
ResetDestParam( nDst, nAdj, TRUE );
}
#endif // __SYS_IDENTIFY
}
void CMover::ResetDestParamRandomOpt( CItemElem* pItemElem )
{
ResetDestParamRandomOptOrigin( pItemElem );
ResetDestParamRandomOptExtension( pItemElem );
}
#ifdef __CLIENT
// pModel를 인자로 받은 이유는....글로벌모델을 사용하는 넘들이 있어서...
void CMover::OverCoatItemRenderCheck( CModelObject* pModel )
{
if( !pModel )
return;
// 외투의상을 입었다면 주방어구 의상은 숨긴다...
int nArryEquip1[5] = { PARTS_CAP, PARTS_UPPER_BODY, PARTS_HAND, PARTS_FOOT, PARTS_CLOAK };
int nArryEquip2[5] = { PARTS_HAT, PARTS_CLOTH, PARTS_GLOVE, PARTS_BOOTS, PARTS_CLOAK2 };
O3D_ELEMENT *pElem = NULL;
O3D_ELEMENT *pElem2 = NULL;
for( int j=0; j<5; j++ )
{
pElem = pModel->GetParts( nArryEquip1[j] );
if( !pElem )
continue;
pElem2 = pModel->GetParts( nArryEquip2[j] );
if( pElem2 )
{
if( IsActiveMover() )
{
CItemElem* pItemElemOvercoat = GetEquipItem( nArryEquip2[j] );
if( pItemElemOvercoat )
{
if( pItemElemOvercoat->IsFlag( CItemElem::expired ) )
{
pElem->m_nEffect &= ~XE_HIDE;
pElem2->m_nEffect |= XE_HIDE;
continue;
}
}
}
else
{
DWORD dwId = m_aEquipInfo[ nArryEquip2[j] ].dwId;
if( (m_aEquipInfo[ nArryEquip2[j] ].byFlag & CItemElem::expired) )
{
pElem->m_nEffect &= ~XE_HIDE;
pElem2->m_nEffect |= XE_HIDE;
continue;
}
}
pElem->m_nEffect |= XE_HIDE;
}
}
}
#endif // __CLIENT
#ifdef __WORLDSERVER
void CMover::ProcInstantBanker()
{
if( m_dwTickCreated && m_dwIndex == MI_INFO_PENG )
{
LPCHARACTER lpCharacter = GetCharacter();
if( lpCharacter && lstrcmp( lpCharacter->m_szKey, "MaFl_InstantBank" ) == 0 )
{
if( GetTickCount() > m_dwTickCreated + TIMEWAIT_INSTANT_BANKER )
Delete();
}
}
}
void CMover::ProcInstantGC()
{
if( CGuildCombat::WAR_STATE <= g_GuildCombatMng.m_nState && m_dwIndex == MI_MADA_ACHABEN )
{
LPCHARACTER lpCharacter = GetCharacter();
if( lpCharacter && lstrcmp( lpCharacter->m_szKey, "Mada_Guildcombatshop" ) == 0 )
{
Delete();
}
}
}
#endif // __WORLDSERVER
CItemBase* CMover::GetVendorItem()
{
return NULL;
}
void CMover::AddSkillPoint( int nPoint )
{
int nMaxPoint = 1280; // 최대인 JOB_ELEMENTOR 꺼로 설정함
if( IsPro() )
{
if( m_nJob == JOB_KNIGHT || m_nJob == JOB_BLADE )
nMaxPoint = 870;
else if( m_nJob == JOB_JESTER || m_nJob == JOB_RANGER )
nMaxPoint = 910;
else if( m_nJob == JOB_RINGMASTER )
nMaxPoint = 902;
else if( m_nJob == JOB_BILLPOSTER || m_nJob == JOB_PSYCHIKEEPER )
nMaxPoint = 950;
}
if( m_nSkillLevel >= nMaxPoint )
return;
if( nMaxPoint < m_nSkillLevel + nPoint ) // 더 해지면 넘는 경우(현재 넘지 않음)
nPoint = nMaxPoint - m_nSkillLevel; // 맥스치에 모자른 만큼만 포인트 지급
m_nSkillPoint += nPoint;
m_nSkillLevel += nPoint;
}
// 전투중인가?
BOOL CMover::IsAttackMode()
{
#if __VER >= 9 // __RECOVERY10
return ( m_nAtkCnt && m_nAtkCnt < (SEC1 * 10) );
#else // __RECOVERY10
return ( m_nAtkCnt && m_nAtkCnt < (SEC1 * 5) );
#endif // __RECOVERY10
}
BOOL CMover::IsDropable( CItemElem* pItemElem, BOOL bPK )
{
return ( IsDropableState( bPK )
&& IsUsableItem( pItemElem )
&& !pItemElem->IsBinds()
&& !( pItemElem->GetProp()->dwItemKind3 == IK3_CLOAK && pItemElem->m_idGuild )
&& !m_Inventory.IsEquip( pItemElem->m_dwObjId )
&& !IsUsing( pItemElem )
&& !( pItemElem->GetProp()->dwParts == PARTS_RIDE && pItemElem->GetProp()->dwItemJob == JOB_VAGRANT )
&& !pItemElem->IsCharged()
#if __VER >= 9 // __PET_0410
&& pItemElem->GetProp()->dwItemKind3 != IK3_EGG
#endif // __PET_0410
#ifdef __JEFF_11
&& pItemElem->m_dwItemId != II_CHP_RED
#endif // __JEFF_11
#if __VER >= 11 // __MA_VER11_05 // 케릭터 봉인 거래 기능 world,database,neuz
&& pItemElem->m_dwItemId != II_SYS_SYS_SCR_SEALCHARACTER
#endif // __MA_VER11_05 // 케릭터 봉인 거래 기능 world,database,neuz
);
}
#ifdef __CLIENT
BOOL CMover::IsStateDbuff()
{
int nAdjParam = GetAdjParam( DST_CHRSTATE );
if( nAdjParam & CHS_STUN || nAdjParam & CHS_POISON || nAdjParam & CHS_DARK ||
nAdjParam & CHS_GROGGY || nAdjParam & CHS_SILENT || nAdjParam & CHS_BLEEDING )
{
return TRUE;
}
return FALSE;
}
#endif
int __IsEndQuestCondition( CMover* pMover, int nQuestId )
{
QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuestId );
if( pQuestProp )
{
int nResult = 0;
LPQUEST pCurQuest = pMover->GetQuest( nQuestId );
if( pCurQuest == NULL || pCurQuest->m_nState == QS_END )
return 0;
// 시간 제한 체크 1
if( pQuestProp->m_nEndCondLimitTime == 0 || pCurQuest->m_wTime )
nResult++;
// 정찰 임무 2
if( pQuestProp->m_dwEndCondPatrolWorld == 0 || pCurQuest->m_bPatrol )
nResult++;
// NPC 퇴치 갯수 3,4
for( int i = 0; i < 2; i++ )
{
if( pQuestProp->m_nEndCondKillNPCIdx[ i ] == 0 || pCurQuest->m_nKillNPCNum[ i ] >= pQuestProp->m_nEndCondKillNPCNum[ i ] )
nResult++;
}
// 스킬 5
if( pQuestProp->m_nEndCondSkillIdx == 0 )
nResult++;
else
{
LPSKILL lpSkill = pMover->GetSkill( pQuestProp->m_nEndCondSkillIdx );
if( lpSkill )
{
if( pMover->CheckSkill( pQuestProp->m_nEndCondSkillIdx ) && lpSkill->dwLevel >= (DWORD)( pQuestProp->m_nEndCondSkillLvl ) )
nResult++;
}
}
#if __VER >= 8 // __S8_PK
// Penya 6
if( pQuestProp->m_nEndCondGold == 0 )
nResult++;
else
{
if( pMover->GetGold() >= pQuestProp->m_nEndCondGold )
nResult++;
}
// 레벨 7
if( pQuestProp->m_nEndCondLevelMin == 0 || ( pMover->GetLevel() >= pQuestProp->m_nEndCondLevelMin && pMover->GetLevel() <= pQuestProp->m_nEndCondLevelMax ) )
nResult++;
#if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans
if( pQuestProp->m_nEndCondExpPercentMin == 0 || ( pMover->GetExpPercent() >= pQuestProp->m_nEndCondExpPercentMin && pMover->GetExpPercent() <= pQuestProp->m_nEndCondExpPercentMax ) )
nResult++;
#endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans
#else // __VER >= 8 // __S8_PK
// 카르마 6
if( pQuestProp->m_nEndCondKarmaPoint == 0 )
nResult++;
else
{
if( pQuestProp->m_nEndCondKarmaComp == 0 )
{
if( pMover->GetKarma() == pQuestProp->m_nEndCondKarmaPoint )
nResult++;
}
else
if( pQuestProp->m_nEndCondKarmaComp == -1 )
{
if( pMover->GetKarma() <= pQuestProp->m_nEndCondKarmaPoint )
nResult++;
}
else
if( pQuestProp->m_nEndCondKarmaComp == 1 )
{
if( pMover->GetKarma() >= pQuestProp->m_nEndCondKarmaPoint )
nResult++;
}
}
// 카오틱 7
if( pQuestProp->m_nEndCondChaotic == 0 )
nResult++;
else
{
if( pQuestProp->m_nEndCondChaotic == 1 && pMover->IsChaotic() )
nResult++;
else
if( pQuestProp->m_nEndCondChaotic == 2 && pMover->IsChaotic() == FALSE )
nResult++;
}
#endif // __VER >= 8 // __S8_PK
#if __VER >= 9 // __PET_0410
if( pQuestProp->m_nEndCondPetExp == 0 )
nResult++;
else
{
CPet* pPet = pMover->GetPet();
if( pPet && pPet->GetExpPercent() >= pQuestProp->m_nEndCondPetExp )
nResult++;
}
if( pQuestProp->m_nEndCondPetLevel == -1 )
nResult++;
else
{
CPet* pPet = pMover->GetPet();
if( pPet && pPet->GetLevel() == pQuestProp->m_nEndCondPetLevel )
nResult++;
}
#endif // __PET_0410
// 변신 8
if( pQuestProp->m_nEndCondDisguiseMoverIndex == 0 )
nResult++;
else
{
if( pQuestProp->m_nEndCondDisguiseMoverIndex == -1 && pMover->IsDisguise() == FALSE )
nResult++;
else
if( pQuestProp->m_nEndCondDisguiseMoverIndex == pMover->GetIndex() )
nResult++;
}
// 스테이트 체크 9
if( pQuestProp->m_nEndCondState == 0 )
{
for( i = QS_BEGIN + 1; i < QS_END; i++ ) // (1~13)
{
if( pQuestProp->m_questState[ i ] == NULL )
break;
}
if( ( i - 1 ) == pCurQuest->m_nState )
nResult++;
}
else
if( pQuestProp->m_nEndCondState == pCurQuest->m_nState )
nResult++;
// 완료 퀘스트 체크 10,11,12,13,14, 15
if( pQuestProp->m_nEndCondCompleteQuestOper == 0 ) //
nResult += 6;
else
if( pQuestProp->m_nEndCondCompleteQuestOper == 1 ) // or
{
for( i = 0; i < 6; i++ )
{
if( pMover->IsCompleteQuest( pQuestProp->m_nEndCondCompleteQuest[ i ] ) )
break;
}
if( i != 6 )
nResult += 6;
}
else
if( pQuestProp->m_nEndCondCompleteQuestOper == 2 ) // and
{
for( i = 0; i < 6; i++ )
{
if( pQuestProp->m_nEndCondCompleteQuest[ i ] == 0 || pMover->IsCompleteQuest( pQuestProp->m_nEndCondCompleteQuest[ i ] ) )
nResult++;
}
}
// else
// 파티 여부 16
if( pQuestProp->m_nEndCondParty == 0 )
nResult++;
else
{
BOOL bParty = FALSE;
BOOL bLeader = FALSE;
int nSize = 0;
#ifdef __WORLDSERVER
CParty* pParty = g_PartyMng.GetParty( pMover->m_idparty );
if( pParty )
{
bParty = TRUE;
nSize = pParty->GetSizeofMember();
bLeader = pParty->m_aMember[0].m_uPlayerId == pMover->m_idPlayer;
}
#else
bParty = g_Party.IsMember( g_pPlayer->m_idPlayer );
nSize = g_Party.GetSizeofMember();
bLeader = ( g_Party.m_aMember[0].m_uPlayerId == pMover->m_idPlayer );
#endif
if( pQuestProp->m_nEndCondParty == 1 && bParty == FALSE )
nResult++;
else
if( pQuestProp->m_nEndCondParty == 2 && bParty == TRUE )
{
if( pQuestProp->m_nEndCondPartyLeader == 0 || ( pQuestProp->m_nEndCondPartyLeader - 1 ) == bLeader )
{
if( pQuestProp->m_nEndCondPartyNum == 0 )
nResult++;
else
if( pQuestProp->m_nEndCondPartyNumComp == 0 )
{
if( nSize == pQuestProp->m_nEndCondPartyNum )
nResult++;
}
else
if( pQuestProp->m_nEndCondPartyNumComp == 1 )
{
if( nSize >= pQuestProp->m_nEndCondPartyNum )
nResult++;
}
else
if( pQuestProp->m_nEndCondPartyNumComp == -1 )
{
if( nSize <= pQuestProp->m_nEndCondPartyNum )
nResult++;
}
}
}
}
// 길드 여부 17
if( pQuestProp->m_nEndCondGuild == 0 )
nResult++;
else
{
BOOL bGuild = FALSE;
BOOL bLeader = FALSE;
int nSize = 0;
CGuild* pGuild = g_GuildMng.GetGuild( pMover->m_idPlayer );
if( pGuild )
{
bGuild = TRUE;
nSize = pGuild->GetSize();
bLeader = ( pGuild->m_idMaster == pMover->m_idPlayer );
}
if( pQuestProp->m_nEndCondGuild == 1 && bGuild == FALSE )
nResult++;
else
if( pQuestProp->m_nEndCondGuild == 2 && bGuild == TRUE )
{
if( pQuestProp->m_nEndCondGuildLeader == 0 || ( pQuestProp->m_nEndCondGuildLeader - 1 ) == bLeader )
{
if( pQuestProp->m_nEndCondGuildNum == 0 )
nResult++;
else
if( pQuestProp->m_nEndCondGuildNumComp == 0 )
{
if( nSize == pQuestProp->m_nEndCondGuildNum )
nResult++;
}
else
if( pQuestProp->m_nEndCondGuildNumComp == 1 )
{
if( nSize >= pQuestProp->m_nEndCondGuildNum )
nResult++;
}
else
if( pQuestProp->m_nEndCondGuildNumComp == -1 )
{
if( nSize <= pQuestProp->m_nEndCondGuildNum )
nResult++;
}
}
}
}
#if __VER >= 8 // __S8_PK
// 설정 아이템이 설정한 갯수가 있으면 충족
int nBufResult = nResult + MAX_QUESTCONDITEM;
if( pQuestProp->m_nEndCondOneItemNum == 0 )
nResult += MAX_QUESTCONDITEM;
else
for( i = 0; i < MAX_QUESTCONDITEM; i++ )
{
if( i < pQuestProp->m_nEndCondOneItemNum )
{
QuestPropItem* pEndCondItem = &pQuestProp->m_paEndCondOneItem[ i ];
if( pEndCondItem->m_nSex == -1 || pEndCondItem->m_nSex == pMover->GetSex() )
{
if( pEndCondItem->m_nType == 0 )
{
if( pEndCondItem->m_nJobOrItem == -1 || pEndCondItem->m_nJobOrItem == pMover->GetJob() )
{
if( pMover->GetItemNum( pEndCondItem->m_nItemIdx ) >= pEndCondItem->m_nItemNum )
{
nResult = nBufResult;
break;
}
}
else
nResult++;
}
else
if( pEndCondItem->m_nType == 1 )
{
if( pEndCondItem->m_nJobOrItem == -1 || pMover->GetItemNum( pEndCondItem->m_nJobOrItem ) )
{
if( pMover->GetItemNum( pEndCondItem->m_nItemIdx ) >= pEndCondItem->m_nItemNum )
{
nResult = nBufResult;
break;
}
}
else
nResult++;
}
}
}
else
nResult++;
}
#endif // __VER >= 8 // __S8_PK
// 수집 아이템 갯수 17 + MAX_QUESTCONDITEM
if( pQuestProp->m_nEndCondItemNum == 0 )
nResult += MAX_QUESTCONDITEM;
else
for( i = 0; i < MAX_QUESTCONDITEM; i++ )
{
if( i < pQuestProp->m_nEndCondItemNum )
{
QuestPropItem* pEndCondItem = &pQuestProp->m_paEndCondItem[ i ];
if( pEndCondItem->m_nSex == -1 || pEndCondItem->m_nSex == pMover->GetSex() )
{
if( pEndCondItem->m_nType == 0 )
{
if( pEndCondItem->m_nJobOrItem == -1 || pEndCondItem->m_nJobOrItem == pMover->GetJob() )
{
if( pEndCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pEndCondItem->m_nItemIdx ) >= pEndCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
else
if( pEndCondItem->m_nType == 1 )
{
if( pEndCondItem->m_nJobOrItem == -1 || pMover->GetItemNum( pEndCondItem->m_nJobOrItem ) )
{
if( pEndCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pEndCondItem->m_nItemIdx ) >= pEndCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
}
}
else
nResult++;
}
#if __VER >= 15 // __CAMPUS
if( pQuestProp->m_nEndCondTSP == 0 )
++nResult;
else
{
if( pMover->GetCampusPoint() >= pQuestProp->m_nEndCondTSP )
++nResult;
}
#endif // __CAMPUS
// 총합이 17 + MAX_QUESTCONDITEM면 퀘스트 조건 성립
#if __VER >= 8 // __S8_PK
#if __VER >= 9 // __PET_0410
#if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans
#if __VER >= 15 // __CAMPUS
if( nResult == 21+ MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#else // __CAMPUS
if( nResult == 20+ MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#endif // __CAMPUS
#else // __LEGEND // 10차 전승시스템 Neuz, World, Trans
if( nResult == 19+ MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans
#else // __PET_0410
#if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans
if( nResult == 18+ MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#else
if( nResult == 17+ MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans
#endif //__PET_0410
#else // __VER >= 8 // __S8_PK
if( nResult == 17+ MAX_QUESTCONDITEM )
#endif // __VER >= 8 // __S8_PK
{
// 모든 조건 달성 순간에 타이머 카운트 중지 시키기
// 이후에 인벤토리가 부족해서 퀘스트를 완료 못시키더라도 시간은 정지된다.
if( pCurQuest->m_wTime )
pCurQuest->m_wTime |= 0x8000;
return 1;
}
}
return 0;
}
#ifdef __WORLDSERVER
#include "User.h"
#endif // __WORLDSERVER
int __IsBeginQuestCondition( CMover* pMover, int nQuestId )
{
QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuestId );
if( pQuestProp )
{
int nResult = 0;
LPQUEST pCurQuest = pMover->GetQuest( nQuestId );
BOOL bComplete = pMover->IsCompleteQuest( nQuestId );
// 퀘스트가 존재하거나, 이미 완료된 적이 있는 퀘스트는 조건 성립 안됨. 반복하기 위해서는 완전히 제거하여 완료 배열에 없어여 한다.
if( pCurQuest || bComplete )
return 0;
#ifdef __WORLDSERVER
// 시작 아이템이 존재할 때 인벤토리에 빈칸이 있는지 검사
int nItemCount = 0;
for( int j=0; j<4; j++ )
if( pQuestProp->m_nBeginSetAddItemIdx[ j ] )
nItemCount++;
if( IsValidObj( pMover ) && static_cast<CUser*>(pMover)->m_Inventory.GetEmptyCount() < nItemCount )
{
static_cast<CUser*>(pMover)->AddDefinedText( TID_GAME_LACKSPACE );
return 0;
}
// 시작 아이템이 존재할 때 인벤토리에 빈칸이 있는지 검사_END
#endif // __WORLDSERVER
// 이전 퀘스트 1,2,3,4,5,6
for( int i = 0; i < 6; i++ )
{
if( pQuestProp->m_anBeginCondPreviousQuest[ i ] == 0 )
nResult++;
else
{
LPQUEST pPreQuest = pMover->GetQuest( pQuestProp->m_anBeginCondPreviousQuest[ i ] );
BOOL bPreComplete = pMover->IsCompleteQuest( pQuestProp->m_anBeginCondPreviousQuest[ i ] );
if( pQuestProp->m_nBeginCondPreviousQuestType == 0 )
{
if( pPreQuest || bPreComplete )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPreviousQuestType == 1 )
{
if( pPreQuest == NULL && bPreComplete )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPreviousQuestType == 2 )
{
if( pPreQuest && bPreComplete == FALSE )
nResult++;
}
}
}
// 이전 퀘스트 7,8,9,10,11,12
for( i = 0; i < 6; i++ )
{
if( pQuestProp->m_anBeginCondExclusiveQuest[ i ] == 0 )
nResult++;
else
{
LPQUEST pPreQuest = pMover->GetQuest( pQuestProp->m_anBeginCondExclusiveQuest[ i ] );
BOOL bPreComplete = pMover->IsCompleteQuest( pQuestProp->m_anBeginCondPreviousQuest[ i ] );
if( pPreQuest == NULL && bPreComplete == FALSE )
nResult++;
}
}
// 직업 13
if( pQuestProp->m_nBeginCondJobNum == 0 )
nResult++;
else
for( int i = 0; i < pQuestProp->m_nBeginCondJobNum; i++ )
{
if( pQuestProp->m_nBeginCondJob[ i ] == pMover->GetJob() )
{
nResult++;
break;
}
}
// 레벨 14
if( pQuestProp->m_nBeginCondLevelMin == 0 || ( pMover->GetLevel() >= pQuestProp->m_nBeginCondLevelMin && pMover->GetLevel() <= pQuestProp->m_nBeginCondLevelMax ) )
nResult++;
// 파티 여부 15
if( pQuestProp->m_nBeginCondParty == 0 )
nResult++;
else
{
BOOL bParty = FALSE;
BOOL bLeader = FALSE;
int nSize = 0;
#ifdef __WORLDSERVER
CParty* pParty = g_PartyMng.GetParty( pMover->m_idparty );
if( pParty )
{
bParty = TRUE;
nSize = pParty->GetSizeofMember();
}
#else
bParty = g_Party.IsMember( g_pPlayer->m_idPlayer );
nSize = g_Party.GetSizeofMember();
#endif
if( pQuestProp->m_nBeginCondParty == 1 && bParty == FALSE )
nResult++;
else
if( pQuestProp->m_nBeginCondParty == 2 && bParty == TRUE )
{
if( pQuestProp->m_nBeginCondPartyLeader == -1 || pQuestProp->m_nBeginCondPartyLeader == bLeader )
{
if( pQuestProp->m_nBeginCondPartyNum == 0 )
nResult++;
else
if( pQuestProp->m_nBeginCondPartyNumComp == 0 )
{
if( nSize == pQuestProp->m_nBeginCondPartyNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPartyNumComp == 1 )
{
if( nSize >= pQuestProp->m_nBeginCondPartyNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPartyNumComp == -1 )
{
if( nSize <= pQuestProp->m_nBeginCondPartyNum )
nResult++;
}
}
}
}
// 길드 여부 16
if( pQuestProp->m_nBeginCondGuild == 0 )
nResult++;
else
{
BOOL bGuild = FALSE;
BOOL bLeader = FALSE;
int nSize = 0;
/*
#ifdef __WORLDSERVER
g_PartyMng.m_AddRemoveLock.Enter( theLineFile );
CParty* pParty = g_PartyMng.GetParty( pMover->m_idparty );
if( pParty )
{
bParty = TRUE;
nSize = pParty->GetSizeofMember();
}
g_PartyMng.m_AddRemoveLock.Leave( theLineFile );
#else
bParty = g_Party.IsMember( g_pPlayer->m_idPlayer );
nSize = g_Party.GetSizeofMember();
#endif
*/
if( pQuestProp->m_nBeginCondGuild == 1 && bGuild == FALSE )
nResult++;
else
if( pQuestProp->m_nBeginCondGuild == 2 && bGuild == TRUE )
{
if( pQuestProp->m_nBeginCondGuildLeader == -1 || pQuestProp->m_nBeginCondGuildLeader == bLeader )
{
if( pQuestProp->m_nBeginCondGuildNum == 0 )
nResult++;
else
if( pQuestProp->m_nBeginCondGuildNumComp == 0 )
{
if( nSize == pQuestProp->m_nBeginCondGuildNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondGuildNumComp == 1 )
{
if( nSize >= pQuestProp->m_nBeginCondGuildNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondGuildNumComp == -1 )
{
if( nSize <= pQuestProp->m_nBeginCondGuildNum )
nResult++;
}
}
}
}
// 성별 17
if( pQuestProp->m_nBeginCondSex == -1 || pQuestProp->m_nBeginCondSex == pMover->GetSex() )
nResult++;
// 스킬 18
if( pQuestProp->m_nBeginCondSkillIdx == 0 )
nResult++;
else
{
LPSKILL lpSkill = pMover->GetSkill( pQuestProp->m_nBeginCondSkillIdx );
if( lpSkill )
{
if( pMover->CheckSkill( pQuestProp->m_nBeginCondSkillLvl ) && lpSkill->dwLevel >= (DWORD)( pQuestProp->m_nBeginCondSkillLvl ) )
nResult++;
}
}
#if __VER >= 8 // __S8_PK
// PK Value 19
if( pQuestProp->m_nBeginCondPKValue == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondPKValue <= pMover->GetPKValue() )
nResult++;
}
// 아이템이 없는것 검사 MAX_QUESTCONDITEM
if( pQuestProp->m_nBeginCondNotItemNum == 0 )
nResult += MAX_QUESTCONDITEM;
else
for( int i = 0; i < MAX_QUESTCONDITEM; i++ )
{
if( i < pQuestProp->m_nBeginCondNotItemNum )
{
QuestPropItem* pBeginCondItem = &pQuestProp->m_paBeginCondNotItem[ i ];
if( pBeginCondItem->m_nSex == -1 || pBeginCondItem->m_nSex == pMover->GetSex() )
{
if( pBeginCondItem->m_nType == 0 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pBeginCondItem->m_nJobOrItem == pMover->GetJob() )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) < pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
else
if( pBeginCondItem->m_nType == 1 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pMover->GetItemNum( pBeginCondItem->m_nJobOrItem ) )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) < pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
}
}
else
nResult++;
}
#else // __VER >= 8 // __S8_PK
// 카르마 19
if( pQuestProp->m_nBeginCondKarmaPoint == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondKarmaComp == 0 )
{
if( pMover->GetKarma() == pQuestProp->m_nBeginCondKarmaPoint )
nResult++;
}
else
if( pQuestProp->m_nBeginCondKarmaComp == -1 )
{
if( pMover->GetKarma() < pQuestProp->m_nBeginCondKarmaPoint )
nResult++;
}
else
if( pQuestProp->m_nBeginCondKarmaComp == 1 )
{
if( pMover->GetKarma() > pQuestProp->m_nBeginCondKarmaPoint )
nResult++;
}
}
// 카오틱 20
if( pQuestProp->m_nBeginCondChaotic == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondChaotic == 1 && pMover->IsChaotic() )
nResult++;
else
if( pQuestProp->m_nBeginCondChaotic == 2 && pMover->IsChaotic() == FALSE )
nResult++;
}
#endif // __VER >= 8 // __S8_PK
// 변신 21
if( pQuestProp->m_nBeginCondDisguiseMoverIndex == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondDisguiseMoverIndex == -1 && pMover->IsDisguise() == FALSE )
nResult++;
else
if( pQuestProp->m_nBeginCondDisguiseMoverIndex == pMover->GetIndex() )
nResult++;
}
#if __VER >= 9 // __PET_0410
if( pQuestProp->m_nBeginCondPetExp == 0 )
nResult++;
else
{
CPet* pPet = pMover->GetPet();
if( pPet && pPet->GetExpPercent() >= pQuestProp->m_nBeginCondPetExp )
nResult++;
}
if( pQuestProp->m_nBeginCondPetLevel == -1 )
nResult++;
else
{
CPet* pPet = pMover->GetPet();
if( pPet && pPet->GetLevel() == pQuestProp->m_nBeginCondPetLevel )
nResult++;
}
#endif // __PET_0410
#if __VER >= 12 // __MOD_TUTORIAL
if( pQuestProp->m_nBeginCondTutorialState == -1
|| pMover->GetTutorialState() >= pQuestProp->m_nBeginCondTutorialState )
nResult++;
#endif // __MOD_TUTORIAL
// 수집 아이템 갯수 21 + MAX_QUESTCONDITEM
if( pQuestProp->m_nBeginCondItemNum == 0 )
nResult += MAX_QUESTCONDITEM;
else
for( int i = 0; i < MAX_QUESTCONDITEM; i++ )
{
if( i < pQuestProp->m_nBeginCondItemNum )
{
QuestPropItem* pBeginCondItem = &pQuestProp->m_paBeginCondItem[ i ];
if( pBeginCondItem->m_nSex == -1 || pBeginCondItem->m_nSex == pMover->GetSex() )
{
if( pBeginCondItem->m_nType == 0 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pBeginCondItem->m_nJobOrItem == pMover->GetJob() )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) >= pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
else
if( pBeginCondItem->m_nType == 1 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pMover->GetItemNum( pBeginCondItem->m_nJobOrItem ) )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) >= pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
}
}
else
nResult++;
}
#if __VER >= 15 // __CAMPUS
if( pQuestProp->m_nBeginCondTSP == 0 )
++nResult;
else
{
if( pMover->GetCampusPoint() >= pQuestProp->m_nBeginCondTSP )
++nResult;
}
#endif // __CAMPUS
#if __VER >= 12 // __MOD_TUTORIAL
#if __VER >= 15 // __CAMPUS
if( nResult == 24 + MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#else // __CAMPUS
if( nResult == 23 + MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#endif // __CAMPUS
#else // __MOD_TUTORIAL
if( nResult == 22 + MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#endif // __MOD_TUTORIAL
return 1;
}
return 0;
}
#if __VER >= 15 // __IMPROVE_QUEST_INTERFACE
int __IsNextLevelQuest( CMover* pMover, int nQuestId )
{
QuestProp* pQuestProp = prj.m_aPropQuest.GetAt( nQuestId );
if( pQuestProp )
{
int nResult = 0;
LPQUEST pCurQuest = pMover->GetQuest( nQuestId );
BOOL bComplete = pMover->IsCompleteQuest( nQuestId );
// 퀘스트가 존재하거나, 이미 완료된 적이 있는 퀘스트는 조건 성립 안됨. 반복하기 위해서는 완전히 제거하여 완료 배열에 없어여 한다.
if( pCurQuest || bComplete )
return 0;
// 이전 퀘스트 1,2,3,4,5,6
for( int i = 0; i < 6; i++ )
{
if( pQuestProp->m_anBeginCondPreviousQuest[ i ] == 0 )
nResult++;
else
{
LPQUEST pPreQuest = pMover->GetQuest( pQuestProp->m_anBeginCondPreviousQuest[ i ] );
BOOL bPreComplete = pMover->IsCompleteQuest( pQuestProp->m_anBeginCondPreviousQuest[ i ] );
if( pQuestProp->m_nBeginCondPreviousQuestType == 0 )
{
if( pPreQuest || bPreComplete )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPreviousQuestType == 1 )
{
if( pPreQuest == NULL && bPreComplete )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPreviousQuestType == 2 )
{
if( pPreQuest && bPreComplete == FALSE )
nResult++;
}
}
}
// 이전 퀘스트 7,8,9,10,11,12
for( i = 0; i < 6; i++ )
{
if( pQuestProp->m_anBeginCondExclusiveQuest[ i ] == 0 )
nResult++;
else
{
LPQUEST pPreQuest = pMover->GetQuest( pQuestProp->m_anBeginCondExclusiveQuest[ i ] );
BOOL bPreComplete = pMover->IsCompleteQuest( pQuestProp->m_anBeginCondPreviousQuest[ i ] );
if( pPreQuest == NULL && bPreComplete == FALSE )
nResult++;
}
}
// 직업 13
if( pQuestProp->m_nBeginCondJobNum == 0 )
nResult++;
else
for( int i = 0; i < pQuestProp->m_nBeginCondJobNum; i++ )
{
if( pQuestProp->m_nBeginCondJob[ i ] == pMover->GetJob() )
{
nResult++;
break;
}
}
// 레벨 14
if( pMover->GetLevel() < pQuestProp->m_nBeginCondLevelMin && pMover->GetLevel() + 5 >= pQuestProp->m_nBeginCondLevelMin )
nResult++;
// 파티 여부 15
if( pQuestProp->m_nBeginCondParty == 0 )
nResult++;
else
{
BOOL bParty = FALSE;
BOOL bLeader = FALSE;
int nSize = 0;
#ifdef __WORLDSERVER
CParty* pParty = g_PartyMng.GetParty( pMover->m_idparty );
if( pParty )
{
bParty = TRUE;
nSize = pParty->GetSizeofMember();
}
#else
bParty = g_Party.IsMember( g_pPlayer->m_idPlayer );
nSize = g_Party.GetSizeofMember();
#endif
if( pQuestProp->m_nBeginCondParty == 1 && bParty == FALSE )
nResult++;
else
if( pQuestProp->m_nBeginCondParty == 2 && bParty == TRUE )
{
if( pQuestProp->m_nBeginCondPartyLeader == -1 || pQuestProp->m_nBeginCondPartyLeader == bLeader )
{
if( pQuestProp->m_nBeginCondPartyNum == 0 )
nResult++;
else
if( pQuestProp->m_nBeginCondPartyNumComp == 0 )
{
if( nSize == pQuestProp->m_nBeginCondPartyNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPartyNumComp == 1 )
{
if( nSize >= pQuestProp->m_nBeginCondPartyNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondPartyNumComp == -1 )
{
if( nSize <= pQuestProp->m_nBeginCondPartyNum )
nResult++;
}
}
}
}
// 길드 여부 16
if( pQuestProp->m_nBeginCondGuild == 0 )
nResult++;
else
{
BOOL bGuild = FALSE;
BOOL bLeader = FALSE;
int nSize = 0;
/*
#ifdef __WORLDSERVER
g_PartyMng.m_AddRemoveLock.Enter( theLineFile );
CParty* pParty = g_PartyMng.GetParty( pMover->m_idparty );
if( pParty )
{
bParty = TRUE;
nSize = pParty->GetSizeofMember();
}
g_PartyMng.m_AddRemoveLock.Leave( theLineFile );
#else
bParty = g_Party.IsMember( g_pPlayer->m_idPlayer );
nSize = g_Party.GetSizeofMember();
#endif
*/
if( pQuestProp->m_nBeginCondGuild == 1 && bGuild == FALSE )
nResult++;
else
if( pQuestProp->m_nBeginCondGuild == 2 && bGuild == TRUE )
{
if( pQuestProp->m_nBeginCondGuildLeader == -1 || pQuestProp->m_nBeginCondGuildLeader == bLeader )
{
if( pQuestProp->m_nBeginCondGuildNum == 0 )
nResult++;
else
if( pQuestProp->m_nBeginCondGuildNumComp == 0 )
{
if( nSize == pQuestProp->m_nBeginCondGuildNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondGuildNumComp == 1 )
{
if( nSize >= pQuestProp->m_nBeginCondGuildNum )
nResult++;
}
else
if( pQuestProp->m_nBeginCondGuildNumComp == -1 )
{
if( nSize <= pQuestProp->m_nBeginCondGuildNum )
nResult++;
}
}
}
}
// 성별 17
if( pQuestProp->m_nBeginCondSex == -1 || pQuestProp->m_nBeginCondSex == pMover->GetSex() )
nResult++;
// 스킬 18
if( pQuestProp->m_nBeginCondSkillIdx == 0 )
nResult++;
else
{
LPSKILL lpSkill = pMover->GetSkill( pQuestProp->m_nBeginCondSkillIdx );
if( lpSkill )
{
if( pMover->CheckSkill( pQuestProp->m_nBeginCondSkillLvl ) && (int)( lpSkill->dwLevel ) >= pQuestProp->m_nBeginCondSkillLvl )
nResult++;
}
}
#if __VER >= 8 // __S8_PK
// PK Value 19
if( pQuestProp->m_nBeginCondPKValue == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondPKValue <= pMover->GetPKValue() )
nResult++;
}
// 아이템이 없는것 검사 MAX_QUESTCONDITEM
if( pQuestProp->m_nBeginCondNotItemNum == 0 )
nResult += MAX_QUESTCONDITEM;
else
for( int i = 0; i < MAX_QUESTCONDITEM; i++ )
{
if( i < pQuestProp->m_nBeginCondNotItemNum )
{
QuestPropItem* pBeginCondItem = &pQuestProp->m_paBeginCondNotItem[ i ];
if( pBeginCondItem->m_nSex == -1 || pBeginCondItem->m_nSex == pMover->GetSex() )
{
if( pBeginCondItem->m_nType == 0 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pBeginCondItem->m_nJobOrItem == pMover->GetJob() )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) < pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
else
if( pBeginCondItem->m_nType == 1 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pMover->GetItemNum( pBeginCondItem->m_nJobOrItem ) )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) < pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
}
}
else
nResult++;
}
#else // __VER >= 8 // __S8_PK
// 카르마 19
if( pQuestProp->m_nBeginCondKarmaPoint == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondKarmaComp == 0 )
{
if( pMover->GetKarma() == pQuestProp->m_nBeginCondKarmaPoint )
nResult++;
}
else
if( pQuestProp->m_nBeginCondKarmaComp == -1 )
{
if( pMover->GetKarma() < pQuestProp->m_nBeginCondKarmaPoint )
nResult++;
}
else
if( pQuestProp->m_nBeginCondKarmaComp == 1 )
{
if( pMover->GetKarma() > pQuestProp->m_nBeginCondKarmaPoint )
nResult++;
}
}
// 카오틱 20
if( pQuestProp->m_nBeginCondChaotic == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondChaotic == 1 && pMover->IsChaotic() )
nResult++;
else
if( pQuestProp->m_nBeginCondChaotic == 2 && pMover->IsChaotic() == FALSE )
nResult++;
}
#endif // __VER >= 8 // __S8_PK
// 변신 21
if( pQuestProp->m_nBeginCondDisguiseMoverIndex == 0 )
nResult++;
else
{
if( pQuestProp->m_nBeginCondDisguiseMoverIndex == -1 && pMover->IsDisguise() == FALSE )
nResult++;
else
if( pQuestProp->m_nBeginCondDisguiseMoverIndex == pMover->GetIndex() )
nResult++;
}
#if __VER >= 9 // __PET_0410
if( pQuestProp->m_nBeginCondPetExp == 0 )
nResult++;
else
{
CPet* pPet = pMover->GetPet();
if( pPet && pPet->GetExpPercent() >= pQuestProp->m_nBeginCondPetExp )
nResult++;
}
if( pQuestProp->m_nBeginCondPetLevel == -1 )
nResult++;
else
{
CPet* pPet = pMover->GetPet();
if( pPet && pPet->GetLevel() == pQuestProp->m_nBeginCondPetLevel )
nResult++;
}
#endif // __PET_0410
#if __VER >= 12 // __MOD_TUTORIAL
if( pQuestProp->m_nBeginCondTutorialState == -1
|| pMover->GetTutorialState() >= pQuestProp->m_nBeginCondTutorialState )
nResult++;
#endif // __MOD_TUTORIAL
// 수집 아이템 갯수 21 + MAX_QUESTCONDITEM
if( pQuestProp->m_nBeginCondItemNum == 0 )
nResult += MAX_QUESTCONDITEM;
else
for( int i = 0; i < MAX_QUESTCONDITEM; i++ )
{
if( i < pQuestProp->m_nBeginCondItemNum )
{
QuestPropItem* pBeginCondItem = &pQuestProp->m_paBeginCondItem[ i ];
if( pBeginCondItem->m_nSex == -1 || pBeginCondItem->m_nSex == pMover->GetSex() )
{
if( pBeginCondItem->m_nType == 0 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pBeginCondItem->m_nJobOrItem == pMover->GetJob() )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) >= pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
else
if( pBeginCondItem->m_nType == 1 )
{
if( pBeginCondItem->m_nJobOrItem == -1 || pMover->GetItemNum( pBeginCondItem->m_nJobOrItem ) )
{
if( pBeginCondItem->m_nItemIdx == 0 || pMover->GetItemNum( pBeginCondItem->m_nItemIdx ) >= pBeginCondItem->m_nItemNum )
nResult++;
}
else
nResult++;
}
}
}
else
nResult++;
}
#if __VER >= 15 // __CAMPUS
if( pQuestProp->m_nBeginCondTSP == 0 )
++nResult;
else
{
if( pMover->GetCampusPoint() >= pQuestProp->m_nBeginCondTSP )
++nResult;
}
#endif // __CAMPUS
#if __VER >= 12 // __MOD_TUTORIAL
#if __VER >= 15 // __CAMPUS
if( nResult == 24 + MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#else // __CAMPUS
if( nResult == 23 + MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#endif // __CAMPUS
#else // __MOD_TUTORIAL
if( nResult == 22 + MAX_QUESTCONDITEM + MAX_QUESTCONDITEM )
#endif // __MOD_TUTORIAL
return 1;
}
return 0;
}
#endif // __IMPROVE_QUEST_INTERFACE
#if __VER >= 8 // __S8_PK
void CMover::SetPKValue( int nValue )
{
if( nValue >= 0 ) // overflow!!
m_nPKValue = nValue;
}
void CMover::SetPKPropensity( DWORD dwValue )
{
int nValue = dwValue;
if( nValue >= 0 ) // overflow!!
m_dwPKPropensity = dwValue;
}
DWORD CMover::NextPKPropensity( int nPKValue )
{
int nResult = 60 * nPKValue * nPKValue;
if( nResult < 0 ) // overflow!!
nResult = 0x7fffffff;
return nResult;
}
#else // __VER >= 8 // __S8_PK
BOOL CMover::IsGuardReactionChao()
{
if( m_nSlaughter <= -2000 )
return TRUE;
return FALSE;
}
BOOL CMover::IsGuardReactionNormal()
{
if( m_nSlaughter > 0 )
return TRUE;
return FALSE;
}
#endif // __VER < 8 // __S8_PK
void CMover::SetJobLevel( int nLevel, int nJob )
{
#if 0
if( IsBaseJob() )
{
m_aJobLv[ nJob ] = nLevel;
}
else
{
if( nLevel > MAX_EXPJOBLEVEL )
m_aJobLv[ nJob ] = prj.m_aExpJobLevel[ MAX_EXPJOBLEVEL ];
else
m_aJobLv[ nJob ] = prj.m_aExpJobLevel[ nLevel ];
}
#endif
}
#ifdef __WORLDSERVER
void CMover::ProcessSFXDamage( void )
{
ProcessSFXExpire();
//#ifdef __INFINITE_0227
// DWORD dwTickCount = GetTickCount();
// int cbSFXInfo = m_mapSFXInfo.size();
// int cbSFXCount = m_mapSFXCount.size();
// int nInfo = 0;
// int nCount = 0;
//#endif // __INFINITE_0227
map<OBJID, queue<SFXHIT_INFO> >::iterator iInfo = m_mapSFXInfo.begin();
while( iInfo != m_mapSFXInfo.end() )
{
map<OBJID, queue<SFXHIT_INFO> >::iterator iInfo2 = iInfo;
++iInfo;
OBJID idTarget = iInfo2->first;
queue<SFXHIT_INFO> &qInfo = iInfo2->second;
map<OBJID, queue<SFXHIT_COUNT> >::iterator iCount = m_mapSFXCount.find( idTarget );
if( iCount == m_mapSFXCount.end() )
continue;
queue<SFXHIT_COUNT> &qCount = iCount->second;
// qInfo, qCount
while( qInfo.size() > 0 && qCount.size() > 0 )
{
SFXHIT_INFO &si = qInfo.front();
SFXHIT_COUNT &sc = qCount.front();
if( si.dwSkill == sc.dwSkill )
{
//#ifdef __INFINITE_0227
// nInfo++;
// nCount++;
//#endif // __INFINITE_0227
if( AttackBySFX( this, si ) == FALSE ) // 데미지 처리
{
m_mapSFXInfo.erase( idTarget );
m_mapSFXCount.erase( idTarget );
break;
}
qInfo.pop();
qCount.pop();
}
else
{
TRACE( "예외 처리\n" );
if( si.dwTickCount > sc.dwTickCount )
{
while( qCount.size() > 0 )
{
//#ifdef __INFINITE_0227
// nCount++;
//#endif // __INFINITE_0227
SFXHIT_COUNT &sc1 = qCount.front();
if( si.dwSkill == sc1.dwSkill )
break;
qCount.pop();
}
}
else if( si.dwTickCount < sc.dwTickCount )
{
while( qInfo.size() > 0 )
{
//#ifdef __INFINITE_0227
// nInfo++;
//#endif // __INFINITE_0227
SFXHIT_INFO &si1 = qInfo.front();
if( si1.dwSkill == sc.dwSkill )
break;
qInfo.pop();
}
}
else
{
//#ifdef __INFINITE_0227
// nInfo++;
// nCount++;
//#endif // __INFINITE_0227
// print
qInfo.pop();
qCount.pop();
}
}
}
}
//#ifdef __INFINITE_0227
// DWORD d = GetTickCount() - dwTickCount;
// if( d > 10 ) // > 10 ms
// Error( "ProcessSFXDamage: %d ms, i = %d, c = %d, i2 = %d, c2 = %d, n = %s, j = %d",
// d, cbSFXInfo, cbSFXCount, nInfo, nCount, m_szName, m_nJob );
//#endif // __INFINITE_0227
}
void CMover::ProcessSFXExpire( void )
{
DWORD dwTickCount = GetTickCount();
//#ifdef __INFINITE_0227
// int cbSFXInfo = m_mapSFXInfo.size();
// int cbSFXCount = m_mapSFXCount.size();
// int nInfo = 0;
// int nCount = 0;
//#endif // __INFINITE_0227
// 1.1
map<OBJID, queue<SFXHIT_INFO> >::iterator iInfo = m_mapSFXInfo.begin();
while( iInfo != m_mapSFXInfo.end() )
{
map<OBJID, queue<SFXHIT_INFO> >::iterator i2 = iInfo;
++iInfo;
OBJID idTarget = i2->first;
queue<SFXHIT_INFO> &q = i2->second;
while( q.size() > 0 )
{
//#ifdef __INFINITE_0227
// nInfo++;
//#endif // __INFINITE_0227
SFXHIT_INFO &si = q.front();
if( si.dwTickCount + SEC( 10 ) < dwTickCount ) // 만료 시간 경과
{
q.pop(); // 만료 정보 제거
TRACE( "idTarget=%d, INFO 만료정보 제거 됨\n", idTarget );
continue;
}
else
break;
}
if( q.size() == 0 )
{
m_mapSFXInfo.erase( idTarget );
TRACE( "idTarget=%d, INFO 완전 삭제\n", idTarget);
}
}
// 1.2
map<OBJID, queue<SFXHIT_COUNT> >::iterator iCount = m_mapSFXCount.begin();
while( iCount != m_mapSFXCount.end() )
{
map<OBJID, queue<SFXHIT_COUNT> >::iterator i2 = iCount;
++iCount;
OBJID idTarget = i2->first;
queue<SFXHIT_COUNT> &q = i2->second;
while( q.size() > 0 )
{
//#ifdef __INFINITE_0227
// nCount++;
//#endif // __INFINITE_0227
SFXHIT_COUNT &sc = q.front();
if( sc.dwTickCount + SEC( 10 ) < dwTickCount ) // 만료 시간 경과
{
q.pop(); // 만료 정보 제거
TRACE( "idTarget=%d, COUNT 만료정보 제거 됨\n", idTarget );
continue;
}
else
break;
}
if( q.size() == 0 )
{
m_mapSFXCount.erase( idTarget );
TRACE( "idTarget=%d, COUNT 완전 삭제\n", idTarget);
}
}
/*
#ifdef __INFINITE_0227
DWORD d = GetTickCount() - dwTickCount;
if( d > 10 ) // > 10 ms
Error( "ProcessSFXExpire: %d ms, i = %d, c = %d, i2 = %d, c2 = %d, n = %s, j = %d",
d, cbSFXInfo, cbSFXCount, nInfo, nCount, m_szName, m_nJob );
#endif // __INFINITE_0227
*/
}
#endif // __WORLDSERVER
#ifdef __CLIENT
void CMover::ProcessEyeFlash()
{
#if __VER >= 8 //__Y_EYE_FLASH_8
if( IsPlayer() && m_pModel && HasBuffByIk3(IK3_TEXT_DISGUISE) == FALSE && IsDisguise() == FALSE )
{
CModelObject* pModelObj = (CModelObject*)m_pModel;
O3D_ELEMENT* pElement = NULL;
pElement = pModelObj->GetParts(PARTS_HEAD);
if( pElement && pElement->m_pObject3D )
{
GMOBJECT* pGmObj = pElement->m_pObject3D->GetGMOBJECT(0);
if( pGmObj )
{
if( m_fDistCamera <= 11.0f )
{
if( IsDie() )
{
(*pGmObj->m_pMtrlBlkTexture) = CMover::m_pTextureEyeFlash[m_bySex][m_dwHeadMesh];
}
else
{
if( m_tmEye[0].IsTimeOut() )
{
FLOAT fSec = 50; // 깜박거리는 시간...
(*pGmObj->m_pMtrlBlkTexture) = CMover::m_pTextureEyeFlash[m_bySex][m_dwHeadMesh];
m_tmEye[0].Set( fSec+1000 );
m_tmEye[1].Set( fSec );
}
if( m_tmEye[1].IsTimeOut() )
{
// 눈떠있는 시간...
FLOAT fSec = xRandomF( 2 ) + 5;
fSec *= 1000.0f;
if( xRandom( 100 ) < 10 )
fSec = 500.0f;
(*pGmObj->m_pMtrlBlkTexture) = CMover::m_pTextureEye[m_bySex][m_dwHeadMesh];
m_tmEye[1].Set( fSec+1000 );
m_tmEye[0].Set( fSec );
}
}
}
else
{
if( IsDie() )
(*pGmObj->m_pMtrlBlkTexture) = CMover::m_pTextureEyeFlash[m_bySex][m_dwHeadMesh];
else
(*pGmObj->m_pMtrlBlkTexture) = CMover::m_pTextureEye[m_bySex][m_dwHeadMesh];
}
}
}
}
#endif //__Y_EYE_FLASH_8
}
#if __VER >= 14 // __WING_ITEM
void CMover::WingMotionSetting( const CModelObject* pModel )
{
if( m_pRide == NULL && m_pRide->m_pBone == NULL )
return;
if( ( m_pActMover->GetState() & OBJSTA_STAND ) && ( D3DXVec3LengthSq( &m_pActMover->m_vDelta ) <= 0.000f ) && pModel->m_fFrameCurrent == 0.0f )
{
if( m_eWingStateFlag != FLOATING )
{
CString strMotion = m_pRide->GetMotionFileName( _T("stand") );
assert( strMotion != _T("") );
m_pRide->LoadMotion( strMotion );
m_pRide->SetMotionBlending( TRUE );
m_pRide->SetLoop( ANILOOP_LOOP );
m_eWingStateFlag = FLOATING;
}
}
else if( m_pActMover->GetStateFlag() & OBJSTAF_ACC )
{
if( m_eWingStateFlag != FLYING )
{
CString strMotion = m_pRide->GetMotionFileName( _T("walk") );
assert( strMotion != _T("") );
m_pRide->LoadMotion( strMotion );
m_pRide->SetMotionBlending( TRUE );
m_pRide->SetLoop( ANILOOP_LOOP );
m_eWingStateFlag = FLYING;
}
}
else if( ( m_pActMover->GetState() & OBJSTA_LTURN ) || ( m_pActMover->GetState() & OBJSTA_RTURN ) )
{
if( m_eWingStateFlag != TURNING )
m_eWingStateFlag = TURNING;
}
}
float CMover::GetRideFrameSpeed( void )
{
float fFrameSpeed = 1.0f;
if( m_pRide )
{
float fNowLengthSq = D3DXVec3LengthSq( &m_pActMover->m_vDelta );
fFrameSpeed = 1.0f + ( fabs( fNowLengthSq - m_fOldLengthSq ) * 7000.0f );
m_fOldLengthSq = fNowLengthSq;
if( ( m_pActMover->GetStateFlag() & OBJSTAF_ACC ) && ( m_pActMover->GetStateFlag() & OBJSTAF_TURBO ) )// 가속 상태이고 터보 상태일 때
fFrameSpeed += 1.2f;
if( fFrameSpeed < 1.0f )
fFrameSpeed = 1.0f;
if( fFrameSpeed > 4.0f )
fFrameSpeed = 4.0f;
}
return fFrameSpeed;
}
#endif // __WING_ITEM
#endif //__CLIENT
#ifdef __CLIENT
#if __VER >= 8 //__CSC_VER8_5
void CMover::CreateAngelParticle( D3DXVECTOR3 vPos )
{
FLOAT fAngXZ, fAngH, fDist, fSpeed;
D3DXVECTOR3 vVel;
fAngXZ = GetAngle();
fAngXZ += 180.0f;
fAngXZ = D3DXToRadian( fAngXZ );
vPos.y += 1.1f;
for( int j = 0; j < 2; j ++ )
{
vPos.y -= 0.03f;
{
fAngXZ = (float)(-45.0f + xRandomF(90));
fAngXZ += GetAngle();
fAngXZ += 180.0f;
fAngXZ = D3DXToRadian( fAngXZ );
fAngH = (float)(GetAngleX() + xRandomF(-30) + xRandomF(30) );
fAngH = D3DXToRadian( fAngH );
fSpeed = xRandomF(0.02f);
fDist = cosf(-fAngH) * fSpeed;
vVel.x = sinf(fAngXZ) * fDist;
vVel.z = -cosf(fAngXZ) * fDist;
vVel.y = -sinf(-fAngH) * fSpeed;
g_ParticleMng.CreateParticle( m_dwAngelKind + xRandom(3), vPos, vVel, GetPos().y + 0.5f );
}
}
}
#endif //__CSC_VER8_5
#if __VER >= 9 // __PET_0410
void CMover::CreatePetParticle( D3DXVECTOR3 vPos )
{
FLOAT fAngXZ, fAngH, fDist, fSpeed;
D3DXVECTOR3 vVel;
fAngXZ = GetAngle();
fAngXZ += 180.0f;
fAngXZ = D3DXToRadian( fAngXZ );
for( int j = 0; j < 4; j ++ )
{
vPos.y -= 0.03f;
{
fAngXZ = (float)(-45.0f + xRandomF(360));
fAngXZ += GetAngle();
fAngXZ += 180.0f;
fAngXZ = D3DXToRadian( fAngXZ );
fAngH = (float)(GetAngleX() + xRandomF(-130) + xRandomF(130) );
fAngH = D3DXToRadian( fAngH );
fSpeed = xRandomF(0.015f);
fDist = cosf(-fAngH) * fSpeed;
vVel.x = sinf(fAngXZ) * fDist;
vVel.z = -cosf(fAngXZ) * fDist;
vVel.y = -sinf(-fAngH) * fSpeed;
g_ParticleMng.CreateParticle( 13 + xRandom(11), vPos, vVel, GetPos().y + 0.5f );
}
}
}
#endif //__PET_0410
#endif //__CLIENT
#if __VER >= 9 // __PET_0410
void CMover::ProcessPet( void )
{
#ifdef __CLIENT
// m_dwPetId 가 존재하는데, m_pPet이 없으면, 생성한다.
// 생성시, ActiveMover인 경우와, 아닌경우를 분리해서 처리한다.
if( HasActivatedSystemPet() )
{
if( m_pet.GetObj() == NULL )
{
DWORD dwIndex = 0;
if( IsActiveMover() )
{
CItemElem* pItemElem = GetPetItem();
if( pItemElem && pItemElem->m_pPet )
dwIndex = pItemElem->m_pPet->GetIndex();
}
else //
dwIndex = (DWORD)LOWORD( GetPetId() );
if( dwIndex > 0 )
{
CMover* pPet = (CMover *)CreateObj( D3DDEVICE, OT_MOVER, dwIndex );
#ifdef __PET_1024
if( m_pet.HasName() )
pPet->SetName( m_pet.GetName() );
#endif // __PET_1024
pPet->InitMotion( MTI_STAND );
pPet->UpdateLocalMatrix();
pPet->m_pAIInterface = new CAIEgg( pPet, GetId() );
pPet->m_dwAIInterface = AII_EGG;
pPet->m_dwAIInterfaceState = 2;
pPet->SetPos( GetPos() );
pPet->m_vScrPos = GetPos();
GetWorld()->AddObj( pPet, FALSE );
m_pet.SetObj( pPet );
pPet->InitInterpolation();
if( IsActiveMover() )
lstrcpy( pPet->m_szCharacterKey, "MaFl_Pet" );
CreatePetSfx();
m_pet.SetLevelup( 0 );
if( FALSE == g_WndMng.GetWndBase( APP_PET_STATUS ) && this->IsActiveMover() )
{
SAFE_DELETE( g_WndMng.m_pWndPetStatus );
g_WndMng.m_pWndPetStatus = new CWndPetStatus;
g_WndMng.m_pWndPetStatus->Initialize();
}
// if( FALSE == g_WndMng.GetWndBase( APP_BUFFPET_STATUS ) )
// {
// SAFE_DELETE( g_WndMng.m_pWndBuffPetStatus );
// g_WndMng.m_pWndBuffPetStatus = new CWndBuffPetStatus;
// g_WndMng.m_pWndBuffPetStatus->Initialize();
// }
}
}
}
else
{
if( m_pet.GetObj() )
{
m_pet.GetObj()->Delete();
m_pet.SetObj( NULL );
if( g_WndMng.GetWndBase( APP_PET_STATUS ) && this->IsActiveMover() )
g_WndMng.m_pWndPetStatus->Destroy();
// if( g_WndMng.GetWndBase( APP_BUFFPET_STATUS ) && this->IsActiveMover( ) )
// g_WndMng.m_pWndBuffPetStatus->Destroy();
}
}
if( m_pet.GetObj() != NULL )
{
if(IsActiveMover())
{
CItemElem* m_pPetElem = g_pPlayer->GetPetItem();
if(m_pPetElem != NULL && m_pPetElem->m_pPet->GetLevel() == PL_S )
CreatePetParticle( m_pet.GetObj()->GetScrPos());
}
else
{
DWORD dwLevel = (DWORD)HIWORD( GetPetId() );
if(dwLevel == PL_S)
CreatePetParticle( m_pet.GetObj()->GetScrPos());
}
}
#else // __CLIENT
ProcessPetAvail();
ProcessPetEnergy();
ProcessPetExp();
#if __VER >= 15 // __PETVIS
ProcessVisPet();
#endif // __PETVIS
#endif // __CLIENT
}
CItemElem* CMover::GetPetItem( void )
{
if( HasActivatedSystemPet() )
{
CItemElem* pItemElem = static_cast<CItemElem*>( GetItemId( m_dwPetId ) );
if( pItemElem && pItemElem->IsPet() )
return pItemElem;
}
return NULL;
}
CPet* CMover::GetPet( void )
{
CItemElem* pItemElem = GetPetItem();
if( pItemElem )
return pItemElem->m_pPet;
return NULL;
}
void CMover::PetLevelup( void )
{
#ifdef __CLIENT
if( m_pet.GetObj() ) // 제거 하면, 프로세스에서 재생
{
m_pet.SetLevelup( PF_PET_LEVEL_UP );
m_pet.GetObj()->Delete();
m_pet.SetObj( NULL );
}
#else // __CLIENT
CItemElem* pItemElem = GetPetItem();
CPet* pPet = pItemElem->m_pPet;
if( pPet->GetLevel() == PL_EGG ) // 부화
{
pPet->SetKind( CPetProperty::GetInstance()->Hatch() );
pPet->SetLife( 1 );
#if __VER >= 13 // __HONORABLE_TITLE // 달인
((CUser*)this)->SetHonorAdd(HS_HATCHING_EGG,HI_COUNT_CHECK);
#endif // __HONORABLE_TITLE // 달인
}
pPet->IncLevel();
pItemElem->m_dwItemId = pPet->GetItemId();
pPet->SetExp( 0 );
pPet->SetEnergy( pPet->GetMaxEnergy() );
BYTE nAvailLevel = CPetProperty::GetInstance()->GetLevelupAvailLevel( pPet->GetLevel() );
pPet->SetAvailLevel( pPet->GetLevel(), nAvailLevel );
if( HasPet() )
RemovePet();
g_dpDBClient.CalluspPetLog( m_idPlayer, pItemElem->GetSerialNumber(), 0, PETLOGTYPE_LEVELUP, pPet );
( (CUser*)this )->AddPet( pPet, PF_PET_LEVEL_UP ); // 自
g_UserMng.AddPetLevelup( this, MAKELONG( (WORD)pPet->GetIndex(), (WORD)pPet->GetLevel() ) ); // 他
#endif // __CLIENT
}
#ifdef __WORLDSERVER
void CMover::ProcessPetAvail( void )
{
CPet* pPet = GetPet();
if( pPet )
{
if( HasPet() == FALSE )
{
CItemElem* pItemElem = GetPetItem();
DWORD dwDestParam;
int nParam;
pPet->GetAvailDestParam( dwDestParam, nParam );
if( dwDestParam > 0 )
{
// wID: dwItemId
// dwLevel: dwDestParam(H) + nParam(L)
AddBuff( BUFF_PET, (WORD)( pItemElem->m_dwItemId ), MAKELONG( (WORD)nParam, (WORD)dwDestParam ), 0 );
SetDestParam( dwDestParam, nParam, NULL_CHGPARAM, TRUE );
}
#if __VER >= 12 // __PET_0519
SetDestParamRandomOptExtension( pItemElem );
#endif // __PET_0519
}
}
else
{
PetRelease();
}
}
void CMover::ProcessPetEnergy( void )
{
//#ifdef __INTERNALSERVER
// if( ( m_nCount & 3 ) != 0 ) // 기력이 0.2초에 1p 감소
//#else // __INTERNALSERVER
if( ( m_nCount & 15 ) != 0 ) // 기력이 1초에 1p 감소
//#endif // __INTERNALSERVER
return;
CPet* pPet = GetPet();
if( pPet == NULL )
return;
if( pPet->GetLevel() == PL_EGG )
return;
if( HasBuff( BUFF_ITEM, II_SYS_SYS_SCR_PET_TONIC_A )
|| HasBuff( BUFF_ITEM, II_SYS_SYS_SCR_PET_TONIC_B )
) // 펫 전용 영양제(A) // 펫 전용 영양제(B) 사용시 기력 감소 없음.
return;
#if __VER >= 12 // __JHMA_VER12_1 //12차 극단유료아이템
if( HasBuff( BUFF_ITEM2, II_SYS_SYS_SCR_SPETGOOD )
&& pPet->GetLevel() == PL_S
) // S급 펫 전용 먹이
return;
#endif // //12차 극단유료아이템
// 자동 먹이 가방
if( HasBuff( BUFF_ITEM, II_SYS_SYS_SCR_PET_FEED_POCKET )
#ifdef __JEFF_11_1
|| HasBuff( BUFF_ITEM, II_SYS_SYS_SCR_PET_FEED_POCKET02 )
#endif // __JEFF_11_1
)
{
// 먹이를 검색해서 개수를 감소시킨다.
CItemElem* ptr;
int nMax = m_Inventory.GetMax();
for( int i = 0 ; i < nMax; i++ )
{
ptr = m_Inventory.GetAtId( i );
if( IsUsableItem( ptr ) && ptr->m_dwItemId == II_SYS_SYS_FEED_01 ) // 사용 가능한 먹이면
{
if( ( m_nCount & 0X1F ) == 0 ) // 2초당 먹이 1소모 // 0723
UpdateItem( (BYTE)( ptr->m_dwObjId ), UI_NUM, ptr->m_nItemNum - 1 );
return;
}
}
}
CItemElem* pItemElem = GetPetItem();
// 기력이 0이하면, 생명 1 감소
int nEnergy = (int)pPet->GetEnergy();
if( --nEnergy <= 0 )
{
int nLife = (int)pPet->GetLife();
if( --nLife >= 0 )
{
// 생명이 0 이상이면, 부활
pPet->SetLife( nLife );
pPet->SetEnergy( CPetProperty::GetInstance()->GetMaxEnergy( pPet->GetLevel() ) );
// pPet->SetExp( 0 );
g_dpDBClient.CalluspPetLog( m_idPlayer, pItemElem->GetSerialNumber(), 0, PETLOGTYPE_DEATH, pPet );
}
else
{
// 생명이 0 미만이면, 완전 소멸
pPet->SetLife( 0 );
pPet->SetEnergy( 0 );
pPet->SetExp( 0 );
// 만료 아이템의 경우, 알이면 사망이라고 표시
pItemElem->SetFlag( CItemElem::expired );
UpdateItem( (BYTE)( pItemElem->m_dwObjId ), UI_FLAG, MAKELONG( pItemElem->m_dwObjIndex, pItemElem->m_byFlag ) );
g_dpDBClient.CalluspPetLog( m_idPlayer, pItemElem->GetSerialNumber(), 0, PETLOGTYPE_DEATH, pPet );
// 펫 소환 해제
PetRelease();
}
}
else
{
pPet->SetEnergy( nEnergy );
}
( (CUser*)this )->AddPetState( pItemElem->m_dwObjId , pPet->GetLife(), pPet->GetEnergy(), pPet->GetExp() );
}
void CMover::ProcessPetExp( void )
{
//#ifdef __INTERNALSERVER
// if( ( m_nCount & 3 ) != 0 ) // 0.2초
//#else // __INTERNALSERVER
if( ( m_nCount & 1023 ) != 0 ) // // 경험치가 1분에 1회 상승
//#endif // // 경험치가 1분에 1회 상승
return;
CPet* pPet = GetPet();
if( pPet == NULL )
return;
// 등급이 알이거나, S가 아니면,
if( pPet->GetLevel() != PL_EGG && pPet->GetLevel() != PL_S )
{
if( pPet->GetExp() == MAX_PET_EXP )
return;
float fFactor = HasBuff( BUFF_ITEM, II_SYS_SYS_SCR_PET_TONIC_B )? 1.5F: 1.0F;
// 100000 = 100%
DWORD dwExp = (DWORD)( pPet->GetExp() + CPetProperty::GetInstance()->GetIncrementExp( pPet->GetLevel() ) * fFactor );
if( dwExp > MAX_PET_EXP )
dwExp = MAX_PET_EXP;
pPet->SetExp( dwExp );
( (CUser*)this )->AddPetSetExp( dwExp );
}
}
#endif // __WORLDSERVER
#ifdef __CLIENT
void CMover::CreatePetSfx( void )
{
CMover* pPet = m_pet.GetObj();
if( !pPet )
return;
switch( m_pet.GetLevelup() )
{
case PF_PET_LEVEL_UP:
//level up Sound
PLAYSND( "PCSkillCastCheer.wav" );
//level up Effect
break;
case PF_PET_LEVEL_DOWN: // 신찬 : 펫 테이머의 실수 사용 직후
// 공통 효과
break;
case PF_PET_GET_AVAIL: // 신찬 : 펫 테이머의 기적 사용 직후
if( IsActiveMover() )
{
CWndPetMiracle* pWndMiracle = (CWndPetMiracle*)g_WndMng.GetWndBase( APP_PET_MIRACLE );
if(pWndMiracle != NULL)
{
CPet* pCPet = GetPet();
int nLevel = pCPet->GetLevel();
pWndMiracle->ReceiveResult(pCPet->GetAvailLevel(nLevel-1), pCPet->GetAvailLevel(nLevel));
}
}
break;
}
}
#endif // __CLIENT
void CMover::PetRelease( void )
{
#ifdef __CLIENT
if( m_pet.GetObj() )
{
m_pet.GetObj()->Delete();
m_pet.SetObj( NULL );
}
SetPetId( NULL_ID );
PLAYSND( "ItemGnCollector.wav" );
#else // __CLIENT
CItemElem* pItemElem = GetPetItem();
if( !( pItemElem && pItemElem->m_pPet ) )
return;
CPetProperty* pProperty = CPetProperty::GetInstance();
CPet* pPet = pItemElem->m_pPet;
PPETPENALTY pPenalty = pProperty->GetPenalty( pPet->GetLevel() );
if( pPenalty )
{
if( pPenalty->fExp > 0.0f )
{
//Pet 소환 후 해제 시 D~A레벨에선 경험치를 잃게 되며,
// 최소 0%에서는 더 이상 감소하지 않는다.
DWORD dwExp = (DWORD)( 100000 * pPenalty->fExp / 100.0F );
if( dwExp > pPet->GetExp() )
dwExp = pPet->GetExp();
pPet->SetExp( pPet->GetExp() - dwExp );
}
if( pPenalty->wEnergy > 0 )
{
// S레벨에선 HP가 감소하며, 최소 5P 이하로는 더 이상 감소하지 않는다.
int nHP = (int)pPet->GetEnergy();
int nPenalty = (int)pPenalty->wEnergy;
if( nHP < 5 )
nPenalty = 0;
else if( nHP - nPenalty < 5 )
nPenalty = nHP - 5;
pPet->SetEnergy( nHP - (WORD)nPenalty );
}
( (CUser*)this )->AddPetState( pItemElem->m_dwObjId, pPet->GetLife(), pPet->GetEnergy(), pPet->GetExp() );
}
if( HasPet() )
RemovePet();
//#if __VER >= 12 // __PET_0519 // RemovePet() 안으로 이동
// // 시스템 펫 해제 시, 시스템 펫 각성 효과 제거
// ResetDestParamRandomOptExtension( pItemElem );
//#endif // __PET_0519
g_dpDBClient.CalluspPetLog( m_idPlayer, pItemElem->GetSerialNumber(), 0, PETLOGTYPE_RELEASE, pItemElem->m_pPet );
SetPetId( NULL_ID );
g_UserMng.AddPetRelease( this );
#endif // __CLIENT
}
#endif // __PET_0410
#if __VER >= 12 // __PET_0519
// 11차 이전까지 현재 소환중인 먹펫 확인 불가
// 이를 가능하게 하기 위해 먹펫 객체에 아이템 식별자를 추가함
BOOL CMover::IsUsingEatPet( CItemElem* pItemElem )
{
if( HasActivatedEatPet() ) // 소환중인 먹펫이 있으면
{
CMover* pEatPet = prj.GetMover( GetEatPetId() ); // 먹펫 객체를 찾아서
if( IsValidObj( pEatPet ) )
{
// 아이템 식별자가 같으면 소환중인 먹펫이다
CAIPet* pAIPet = static_cast<CAIPet*>( pEatPet->m_pAIInterface );
if( pAIPet && pAIPet->GetPetItemId() == pItemElem->m_dwObjId )
return TRUE;
}
}
return FALSE;
}
#endif // __PET_0519
BOOL CMover::IsUsing( CItemElem* pItemElem )
{ // 사용중인 아이템인가?
#if __VER >= 12 // __PET_0519
if( IsUsingEatPet( pItemElem ) ) // 소환중인 먹펫이면
return TRUE;
#else // __PET_0519
if( HasActivatedEatPet() && pItemElem->IsEatPet() )
return TRUE;
#endif // __PET_0519
#if __VER >= 9 // __PET_0410
if( GetPetId() == pItemElem->m_dwObjId )
return TRUE;
if( pItemElem->m_dwItemId == II_SYS_SYS_SCR_PET_FEED_POCKET && pItemElem->m_dwKeepTime > 0
&& HasBuff( BUFF_ITEM, (WORD)( pItemElem->m_dwItemId ) ) && !pItemElem->IsFlag( CItemElem::expired ))
return TRUE;
#endif // __PET_0410
#ifdef __SYS_TICKET
if( pItemElem == GetTicket() )
return TRUE;
#endif // __SYS_TICKET
return FALSE;
}
#if __VER >= 13 // __HONORABLE_TITLE // 달인
void CMover::SetHonorCount(int nIdx , int nCount )
{
if( nIdx < 0 || nIdx >= MAX_HONOR_TITLE)
return;
if( nCount < INT_MAX )
m_aHonorTitle[nIdx] = nCount;
}
void CMover::SetHonorAdd(int nSmallIdx,int nLargeGroup,int nDefault )
{
#ifdef __WORLDSERVER
ASSERT( IsPlayer() );
HonorData* pHonorData = CTitleManager::Instance()->GetHonorDataByID(nSmallIdx,nLargeGroup);
if(pHonorData)
{
if( nDefault == 0)
SetHonorCount(pHonorData->nID,m_aHonorTitle[pHonorData->nID] + 1);
else
SetHonorCount(pHonorData->nID,nDefault);
if(pHonorData->nNeed == GetHonorTitle(pHonorData->nID) )
{
( (CUser*)this )->AddHonorListAck();
g_dpDBClient.SendLogGetHonorTime(this,pHonorData->nID);
}
}
/*
int nIdx = CTitleManager::Instance()->GetIdx(nSmallIdx,nLargeGroup);
if( nIdx >= 0)
{
SetHonorCount(nIdx,m_aHonorTitle[nIdx] + 1);
int nNeedCount = CTitleManager::Instance()->GetNeedCount(nSmallIdx,nLargeGroup);
if( nNeedCount == GetHonorTitle(nIdx) )
{
( (CUser*)this )->AddHonorListAck();
g_dpDBClient.SendLogGetHonorTime(this,nIdx);
}
}
*/
#endif // __WORLDSERVER
}
void CMover::CheckHonorStat()
{
#ifdef __WORLDSERVER
if( m_nHonor < -1 || m_nHonor >= MAX_HONOR_TITLE)
m_nHonor = -1;
int nIdx = 0;
nIdx = CTitleManager::Instance()->GetIdx(JOB_KNIGHT_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_KNIGHT_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_BLADE_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_BLADE_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_JESTER_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_JESTER_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_RANGER_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_RANGER_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_RINGMASTER_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_RINGMASTER_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_BILLPOSTER_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_BILLPOSTER_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_PSYCHIKEEPER_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_PSYCHIKEEPER_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_ELEMENTOR_MASTER,HI_EARN_TITLE);
if( m_nJob == JOB_ELEMENTOR_MASTER )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_KNIGHT_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_KNIGHT_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_BLADE_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_BLADE_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_JESTER_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_JESTER_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_RANGER_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_RANGER_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_RINGMASTER_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_RINGMASTER_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_BILLPOSTER_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_BILLPOSTER_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_PSYCHIKEEPER_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_PSYCHIKEEPER_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(JOB_ELEMENTOR_HERO,HI_EARN_TITLE);
if( m_nJob == JOB_ELEMENTOR_HERO )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
nIdx = CTitleManager::Instance()->GetIdx(HS_STR,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nStr);
nIdx = CTitleManager::Instance()->GetIdx(HS_STA,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nSta);
nIdx = CTitleManager::Instance()->GetIdx(HS_DEX,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nDex);
nIdx = CTitleManager::Instance()->GetIdx(HS_INT,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nInt);
//10 HI_COUNT_CHECK HS_PVP_POINT01 10 IDS_TITLE_TXT_0011 //초보 파이터 // 초보 파이터
//11 HI_COUNT_CHECK HS_PVP_POINT02 100 IDS_TITLE_TXT_0012 //견습 파이터 // 견습 파이터
//12 HI_COUNT_CHECK HS_PVP_POINT03 1000 IDS_TITLE_TXT_0013 //노력하는 파이터 // 노력하는 파이터
//1/3 HI_COUNT_CHECK HS_PVP_POINT04 4000 IDS_TITLE_TXT_0014 //패기있는 파이터 // 패기있는 파이터
//14 HI_COUNT_CHECK HS_PVP_POINT05 10000 IDS_TITLE_TXT_0015 //알려진 파이터 // 알려진 파이터
//15 HI_COUNT_CHECK HS_PVP_POINT06 20000 IDS_TITLE_TXT_0016 //강한 파이터 // 강한 파이터
//16 HI_COUNT_CHECK HS_PVP_POINT07 50000 IDS_TITLE_TXT_0017 //유명한 파이터 // 유명한 파이터
//17 HI_COUNT_CHECK HS_PVP_POINT08 1000000 IDS_TITLE_TXT_0018 //훌륭한 파이터 // 훌륭한 파이터
//18 HI_COUNT_CHECK HS_PVP_POINT09 5000000 IDS_TITLE_TXT_0019 //인기많은 파이터 // 인기많은 파이터
//19 HI_COUNT_CHECK HS_PVP_POINT10 100000000 IDS_TITLE_TXT_0020 //최강의 파이터 //
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT01,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT02,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT03,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT04,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT05,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT06,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT07,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT08,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT09,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PVP_POINT10,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nFame);
nIdx = CTitleManager::Instance()->GetIdx(HS_PK_COUNT,HI_COUNT_CHECK);
SetHonorCount(nIdx,m_nPKValue);
nIdx = CTitleManager::Instance()->GetIdx(HS_LORD,HI_EARN_TITLE);
if( CSLord::Instance()->IsLord( m_idPlayer ) )
SetHonorCount(nIdx,1);
else
SetHonorCount(nIdx,0);
if( GetHonorTitle(m_nHonor) < CTitleManager::Instance()->GetNeedCount(m_nHonor,-1))
m_nHonor = -1;
#endif // __WORLDSERVER
}
void CMover::CheckHonorTime()
{
#ifdef __WORLDSERVER
// m_dwHonorCheckTime
if( m_pActMover->GetActionState() == OBJSTA_COLLECT ) //채집중
{
DWORD dwTick = GetTickCount();
if( ( m_dwHonorCheckTime + 3600000 ) < dwTick )
{
m_dwHonorCheckTime = dwTick;
((CUser*)this)->SetHonorAdd(HS_COLLECT,HI_ELASPED_TIME);
}
}
if( m_vtInfo.VendorIsVendor() || m_vtInfo.IsVendorOpen() ) //개인상점중
{
DWORD dwTick = GetTickCount();
if( ( m_dwHonorCheckTime + 3600000 ) < dwTick )
{
m_dwHonorCheckTime = dwTick;
((CUser*)this)->SetHonorAdd(HS_TRADE,HI_ELASPED_TIME);
}
}
#endif // __WORLDSERVER
}
#endif // __HONORABLE_TITLE // 달인
#if __VER >= 9 //__AI_0509
#ifdef __WORLDSERVER
BOOL CMover::IsReturnToBegin( void )
{
if( m_pAIInterface )
return m_pAIInterface->IsReturnToBegin();
return FALSE;
}
#endif // __WORLDSERVER
void CMover::SetSpeedFactor( FLOAT fSpeedFactor )
{
if( fabs( m_fSpeedFactor - fSpeedFactor ) > 0.000001F )
{
m_fSpeedFactor = fSpeedFactor;
#ifdef __WORLDSERVER
g_UserMng.AddSetSpeedFactor( this, fSpeedFactor );
#endif // __WORLDSERVER
}
}
#endif // __AI_0509
#if __VER >= 11 // __SYS_COLLECTING
void CMover::ProcessCollecting( void )
{
#ifdef __CLIENT
CItemElem* pCol = GetCollector();
// pCol = 채집기
if( pCol == NULL )
{
// 통상 상태A
g_WndMng.CloseCollecting();
}
else if( m_pActMover->GetActionState() == OBJSTA_COLLECT )
{
// 채집 상태
// SFX
if( ( m_dwFlag & MVRF_COLLECT ) == 0 )
{
ItemProp *pHandProp = GetActiveHandItemProp();
if( pHandProp->dwSfxObj2 != NULL_ID )
{
D3DXVECTOR3 vSrc, vLocal = D3DXVECTOR3( 0, 0.5f, 0 );
( (CModelObject *)m_pModel )->GetForcePos( &vLocal, 0, PARTS_RWEAPON, GetMatrixWorld() );
vSrc = vLocal;
CSfx *pSfx = CreateSfx( D3DDEVICE, pHandProp->dwSfxObj2, vSrc, GetId(), D3DXVECTOR3( 0, 0, 0 ), NULL_ID, -1 );
if( pSfx )
{
pSfx->SetAngle( -GetAngle() + 90.0f );
//pSfx->SetAngleX(90.0f);
m_dwFlag |= MVRF_COLLECT;
}
}
if(g_WndMng.m_pWndCollecting) g_WndMng.m_pWndCollecting->SetButtonCaption(true);
} // SFX
if(g_WndMng.m_pWndCollecting) g_WndMng.m_pWndCollecting->Update();
if(m_nCltTime < m_nMaxCltTime) ++m_nCltTime;
else if(m_nCltTime >= m_nMaxCltTime) m_nCltTime = m_nMaxCltTime;
}
else
{
// 채집 대기 상태
g_WndMng.OpenCollecting();
g_WndMng.m_pWndCollecting->SetButtonCaption(false);
g_WndMng.m_pWndCollecting->Update();
}
#endif // __CLIENT
}
void CMover::StartCollecting( void )
{
ClearDest();
m_dwFlag |= MVRF_NOACTION;
m_dwMode |= DONMOVE_MODE;
SendActMsg( OBJMSG_STOP );
SendActMsg( OBJMSG_COLLECT );
#ifdef __CLIENT
CItemElem* pCollector = GetCollector();
CCollectingProperty* pProperty = CCollectingProperty::GetInstance();
if( pCollector ) m_nMaxCltTime = pProperty->GetCool( pCollector->GetAbilityOption() ) + 1;
m_nCltTime = 0;
#endif // __CLIENT
}
void CMover::StopCollecting( void )
{
m_dwFlag &= (~MVRF_NOACTION);
m_dwMode &= (~DONMOVE_MODE);
m_pActMover->ResetState( OBJSTA_ACTION_ALL );
m_pActMover->SetMoveState( OBJSTA_STAND );
m_pActMover->RemoveStateFlag( OBJSTAF_ETC );
SetMotion( MTI_STAND );
}
CItemElem* CMover::GetCollector( void )
{
CItemElem* pCol = GetWeaponItem();
if( pCol && ( !pCol->IsCollector() || pCol->IsFlag( CItemElem::expired ) ) )
pCol = NULL;
return pCol;
}
#endif // __SYS_COLLECTING
#if __VER >= 11 // __SYS_POCKET
CItemElem* CMover::GetItemId2( int nPocket, int nItem, BOOL bExpiration )
{
if( nPocket < 0 )
return m_Inventory.GetAtId( nItem );
return m_Pocket.GetAtId( nPocket, nItem, bExpiration );
}
BOOL CMover::CreateItem2( CItemElem* pItem, int nPocket )
{
#ifdef __WORLDSERVER
if( nPocket < 0 )
return CreateItem( pItem );
#endif // __WORLDSERVER
return m_Pocket.Add( nPocket, pItem );
}
void CMover::RemoveItem2( int nItem, short nNum, int nPocket )
{
#ifdef __WORLDSERVER
if( nPocket < 0 )
RemoveItem( nItem, nNum );
else
#endif // __WORLDSERVER
m_Pocket.RemoveAtId( nPocket, nItem, nNum );
}
#endif // __SYS_POCKET
#ifdef __SYS_TICKET
CItemElem* CMover::GetTicket( void )
{
#ifdef __BUFF_1107
IBuff* pBuff = m_buffs.GetBuffByIk3( IK3_TICKET );
if( !pBuff )
return NULL;
#else // __BUFF_1107
LPSKILLINFLUENCE pInfluence = m_SkillState.GetItemBuf( IK3_TICKET );
if( !pInfluence )
return NULL;
#endif // __BUFF_1107
CItemElem* pTicket;
for( DWORD i = 0; i < m_Inventory.m_dwItemMax; i++ )
{
pTicket = m_Inventory.GetAtId( i );
if( pTicket && pTicket->m_dwKeepTime > 0 && pTicket->GetProp()->dwItemKind3 == IK3_TICKET
#ifdef __BUFF_1107
&& pTicket->m_dwItemId == (DWORD)pBuff->GetId()
#else // __BUFF_1107
&& pTicket->m_dwItemId == (DWORD)pInfluence->wID
#endif // __BUFF_1107
&& !pTicket->IsFlag( CItemElem::expired ) )
return pTicket;
}
return NULL;
}
#endif // __SYS_TICKET
BOOL CMover::IsShoutFull( void )
{
return ( IsSMMode( SM_SHOUT15 ) || IsSMMode( SM_SHOUT30 ) || IsSMMode( SM_SHOUT001 ) );
}
BOOL CMover::IsCommBank( void )
{
return ( IsSMMode( SM_BANK15 ) || IsSMMode( SM_BANK30 ) || IsSMMode( SM_BANK001 ) );
}
#ifdef __BS_EFFECT_LUA
const char* CMover::GetNameO3D( )
{
CObject3D* pObj = ((CModelObject*)m_pModel)->GetObject3D( );
if( !pObj )
{
Error( "CMover::GetNameO3D, pObj == NULL" );
return NULL;
}
return pObj->m_szFileName;
}
BOOL CMover::SetDataMTE( const char* alphaTex, const char* eff2ndTex )
{
// 진짜 써야할때 호출된다.
// 이때 비로소 m_pMteData가 할당된다.
CObject3D* pObj = ((CModelObject*)m_pModel)->GetObject3D( );
if( !pObj )
{
Error( "CMover::GetNameO3D, pObj == NULL" );
return FALSE;
}
if( NULL == pObj->m_pMteData )
pObj->m_pMteData = new CObject3D::MTE_DATA;
CObject3D::MTE_DATA* pData = pObj->m_pMteData;
char szAlphaTexture[MAX_PATH];
GetFileTitle( alphaTex, szAlphaTexture );
strcat( szAlphaTexture, "-ef01.tga" );
pData->_pTex[ 0 ] = TexturePool::Get()->GetTexture( DIR_SFXTEX, std::string(szAlphaTexture) );
pData->_pTex[ 1 ] = TexturePool::Get()->GetTexture( DIR_SFXTEX, std::string(eff2ndTex) );
if( NULL == pData->_pTex[ 0 ] || NULL == pData->_pTex[ 1 ] )
{
Error( "Failed loading MTE texture %s or %s", szAlphaTexture, eff2ndTex );
return FALSE;
}
//ok... now you can use this data
return TRUE;
}
#endif //__BS_EFFECT_LUA
#if __VER >= 12 // __LORD
int CMover::GetPerinNum( void )
{
int nPerin = 0;
for( int i = 0; i < m_Inventory.GetMax(); i++ )
{
CItemElem* pItem = static_cast<CItemElem*>( GetItemId( i ) );
if( pItem && pItem->IsPerin() && ::IsUsableItem( pItem ) )
nPerin += pItem->m_nItemNum;
}
return nPerin;
}
// 소유하고있는 페린과 페냐의 합을 반환한다.
__int64 CMover::GetTotalGold( void )
{
return static_cast<__int64>( GetPerinNum() ) * PERIN_VALUE + static_cast<__int64>( GetGold() );
}
#ifdef __WORLDSERVER
int CMover::RemovePerin( int nPerin )
{
int nRest = nPerin;
for( int i = 0; i < m_Inventory.GetMax() && nRest > 0; i++ )
{
CItemElem* pItem = static_cast<CItemElem*>( GetItemId( i ) );
if( pItem && pItem->IsPerin() && ::IsUsableItem( pItem ) )
{
int nRemove = nRest >= pItem->m_nItemNum? pItem->m_nItemNum: nRest;
UpdateItem( i, UI_NUM, pItem->m_nItemNum - nRemove );
nRest -= nRemove;
}
}
return nPerin - nRest;
}
// iGold만큼의 페린과 페냐를 소모하고 이를 클라이언트 통보한다.
// 康 2008-10-08: 수정
int CMover::RemoveTotalGold( __int64 iGold )
{
ASSERT( iGold <= GetTotalGold() );
int nPerin = (int)( RemovePerin( (int)( iGold / PERIN_VALUE ) ) );
__int64 iRest = iGold - ( static_cast<__int64>( nPerin ) * PERIN_VALUE );
if( iRest > GetGold() ) // 페냐가 모자르면
{
RemovePerin( 1 ); // 1억 페냐를 추가 삭제하고,
iRest = -( PERIN_VALUE - iRest ); // '1억 - 나머지' 페냐를 더하도록 부호를 바꾼다.
}
AddGold( static_cast<int>( -iRest ), TRUE );
return nPerin;
}
#endif // __WORLDSERVER
#endif // __LORD
#ifdef __CLIENT
CClientPet::CClientPet()
:
m_pObj( NULL ),
m_nLevelup( 0 )
{
#ifdef __PET_1024
m_szName[0] = '\0';
#endif // __PET_1024
}
CClientPet::~CClientPet()
{
}
#ifdef __PET_1024
void CClientPet::SetName( char * szName )
{
strncpy( m_szName, szName, MAX_PET_NAME-1 );
m_szName[MAX_PET_NAME-1] = '\0';
}
#endif // __PET_1024
#endif // __CLIENT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment