void CAPet::Mount( bool bMount ) { m_bMount = bMount; // 주인관련 처리 if( m_pOwner ) { CArea* area = m_pOwner->m_pArea; if( bMount ) // 탈때 { if(m_pArea != NULL) // NULL이 아니면 실행, NULL이면 건너뛸것. m_pArea->MoveChar( this, GET_YLAYER(m_pOwner), GET_X(m_pOwner), GET_Z(m_pOwner), GET_H(m_pOwner), GET_R(m_pOwner), MSG_MOVE_STOP, NULL ); // 소환 해제 while ( m_pOwner->m_elementalList) m_pOwner->UnsummonElemental(m_pOwner->m_elementalList); } if(area) { { // 사라졌다 나타나기 CNetMsg::SP rmsg(new CNetMsg); DisappearMsg(rmsg, this); area->SendToCell(rmsg, this, true); } { CNetMsg::SP rmsg(new CNetMsg); AppearMsg(rmsg, this); area->SendToCell(rmsg, this, true); } } if (m_pArea) { CNetMsg::SP rmsg(new CNetMsg); ExAPetStatusMsg( rmsg, this ); m_pArea->SendToCell(rmsg, GetOwner(), true); } m_pOwner->CalcStatus(true); { CNetMsg::SP rmsg(new CNetMsg); ExAPetFuntionMsg( rmsg, MSG_SUB_MOUNT_REP, this , 0 ); m_pOwner->m_pArea->SendToCell(rmsg, m_pOwner, true); } } }
void do_GMSummon(CPC *a1, char *a2) { int v3; // [sp+28h] [bp-20h]@21 int v4; // [sp+2Ch] [bp-1Ch]@21 CNPC *v6; // [sp+34h] [bp-14h]@12 int v8; // [sp+3Ch] [bp-Ch]@10 char v9; // [sp+43h] [bp-5h]@5 char *s; // [sp+44h] [bp-4h]@4 if(a2) { if(*a2) { TrimString(a2); s = a2; if(strlen(a2)) { v9 = 0; while(*s) { if(!(*(short *)(_ctype_b + 2 * *s) & 0x800)) { v9 = 1; break; } ++s; } v8 = -1; if(!v9) v8 = atoi(a2); v6 = 0; if(v9) { for(int i = 0; i < gserver.Unk452200.Unk4; ++i) { if(!strcmp(gserver.Unk452200.Unk0[i].Unk4, a2)) { v6 = gserver.Unk452200.Create(gserver.Unk452200.Unk0[i].Unk0); break; } } } else { v6 = gserver.Unk452200.Create(v8); } if(v6) { v6->Unk120.Unk0 = a1->Unk120.Unk0 + 2.0; v6->Unk120.Unk16 = a1->Unk120.Unk16; v6->Unk120.Unk4 = a1->Unk120.Unk4 + 2.0; v6->Unk120.Unk12 = GetRandom(0, 62831) / 10000; v6->Unk476 = v6->Unk120.Unk0; v6->Unk480 = v6->Unk120.Unk16; v6->Unk484 = v6->Unk120.Unk4; v6->Unk752 = 0; a1->Unk412->AddNPC(v6); a1->Unk412->PointToCellNum(v6->Unk120.Unk0, v6->Unk120.Unk4, &v4, &v3); a1->Unk412->CharToCell(v6, v6->Unk120.Unk16, v4, v3); CNetMsg v2; AppearMsg(v2, v6, 1); a1->Unk412->SendToCell(v2, v6->Unk120.Unk16, v4, v3, 4); } } } } }
bool CAPet::TransFormationCheck() { if( m_pProto->m_TansType != APET_TRANS_NONE ) { int comp = 0; char oldState = this->m_cTransSate; switch( m_pProto->m_TansType) { case APET_TRANS_TIME: { int nowsec = gserver->getNowSecond() % 3600; if (nowsec == (3600 - 30) || nowsec == (3600 / 2) - 30) // 30초 전 { CNetMsg::SP rmsg(new CNetMsg); SysMsg(rmsg, MSG_SYS_TRANSLATE_START ); SEND_Q(rmsg, m_pOwner->m_desc); } else if (nowsec >= 0 && nowsec <= (3600 / 2)) // 정각s { m_cTransSate = 0; } else { m_cTransSate = 1; } } break; case APET_TRANS_FAITH: comp = m_nFaith; break; case APET_TRANS_STM: comp = m_nStm; break; } // 옵션이 0 또는 100 이상일때 강제로 설정해주는 부분 if( m_cForceTrans == 1 ) // 무조건 변신 this->m_cTransSate = 1; else if ( m_cForceTrans == 2 ) // 무조건 변신 안함 this->m_cTransSate = 0; if( oldState != m_cTransSate ) { // 변신했는데 마운트 타입이 아닌경우 if( m_pProto->m_nMount[ (unsigned int)m_cTransSate ] < 1 && IsMount() ) { Mount(false); } else { CArea* area = m_pOwner->m_pArea; { CNetMsg::SP rmsg(new CNetMsg); DisappearMsg(rmsg, this); area->SendToCell(rmsg, this, true); } { CNetMsg::SP rmsg(new CNetMsg); AppearMsg(rmsg, this); area->SendToCell(rmsg, this, true); } } CalcStatus(false); return true; } } return false; }
void CAPet::Appear(bool bIncludeOwner, bool bAction ) { //#ifdef MONSTER_COMBO_BUGFIX // GAMELOG << init("APET APEAR PREV") // << m_index << end; //#endif // MONSTER_COMBO_BUGFIX" if (m_pOwner == NULL) { //#ifdef MONSTER_COMBO_BUGFIX // GAMELOG << init("MONSTER_COMBO_BUGFIX") << "OWNER NULL"<< end; //#endif // MONSTER_COMBO_BUGFIX return ; } CArea* area = m_pOwner->m_pArea; if (area == NULL) { //#ifdef MONSTER_COMBO_BUGFIX // GAMELOG << init("MONSTER_COMBO_BUGFIX") << "AREA NULL" << end; //#endif // MONSTER_COMBO_BUGFIX return ; } if (m_bSummon) { //#ifdef MONSTER_COMBO_BUGFIX // GAMELOG << init("MONSTER_COMBO_BUGFIX") << "SUMMON FALSE" << end; //#endif // MONSTER_COMBO_BUGFIX return ; } // 셀에 넣기 m_pZone = area->m_zone; m_pArea = area; m_pos = m_pOwner->m_pos; int cx, cz; area->PointToCellNum(GET_X(this), GET_Z(this), &cx, &cz); area->CharToCell(this, GET_YLAYER(this), cx, cz); { CNetMsg::SP rmsg(new CNetMsg); // 나타남을 알림 AppearMsg(rmsg, this, true, true); area->SendToCell(rmsg, this, bIncludeOwner); } CalcStatus(false); { CNetMsg::SP rmsg(new CNetMsg); ExAPetStatusMsg( rmsg, this ); m_pArea->SendToCell(rmsg, GetOwner(), true); } for( int i=0 ; i < APET_WEARPOINT; i++ ) { if( m_wearing[i] ) { CNetMsg::SP rmsg(new CNetMsg); AddItemExAPetMsg(rmsg, m_wearing[i]); SEND_Q(rmsg, GetOwner()->m_desc); } } m_bSummon = true; //#ifdef MONSTER_COMBO_BUGFIX // GAMELOG << init("APET APEAR AFTER") // << m_index << delim // << m_cellX << delim // << m_cellZ << end; //#endif // MONSTER_COMBO_BUGFIX }
void ProcDead(CNPC* df, CCharacter* of) { CPC* opc = NULL; CNPC* onpc = NULL; CPet* opet = NULL; CElemental* oelemental = NULL; CAPet* oapet = NULL; bool bNPCKilledNPC = false; // npc가 npc를 죽인 경우 꼭 이것을 true로 해줘야한다. switch (of->m_type) { case MSG_CHAR_PC: opc = TO_PC(of); if (opc == NULL) goto END_PROC; break; case MSG_CHAR_NPC: onpc = TO_NPC(of); break; case MSG_CHAR_PET: opet = TO_PET(of); opc = opet->GetOwner(); if (opc == NULL) goto END_PROC; break; case MSG_CHAR_ELEMENTAL: oelemental = TO_ELEMENTAL(of); opc = oelemental->GetOwner(); if (opc == NULL) goto END_PROC; break; case MSG_CHAR_APET: oapet = TO_APET(of); opc = oapet->GetOwner(); if( opc == NULL ) goto END_PROC; break; default: goto END_PROC; } #ifdef SYSTEM_TREASURE_MAP // if( df->m_idNum == TREASURE_BOX_NPC_INDEX) // 보물상자 npc를 잡았다. 정보를 없애주자. // df->m_pZone->RemoveTreasureBoxNpc(df ); #endif // 공주구출 퀘스트 (퍼스널 던전 2) 실패 ProcDead_PD2(df); // 죽은 것이 테이밍 몬스터일 경우 if (df->Check_MobFlag( STATE_MONSTER_TAMING ) ) { CPC* owner = NULL; // 몬스터를 테이밍한 캐릭터 owner = df->GetOwner(); // 몬스터가 테이밍 되었는지 확인 // 주인이 공격하고 있는 타겟을 지워준다. 주인이 테이밍 중이 아닌걸로 바꿔준다. if ( owner ) { owner->DeleteSlave( df ); } goto SKIP_DROP; } // 죽인 것이 테이밍 몬스터일 경우 if (onpc && onpc->Check_MobFlag( STATE_MONSTER_TAMING ) ) { CPC* owner = NULL; // 몬스터를 테이밍한 캐릭터 owner = onpc->GetOwner(); // 몬스터가 테이밍 되었는지 확인 // 주인이 공격하고 있는 타겟을 지워준다. if ( owner ) { owner->SetOwners_target(NULL); // opc에 주인을 넣어준다. opc = owner; bNPCKilledNPC = true; } else goto SKIP_DROP; } else if( onpc && onpc->GetOwner() ) // 공격한 NPC가 오너가 있다면 { CNPC* sumNpc = onpc->GetOwner()->GetSummonNpc(onpc); if( sumNpc ) { if( sumNpc->Check_MobFlag((STATE_MONSTER_MERCENARY)) ) { sumNpc->GetOwner()->SetSummonOwners_target(NULL); } opc = onpc->GetOwner(); bNPCKilledNPC = true; } else goto SKIP_DROP; } if( df && df->GetOwner() ) // 죽은 넘이 owner 있다면 { if( df->Check_MobFlag(STATE_MONSTER_PARASITE) ) // 패러사이트에 걸려있다면. { int parasiteCnt = GetRandom(0,3); parasiteCnt -= df->GetOwner()->GetBombSummonCont(); if( parasiteCnt > 0 ) { int parasiteIdx = df->m_assist.GetSummonNpcIndex(); if( parasiteIdx > 0 ) { int i; for(i=0; i<parasiteCnt; i++) { CNPC* pParasiteNPC; pParasiteNPC = gserver->m_npcProtoList.Create(parasiteIdx, NULL ); if( pParasiteNPC == NULL ) continue; GET_X(pParasiteNPC) = GET_X(df); GET_Z(pParasiteNPC) = GET_Z(df); GET_R(pParasiteNPC) = GET_R(df); GET_YLAYER(pParasiteNPC) = GET_YLAYER(df); float fRand = GetRandom(0,1) ? 1.0f : -1.0f ; float x = 2.0f + ( fRand * (float)(GetRandom( 0 , 200 ) / 100.0f) ); fRand = GetRandom(0,1) ? 1 : -1 ; float z = 2.0f + ( fRand * (float)(GetRandom( 0 , 200 ) / 100.0f) ); pParasiteNPC->m_regenX = GET_X(pParasiteNPC) += x; pParasiteNPC->m_regenZ = GET_Z(pParasiteNPC) += z; pParasiteNPC->m_regenY = GET_YLAYER(pParasiteNPC); pParasiteNPC->CalcStatus(false); CSkill * pSkill = gserver->m_skillProtoList.Create( 1133 ); // 자살 공격 if( pSkill == NULL ) { delete pParasiteNPC ; pParasiteNPC = NULL; continue; } pParasiteNPC->SetOwner(df->GetOwner()); bool bApply; if( 0 != ApplySkill((CCharacter*)df->GetOwner(), (CCharacter*)pParasiteNPC, pSkill, -1, bApply) ) { delete pSkill; pSkill = NULL; delete pParasiteNPC; continue; } delete pSkill; pSkill = NULL; if( bApply == false ) { delete pParasiteNPC ; pParasiteNPC = NULL; continue; } df->GetOwner()->SetBombSummonNPC(pParasiteNPC); int cx, cz; df->m_pArea->AddNPC(pParasiteNPC); df->m_pArea->PointToCellNum(GET_X(pParasiteNPC), GET_Z(pParasiteNPC), &cx, &cz); df->m_pArea->CharToCell(pParasiteNPC, GET_YLAYER(pParasiteNPC), cx, cz); { CNetMsg::SP rmsg(new CNetMsg); AppearMsg(rmsg, pParasiteNPC, true); df->m_pArea->SendToCell(rmsg, GET_YLAYER(pParasiteNPC), cx, cz); } } } } } CNPC* sumNpc = df->GetOwner()->GetSummonNpc(df); if( sumNpc ) { #ifdef BUGFIX_MERCNERAY_DELETE sumNpc->GetOwner()->SummonNpcRemove(df, false); #else sumNpc->GetOwner()->SummonNpcRemove(df); #endif goto SKIP_DROP; } } /* */ // 이곳으로 넘어오면 테이밍이 아니므로, 모든 몬스터는 몬스터에게 죽으면 패스 else if (onpc && !bNPCKilledNPC) { goto SKIP_DROP; } // pc가 npc를 죽이면 테이밍 몬스터의 타겟을 지워준다. if (opc) { opc->SetOwners_target(NULL); opc->SetSummonOwners_target(NULL); } // 리더 사망시 처리 if (!df->m_proto->CheckFlag(NPC_RAID)) ProcFollowNPC(df); // 공성 포인트 계산 if (opc) CalcWarPoint(opc, df); // 죽은 NPC가 공성탑이나 수호병이 아닐 경우 처리 if (!df->m_proto->CheckFlag(NPC_CASTLE_TOWER | NPC_CASTLE_GUARD)) { int level = -1; LONGLONG nTotalDamage = 0; // 우선권 PC, 평균 레벨 구하기 CPC* tpc = FindPreferencePC(df, &level, &nTotalDamage); #ifdef GER_LOG if( IS_PC( of )) { CPC *user = TO_PC( of ); GAMELOGGEM << init( 0, "CHAR_VICTORY" ) << LOG_VAL("account-id", user->m_desc->m_idname ) << blank << LOG_VAL("character-id", user->m_desc->m_pChar->m_name ) << blank << LOG_VAL("zone-id", user->m_desc->m_pChar->m_pZone->m_index ) << blank << LOG_VAL("victim-id", df->m_index ) << blank /*<< LOG_VAL("opponent-id", kill) << blank*/ << LOG_VAL("longitude", GET_X(user) ) << blank << LOG_VAL("latitude", GET_Z(user) ) << blank << endGer; } #endif // 보스몹 if (df->m_proto->CheckFlag(NPC_BOSS | NPC_MBOSS | NPC_RAID)) { GAMELOG << init("MOB DEAD") << "INDEX" << delim << df->m_proto->m_index << delim << "NAME" << delim << df->m_name << delim << "ZONE" << delim << df->m_pZone->m_index << delim << "POSITION" << delim << GET_X(df) << delim << GET_Z(df) << delim << GET_YLAYER(df) << delim << "KILL BY" << delim; if (opc) { GAMELOG << opc->m_index << delim << opc->m_name << delim << opc->m_nick << delim << opc->m_job << delim << opc->m_job2 << delim << opc->m_level; } else { GAMELOG << of->m_type << delim << of->m_index << delim << of->m_name << delim << of->m_level; } GAMELOG << end; if (df->m_proto->CheckFlag(NPC_BOSS | NPC_MBOSS)) { // 카오 성향 회복 : 보스몹을 잡으면 회복 보너스 if (opc && opc->IsChaotic() && tpc == opc) { if( !gserver->m_bNonPK ) opc->m_pkPenalty += df->m_level / 10; if (opc->m_pkPenalty > 0) opc->m_pkPenalty = 0; { CNetMsg::SP rmsg(new CNetMsg); CharStatusMsg(rmsg, opc, 0); opc->m_pArea->SendToCell(rmsg, opc, false); } opc->m_bChangeStatus = true; } } } // 보스몹 if(opc && opc->m_pArea && df->m_proto->m_index == 1002 && df->m_pZone && df->m_pZone->m_index == ZONE_ALTER_OF_DARK) { // 네임드 몬스터 죽은 것으로 체크 opc->m_pArea->m_CTriggerList.Set_TriggerFlag(TRIGGER_FLAG_NAMEDNPC_DEATH1); opc->m_pArea->m_CTriggerList.Set_TriggerFlag(TRIGGER_FLAG_NAMEDNPC_DEATH1002_BEFORE); opc->m_pArea->m_CTriggerList.SaveTriggerInfo(TRIGGER_SAVE_ALTER_OF_DARK_1002, opc->m_nJoinInzone_RoomNo); //트리거 정보 저장 opc->m_pArea->Change_NpcRegenRaid(TRIGGER_SAVE_ALTER_OF_DARK_1002, 1002); } else if(opc && opc->m_pArea && df->m_proto->m_index == 1003 && df->m_pZone && df->m_pZone->m_index == ZONE_ALTER_OF_DARK) { // 네임드 몬스터 죽은 것으로 체크 opc->m_pArea->m_CTriggerList.Set_TriggerFlag(TRIGGER_FLAG_NAMEDNPC_DEATH2); opc->m_pArea->m_CTriggerList.Set_TriggerFlag(TRIGGER_FLAG_NAMEDNPC_DEATH1003_BEFORE); opc->m_pArea->m_CTriggerList.SaveTriggerInfo(TRIGGER_SAVE_ALTER_OF_DARK_1003, opc->m_nJoinInzone_RoomNo); //트리거 정보 저장 opc->m_pArea->Change_NpcRegenRaid(TRIGGER_SAVE_ALTER_OF_DARK_1003, 1003); } else if(opc && opc->m_pArea && df->m_proto->m_index == 1018 && df->m_pZone && df->m_pZone->m_index == ZONE_ALTER_OF_DARK) { // 네임드 몬스터 죽은 것으로 체크 opc->m_pArea->m_CTriggerList.Set_TriggerFlag(TRIGGER_FLAG_NAMEDNPC_DEATH1018_BEFORE); opc->m_pArea->m_CTriggerList.SaveTriggerInfo(TRIGGER_SAVE_ALTER_OF_DARK_1018, opc->m_nJoinInzone_RoomNo); //트리거 정보 저장 opc->m_pArea->Change_NpcRegenRaid(TRIGGER_SAVE_ALTER_OF_DARK_1018, 1018); } else if (opc && opc->m_pArea && df->m_proto->m_index == 963 && df->m_pZone && df->m_pZone->m_index == ZONE_CAPPELLA_1) { // 트리거를 사용하기 위한 npc963 죽은 count 세기 opc->m_pArea->m_CTriggerList.m_nNPC963_KilledCount += 1; } int nObjectData; int nAkanNpcIdx = df->m_proto->m_index; switch(nAkanNpcIdx) { case 1115: // 파독스의 인형(Hard) case 1170: // 파독스의 인형(Normal) { nObjectData = 10; if(opc && opc->m_pArea && df->m_pZone && df->m_pZone->m_index == ZONE_AKAN_TEMPLE) { CNetMsg::SP rmsg(new CNetMsg); RaidSceneMsg(rmsg, OBJECT_TYPE_TODO, KILL_NPC, nAkanNpcIdx, nObjectData); do_ExRaidScene(opc, rmsg); } } break; case 1112: // 툴만 case 1116: // 파독스 case 1120: // 쿤타 case 1124: // 유작 case 1126: // 고위 연금술사 제롬 case 1127: // 고위 마법술사 미엘 case 1128: // 제사장 미쿠 case 1167: // 툴만 case 1171: // 파독스 case 1175: // 쿤타 case 1179: // 유작 case 1180: // 고위 연금술사 제롬 case 1181: // 고위 마법술사 미엘 case 1182: // 제사장 미쿠 { nObjectData = 1; if(opc && opc->m_pArea && df->m_pZone && df->m_pZone->m_index == ZONE_AKAN_TEMPLE) { { CNetMsg::SP rmsg(new CNetMsg); RaidSceneMsg(rmsg, OBJECT_TYPE_TODO, KILL_NPC, nAkanNpcIdx, nObjectData); do_ExRaidScene(opc, rmsg); } } } break; case 1259: //망각의 신전 { nObjectData = 1; if(opc && opc->m_pArea && df->m_pZone && df->m_pZone->m_index == ZONE_DUNGEON4) { CNetMsg::SP rmsg(new CNetMsg); RaidSceneMsg(rmsg, OBJECT_TYPE_TODO, KILL_NPC, nAkanNpcIdx, nObjectData); do_ExRaidScene(opc, rmsg); } } break; case 1364: { if(opc && opc->m_pArea && df->m_pZone && df->m_pZone->m_index == ZONE_TARIAN_DUNGEON) { CNetMsg::SP rmsg(new CNetMsg); RaidSceneMsg(rmsg, OBJECT_TYPE_TODO, KILL_NPC, nAkanNpcIdx, 1); do_ExRaidScene(opc, rmsg); } } break; default: break; } #ifdef REFORM_PK_PENALTY_201108 // PK 패널티 리폼 :: npc를 잡으면 무조건 헌터 쪽으로 향상 시켜준다. if( !gserver->m_bNonPK ) { if(df && opc) { int nlevel = df->m_level - opc->m_level; int pkPenalty = 0; if( nlevel > 4 ) pkPenalty += 15; else if( nlevel > -5 ) pkPenalty += 10; else if( nlevel <= -5 && nlevel >= -10) pkPenalty += 5; // 성향 수치 상승 증폭제를 사용 중이라면 if( opc->m_assist.m_avRate.pkDispositionPointValue > 0 ) { pkPenalty = pkPenalty * opc->m_assist.m_avRate.pkDispositionPointValue; opc->m_assist.CureByItemIndex(7474); // 성향 수치 상승 증폭제 opc->m_assist.CureByItemIndex(7475); // 성향 수치 상승 증폭제 opc->m_assist.CureByItemIndex(7476); // 성향 수치 상승 증폭제 } opc->AddPkPenalty( pkPenalty ); { CNetMsg::SP rmsg(new CNetMsg); CharStatusMsg(rmsg, opc, 0); opc->m_pArea->SendToCell(rmsg, opc, false); } opc->m_bChangeStatus = true; } } #else // REFORM_PK_PENALTY_201108 // PK 패널티 리폼 if (opc && opc->IsChaotic() && df->m_level >= opc->m_level - 5) { opc->m_pkRecoverNPCCount++; if (opc->m_pkRecoverNPCCount >= 25) { opc->m_pkRecoverNPCCount = 0; if( !gserver->m_bNonPK ) opc->m_pkPenalty++; { CNetMsg::SP rmsg(new CNetMsg); CharStatusMsg(rmsg, opc, 0); opc->m_pArea->SendToCell(rmsg, opc, false); } opc->m_bChangeStatus = true; } } // 카오 성향 회복 #endif // REFORM_PK_PENALTY_201108 // PK 패널티 리폼 // Exp, SP 분배 // 이루틴중 레벨업을 하여 존이동을 하였을 경우 나머지 실행하지 않는다. if( DivisionExpSP(df, tpc, nTotalDamage) ) goto END_PROC; // 아이템 드롭 ProcDropItemAfterBattle(df, opc, tpc, level); // 진행중인 Quest 중 죽은 npc로 진행중이면 UpdateData if (opc && opc == tpc) { if( opc->m_pZone->IsPersonalDungeon() ) { opc->m_pArea->m_nMakeNPC++; #if defined ( LC_GAMIGO ) || defined ( LC_KOR ) || defined ( LC_USA ) if( df->m_proto->m_index == 5 ) { if(opc->m_pArea->m_nMakeNPC < 103) goto SKIP_DROP; else { GAMELOG << init("QUEST COMPLETE PD1", opc) << opc->m_pArea->m_nMakeNPC << end; } } else if(df->m_proto->m_index == 201 && opc->m_pArea->m_nMakeNPC < 50) { goto SKIP_DROP; } #else if( (df->m_proto->m_index == 5 || df->m_proto->m_index == 201 ) && opc->m_pArea->m_nMakeNPC < 50 ) { goto SKIP_DROP; } #endif // LC_GAMIGO || LC_KOR || LC_USA } #ifdef PARTY_QUEST_ITEM_BUG_ ProcDeadQuestProc(opc, df, QTYPE_SCALE_PERSONAL); // 내가 어그로도 먹고 몬스터도 막타 쳤단다. #else CQuest* pQuest = NULL; CQuest* pQuestNext = opc->m_questList.GetNextQuest(NULL, QUEST_STATE_RUN); while ((pQuest = pQuestNext)) { pQuestNext = opc->m_questList.GetNextQuest(pQuestNext, QUEST_STATE_RUN); // 퀘스트 있고 수행중이고 반복, 수집, 격파, 구출 퀘스트이면 switch (pQuest->GetQuestType0()) { case QTYPE_KIND_REPEAT: case QTYPE_KIND_COLLECTION: case QTYPE_KIND_DEFEAT: case QTYPE_KIND_SAVE: pQuest->QuestUpdateDataForParty(opc, df); break; default: break; } } if( pQuest == NULL && opc->IsParty() && opc->m_party ) { int i; const CPartyMember* pPartyMember; CPC* pPartyPC; for(i=0; i<MAX_PARTY_MEMBER; ++i) { pPartyMember = opc->m_party->GetMemberByListIndex(i); if(pPartyMember && pPartyMember->GetMemberPCPtr()) { pPartyPC = pPartyMember->GetMemberPCPtr(); if(opc->m_pArea->FindCharInCell(opc, pPartyPC->m_index, MSG_CHAR_PC)) { pQuest = pPartyPC->m_questList.FindQuestByMob( df->m_idNum); if( pQuest == NULL) continue; if( pQuest->GetPartyScale() != QTYPE_SCALE_PARTY) break; switch (pQuest->GetQuestType0()) { case QTYPE_KIND_REPEAT: case QTYPE_KIND_COLLECTION: case QTYPE_KIND_DEFEAT: case QTYPE_KIND_SAVE: pQuest->QuestUpdateData(pPartyPC, df); break; default: break; } } } } } #endif // PARTY_QUEST_ITEM_BUG_ } #ifdef PARTY_QUEST_ITEM_BUG_ else if(opc) // [2010/12/28 derek] opc == NULL 인데도 들어가져서 퀘스트 찾다가 서버 다운되어 추가함. { #ifdef _BATTLEGROUP_QUEST_BUG_PIX if( opc->IsExped() ) // 어글은 않먹었지만 막타로 잡았으면 ProcDeadQuestProc(opc, df, QTYPE_SCALE_BATTLEGROUP); else #endif ProcDeadQuestProc(opc, df, QTYPE_SCALE_PARTY); } #endif //PARTY_QUEST_ITEM_BUG_ } // 죽은 NPC가 공성탑이나 수호병이 아닐 경우 처리 else { int level = -1; LONGLONG nTotalDamage = 0; // 우선권 PC, 평균 레벨 구하기 CPC* tpc = FindPreferencePC(df, &level, &nTotalDamage); DropWarCastleToken(df, opc, tpc, level); } SKIP_DROP: // 수호탑은 DelNPC() 안하고 UpdateGateState() 후에 메시지로 알린다. if (df->m_proto->CheckFlag(NPC_CASTLE_TOWER) != 0) { int gstate_old = 0, gstate_new = 0; CWarCastle * castle = CWarCastle::GetCastleObject(ZONE_MERAC); CDratanCastle * pCastle = CDratanCastle::CreateInstance(); if (of->m_pZone->m_index == ZONE_MERAC) { if (castle != NULL) { gstate_old = castle->GetGateState(); gstate_old |= pCastle->GetGateState(); castle->UpdateGateState(df); gstate_new = castle->GetGateState(); gstate_new |= pCastle->GetGateState(); } } else if (of->m_pZone->m_index == ZONE_DRATAN) { gstate_old = pCastle->GetGateState(); if (castle != NULL) { gstate_old |= castle->GetGateState(); } pCastle->UpdateGateState(df); gstate_new = pCastle->GetGateState(); if (castle != NULL) { gstate_new |= castle->GetGateState(); } if (df->m_proto->CheckFlag(NPC_WARCASTLE) != 0) { // NPC_CASTLE_TOWER 에 NPC_WARCASTLE 면 // 마스터 타워와 부활진지 int qindex = df->m_proto->m_index; if (qindex >= 390 && qindex <= 396) { // 부활진지 파괴 알림 CNetMsg::SP rmsg(new CNetMsg); CastleTowerQuartersCrushMsg(rmsg, qindex); of->m_pArea->SendToAllClient(rmsg); // 부활진지 파괴 처리 /*pCastle->m_nRebrithGuild[df->m_proto->m_index - 390] = -1; memset((void *)pCastle->m_strRebrithGuild[df->m_proto->m_index - 390], 0, 51);*/ } } } if (gstate_old != gstate_new) { CNetMsg::SP rmsg(new CNetMsg); GuildWarGateStateMsg(rmsg, gstate_old, gstate_new); of->m_pArea->SendToAllClient(rmsg); } DelAttackList(df); if (of->m_pZone->m_index == ZONE_DRATAN) { if( df->m_proto->m_index == 351) { // 마스터 타워 // 모든 타워 기능 정지 pCastle->StopCastleTower(); } else if (df->m_proto->CheckFlag(NPC_CASTLE_TOWER) != 0) { // 공격 수호상 (결계의 눈 등..) 로그 GAMELOG << init("DRATAN CASTLE NPC DEAD : ") << df->m_proto->m_name << " BROKEN BY : " << of->m_name << end; // 마스터 타워가 아닌 모든 타워 int i; // 부활 진지 삭제 // for (i=0; i<7; i++) // { // if (pCastle->m_pRebrithNPC[i] == df) // { // pCastle->m_pRebrithNPC[i] = NULL; // pCastle->m_nRebrithGuild[i] = -1; // memset((void *)pCastle->m_strRebrithGuild[i], 0, 51); //#ifdef BUGFIX_WARCASTLE_REGEN // pCastle->m_nRegenTimeRebirthNPC[i] = gserver->getNowSecond() + pCastle->GetRegenNPCRebirthTime(); //#else // pCastle->m_nRegenTimeRebirthNPC[i] = gserver->m_pulse + pCastle->GetRegenNPCRebirthTime(); //#endif // BUGFIX_WARCASTLE_REGEN // } // } // 워프 타워 삭제 for (i=0; i<5; i++) { if (pCastle->m_pWarpNPC[i] == df) { pCastle->m_pWarpNPC[i] = NULL; } } // 결계의 눈 삭제 for (i=0; i<5; i++) { if (pCastle->m_gateNPC[i] == df) { pCastle->m_gateNPC[i] = NULL; } } // 알림 of->m_pArea->CharFromCell(df, true); of->m_pArea->DelNPC(df); } } return ; } // 수호탑은 DelNPC() 안하고 UpdateGateState() 후에 메시지로 알린다. //#endif #ifdef EXTREME_CUBE if(df->m_bCubeRegen) { CCubeSpace* cube = gserver->m_extremeCube.GetExtremeCube(df->m_pArea->m_index); if(cube) { cube->DelMob(df); if(gserver->m_extremeCube.IsGuildCubeTime() && opc && opc->m_guildInfo && opc->m_guildInfo->guild()) { CCubeMemList* CubeMemList; CubeMemList = gserver->m_extremeCube.FindMemList(opc->m_guildInfo->guild()); if(CubeMemList) { time_t lastCubePoint; time(&lastCubePoint); CNetMsg::SP rmsg(new CNetMsg); HelperAddCubePointMsg(rmsg, opc->m_guildInfo->guild()->index(), df->m_level, lastCubePoint); SEND_Q(rmsg, gserver->m_helper); } } } } if(df->m_pZone != NULL && df->m_proto->m_index == 529 && df->m_pZone->IsExtremeCube()) { CCubeSpace* cube = gserver->m_extremeCube.GetExtremeCube(df->m_pArea->m_index); if(cube && (cube->m_crystal == df) ) { // cube->m_crystal = NULL; cube->DelCrystal(false); cube->m_waitTime = gserver->m_pulse + PULSE_REAL_SEC * 10; return ; } } else if(df->m_pZone != NULL && df->m_proto->m_index == 527 && df->m_pZone->IsExtremeCube()) { CCubeSpace* cube = gserver->m_extremeCube.GetExtremeCube(df->m_pArea->m_index); if(cube && (cube->m_crystal == df) ) { // cube->m_crystal = NULL; cube->DelCrystal(false); cube->m_waitTime = gserver->m_pulse + PULSE_REAL_SEC * 10; return ; } } #endif // EXTREME_CUBE if(df && opc) { vec_affinityList_t::iterator it = df->m_proto->m_affinityList.begin(); vec_affinityList_t::iterator endit = df->m_proto->m_affinityList.end(); int point = 0; for(; it != endit; ++it) { CAffinityProto* proto = *(it); CAffinity* affinity = opc->m_affinityList.FindAffinity(proto->m_index); if(affinity) { point = proto->GetAffinityPointOfNPC(df->m_idNum); int bonus = 0; if(opc->m_avPassiveAddition.affinity_monster > 0) { bonus += opc->m_avPassiveAddition.affinity_monster; } if(opc->m_avPassiveRate.affinity_monster > 0) { bonus = point * (opc->m_avPassiveRate.affinity_monster - 100) / SKILL_RATE_UNIT; } affinity->AddPoint( point, opc, bonus); } } } if(df->m_ctCount > 0) { gserver->m_npc_ctTime.erase(df->m_index); } END_PROC: //rvr 존에서 공격시에 동작해야 되는 함수 (NPC 가 죽었을 경우) if(opc != NULL && of->m_pZone->isRVRZone() && df->m_pZone->isRVRZone()) { ProcDead_RVR(opc, df); } // 모든 몬스터는 몬스터에게 죽으면 패스 if ( onpc || bNPCKilledNPC ) { // 해당 에어리어에 죽은 수를 표시한다. 여기서는 바로 안지우고 따로 처리.. // MobActivity.cpp::MobActivity() 타고 들어오면 꼭 여길 거쳐야한다. onpc->m_pArea->m_nNPC_Killed_NPC++; } else { DelAttackList(df); of->m_pArea->CharFromCell(df, true); of->m_pArea->DelNPC(df); } }