#include "stdafx.h" #include "monster.h" #include "SceneManager.h" #include "MonsterSceneNode.h" #include "GameResourceManager.h" #include "Application.h" #include "WorldManager.h" #include "ObjectManager.h" #include "Hero.h" #include "Skill_Common.h" #include "SkillManager.h" #include "MonsterScript.h" #include "RangeCheck.h" #include "ChatManager.h" #include "DamagePrintManager.h" #include "DramaturgyManager.h" #include "EffectSceneNode.h" #include "SoundSceneNode.h" #include "mode.h" #include "UIManager.h" #include "ChatBubble.h" #include "ResourceManager.h" #include "RenderSystem.h" #include "PlaneObject.h" cMonster::cMonster( unsigned char type ) : cBaseObject( type ) , mMoveOverTime( 0 ) , mpMonsterInfo(0) , mAutoDummy(0) { mGotoX = 0.0f; mGotoY = 0.0f; mDesiredDir = -NiPoint3::UNIT_Y; mPathIndex = 0; mPathCount = 0; mHP = 0; mMP = 0; mMaxHP = 0; mMaxMP = 0; mState = eOBJECT_STATE_IDLE; mMonsterDieTime = 0; mLastGotoX = 0; mLastGotoY = 0; mMoveStopRange = 0.0f; mDelay = 0; mAngle = 0.0f; mAccumAngle = 0.0f; mAxis = NiPoint3::UNIT_Z; mDamageAfterAnim = M_ANITYPE_IDLE1; mMonsterIdx = 0; mMoveSpeed = 0; mFixedObjectSize = 0; mMoveSpeedType = eMOVESPEED_WALK; mCurrentModeIndex = 0; mpImageMode = 0; mpImagePlane = 0; mImageStartAccumTime = ULONG_MAX; mImageEndAccumTime = 0; mPvPTeamType = ePVPDM_TEAMTYPE_MAX; } cMonster::~cMonster() { UIMAN->ClearMonModeImage( mpImagePlane ); SAFE_DELETE( mpImagePlane ); } bool cMonster::Create( sMonsterData* baseInfo, NiPoint3 pos, NiMatrix3 rotate ) { assert(baseInfo); /// ¸ó½ºÅÍ ½ºÅ©¸³Æ® ÆÄÀÏ¿¡¼­ Á¤º¸¸¦ Àоî¿Â´Ù. sMonsterScript* pMonsterInfo; pMonsterInfo = MONSTERSCRIPT->GetMonsterListInfo( baseInfo->mMonsterClassIdx ); if( pMonsterInfo == NULL ) { MessageBox(NULL,_T("sMonsterScript ERROR"),_T("ERROR"),MB_OK); assert(NULL); return false; } mMonsterIdx = baseInfo->mMonsterIdx; // mPos.X = sPos.x; // mPos.Y = sPos.y; /// ¸ó½ºÅÍ ½ºÅ©¸³Æ®¿¡¼­ Àоî¿Â ¸ó½ºÅÍ Á¤º¸ ÀúÀå mpMonsterInfo = pMonsterInfo; mpModeAgent = MONSTERSCRIPT->GetMonsterModeAgent( baseInfo->mMonsterClassIdx ); ///// ¸ó½ºÅÍ ±âº» ¼³Á¤°ª mMaxHP = baseInfo->mMaxHP; mMaxMP = baseInfo->mMaxMP; mHP = baseInfo->mHP; mMP = baseInfo->mMP; mMoveSpeed = baseInfo->mMoveSpeed; mAutoDummy = baseInfo->mAutoDummy; float scale = 1.0f; if( mpMonsterInfo->mMonsterScale > 0.0f ) { scale = mpMonsterInfo->mMonsterScale; } else { assert(0); } mFixedObjectSize = mpMonsterInfo->mMonsterFixSize * scale; mFixedObjectSizePer = baseInfo->mScale; const char* strFile = GAMERESOURCEMAN->GetModelFileName( pMonsterInfo->mKfmIdx ); assert( strFile ); cMonsterSceneNodeParam param; param.mpObject = this; param.mTranslate = pos; param.mRotate = rotate; param.mScale = scale * mFixedObjectSizePer * 0.01f; param.mHeadHeight = (float)mpMonsterInfo->mNameHeight; cString pathName; pathName.Format( "./Data/Monster/%s", strFile ); param.mPathName = pathName; param.mMonClassIndex = GetMonsterClassIdx(); cMonsterSceneNode* pSceneNode = SCENEMAN->CreateMonster( param ); if( !pSceneNode ) { assert(0); return false; } mpObjectSceneNode = pSceneNode; mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE1 ); /// ¼öÁ¤¿ä! // NiPoint3 sFoot = mpObjectSceneNode->GetObjectFoot(); // NiPoint3 sHead = mpObjectSceneNode->GetObjectHead(); // mStatureValue = (sHead.z - sFoot.z) / mpObjectSceneNode->GetWorldScale(); mpObjectSceneNode->ShowNameGauge( true ); mpObjectSceneNode->UpdateNameCardTextValue(); mpObjectSceneNode->UpdateNameCardGaugeValue(); mDesiredDir = rotate*mDesiredDir; mDesiredDir.Unitize(); mGotoX = pos.x; mGotoY = pos.y; mDelay = 0; mAngle = 0.0f; mAccumAngle = 0.0f; mAxis = NiPoint3::UNIT_Z; mPvPTeamType = ePVPDM_TEAMTYPE_MAX; return true; } void cMonster::Update( unsigned long deltaTime, unsigned long accumTime ) { if( mAngle ) { float angle = (float)deltaTime/(float)mDelay *mAngle; if( mAccumAngle + angle >= mAngle ) { angle = mAngle - mAccumAngle; mAngle = 0; mAccumAngle = 0; } else mAccumAngle += angle; NiMatrix3 mat; if( mAxis.z < 0.0f ) mat.FromEulerAnglesXYZ( 0.0f, 0.0f, -angle ); else mat.FromEulerAnglesXYZ( 0.0f, 0.0f, angle ); mpObjectSceneNode->SetRotate( mpObjectSceneNode->GetRotate()*mat ); mDesiredDir = mat * mDesiredDir; mDesiredDir.z = 0.0f; mDesiredDir.Unitize(); } /// HERO¿ÍÀÇ °Å¸®Ã¼Å© /// ¸ðµå À̹ÌÁö Ãâ·Â¿ë if( mState != eOBJECT_STATE_DIE ) { if( mpImageMode ) { // ÀÏÁ¤½Ã°£ ÈÄ¿¡ ¹ß»ý ( 1¹ø¸¸ ¹ß»ý ) if( accumTime >= mImageStartAccumTime ) { NiPoint3 heroPos = HERO->GetPos(); heroPos.z = 0.0f; NiPoint3 pos = GetPos(); pos.z = 0.0f; float tempRange = OBJECTMANAGER->ObjectSizeRange( this, HERO, MODEIMAGE_VALID_DISTANCE ); // HERO ¿Í ÀÏÁ¤°Å¸® ÀÌÇϰ¡ µÇ¸é cRangeCheck rangeCheck( tempRange ); if( rangeCheck.IsRange( pos, heroPos ) ) { // ¸ðµå À̹ÌÁö Ç¥½Ã cString path; path.Format("./language/%s/%s", cApplication::mLangaugeFolder.Cstr(), mpImageMode->mFileName.Cstr() ); NiTexture* tex = RESOURCEMAN->LoadMapTexture( path, false ); if( tex ) { int tx = mpImageMode->mTexX; int ty = mpImageMode->mTexY; int x = (int)((RENDERSYS->GetScreenWidth() - MODEIMAGE_W) * 0.5); mpImagePlane = new cPlaneObject; if( mpImagePlane->Create( tex, x, MODEIMAGE_Y, MODEIMAGE_W, MODEIMAGE_H, tx, ty, tx + MODEIMAGE_W, ty + MODEIMAGE_H ) == false ) { assert( 0 && "failed to create monster mode image"); } UIMAN->SetMonModeImage( mpImagePlane ); } else assert(0); // »èÁ¦ ½Ã°£ ¼³Á¤ mImageEndAccumTime = mImageStartAccumTime + MODEIMAGE_TIME; } mImageStartAccumTime = ULONG_MAX; } // ÀÏÁ¤½Ã°£ ÈÄ »èÁ¦ if( accumTime >= mImageEndAccumTime ) { UIMAN->ClearMonModeImage( mpImagePlane ); SAFE_DELETE( mpImagePlane ); mpImageMode = 0; mImageStartAccumTime = ULONG_MAX; mImageEndAccumTime = 0; } } } switch( mState ) { case eOBJECT_STATE_IDLE: { mIdleTime += deltaTime; if( mIdleTime >= 5000 ) { mIdleTime = 0; mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE2 ); } } break; case eOBJECT_STATE_MOVE: { if( mPathCount == 0 ) return; /// À̵¿ÁßÀ̸é NiPoint3 pos = mpObjectSceneNode->GetWorldTranslate(); /// ¸ó½ºÅÍ À̵¿ ¼Óµµ float speed = (float)mMoveSpeed; /// ¹æÇâ ¼³Á¤ NiPoint2 dir1; dir1.x = mGotoX - pos.x; dir1.y = mGotoY - pos.y; dir1.Unitize(); const unsigned long limitOverTime = 10; unsigned long plusTime; /// ¸ñÀûÁöÁ¡ ³Ñ¾î¼­ ÀúÀåµÈ ½Ã°£À» À̵¿½Ã + if( mMoveOverTime > limitOverTime ) plusTime = limitOverTime; else plusTime = mMoveOverTime; mMoveOverTime = mMoveOverTime - plusTime; /// ¼Óµµ * °æ°ú½Ã°£ ¸¸Å­ÀÇ ¿¹»ó À̵¿ À§Ä¡ °è»ê pos.x += dir1.x * speed * ((deltaTime + plusTime) *0.001f); pos.y += dir1.y * speed * ((deltaTime + plusTime) *0.001f); pos.z = 0.0f; /// ¸ñÀûÁö ÁÂÇ¥¿Í ¿¹»ó À̵¿ À§Ä¡¸¦ ºñ±³ NiPoint2 dir2; dir2.x = mGotoX - pos.x; dir2.y = mGotoY - pos.y; dir2.Unitize(); if( dir2.Dot(dir1) <= 0.0f ) { NiPoint2 overPoint( pos.x, pos.y ); NiPoint2 nextPos( mGotoX, mGotoY ); /// ±æÃ£±â °æ·Î ¸ñÀû ÁöÁ¡À» ³Ñ¾î¼± °æ¿ì ³ÑÀº °Å¸®¸¸Å­ ½Ã°£ º¸°ü float overLength = ( overPoint - nextPos ).Length(); mMoveOverTime = mMoveOverTime + (unsigned long)((overLength/speed)*1000.0f); pos.x = mGotoX; pos.y = mGotoY; if( mPathIndex < mPathCount-1 ) { NiPoint2& nextPos = mPathArray[++mPathIndex]; Move( nextPos.x, nextPos.y ); } else { mPathCount = 0; mPathIndex = 0; mMoveOverTime = 0; SetState( eOBJECT_STATE_IDLE ); } } /// ¸ó½ºÅͰ¡ ¸ñÀûÁö¿¡¼­ ±Ùó(ÀÏÁ¤¹üÀ§)±îÁö µµ´ÞÇϸé Á¤ÁöÇÏ´Â ¸ðµâ if( mMoveStopRange != 0.0f ) { /// ¸ó½ºÅͰ¡ °¡·Á°íÇÏ´Â °æ·ÎÀÇ ÃÖÁ¾ ¸ñÀûÁö NiPoint3 targetPos; NiPoint3 monsterGuessPos( pos.x, pos.y, 0.0f ); /// ³ôÀ̰ª °è»ê if( WORLDMAN->CalcHeight( &monsterGuessPos.z, monsterGuessPos.x, monsterGuessPos.y ) == false ) assert(NULL); cBaseObject* pBaseObject = GetTargetObject(); if( pBaseObject == NULL || pBaseObject->GetState() == eOBJECT_STATE_DIE ) { targetPos.x = mLastGotoX; targetPos.y = mLastGotoY; if( WORLDMAN->CalcHeight( &targetPos.z, targetPos.x, targetPos.y ) == false ) assert(NULL); } else { targetPos.x = pBaseObject->GetXPos(); targetPos.y = pBaseObject->GetYPos(); targetPos.z = pBaseObject->GetZPos(); } float moveStopRangeFix = OBJECTMANAGER->ObjectSizeRange( this, pBaseObject, mMoveStopRange ); /// ÃÖÁ¾ ¸ñÀûÁöÁÖº¯¿¡ ÀÏÁ¤ ¹üÀ§¿¡¼­ ¼­¾ßÇÒ »çÀÌÁî cRangeCheck rangecheck( moveStopRangeFix ); /// ÃÖÁ¾ ¸ñÀûÁö¿Í ÇöÀç À§Ä¡ÀÇ °Å¸®¸¦ ºñ±³ if( rangecheck.IsRange( monsterGuessPos, targetPos ) ) { /// ÁÂÇ¥ º¸Á¤ NiPoint3 p; NiPoint3 d = GetPos() - targetPos; d.Unitize(); p.x = targetPos.x + ((moveStopRangeFix-1.0f)*d.x); p.y = targetPos.y + ((moveStopRangeFix-1.0f)*d.y); if( WORLDMAN->CalcHeight( &p.z, p.x, p.y ) ) { SetPos(p); mLastGotoX = p.x; mLastGotoY = p.y; } else { assert(0); } mMoveStopRange = 0.0f; SetState( eOBJECT_STATE_IDLE ); return; } } /// ³ôÀ̰ª °è»ê if( WORLDMAN->CalcHeight( &pos.z, pos.x, pos.y ) ) { SetPos( pos ); } else { assert( 0 ); SetState( eOBJECT_STATE_IDLE ); } }break; case eOBJECT_STATE_PUSHPULL: { /// À̵¿ÁßÀ̸é NiPoint3 pos = mpObjectSceneNode->GetWorldTranslate(); /// ¸ó½ºÅÍ À̵¿ ¼Óµµ float speed = SKILL_PUSHPULL_SPEED; /// ¹æÇâ ¼³Á¤ NiPoint2 dir1; dir1.x = mGotoX - pos.x; dir1.y = mGotoY - pos.y; dir1.Unitize(); /// ¼Óµµ * °æ°ú½Ã°£ ¸¸Å­ÀÇ ¿¹»ó À̵¿ À§Ä¡ °è»ê pos.x += dir1.x * speed * ( deltaTime * 0.001f ); pos.y += dir1.y * speed * ( deltaTime * 0.001f ); pos.z = 0.0f; /// ¸ñÀûÁö ÁÂÇ¥¿Í ¿¹»ó À̵¿ À§Ä¡¸¦ ºñ±³ NiPoint2 dir2; dir2.x = mGotoX - pos.x; dir2.y = mGotoY - pos.y; dir2.Unitize(); if( dir2.Dot(dir1) <= 0.0f ) { pos.x = mGotoX; pos.y = mGotoY; mPathCount = 0; mPathIndex = 0; mMoveOverTime = 0; SetState( eOBJECT_STATE_IDLE ); } /// ³ôÀ̰ª °è»ê if( WORLDMAN->CalcHeight( &pos.z, pos.x, pos.y ) ) { SetPos( pos ); } else { assert( 0 ); SetState( eOBJECT_STATE_IDLE ); } } break; /// ¸ó½ºÅÍ »óÅ Á×À½ case eOBJECT_STATE_DIE: { /// ¸ó½ºÅͰ¡ Á×ÀºÈÄ 3ÃÊÈÄ¿¡ ¸ó½ºÅÍ »èÁ¦¸®½ºÆ®¿¡ Æ÷ÇÔÇØ °´Ã¼ Á¦°ÅÇÔ if( mMonsterDieTime+3000 < accumTime && mMonsterDieTime != 0 ) { if( HERO->GetTargetObject() == this ) HERO->SetTargetObject( eOBJECTTYPE_NONE, 0 ); OBJECTMAN->AddMonsterDie( GetObjectID() ); } /// ¸ó½ºÅͰ¡ Á×ÀºÈÄ 2ÃÊÈÄ¿¡ ¾ËÆÄ ºí·£µù ½ÃÀÛ else if( mMonsterDieTime+2000 < accumTime && mMonsterDieTime != 0 ) { mpObjectSceneNode->SetAlphaBlended( 0.01f ); } // ÃʱâÈ­ if( mpImageMode ) { UIMAN->ClearMonModeImage( mpImagePlane ); SAFE_DELETE( mpImagePlane ); } mCurrentModeIndex = 0; mpImageMode = 0; mImageStartAccumTime = ULONG_MAX; mImageEndAccumTime = 0; } break; default: break; } /// ¾Ö´Ï¸ÞÀÌ¼Ç ¿¬°á¿¡ ´ëÇÑ Ã³¸® Interpret( accumTime ); } bool cMonster::Move( float x, float y ) { /// Ãß°¡: ºÎµå·¯¿î ¹æÇâ ÀüȯÀ» ³Öµµ·Ï ÇÑ´Ù. NiPoint3 kWorldTranslate = NiPoint3(x, y, 0.0f); NiPoint3 kCurTranslate = mpObjectSceneNode->GetWorldTranslate(); kCurTranslate.z = 0.0f; NiPoint3 kAt = kCurTranslate - kWorldTranslate; if( kAt == NiPoint3::ZERO ) return false; if( kAt.SqrLength() < 0.001f ) { return false; } kAt.Unitize(); float fDot = mDesiredDir.Dot(-kAt); if( fDot < 1.0f - FLT_EPSILON )//0.999999f) { float fAngle = NiACos(fDot); if(mDesiredDir.Cross(-kAt).z > 0) fAngle = -fAngle; mDesiredDir = -kAt; NiMatrix3 kZRot; kZRot.MakeZRotation(fAngle); mpObjectSceneNode->SetRotate( mpObjectSceneNode->GetRotate()*kZRot ); } // Animation Setting - Run SetState( eOBJECT_STATE_MOVE ); /// ¸ñÀûÁö ¼³Á¤ mGotoX = x; mGotoY = y; return true; } void cMonster::Interpret( unsigned long time ) { cActorManagerForPartition* pActor = mpObjectSceneNode->GetActorManager(); if( !pActor ) return; unsigned int id = mpObjectSceneNode->GetTargetAnimation(); /// ÇöÀç ¾Ö´Ï¸ÞÀÌ¼Ç Á¾·á ½ÃÁ¡ ȹµæ float endTime = pActor->GetNextEventTime( cActorManagerForPartition::TEXT_KEY_EVENT, id, "end" ); if( endTime == NI_INFINITY ) return; if( endTime == cActorManagerForPartition::INVALID_TIME ) { endTime = mpObjectSceneNode->GetTargetAnimationScaleEndTime(); } float checkTime = (float)mpObjectSceneNode->GetScaleAccumTime() * 0.001f; if( endTime > 0 && endTime <= checkTime ) { if( M_ANITYPE_IDLE1 == id ) { return; } else if( M_ANITYPE_IDLE2 == id ) { mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE1 ); } else if( M_ANITYPE_ATTACK1 <= id && id <= M_ANITYPE_ATTACK3 ) { SetState( eOBJECT_STATE_IDLE ); } else if( M_ANITYPE_SKILL1 <= id && id <= M_ANITYPE_SKILL2 ) { SetState( eOBJECT_STATE_IDLE ); } else if( id == M_ANITYPE_DAMAGE1 || id == M_ANITYPE_DAMAGE2 ) { /// °ø°Ý¹Þ´Â ¾Ö´Ï¸ÞÀ̼ÇÀÌ ³¡³ª¸é ±âº» ¾Ö´Ï¸ÞÀ̼ÇÀ¸·Î ¹Ù²Û´Ù. if( mDamageAfterAnim == M_ANITYPE_CASTING ) { UpdateSkillAnimation( M_ANITYPE_CASTING ); } else SetState( eOBJECT_STATE_IDLE ); } else { NiSequenceData* seq = pActor->GetSequenceData( id ); // NiControllerSequence* seq = pActor->GetSequence( id ); if( seq ) { if( seq->GetCycleType() != NiTimeController::LOOP ) SetState( eOBJECT_STATE_IDLE ); } else { assert(0); SetState( eOBJECT_STATE_IDLE ); } } } else if( endTime == cActorManagerForPartition::INVALID_TIME ) { /// INVALID_TIME¿¡ ´ëÇÑ º¸Á¤ } } unsigned int cMonster::SetLinkdObject( unsigned int num, char* nif ) { /// °´Ã¼ ¸µÅ©¸¦ Ȱ¼ºÈ­ÇÑ´Ù. return mpObjectSceneNode->LinkObject( num, nif ); } void cMonster::UnLinkdObject( unsigned int num ) { /// °´Ã¼ ¸µÅ©¸¦ ºñȰ¼ºÈ­ÇÑ´Ù. mpObjectSceneNode->UnLinkObject( num ); } bool cMonster::SetDesiredDir( NiPoint3 CurrentPos, NiPoint3 TargetPos, unsigned long delay ) { if( GetState() == eOBJECT_STATE_DIE ) return true; CurrentPos.z = 0; TargetPos.z = 0; /// ÇöÀç ij¸¯ÅÍÀÇ ¹æÇâ NiPoint3 charDir = mDesiredDir; /// ¹Ù¶óºÁ¾ßÇÒ ¹æÇâ NiPoint3 viewDir = TargetPos - CurrentPos; if( viewDir.SqrLength() < 0.001f ) { // assert(0); return false; } viewDir.Unitize(); if( mDesiredDir == viewDir ) { mDelay = 0; mAngle = 0; mAccumAngle = 0; return true; } /// ȸÀü Matrix »êÃâ NiMatrix3 matA, matB, matRot; matA.SetCol( 0, charDir ); matA.SetCol( 1, -NiPoint3::UNIT_Z ); matA.SetCol( 2, charDir.UnitCross( -NiPoint3::UNIT_Z ) ); matB.SetCol( 0, viewDir ); matB.SetCol( 1, -NiPoint3::UNIT_Z ); matB.SetCol( 2, viewDir.UnitCross( -NiPoint3::UNIT_Z ) ); matRot = matB * matA.Transpose(); if( delay == 0 ) { mpObjectSceneNode->SetRotate( mpObjectSceneNode->GetRotate()*matRot ); mDesiredDir = viewDir; mDelay = 0; mAngle = 0; mAccumAngle = 0; } else { mDelay = delay; mAccumAngle = 0; matRot.ExtractAngleAndAxis(mAngle, mAxis.x, mAxis.y, mAxis.z); if( mAngle > 360.0f ) mAngle -= 360.0f; else if( mAngle < 0.0f ) mAngle += 360.0f; } return true; } void cMonster::SetPathArray( NiPoint2* moveArray, unsigned int count ) { assert( moveArray ); count = (count < MAX_PATH_COUNT) ? count : MAX_PATH_COUNT; for( unsigned int i = 0; i < count; ++i ) { mPathArray[i].x = moveArray[i].x; mPathArray[i].y = moveArray[i].y; } mPathIndex = 0; mPathCount = count; if( mPathCount ) { Move( mPathArray[0].x, mPathArray[0].y ); SetLastGoto( mPathArray[count-1].x, mPathArray[count-1].y ); } } void cMonster::SetState( unsigned char state, bool bShowAni ) { if( mState != eOBJECT_STATE_IDLE && state == eOBJECT_STATE_IDLE ) mIdleTime = 0; if( mState ==eOBJECT_STATE_DIE ) return; mState = (eOBJECTSTATE)state; if( mState != eOBJECT_STATE_ATTACK ) { /// ±âº» ¼Óµµ º¸Á¤ if( mpObjectSceneNode ) mpObjectSceneNode->UpdateAniScaleFactor( 1.0f ); } switch( mState ) { case eOBJECT_STATE_DIE: { /// if( bShowAni ) mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DIE1 ); /// Á×Àº ½Ã°£ ±â·Ï - Á×Àº ½Ã°£À¸·Î 2ÃÊ ÈĺÎÅÍ ¾ËÆÄ, 3ÃÊÈÄ ¼Ò¸ê mMonsterDieTime = THEAPP->GetWorldAccumTime(); } break; case eOBJECT_STATE_IDLE: case eOBJECT_STATE_STOP: { /// idle1 or idle2 if( bShowAni ) mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE1 ); } break; case eOBJECT_STATE_MOVE: { switch( mMoveSpeedType ) { case eMOVESPEED_WALK: mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_WORK ); break; case eMOVESPEED_RUN: mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_RUN ); break; } } break; case eOBJECT_STATE_PUSHPULL: { if( bShowAni ) mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DAMAGE1 ); } break; } } void cMonster::HPChange( unsigned long objectHP, unsigned long objectMaxHP ) { assert(objectHP != 0); assert( objectHP <= objectMaxHP ); mHP = objectHP; mMaxHP = objectMaxHP; mpObjectSceneNode->UpdateNameCardGaugeValue(); } void cMonster::HPChangeDie( unsigned long objectMaxHP, cBaseObject* pAttacker, unsigned char attackType ) { assert( GetState() != eOBJECT_STATE_DIE ); if( GetState() != eOBJECT_STATE_DIE ) { if( pAttacker ) { if( mpModeAgent ) { if( mpModeAgent->IsAntiRotation() == false ) SetDesiredDir( GetPos(), pAttacker->GetPos() ); } else SetDesiredDir( GetPos(), pAttacker->GetPos() ); } SetState( eOBJECT_STATE_DIE ); if( attackType == eDAMAGE_CRITICAL ) { mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DIE2 ); SKILLMAN->CreateApplyObject( pAttacker, this, 0, eAPPLYDRAMA_DIE2 ); } else { SKILLMAN->CreateApplyObject( pAttacker, this, 0, eAPPLYDRAMA_DIE1 ); } /// »ç¸Á½Ã º¸À¯ È¿°ú Á¦°Å.. ClearAllBuff( true ); ClearAllDeBuff( true ); } else { assert(0); } mHP = 0; mMaxHP = objectMaxHP; mpObjectSceneNode->UpdateNameCardGaugeValue(); } void cMonster::MPChange( unsigned long objectMP, unsigned long objectMaxMP ) { if( GetState() == eOBJECT_STATE_DIE ) { assert(objectMP == 0); } mMP = objectMP; mMaxMP = objectMaxMP; mpObjectSceneNode->UpdateNameCardGaugeValue(); } void cMonster::SetMoveSpeed( unsigned int moveSpeed, eMOVE_SPEED_TYPE moveSpeedType ) { mMoveSpeed = moveSpeed; /// ±âÁ¸°ª À¯Áö if( eMOVESPEED_STOP != moveSpeedType ) mMoveSpeedType = moveSpeedType; } void cMonster::SetFixedObjectSizeScale( unsigned short scalePer, bool init ) { mFixedObjectSizePer = scalePer; if( mpMonsterInfo == NULL ) { assert(0); return ; } float scale = 1.0f; if( mpMonsterInfo->mMonsterScale > 0.0f ) { scale = mpMonsterInfo->mMonsterScale; } else { assert(0); } mFixedObjectSize = mpMonsterInfo->mMonsterFixSize * (float)scalePer * 0.01f; mpObjectSceneNode->SetTargetScale( scale * (float)scalePer * 0.01f, init ); } void cMonster::MoveStop( float x, float y ) { mGotoX = x; mGotoY = y; mLastGotoX = x; mLastGotoY = y; mPathIndex = 0; mPathCount = 0; if( mState == eOBJECT_STATE_MOVE ) SetState( eOBJECT_STATE_IDLE ); FixPos( x, y ); } void cMonster::MonsterAttack( unsigned long uIdx, unsigned long skillIdx, cBaseObject* pTarget, float attackSpeedFactor ) { if( GetState() == eOBJECT_STATE_DIE ) return; if( pTarget ) SetDesiredDir( GetPos(), pTarget->GetPos() ); SKILLMAN->CreateSkillObject( uIdx, skillIdx, 0, this, pTarget, attackSpeedFactor ); SetState( eOBJECT_STATE_ATTACK ); } void cMonster::MonsterAttack( unsigned long uIdx, unsigned long skillIdx, NiPoint3 fieldPos, float attackSpeedFactor ) { if( GetState() == eOBJECT_STATE_DIE ) return; NiPoint3 pos = fieldPos; if( WORLDMAN->CalcHeight(&pos.z, pos.x, pos.y) == false ) { assert(0); return; } SetDesiredDir( GetPos(), pos ); SKILLMAN->CreateSkillObject( uIdx, skillIdx, 0, this, pos, attackSpeedFactor ); SetState( eOBJECT_STATE_ATTACK ); } void cMonster::ApplyDamageDrama( int damage, unsigned int damageType, cBaseObject* pAttacker ) { cBaseObject::ApplyDamageDrama( damage, damageType, pAttacker ); if( GetState() == eOBJECT_STATE_DIE ) return; unsigned int ani = mpObjectSceneNode->GetTargetAnimation(); mDamageAfterAnim = M_ANITYPE_IDLE1; switch( ani ) { case M_ANITYPE_WORK: case M_ANITYPE_RUN: case M_ANITYPE_SKILL1: case M_ANITYPE_SKILL2: case M_ANITYPE_ATTACK3: case M_ANITYPE_DAMAGE1: // case M_ANITYPE_DAMAGE2: case M_ANITYPE_CASTING: case M_ANITYPE_DIE1: case M_ANITYPE_DIE2: return; } if( ani >= M_ANITYPE_MODEANI ) return; if( M_ANITYPE_ATTACK1 <= ani && ani <= M_ANITYPE_ATTACK3 ) { if( GetTargetObject() != pAttacker ) return; unsigned long time = mpObjectSceneNode->GetTargetAnimationEndTime() - 200; if( THEAPP->GetWorldAccumTime() < time ) return; } if( ani == M_ANITYPE_CASTING ) mDamageAfterAnim = M_ANITYPE_CASTING; /// damageµ¿ÀÛ Àû¿ë if( damageType < eDAMAGEPRINT_HEAL_OUR ) { mIdleTime = 0; if( GetState() != eOBJECT_STATE_ATTACK ) { if( mpObjectSceneNode->GetTargetAnimation() == M_ANITYPE_IDLE1 || mpObjectSceneNode->GetTargetAnimation() == M_ANITYPE_IDLE2 ) { if( pAttacker ) { if( mpModeAgent ) { if( mpModeAgent->IsAntiRotation() == false ) SetDesiredDir( GetPos(), pAttacker->GetPos() ); } else SetDesiredDir( GetPos(), pAttacker->GetPos() ); } } } if( damageType == eDAMAGEPRINT_CRITICAL_ENEMY || damageType == eDAMAGEPRINT_CRITICAL_OUR || damageType == eDAMAGEPRINT_MP_CRITICAL ) { UpdateAnimationSpeed(1.0f); mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DAMAGE2 ); } else { UpdateAnimationSpeed(1.0f); mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_DAMAGE1 ); } } } void cMonster::PlayIdle2Ani() { if( GetState() != eOBJECT_STATE_IDLE ) return; mpObjectSceneNode->SetTargetAnimation( M_ANITYPE_IDLE2 ); } void cMonster::ActiveChatBubble( sTextItem* text ) { mpObjectSceneNode->ActiveChatBubble( text ); } bool cMonster::IsPrecedeAttack() { return ( mpMonsterInfo ) ? mpMonsterInfo->mIsPrecedeAttack : false; } bool cMonster::IsChangeMonCheck() { return ( mpMonsterInfo ) ? mpMonsterInfo->mIsChgMonCheck : false; } void cMonster::UpdateNameCardTextValue() { if( mpObjectSceneNode ) mpObjectSceneNode->UpdateNameCardTextValue(); } void cMonster::ChangeMonsterMode( long modeIdx ) { mCurrentModeIndex = 0; mpImageMode = 0; // ±âÁ¸ À̹ÌÁö »èÁ¦ if( mpImagePlane ) { UIMAN->ClearMonModeImage( mpImagePlane ); SAFE_DELETE( mpImagePlane ); mImageStartAccumTime = ULONG_MAX; mImageEndAccumTime = 0; } /// ±âÁ¸ ¸ðµå Á¤º¸ Á¦°Å if( mModeLoopEffectList.IsEmpty() == false ) { cModeLoopList::cIterator i = mModeLoopEffectList.Begin(); cModeLoopList::cIterator end = mModeLoopEffectList.End(); for( ; i != end; ++i ) { unsigned long idx = (unsigned long)*i; cEffectSceneNode* n = SCENEMAN->GetEffectSceneNode( idx ); if( n ) n->SetLoopFlag( false ); } mModeLoopEffectList.Clear(); } if( mModeLoopSoundList.IsEmpty() == false ) { cModeLoopList::cIterator i = mModeLoopSoundList.Begin(); cModeLoopList::cIterator end = mModeLoopSoundList.End(); for( ; i != end; ++i ) { unsigned long idx = (unsigned long)*i; cSoundSceneNode* n = SCENEMAN->GetSoundSceneNode( idx ); if( n ) n->FadeOut(); } mModeLoopSoundList.Clear(); } if( modeIdx < 0 ) return; if( GetState() == eOBJECT_STATE_DIE ) return; /// ½Å±Ô ¸ðµå InitÁ¤º¸ ó¸® cModeAgent* pAgent = MONSTERSCRIPT->GetMonsterModeAgent( GetMonsterClassIdx() ); if( pAgent == 0 ) return; cMode* pMode = pAgent->GetMode( modeIdx ); if( pMode == 0 ) return; // ÇöÀç ¸ðµå Á¤º¸ mCurrentModeIndex = modeIdx; cModeInfoArr* arr = pMode->GetInitModeInfoArr(); for( unsigned int i=0; iGetSize(); i++ ) { sModeInfoBase* p = (sModeInfoBase*)((*arr)[i]); switch( p->type ) { case eMODEINFO_SPEECH: { // äÆÃ sModeSpeech* modeData = (sModeSpeech*)p; sTextItem* speech = GAMERESOURCEMAN->GetMonsterTalk( modeData->mSpeechIdx, this, HERO ); if( speech ) { cStringT str; str += GetName(); str += _T(":"); sTextItem* check = speech; while( check ) { str += check->mText; check = check->mpNext; } switch( modeData->mSpeechType ) { case eM_TALKVIEW_BALLOON: /// ¸»Ç³¼± { ActiveChatBubble( speech ); } break; case eM_TALKVIEW_NORMAL: /// ¸»Ç³¼± + (ÀϹÝ)äÆÃâ { ActiveChatBubble( speech ); CHATMANAGER->AddChatMsg( str.Cstr(), eCHAT_NORMAL ); } break; case eM_TALKVIEW_SHOUT: /// ¸»Ç³¼± + (¿ÜÄ¡±â)äÆÃâ { ActiveChatBubble( speech ); CHATMANAGER->AddChatMsg( str.Cstr(), eCHAT_SHOUT ); } break; } } else assert(0); } break; case eMODEINFO_MODESTATE: { /// Animation sModeState* modeData = (sModeState*)p; if( mpObjectSceneNode ) mpObjectSceneNode->SetTargetAnimation( modeData->mAnimationIdx ); } break; case eMODEINFO_APPLYRESOURCE: { sModeResource* modeData = (sModeResource*)p; sModeObj* pobj = pAgent->GetModeObject( modeData->mModeObjIdx ); if( pobj == 0 ) break; switch( pobj->kind ) { case eMODEOBJ_EFFECT: { NiTransform trans; trans.m_Translate = modeData->mVar; trans.m_fScale = pobj->scale; trans.m_Rotate = pobj->rot; if( modeData->mFollow == false ) { NiMatrix3 mat = GetModelRot(); trans.m_Rotate = pobj->rot*mat; } char pathName[256] = {0,}; ::sprintf_s( pathName, "./Data/Effect/%s", pobj->file.Cstr() ); cEffectSceneNode* pNode = SetLinkdEffect( modeData->mLinkPos, pathName, &trans, modeData->mLoop, modeData->mFollow ); if( pNode && modeData->mLoop ) mModeLoopEffectList.PushBack( pNode->GetIndexByManger() ); } break; case eMODEOBJ_SOUND: { /// »ç¿îµå Àû¿ë cSoundSceneNode* pNode = SetLinkdSound( pobj->soundListIndex, modeData->mLoop ); if( pNode && modeData->mLoop ) mModeLoopSoundList.PushBack( pNode->GetIndexByManger() ); } break; default: { assert(0); } break; } } break; case eMODEINFO_IMAGE: { // ¸ðµå À̹ÌÁö Ãâ·Â¿ë sModeImage* modeData = (sModeImage*)p; mpImageMode = modeData; // mImageStartAccumTime = mpImageMode->mTime + THEAPP->GetWorldAccumTime(); } break; default: break; } } } cEffectSceneNode* cMonster::SetLinkdEffect( unsigned int num, const char* nif, NiTransform* trans, bool bLoop, bool bFollow ) { if( ::strlen(nif) == 0 ) return 0; if( num >= eLINK_RWEAPON ) return 0; if( mpMonsterInfo && trans ) { trans->m_fScale *= mpMonsterInfo->mEffectScale; } return mpObjectSceneNode->LinkEffect( num, nif, trans, bLoop, bFollow ); } void cMonster::UpdateTutorialBoard() { if( mpObjectSceneNode ) { ((cMonsterSceneNode*)mpObjectSceneNode)->UpdateTutorialBoard(); } } void cMonster::ClearTutorialBoard() { if( mpObjectSceneNode ) { ((cMonsterSceneNode*)mpObjectSceneNode)->ClearTutorialBoard(); } } void cMonster::SetSkillPushPull( float posX, float posY ) { mGotoX = posX; mGotoY = posY; mPathIndex = 0; mPathCount = 0; SetMoveStopRange( 0 ); SetState( eOBJECT_STATE_PUSHPULL ); }