void CAISocket::RecvNpcDead(Packet & pkt) { uint16 nid = pkt.read<uint16>(); CNpc* pNpc = g_pMain->m_arNpcArray.GetData(nid); if (pNpc == NULL) return; C3DMap* pMap = pNpc->GetMap(); if (pMap == NULL) return; if (pNpc->m_byObjectType == SPECIAL_OBJECT) { _OBJECT_EVENT *pEvent = pMap->GetObjectEvent(pNpc->m_sSid); if (pEvent) pEvent->byLife = 0; } pMap->RegionNpcRemove(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, nid); Packet result(WIZ_DEAD); result << nid; g_pMain->Send_Region(&result, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z); pNpc->m_sRegion_X = pNpc->m_sRegion_Z = 0; }
void CAISocket::RecvNpcInfo(Packet & pkt) { std::string strName; uint8 Mode, byDirection; uint16 sNid; pkt.SByte(); pkt >> Mode >> sNid; CNpc *pNpc = g_pMain->m_arNpcArray.GetData(sNid); if (pNpc == NULL) return; pkt >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2 >> pNpc->m_bZone >> strName >> pNpc->m_bNation >> pNpc->m_bLevel >> pNpc->m_curx >> pNpc->m_curz >> pNpc->m_cury >> byDirection >> pNpc->m_NpcState >> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen >> pNpc->m_sTotalHitrate >> pNpc->m_sTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_byObjectType >> pNpc->m_byTrapNumber; if (strName.empty() || strName.length() > MAX_NPC_SIZE) { pNpc->DecRef(); return; } pNpc->m_byDirection = byDirection; strcpy(pNpc->m_strName, strName.c_str()); if (pNpc->GetMap() == NULL) return; pNpc->InsertRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ()); pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ()); if (pNpc->m_byObjectType == SPECIAL_OBJECT) { _OBJECT_EVENT *pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid ); if (pEvent != NULL) pEvent->byLife = 1; } if (Mode == 0) { TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->GetID(), pNpc->m_strName); return; } pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY()); }
void CAISocket::RecvGateOpen( char* pBuf ) { int index = 0, nNid = 0, nSid = 0, nGateFlag = 0; CNpc* pNpc = NULL; _OBJECT_EVENT* pEvent = NULL; nNid = GetShort(pBuf, index); nSid = GetShort(pBuf, index); nGateFlag = GetByte(pBuf, index); pNpc = m_pMain->m_arNpcArray.GetData(nNid); if (pNpc == NULL) { TRACE("#### RecvGateOpen Npc Pointer null : nid=%d ####\n", nNid); return; } pNpc->m_byGateOpen = nGateFlag; // possibly not needed (we'll do it below), but need to make sure. pEvent = pNpc->GetMap()->GetObjectEvent(nSid); if (pEvent == NULL) { TRACE("#### RecvGateOpen Npc Object fail : nid=%d, sid=%d ####\n", nNid, nSid); return; } //TRACE("---> RecvGateOpen Npc Object fail : nid=%d, sid=%d, nGateFlag = %d ####\n", nNid, nSid, nGateFlag); if (pNpc->isGate()) pNpc->SendGateFlag(nGateFlag, false); }
// TO-DO: Remove this. NPCs don't just randomly die, it would make sense to do this as a result of the cause, not just because. void CAISocket::RecvNpcDead(Packet & pkt) { uint16 nid = pkt.read<uint16>(); CNpc* pNpc = g_pMain->m_arNpcArray.GetData(nid); if (pNpc == NULL) return; C3DMap* pMap = pNpc->GetMap(); if (pMap == NULL) return; pNpc->OnDeath(NULL); }
// TO-DO: Remove this. NPCs don't just randomly die, it would make sense to do this as a result of the cause, not just because. void CAISocket::RecvNpcDead(Packet & pkt) { CNpc * pNpc; Unit * pAttacker; uint16 nid, attackerID; pkt >> nid >> attackerID; pNpc = g_pMain->GetNpcPtr(nid); if (pNpc == nullptr || pNpc->GetMap() == nullptr) return; pAttacker = g_pMain->GetUnitPtr(attackerID); pNpc->OnDeath(pAttacker); }
void CAISocket::RecvNpcDead(char* pBuf) { int index = 0, send_index = 0; int nid = 0; char send_buff[256]; _OBJECT_EVENT* pEvent = NULL; nid = GetShort(pBuf,index); if(nid >= NPC_BAND) { CNpc* pNpc = m_pMain->m_arNpcArray.GetData(nid); if(!pNpc) return; C3DMap* pMap = pNpc->GetMap(); if (pMap == NULL) return; if( pNpc->m_byObjectType == SPECIAL_OBJECT ) { pEvent = pMap->GetObjectEvent( pNpc->m_sSid ); if( pEvent ) pEvent->byLife = 0; } //pNpc->NpcInOut( NPC_OUT ); //TRACE("RecvNpcDead - (%d,%s)\n", pNpc->m_sNid, pNpc->m_strName); pMap->RegionNpcRemove(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, nid); //TRACE("--- RecvNpcDead : Npc를 Region에서 삭제처리.. ,, zone=%d, region_x=%d, y=%d\n", pNpc->m_sZoneIndex, pNpc->m_sRegion_X, pNpc->m_sRegion_Z); SetByte( send_buff, WIZ_DEAD, send_index ); SetShort( send_buff, nid, send_index ); m_pMain->Send_Region(send_buff, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false); pNpc->m_sRegion_X = 0; pNpc->m_sRegion_Z = 0; } }
void CAISocket::RecvMagicAttackResult(Packet & pkt) { uint32 magicid; uint16 sid, tid; uint8 byCommand; /* This is all so redundant... When everything's switched over to pass in Packets we can just pass it through directly! As it is now.. we still need a length (which we can hardcode, but meh) */ pkt >> byCommand >> magicid >> sid >> tid; if (byCommand == MAGIC_CASTING || (byCommand == MAGIC_EFFECTING && sid >= NPC_BAND && tid >= NPC_BAND)) { CNpc *pNpc = g_pMain->m_arNpcArray.GetData(sid); if (!pNpc) return; g_pMain->Send_Region(&pkt, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z); } else if (byCommand == MAGIC_EFFECTING) { if (sid >= USER_BAND && sid < NPC_BAND) { CUser *pUser = g_pMain->GetUserPtr(sid); if (pUser == NULL || pUser->isDead()) return; g_pMain->Send_Region(&pkt, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ); return; } // If we're an NPC, casting a skill (rather, it's finished casting) on a player... pkt.rpos(0); m_MagicProcess.MagicPacket(pkt); } }
void CAISocket::RecvNpcInfo(Packet & pkt) { std::string strName; uint8 Mode, byDirection; uint16 sNid; pkt.SByte(); pkt >> Mode >> sNid; CNpc *pNpc = g_pMain->m_arNpcArray.GetData(sNid); if (pNpc == NULL) return; pkt >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2 >> pNpc->m_bZoneID >> strName >> pNpc->m_byGroup >> pNpc->m_byLevel >> pNpc->m_fCurX >> pNpc->m_fCurZ >> pNpc->m_fCurY >> byDirection >> pNpc->m_NpcState >> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen >> pNpc->m_sTotalHitrate >> pNpc->m_sTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_byObjectType; if (strName.empty() || strName.length() > MAX_NPC_SIZE) { delete pNpc; return; } pNpc->m_byDirection = byDirection; strcpy(pNpc->m_strName, strName.c_str()); // Bug? Test? // pNpc->m_NpcState = NPC_DEAD; if (pNpc->m_NpcState == NPC_LIVE) { char strLog[256]; CTime t = CTime::GetCurrentTime(); sprintf_s(strLog, sizeof(strLog), "## time(%d:%d-%d) npc regen check(%d) : nid=%d, name=%s, x=%d, z=%d, rx=%d, rz=%d ## \r\n", t.GetHour(), t.GetMinute(), t.GetSecond(), pNpc->m_NpcState, pNpc->GetID(), pNpc->m_strName, (int)pNpc->m_fCurX, (int)pNpc->m_fCurZ, pNpc->GetRegionX(), pNpc->GetRegionZ()); EnterCriticalSection( &g_LogFile_critical ); g_pMain->m_RegionLogFile.Write( strLog, strlen(strLog) ); LeaveCriticalSection( &g_LogFile_critical ); TRACE(strLog); // to-do: replace with g_pMain->WriteRegionLog(...); } if (pNpc->GetMap() == NULL) return; pNpc->InsertRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ()); pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ()); if (pNpc->m_byObjectType == SPECIAL_OBJECT) { _OBJECT_EVENT *pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid ); if (pEvent != NULL) pEvent->byLife = 1; } if (Mode == 0) { TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->GetID(), pNpc->m_strName); return; } pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY()); }
void CAISocket::RecvNpcInfoAll(Packet & pkt) { uint8 bCount = pkt.read<uint8>(); // max of 20 pkt.SByte(); for (int i = 0; i < bCount; i++) { uint8 bType, bDirection; std::string strName; CNpc* pNpc = new CNpc(); pNpc->Initialize(); pkt >> bType >> pNpc->m_sNid >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2 >> pNpc->m_bZoneID >> strName >> pNpc->m_byGroup >> pNpc->m_byLevel >> pNpc->m_fCurX >> pNpc->m_fCurZ >> pNpc->m_fCurY >> bDirection >> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen >> pNpc->m_sTotalHitrate >> pNpc->m_sTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_byObjectType; if (strName.empty() || strName.length() > MAX_NPC_SIZE) { delete pNpc; continue; } //TRACE("Recv --> NpcUserInfo : uid = %d, x=%f, z=%f.. \n", nid, fPosX, fPosZ); strcpy(pNpc->m_strName, strName.c_str()); pNpc->m_pMap = g_pMain->GetZoneByID(pNpc->GetZoneID()); pNpc->m_NpcState = NPC_LIVE; pNpc->m_byDirection = bDirection; pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ()); if (pNpc->GetMap() == NULL) { delete pNpc; pNpc = NULL; continue; } if (pNpc->m_byObjectType == SPECIAL_OBJECT) { _OBJECT_EVENT* pEvent = pNpc->GetMap()->GetObjectEvent(pNpc->m_sSid); if (pEvent != NULL) pEvent->byLife = 1; } // TRACE("Recv --> NpcUserInfoAll : uid=%d, sid=%d, name=%s, x=%f, z=%f. gate=%d, objecttype=%d \n", nid, sPid, szName, fPosX, fPosZ, byGateOpen, byObjectType); if (!g_pMain->m_arNpcArray.PutData(pNpc->GetID(), pNpc)) { TRACE("Npc PutData Fail - %d\n", pNpc->GetID()); delete pNpc; continue; } if (bType == 0) { TRACE("Recv --> NpcUserInfoAll : nid=%d, sid=%d, name=%s\n", pNpc->GetID(), pNpc->m_sSid, strName.c_str()); continue; } // RegionNpcAdd() pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY()); } }
void CUser::MagicSystem( Packet & pkt ) { uint8 command, subcommand; uint32 magicid; time_t skill_received_time; uint16 sid, tid, data1, data2, data3, data4, data5, data6, data7; CUser *pUser, *pTargetUser = NULL; CNpc *pMon = NULL; skill_received_time = GetTickCount(); //Retrieve the time at which the Magic packet is going for internal processing. command = pkt.GetOpcode(); pkt >> subcommand >> magicid >> sid >> tid; if( sid < 0 || tid < 0 || tid > INVALID_BAND || sid != (uint16)GetSocketID()) //Return if there's an invalid source or target received. return; if( sid < MAX_USER ) { if (isDead()) return; } if(tid >= NPC_BAND) { pMon = m_pMain->m_arNpcArray.GetData(tid); if( !pMon || pMon->m_NpcState == NPC_DEAD ) return; } else if( tid < MAX_USER ) { pTargetUser = m_pMain->GetUserPtr(tid); if ( !pTargetUser ) return; } /* Do ALL required pre-liminary checks here, will wrap that into another function, until then leaving this disabled. */ //if(!CheckSkillCooldown(magicid, skill_received_time)) //Check if the skill is off-cooldown. // return; //LogSkillCooldown(magicid, skill_received_time); Use this <if> the skill is successfully casted! pkt >> data1 >> data2 >> data3 >> data4 >> data5 >> data6 >> data7; switch(command) { case MAGIC_CASTING: break; case MAGIC_FLYING: break; case MAGIC_EFFECTING: break; case MAGIC_FAIL: goto echo; break; case MAGIC_TYPE3_END: //This is also MAGIC_TYPE4_END break; case MAGIC_CANCEL: break; case MAGIC_CANCEL2: break; } echo : Packet result(WIZ_MAGIC_PROCESS); result << subcommand << magicid << sid << tid << data1 << data2 << data3 << data4 << data5 << data6 << data7; if (sid < MAX_USER) { m_pMain->Send_Region( &result, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ ); } else if ( sid >= NPC_BAND) { m_pMain->Send_Region( &result, pMon->GetMap(), pMon->m_sRegion_X, pMon->m_sRegion_Z ); } }
void CAISocket::RecvNpcInfo(char* pBuf) { int index = 0; BYTE Mode; // 01(INFO_MODIFY) : NPC 정보 변경 // 02(INFO_DELETE) : NPC 정보 삭제 short nid; // NPC index short sid; // NPC index short sPid; // NPC Picture Number short sSize = 100; // NPC Size int iWeapon_1; // 오른손 무기 int iWeapon_2; // 왼손 무기 BYTE bZone; // Current zone number char szName[MAX_NPC_SIZE+1]; // NPC Name BYTE byGroup; // 소속 집단 BYTE byLevel; // level float fPosX; // X Position float fPosZ; // Z Position float fPosY; // Y Position BYTE byDirection; // 방향 BYTE tState; // NPC 상태 // 00 : NPC Dead // 01 : NPC Live BYTE tNpcKind; // 00 : Monster // 01 : NPC int iSellingGroup; int nMaxHP; // 최대 HP int nHP; // 현재 HP BYTE byGateOpen; short sHitRate; // 공격 성공률 BYTE byObjectType; // 보통 : 0, 특수 : 1 Mode = GetByte(pBuf, index); nid = GetShort(pBuf, index); sid = GetShort(pBuf, index); sPid = GetShort(pBuf, index); sSize = GetShort(pBuf, index); iWeapon_1 = GetDWORD(pBuf, index); iWeapon_2 = GetDWORD(pBuf, index); bZone = GetByte(pBuf, index); int nLength = GetVarString(szName, pBuf, sizeof(BYTE), index); if(nLength < 0 || nLength > MAX_NPC_SIZE) return; // 잘못된 monster 아이디 byGroup = GetByte(pBuf, index); byLevel = GetByte(pBuf, index); fPosX = Getfloat(pBuf, index); fPosZ = Getfloat(pBuf, index); fPosY = Getfloat(pBuf, index); byDirection = GetByte(pBuf, index); tState = GetByte(pBuf, index); tNpcKind = GetByte(pBuf, index); iSellingGroup = GetDWORD(pBuf, index); nMaxHP = GetDWORD(pBuf, index); nHP = GetDWORD(pBuf, index); byGateOpen = GetByte(pBuf, index); sHitRate = GetShort(pBuf, index); byObjectType = GetByte(pBuf, index); CNpc* pNpc = NULL; pNpc = m_pMain->m_arNpcArray.GetData(nid); if(!pNpc) return; pNpc->m_NpcState = NPC_DEAD; if( pNpc->m_NpcState == NPC_LIVE ) { // 살아 있는데 또 정보를 받는 경우 char strLog[256]; CTime t = CTime::GetCurrentTime(); sprintf_s(strLog, sizeof(strLog), "## time(%d:%d-%d) npc regen check(%d) : nid=%d, name=%s, x=%d, z=%d, rx=%d, rz=%d ## \r\n", t.GetHour(), t.GetMinute(), t.GetSecond(), pNpc->m_NpcState, nid, szName, (int)pNpc->m_fCurX, (int)pNpc->m_fCurZ, pNpc->m_sRegion_X, pNpc->m_sRegion_Z); EnterCriticalSection( &g_LogFile_critical ); m_pMain->m_RegionLogFile.Write( strLog, strlen(strLog) ); LeaveCriticalSection( &g_LogFile_critical ); TRACE(strLog); // to-do: replace with m_pMain->WriteRegionLog(...); } pNpc->m_NpcState = NPC_LIVE; pNpc->m_sNid = nid; pNpc->m_sSid = sid; pNpc->m_sPid = sPid; pNpc->m_sSize = sSize; pNpc->m_iWeapon_1 = iWeapon_1; pNpc->m_iWeapon_2 = iWeapon_2; strcpy(pNpc->m_strName, szName); pNpc->m_byGroup = byGroup; pNpc->m_byLevel = byLevel; pNpc->m_bCurZone = bZone; pNpc->m_pMap = m_pMain->GetZoneByID(bZone); pNpc->m_fCurX = fPosX; pNpc->m_fCurZ = fPosZ; pNpc->m_fCurY = fPosY; pNpc->m_byDirection = byDirection; pNpc->m_NpcState = tState; pNpc->m_tNpcType = tNpcKind; pNpc->m_iSellingGroup = iSellingGroup; pNpc->m_iMaxHP = nMaxHP; pNpc->m_iHP = nHP; pNpc->m_byGateOpen = byGateOpen; pNpc->m_sHitRate = sHitRate; pNpc->m_byObjectType = byObjectType; if (pNpc->GetMap() == NULL) return; int nRegX = (int)fPosX / VIEW_DISTANCE; int nRegZ = (int)fPosZ / VIEW_DISTANCE; pNpc->m_sRegion_X = nRegX; pNpc->m_sRegion_Z = nRegZ; _OBJECT_EVENT* pEvent = NULL; if( pNpc->m_byObjectType == SPECIAL_OBJECT ) { pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid ); if( pEvent ) pEvent->byLife = 1; } if(Mode == 0) { TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->m_sNid, pNpc->m_strName); return; } pNpc->NpcInOut(NPC_IN, fPosX, fPosZ, fPosY); }
void CAISocket::RecvMagicAttackResult(char* pBuf) { int index = 0, send_index = 1, sid = -1, tid = -1, magicid=0; BYTE byCommand; short data0, data1, data2, data3, data4, data5; CNpc* pNpc = NULL; CUser* pUser = NULL; char send_buff[1024]; //byType = GetByte(pBuf,index); // who ( 1:mon->user 2:mon->mon ) //byAttackType = GetByte(pBuf,index); // attack type ( 1:long attack, 2:magic attack byCommand = GetByte(pBuf,index); // magic type ( 1:casting, 2:flying, 3:effecting, 4:fail ) magicid = GetDWORD(pBuf,index); sid = GetShort(pBuf,index); tid = GetShort(pBuf,index); data0 = GetShort(pBuf,index); data1 = GetShort(pBuf,index); data2 = GetShort(pBuf,index); data3 = GetShort(pBuf,index); data4 = GetShort(pBuf,index); data5 = GetShort(pBuf,index); SetByte( send_buff, byCommand, send_index ); SetDWORD( send_buff, magicid, send_index ); SetShort( send_buff, sid, send_index ); SetShort( send_buff, tid, send_index ); SetShort( send_buff, data0, send_index ); SetShort( send_buff, data1, send_index ); SetShort( send_buff, data2, send_index ); SetShort( send_buff, data3, send_index ); SetShort( send_buff, data4, send_index ); SetShort( send_buff, data5, send_index ); if(byCommand == 0x01) { // casting pNpc = m_pMain->m_arNpcArray.GetData(sid); if(!pNpc) return; index = 0; SetByte( send_buff, WIZ_MAGIC_PROCESS, index ); m_pMain->Send_Region(send_buff, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false); } else if(byCommand == 0x03) { // effecting //pNpc = m_pMain->m_arNpcArray.GetData(tid); //if(!pNpc) return; if( sid >= USER_BAND && sid < NPC_BAND) { pUser = m_pMain->GetUserPtr(sid); if (pUser == NULL || pUser->isDead()) return; index = 0; SetByte( send_buff, WIZ_MAGIC_PROCESS, index ); m_pMain->Send_Region(send_buff, send_index, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ, NULL, false); } else if(sid >= NPC_BAND) { if(tid >= NPC_BAND) { pNpc = m_pMain->m_arNpcArray.GetData(tid); if(!pNpc) return; index = 0; SetByte( send_buff, WIZ_MAGIC_PROCESS, index ); m_pMain->Send_Region(send_buff, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false); return; } send_index = 0; SetByte( send_buff, byCommand, send_index ); SetDWORD( send_buff, magicid, send_index ); SetShort( send_buff, sid, send_index ); SetShort( send_buff, tid, send_index ); SetShort( send_buff, data0, send_index ); SetShort( send_buff, data1, send_index ); SetShort( send_buff, data2, send_index ); SetShort( send_buff, data3, send_index ); SetShort( send_buff, data4, send_index ); SetShort( send_buff, data5, send_index ); m_MagicProcess.MagicPacket(send_buff, send_index); } } }
void CAISocket::RecvNpcAttack(char* pBuf) { int index = 0, send_index = 0, sid = -1, tid = -1, nHP = 0, temp_damage = 0; BYTE type, result, byAttackType = 0; float fDir=0.0f; short damage = 0; CNpc* pNpc = NULL, *pMon = NULL; CUser* pUser = NULL; char pOutBuf[1024]; _OBJECT_EVENT* pEvent = NULL; type = GetByte(pBuf,index); result = GetByte(pBuf,index); sid = GetShort(pBuf,index); tid = GetShort(pBuf,index); damage = GetShort(pBuf,index); nHP = GetDWORD(pBuf,index); byAttackType = GetByte(pBuf, index); //TRACE("CAISocket-RecvNpcAttack : sid=%s, tid=%d, zone_num=%d\n", sid, tid, m_iZoneNum); if(type == 0x01) // user attack -> npc { pNpc = m_pMain->m_arNpcArray.GetData(tid); if(!pNpc) return; pNpc->m_iHP -= damage; if( pNpc->m_iHP < 0 ) pNpc->m_iHP = 0; if(result == 0x04) { // 마법으로 죽는경우 SetByte( pOutBuf, WIZ_DEAD, send_index ); SetShort( pOutBuf, tid, send_index ); m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false); } else { SetByte(pOutBuf, WIZ_ATTACK, send_index); SetByte( pOutBuf, byAttackType, send_index ); // 직접:1, 마법:2, 지속마법:3 //if(result == 0x04) // 마법으로 죽는경우 // SetByte( pOutBuf, 0x02, send_index ); //else // 단순공격으로 죽는경우 SetByte( pOutBuf, result, send_index ); SetShort( pOutBuf, sid, send_index ); SetShort( pOutBuf, tid, send_index ); m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false); } pUser = m_pMain->GetUserPtr(sid); if (pUser != NULL) { pUser->SendTargetHP( 0, tid, -damage ); if( byAttackType != MAGIC_ATTACK && byAttackType != DURATION_ATTACK) { pUser->ItemWoreOut(ATTACK, damage); // LEFT HAND!!! by Yookozuna temp_damage = damage * pUser->m_bMagicTypeLeftHand / 100 ; switch (pUser->m_bMagicTypeLeftHand) { // LEFT HAND!!! case ITEM_TYPE_HP_DRAIN : // HP Drain pUser->HpChange(temp_damage, 0); break; case ITEM_TYPE_MP_DRAIN : // MP Drain pUser->MSpChange(temp_damage); break; } temp_damage = 0; // reset data; // RIGHT HAND!!! by Yookozuna temp_damage = damage * pUser->m_bMagicTypeRightHand / 100 ; switch (pUser->m_bMagicTypeRightHand) { // LEFT HAND!!! case ITEM_TYPE_HP_DRAIN : // HP Drain pUser->HpChange(temp_damage, 0); break; case ITEM_TYPE_MP_DRAIN : // MP Drain pUser->MSpChange(temp_damage); break; } // } } if(result == 0x02 || result == 0x04) // npc dead { pNpc->GetMap()->RegionNpcRemove(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, tid); // TRACE("--- Npc Dead : Npc를 Region에서 삭제처리.. ,, region_x=%d, y=%d\n", pNpc->m_sRegion_X, pNpc->m_sRegion_Z); pNpc->m_sRegion_X = 0; pNpc->m_sRegion_Z = 0; pNpc->m_NpcState = NPC_DEAD; if( pNpc->m_byObjectType == SPECIAL_OBJECT ) { pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid ); if( pEvent ) pEvent->byLife = 0; } if (pNpc->m_tNpcType == 2 && pUser != NULL) // EXP pUser->GiveItem(900001000, 1); } } else if(type == 0x02) // npc attack -> user { pNpc = m_pMain->m_arNpcArray.GetData(sid); if(!pNpc) return; //TRACE("CAISocket-RecvNpcAttack 222 : sid=%s, tid=%d, zone_num=%d\n", sid, tid, m_iZoneNum); if( tid >= USER_BAND && tid < NPC_BAND) { pUser = m_pMain->GetUserPtr(tid); if(pUser == NULL) return; // sungyong 2002. 02.04 /* if( sHP <= 0 && pUser->m_pUserData->m_sHp > 0 ) { TRACE("Npc Attack : id=%s, result=%d, AI_HP=%d, GM_HP=%d\n", pUser->m_pUserData->m_id, result, sHP, pUser->m_pUserData->m_sHp); if(result == 0x02) pUser->HpChange(-1000, 1); } else pUser->HpChange(-damage, 1); */ // ~sungyong 2002. 02.04 if( pUser->m_MagicProcess.m_bMagicState == CASTING ) pUser->m_MagicProcess.IsAvailable( 0, -1, -1, MAGIC_EFFECTING ,0,0,0 ); pUser->HpChange(-damage, 1, true); pUser->ItemWoreOut(DEFENCE, damage); SetByte(pOutBuf, WIZ_ATTACK, send_index); SetByte( pOutBuf, byAttackType, send_index ); if(result == 0x03) SetByte( pOutBuf, 0x00, send_index ); else SetByte( pOutBuf, result, send_index ); SetShort( pOutBuf, sid, send_index ); SetShort( pOutBuf, tid, send_index ); m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false); // TRACE("RecvNpcAttack : id=%s, result=%d, AI_HP=%d, GM_HP=%d\n", pUser->m_pUserData->m_id, result, sHP, pUser->m_pUserData->m_sHp); //TRACE("RecvNpcAttack ==> sid = %d, tid = %d, result = %d\n", sid, tid, result); if(result == 0x02) { // user dead if (pUser->m_bResHpType == USER_DEAD) return; // 유저에게는 바로 데드 패킷을 날림... (한 번 더 보냄, 유령을 없애기 위해서) send_index = 0; SetByte(pOutBuf, WIZ_DEAD, send_index); SetShort(pOutBuf, pUser->GetSocketID(), send_index); m_pMain->Send_Region(pOutBuf, send_index, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ); pUser->m_bResHpType = USER_DEAD; DEBUG_LOG("*** User Dead, id=%s, result=%d, AI_HP=%d, GM_HP=%d, x=%d, z=%d", pUser->m_pUserData->m_id, result, nHP, pUser->m_pUserData->m_sHp, (int)pUser->m_pUserData->m_curx, (int)pUser->m_pUserData->m_curz); send_index = 0; if( pUser->m_pUserData->m_bFame == COMMAND_CAPTAIN ) { // 지휘권한이 있는 유저가 죽는다면,, 지휘 권한 박탈 pUser->m_pUserData->m_bFame = CHIEF; SetByte( pOutBuf, WIZ_AUTHORITY_CHANGE, send_index ); SetByte( pOutBuf, COMMAND_AUTHORITY, send_index ); SetShort( pOutBuf, pUser->GetSocketID(), send_index ); SetByte( pOutBuf, pUser->m_pUserData->m_bFame, send_index ); m_pMain->Send_Region( pOutBuf, send_index, pUser->GetMap(), pUser->m_RegionX, pUser->m_RegionZ ); // sungyong tw pUser->Send( pOutBuf, send_index ); // ~sungyong tw TRACE("---> AISocket->RecvNpcAttack() Dead Captain Deprive - %s\n", pUser->m_pUserData->m_id); if( pUser->m_pUserData->m_bNation == KARUS ) m_pMain->Announcement( KARUS_CAPTAIN_DEPRIVE_NOTIFY, KARUS ); else if( pUser->m_pUserData->m_bNation == ELMORAD ) m_pMain->Announcement( ELMORAD_CAPTAIN_DEPRIVE_NOTIFY, ELMORAD ); } if(pNpc->m_tNpcType == NPC_PATROL_GUARD) { // 경비병에게 죽는 경우라면.. pUser->ExpChange( -pUser->m_iMaxExp/100 ); //TRACE("RecvNpcAttack : 경험치를 1%깍기 id = %s\n", pUser->m_pUserData->m_id); } else { // if( pUser->m_pUserData->m_bZone != pUser->m_pUserData->m_bNation && pUser->m_pUserData->m_bZone < 3) { pUser->ExpChange(-pUser->m_iMaxExp / 100); //TRACE("정말로 1%만 깍였다니까요 ㅠ.ㅠ"); } // else { pUser->ExpChange( -pUser->m_iMaxExp/20 ); } //TRACE("RecvNpcAttack : 경험치를 5%깍기 id = %s\n", pUser->m_pUserData->m_id); } } } else if(tid >= NPC_BAND) // npc attack -> monster { pMon = m_pMain->m_arNpcArray.GetData(tid); if(!pMon) return; pMon->m_iHP -= damage; if( pMon->m_iHP < 0 ) pMon->m_iHP = 0; send_index = 0; SetByte(pOutBuf, WIZ_ATTACK, send_index); SetByte( pOutBuf, byAttackType, send_index ); SetByte( pOutBuf, result, send_index ); SetShort( pOutBuf, sid, send_index ); SetShort( pOutBuf, tid, send_index ); if(result == 0x02) { // npc dead pNpc->GetMap()->RegionNpcRemove(pMon->m_sRegion_X, pMon->m_sRegion_Z, tid); // TRACE("--- Npc Dead : Npc를 Region에서 삭제처리.. ,, region_x=%d, y=%d\n", pMon->m_sRegion_X, pMon->m_sRegion_Z); pMon->m_sRegion_X = 0; pMon->m_sRegion_Z = 0; pMon->m_NpcState = NPC_DEAD; if( pNpc->m_byObjectType == SPECIAL_OBJECT ) { pEvent = pNpc->GetMap()->GetObjectEvent( pMon->m_sSid ); if( pEvent ) pEvent->byLife = 0; } } m_pMain->Send_Region(pOutBuf, send_index, pNpc->GetMap(), pNpc->m_sRegion_X, pNpc->m_sRegion_Z, NULL, false); } } }
// ai server에 처음 접속시 npc의 모든 정보를 받아온다.. void CAISocket::RecvNpcInfoAll(char* pBuf) { int index = 0; BYTE byCount = 0; // 마리수 BYTE byType; // 0:처음에 등장하지 않는 몬스터, 1:등장 short nid; // NPC index short sid; // NPC index BYTE bZone; // Current zone number short sPid; // NPC Picture Number short sSize = 100; // NPC Size int iweapon_1; int iweapon_2; char szName[MAX_NPC_SIZE+1]; // NPC Name BYTE byGroup; // 소속 집단 BYTE byLevel; // level float fPosX; // X Position float fPosZ; // Z Position float fPosY; // Y Position BYTE byDirection; // BYTE tNpcType; // 00 : Monster // 01 : NPC int iSellingGroup; int nMaxHP; // 최대 HP int nHP; // 현재 HP BYTE byGateOpen; // 성문일경우 열림과 닫힘 정보 short sHitRate; BYTE byObjectType; // 보통 : 0, 특수 : 1 byCount = GetByte(pBuf, index); for(int i=0; i<byCount; i++) { byType = GetByte(pBuf, index); nid = GetShort(pBuf, index); sid = GetShort(pBuf, index); sPid = GetShort(pBuf, index); sSize = GetShort(pBuf, index); iweapon_1 = GetDWORD(pBuf, index); iweapon_2 = GetDWORD(pBuf, index); bZone = GetByte(pBuf, index); int nLength = GetVarString(szName, pBuf, sizeof(BYTE), index); byGroup = GetByte(pBuf, index); byLevel = GetByte(pBuf, index); fPosX = Getfloat(pBuf, index); fPosZ = Getfloat(pBuf, index); fPosY = Getfloat(pBuf, index); byDirection = GetByte(pBuf, index); tNpcType = GetByte(pBuf, index); iSellingGroup = GetDWORD(pBuf, index); nMaxHP = GetDWORD(pBuf, index); nHP = GetDWORD(pBuf, index); byGateOpen = GetByte(pBuf, index); sHitRate = GetShort(pBuf, index); byObjectType = GetByte(pBuf, index); //TRACE("RecvNpcInfoAll : nid=%d, szName=%s, count=%d\n", nid, szName, byCount); if(nLength < 0 || nLength > MAX_NPC_SIZE) { TRACE("#### RecvNpcInfoAll Fail : szName=%s\n", szName); continue; // 잘못된 monster 아이디 } //TRACE("Recv --> NpcUserInfo : uid = %d, x=%f, z=%f.. \n", nid, fPosX, fPosZ); CNpc* pNpc = NULL; pNpc = new CNpc; if(pNpc == NULL) { TRACE("#### Recv --> NpcUserInfoAll POINT Fail: uid=%d, sid=%d, name=%s, zone=%d, x=%f, z=%f.. \n", nid, sPid, szName, bZone, fPosX, fPosZ); continue; } pNpc->Initialize(); pNpc->m_sNid = nid; pNpc->m_sSid = sid; pNpc->m_sPid = sPid; pNpc->m_sSize = sSize; pNpc->m_iWeapon_1 = iweapon_1; pNpc->m_iWeapon_2 = iweapon_2; strcpy(pNpc->m_strName, szName); pNpc->m_byGroup = byGroup; pNpc->m_byLevel = byLevel; pNpc->m_bCurZone = bZone; pNpc->m_pMap = m_pMain->GetZoneByID(bZone); pNpc->m_fCurX = fPosX; pNpc->m_fCurZ = fPosZ; pNpc->m_fCurY = fPosY; pNpc->m_byDirection = byDirection; pNpc->m_NpcState = NPC_LIVE; pNpc->m_tNpcType = tNpcType; pNpc->m_iSellingGroup = iSellingGroup; pNpc->m_iMaxHP = nMaxHP; pNpc->m_iHP = nHP; pNpc->m_byGateOpen = byGateOpen; pNpc->m_sHitRate = sHitRate; pNpc->m_byObjectType = byObjectType; pNpc->m_NpcState = NPC_LIVE; int nRegX = (int)fPosX / VIEW_DISTANCE; int nRegZ = (int)fPosZ / VIEW_DISTANCE; pNpc->m_sRegion_X = nRegX; pNpc->m_sRegion_Z = nRegZ; if (pNpc->GetMap() == NULL) { delete pNpc; pNpc = NULL; continue; } _OBJECT_EVENT* pEvent = NULL; if (pNpc->m_byObjectType == SPECIAL_OBJECT) { pEvent = pNpc->GetMap()->GetObjectEvent(pNpc->m_sSid); if( pEvent ) pEvent->byLife = 1; } // TRACE("Recv --> NpcUserInfoAll : uid=%d, sid=%d, name=%s, x=%f, z=%f. gate=%d, objecttype=%d \n", nid, sPid, szName, fPosX, fPosZ, byGateOpen, byObjectType); if( !m_pMain->m_arNpcArray.PutData( pNpc->m_sNid, pNpc) ) { TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid); delete pNpc; pNpc = NULL; continue; } if( byType == 0 ) { TRACE("Recv --> NpcUserInfoAll : 등록하면 안돼여,, uid=%d, sid=%d, name=%s\n", nid, sPid, szName); continue; // region에 등록하지 말기... } pNpc->GetMap()->RegionNpcAdd(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, pNpc->m_sNid); } }
void CAISocket::RecvNpcInfoAll(Packet & pkt) { uint8 bCount = pkt.read<uint8>(); // max of 20 pkt.SByte(); for (int i = 0; i < bCount; i++) { uint8 bDirection; std::string strName; CNpc* pNpc = new CNpc(); pNpc->Initialize(); pkt >> pNpc->m_NpcState >> pNpc->m_sNid >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2 >> pNpc->m_bZone >> strName >> pNpc->m_bNation >> pNpc->m_bLevel >> pNpc->m_curx >> pNpc->m_curz >> pNpc->m_cury >> bDirection >> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen >> pNpc->m_fTotalHitrate >> pNpc->m_fTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_sTotalHit >> pNpc->m_byObjectType >> pNpc->m_byTrapNumber >> pNpc->m_bMonster >> pNpc->m_sFireR >> pNpc->m_sColdR >> pNpc->m_sLightningR >> pNpc->m_sMagicR >> pNpc->m_sDiseaseR >> pNpc->m_sPoisonR; if (strName.empty()) strName = "<the spawn with no name>"; if (strName.length() > MAX_NPC_SIZE) { pNpc->DecRef(); continue; } pNpc->m_pMap = g_pMain->GetZoneByID(pNpc->GetZoneID()); if (pNpc->GetMap() == nullptr) { pNpc->DecRef(); continue; } //TRACE("Recv --> NpcUserInfo : uid = %d, x=%f, z=%f.. \n", nid, fPosX, fPosZ); pNpc->m_strName = strName; pNpc->m_byDirection = bDirection; pNpc->SetRegion(pNpc->GetNewRegionX(), pNpc->GetNewRegionZ()); if (pNpc->m_byObjectType == SPECIAL_OBJECT) { _OBJECT_EVENT* pEvent = pNpc->GetMap()->GetObjectEvent(pNpc->m_sSid); if (pEvent != nullptr) pEvent->byLife = 1; } // TRACE("Recv --> NpcUserInfoAll : uid=%d, sid=%d, name=%s, x=%f, z=%f. gate=%d, objecttype=%d \n", nid, sPid, szName, fPosX, fPosZ, byGateOpen, byObjectType); if (!g_pMain->m_arNpcArray.PutData(pNpc->GetID(), pNpc)) { TRACE("Npc PutData Fail - %d\n", pNpc->GetID()); pNpc->DecRef(); continue; } if (pNpc->m_NpcState == NPC_DEAD) { TRACE("Recv --> NpcUserInfoAll : nid=%d, sid=%d, name=%s\n", pNpc->GetID(), pNpc->m_sSid, strName.c_str()); continue; } pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY()); } }
void CAISocket::RecvNpcInfo(Packet & pkt) { std::string strName; uint8 Mode, byDirection; uint16 sNid; bool bCreated = false; pkt.SByte(); pkt >> Mode >> sNid; CNpc *pNpc = g_pMain->GetNpcPtr(sNid); if (pNpc == nullptr) { pNpc = new CNpc(); pNpc->m_sNid = sNid; bCreated = true; } pkt >> pNpc->m_sSid >> pNpc->m_sPid >> pNpc->m_sSize >> pNpc->m_iWeapon_1 >> pNpc->m_iWeapon_2 >> pNpc->m_bZone >> strName >> pNpc->m_bNation >> pNpc->m_bLevel >> pNpc->m_curx >> pNpc->m_curz >> pNpc->m_cury >> byDirection >> pNpc->m_tNpcType >> pNpc->m_iSellingGroup >> pNpc->m_iMaxHP >> pNpc->m_iHP >> pNpc->m_byGateOpen >> pNpc->m_fTotalHitrate >> pNpc->m_fTotalEvasionrate >> pNpc->m_sTotalAc >> pNpc->m_sTotalHit >> pNpc->m_byObjectType >> pNpc->m_byTrapNumber >> pNpc->m_bMonster >> pNpc->m_sFireR >> pNpc->m_sColdR >> pNpc->m_sLightningR >> pNpc->m_sMagicR >> pNpc->m_sDiseaseR >> pNpc->m_sPoisonR; if (strName.empty() || strName.length() > MAX_NPC_SIZE) { pNpc->DecRef(); return; } pNpc->m_NpcState = Mode; pNpc->m_byDirection = byDirection; pNpc->m_strName = strName; pNpc->m_pMap = g_pMain->GetZoneByID(pNpc->GetZoneID()); if (pNpc->GetMap() == nullptr) { pNpc->DecRef(); return; } pNpc->RegisterRegion(); if (pNpc->m_byObjectType == SPECIAL_OBJECT) { _OBJECT_EVENT *pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid ); if (pEvent != nullptr) pEvent->byLife = 1; } if (bCreated) g_pMain->m_arNpcArray.PutData(pNpc->GetID(), pNpc); if (pNpc->m_NpcState == NPC_DEAD) { TRACE("RecvNpcInfo - dead monster nid=%d, name=%s\n", pNpc->GetID(), pNpc->GetName().c_str()); return; } pNpc->SendInOut(INOUT_IN, pNpc->GetX(), pNpc->GetZ(), pNpc->GetY()); }
bool CServerDlg::LoadSpawnCallback(OdbcCommand *dbCommand) { // Avoid allocating stack space for these. // This method will only ever run in the same thread. static int nRandom = 0; static double dbSpeed = 0; static CNpcTable * pNpcTable = NULL; static CRoomEvent* pRoom = NULL; static char szPath[500]; static float fRandom_X = 0.0f, fRandom_Z = 0.0f; // Unfortunately we cannot simply read what we need directly // into the CNpc instance. We have to resort to creating // copies of the data to allow for the way they handle multiple spawns... // Best we can do, I think, is to avoid allocating it on the stack. static uint8 bNumNpc, bZoneID, bActType, bRegenType, bDungeonFamily, bSpecialType, bTrapNumber, bDirection, bDotCnt; static uint16 sSid, sRegTime; static uint32 nServerNum; static int32 iLeftX, iTopZ, iRightX, iBottomZ, iLimitMinX, iLimitMinZ, iLimitMaxX, iLimitMaxZ; dbCommand->FetchByte(1, bZoneID); dbCommand->FetchUInt16(2, sSid); dbCommand->FetchByte(3, bActType); dbCommand->FetchByte(4, bRegenType); dbCommand->FetchByte(5, bDungeonFamily); dbCommand->FetchByte(6, bSpecialType); dbCommand->FetchByte(7, bTrapNumber); dbCommand->FetchInt32(8, iLeftX); dbCommand->FetchInt32(9, iTopZ); dbCommand->FetchInt32(10, iRightX); dbCommand->FetchInt32(11, iBottomZ); dbCommand->FetchInt32(12, iLimitMinZ); dbCommand->FetchInt32(13, iLimitMinX); dbCommand->FetchInt32(14, iLimitMaxX); dbCommand->FetchInt32(15, iLimitMaxZ); dbCommand->FetchByte(16, bNumNpc); dbCommand->FetchUInt16(17, sRegTime); dbCommand->FetchByte(18, bDirection); dbCommand->FetchByte(19, bDotCnt); dbCommand->FetchString(20, szPath, sizeof(szPath)); nServerNum = GetServerNumber(bZoneID); if (m_byZone == nServerNum || m_byZone == UNIFY_ZONE) { uint8 bPathSerial = 1; for (uint8 j = 0; j < bNumNpc; j++) { CNpc * pNpc = new CNpc(); pNpc->m_byMoveType = bActType; pNpc->m_byInitMoveType = bActType; bool bMonster = (bActType < 100); if (bMonster) { pNpcTable = m_arMonTable.GetData(sSid); } else { pNpc->m_byMoveType = bActType - 100; pNpcTable = m_arNpcTable.GetData(sSid); } if (pNpcTable == NULL) { printf("NPC %d not found in %s table.\n", pNpc->m_sNid, bMonster ? "K_MONSTER" : "K_NPC"); delete pNpc; return false; } pNpc->Load(m_TotalNPC++, pNpcTable); pNpc->m_byBattlePos = 0; if (pNpc->m_byMoveType >= 2) { pNpc->m_byBattlePos = myrand(1, 3); pNpc->m_byPathCount = bPathSerial++; } pNpc->InitPos(); pNpc->m_bCurZone = bZoneID; nRandom = abs(iLeftX - iRightX); if (nRandom <= 1) fRandom_X = (float)iLeftX; else { if (iLeftX < iRightX) fRandom_X = (float)myrand(iLeftX, iRightX); else fRandom_X = (float)myrand(iRightX, iLeftX); } nRandom = abs(iTopZ - iBottomZ); if (nRandom <= 1) fRandom_Z = (float)iTopZ; else { if (iTopZ < iBottomZ) fRandom_Z = (float)myrand(iTopZ, iBottomZ); else fRandom_Z = (float)myrand(iBottomZ, iTopZ); } pNpc->m_fCurX = fRandom_X; pNpc->m_fCurY = 0; pNpc->m_fCurZ = fRandom_Z; pNpc->m_sRegenTime = sRegTime * SECOND; pNpc->m_byDirection = bDirection; pNpc->m_sMaxPathCount = bDotCnt; if ((pNpc->m_byMoveType == 2 || pNpc->m_byMoveType == 3) && bDotCnt == 0) { pNpc->m_byMoveType = 1; TRACE("##### ServerDlg:CreateNpcThread - Path type Error : nid=%d, sid=%d, name=%s, acttype=%d, path=%d #####\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byMoveType, pNpc->m_sMaxPathCount); } if (bDotCnt > 0) { int index = 0; for (int l = 0; l < bDotCnt; l++) { static char szX[5], szZ[5]; memset(szX, 0, sizeof(szX)); memset(szZ, 0, sizeof(szZ)); memcpy(szX, szPath + index, 4); index += 4; memcpy(szZ, szPath + index, 4); index += 4; pNpc->m_PathList.pPattenPos[l].x = atoi(szX); pNpc->m_PathList.pPattenPos[l].z = atoi(szZ); } } pNpc->m_tItemPer = pNpcTable->m_tItemPer; // NPC Type pNpc->m_tDnPer = pNpcTable->m_tDnPer; // NPC Type pNpc->m_nInitMinX = pNpc->m_nLimitMinX = iLeftX; pNpc->m_nInitMinY = pNpc->m_nLimitMinZ = iTopZ; pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX = iRightX; pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ = iBottomZ; // dungeon work pNpc->m_byDungeonFamily = bDungeonFamily; pNpc->m_bySpecialType = bSpecialType; pNpc->m_byRegenType = bRegenType; pNpc->m_byTrapNumber = bTrapNumber; if (pNpc->m_byDungeonFamily > 0) { pNpc->m_nLimitMinX = iLimitMinX; pNpc->m_nLimitMinZ = iLimitMinZ; pNpc->m_nLimitMaxX = iLimitMaxX; pNpc->m_nLimitMaxZ = iLimitMaxZ; } pNpc->m_pZone = GetZoneByID(pNpc->m_bCurZone); if (pNpc->GetMap() == NULL) { printf(_T("Error: NPC %d in zone %d that does not exist."), sSid, bZoneID); delete pNpc; return false; } if (!m_arNpc.PutData(pNpc->m_sNid, pNpc)) { --m_TotalNPC; TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid); delete pNpc; continue; } pNpc->SetUid(pNpc->m_fCurX, pNpc->m_fCurZ, pNpc->m_sNid + NPC_BAND); if (pNpc->GetMap()->m_byRoomEvent > 0 && pNpc->m_byDungeonFamily > 0) { pRoom = pNpc->GetMap()->m_arRoomEventArray.GetData(pNpc->m_byDungeonFamily); if (pRoom == NULL) { printf("Error : CServerDlg,, Map Room Npc Fail!!\n"); delete pNpc; return false; } // this is why their CSTLMap class sucks. int *pInt = new int; *pInt = pNpc->m_sNid; if (!pRoom->m_mapRoomNpcArray.PutData(pNpc->m_sNid, pInt)) { delete pInt; TRACE("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d ###\n", pNpc->m_sNid, pNpc->m_proto->m_sSid); } } } } return true; }
// Npc Thread 를 만든다. BOOL CServerDlg::CreateNpcThread() { BOOL bMoveNext = TRUE; int nSerial = m_sMapEventNpc; int nPathSerial = 1; int nNpcCount = 0; int i=0, j=0; int nRandom = 0, nServerNum = 0; double dbSpeed = 0; m_TotalNPC = 0; // DB에 있는 수 m_CurrentNPC = 0; m_CurrentNPCError = 0; CNpcTable* pNpcTable = NULL; CRoomEvent* pRoom = NULL; CNpcPosSet NpcPosSet; char szPath[500]; char szX[5]; char szZ[5]; float fRandom_X = 0.0f; float fRandom_Z = 0.0f; int nMonsterNumber = 0; try { if(NpcPosSet.IsOpen()) NpcPosSet.Close(); if(!NpcPosSet.Open()) { AfxMessageBox(_T("MONSTER_POS DB Open Fail!")); return FALSE; } if(NpcPosSet.IsBOF()) { AfxMessageBox(_T("MONSTER_POS DB Empty!")); return FALSE; } NpcPosSet.MoveFirst(); while(!NpcPosSet.IsEOF()) { nMonsterNumber = NpcPosSet.m_NumNPC; //if( NpcPosSet.m_ZoneID == 101 ) { // 테스트를 위해서,, // nMonsterNumber = 1; //if(nMonsterNumber > 4) { // nMonsterNumber = nMonsterNumber / 4; //} //} nServerNum = 0; nServerNum = GetServerNumber( NpcPosSet.m_ZoneID ); if( m_byZone == nServerNum || m_byZone == UNIFY_ZONE) { for(j=0; j<nMonsterNumber; j++) { CNpc* pNpc = new CNpc(); pNpc->m_byMoveType = NpcPosSet.m_ActType; pNpc->m_byInitMoveType = NpcPosSet.m_ActType; bool bMonster = (NpcPosSet.m_ActType < 100); if (bMonster) pNpcTable = m_arMonTable.GetData(NpcPosSet.m_NpcID); else { pNpc->m_byMoveType = NpcPosSet.m_ActType - 100; //pNpc->m_byInitMoveType = NpcPosSet.m_ActType - 100; pNpcTable = m_arNpcTable.GetData(NpcPosSet.m_NpcID); } if (pNpcTable == NULL) { char buff[128] = {0}; sprintf(buff, "NPC %d not found in %s table.", pNpc->m_sNid, bMonster ? "K_MONSTER" : "K_NPC"); AfxMessageBox(buff); delete pNpc; return FALSE; } pNpc->Load(nSerial++, pNpcTable); pNpc->m_byBattlePos = 0; if(pNpc->m_byMoveType >= 2) { pNpc->m_byBattlePos = myrand( 1, 3 ); pNpc->m_byPathCount = nPathSerial++; } pNpc->InitPos(); if( bMoveNext ) { bMoveNext = FALSE; nNpcCount = NpcPosSet.m_NumNPC; } //////// MONSTER POS //////////////////////////////////////// pNpc->m_bCurZone = NpcPosSet.m_ZoneID; // map에 몬스터의 위치를 랜덤하게 위치시킨다.. (테스트 용 : 수정-DB에서 읽어오는데로 몬 위치 결정) nRandom = abs(NpcPosSet.m_LeftX - NpcPosSet.m_RightX); if(nRandom <= 1) fRandom_X = (float)NpcPosSet.m_LeftX; else { if(NpcPosSet.m_LeftX < NpcPosSet.m_RightX) fRandom_X = (float)myrand(NpcPosSet.m_LeftX, NpcPosSet.m_RightX); else fRandom_X = (float)myrand(NpcPosSet.m_RightX, NpcPosSet.m_LeftX); } nRandom = abs(NpcPosSet.m_TopZ - NpcPosSet.m_BottomZ); if(nRandom <= 1) fRandom_Z = (float)NpcPosSet.m_TopZ; else { if(NpcPosSet.m_TopZ < NpcPosSet.m_BottomZ) fRandom_Z = (float)myrand(NpcPosSet.m_TopZ, NpcPosSet.m_BottomZ); else fRandom_Z = (float)myrand(NpcPosSet.m_BottomZ, NpcPosSet.m_TopZ); } pNpc->m_fCurX = fRandom_X; pNpc->m_fCurY = 0; pNpc->m_fCurZ = fRandom_Z; pNpc->m_sRegenTime = NpcPosSet.m_RegTime * 1000; // 초(DB)단위-> 밀리세컨드로 pNpc->m_byDirection = NpcPosSet.m_byDirection; pNpc->m_sMaxPathCount = NpcPosSet.m_DotCnt; if( pNpc->m_byMoveType >= 2 && NpcPosSet.m_DotCnt == 0 ) { pNpc->m_byMoveType = 1; TRACE("##### ServerDlg:CreateNpcThread - Path type Error : nid=%d, sid=%d, name=%s, acttype=%d, path=%d #####\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byMoveType, pNpc->m_sMaxPathCount); } int index = 0; strcpy_s(szPath, sizeof(szPath), NpcPosSet.m_path); if(NpcPosSet.m_DotCnt != 0) { for(int l = 0; l<NpcPosSet.m_DotCnt; l++) { memset(szX, 0x00, 5); memset(szZ, 0x00, 5); GetString(szX, szPath, 4, index); GetString(szZ, szPath, 4, index); pNpc->m_PathList.pPattenPos[l].x = atoi(szX); pNpc->m_PathList.pPattenPos[l].z = atoi(szZ); // TRACE(" l=%d, x=%d, z=%d\n", l, pNpc->m_PathList.pPattenPos[l].x, pNpc->m_PathList.pPattenPos[l].z); } } //pNpc->m_byType = NpcPosSet.m_byType; pNpc->m_tItemPer = pNpcTable->m_tItemPer; // NPC Type pNpc->m_tDnPer = pNpcTable->m_tDnPer; // NPC Type pNpc->m_nInitMinX = pNpc->m_nLimitMinX = NpcPosSet.m_LeftX; pNpc->m_nInitMinY = pNpc->m_nLimitMinZ = NpcPosSet.m_TopZ; pNpc->m_nInitMaxX = pNpc->m_nLimitMaxX = NpcPosSet.m_RightX; pNpc->m_nInitMaxY = pNpc->m_nLimitMaxZ = NpcPosSet.m_BottomZ; // dungeon work pNpc->m_byDungeonFamily = NpcPosSet.m_DungeonFamily; pNpc->m_bySpecialType = NpcPosSet.m_SpecialType; pNpc->m_byRegenType = NpcPosSet.m_RegenType; pNpc->m_byTrapNumber = NpcPosSet.m_TrapNumber; if( pNpc->m_byDungeonFamily > 0 ) { pNpc->m_nLimitMinX = NpcPosSet.m_LimitMinX; pNpc->m_nLimitMinZ = NpcPosSet.m_LimitMinZ; pNpc->m_nLimitMaxX = NpcPosSet.m_LimitMaxX; pNpc->m_nLimitMaxZ = NpcPosSet.m_LimitMaxZ; } pNpc->m_pZone = GetZoneByID(pNpc->m_bCurZone); if (pNpc->GetMap() == NULL) { AfxMessageBox("Error : CServerDlg,, Invaild zone Index!!"); delete pNpc; return FALSE; } if( !m_arNpc.PutData( pNpc->m_sNid, pNpc) ) { TRACE("Npc PutData Fail - %d\n", pNpc->m_sNid); delete pNpc; pNpc = NULL; continue; } pNpc->SetUid(pNpc->m_fCurX, pNpc->m_fCurZ, pNpc->m_sNid + NPC_BAND); // if (pNpc->GetMap()->m_byRoomEvent > 0 && pNpc->m_byDungeonFamily > 0 ) { pRoom = pNpc->GetMap()->m_arRoomEventArray.GetData( pNpc->m_byDungeonFamily ); if (pRoom == NULL) { TRACE("Error : CServerDlg,, Map Room Npc Fail!! : nid=%d, sid=%d, name=%s, fam=%d, zone=%d\n", pNpc->m_sNid+NPC_BAND, pNpc->m_proto->m_sSid, pNpc->m_proto->m_strName, pNpc->m_byDungeonFamily, pNpc->m_bCurZone); AfxMessageBox("Error : CServerDlg,, Map Room Npc Fail!!"); delete pNpc; return FALSE; } int *pInt = new int; *pInt = pNpc->m_sNid; if( !pRoom->m_mapRoomNpcArray.PutData( pNpc->m_sNid, pInt ) ) { TRACE("### Map - Room Array MonsterNid Fail : nid=%d, sid=%d ###\n", pNpc->m_sNid, pNpc->m_proto->m_sSid); } } m_TotalNPC = nSerial; if(--nNpcCount > 0) continue; bMoveNext = TRUE; nNpcCount = 0; } } nPathSerial = 1; NpcPosSet.MoveNext(); } NpcPosSet.Close(); } catch(CDBException* e) { e->ReportError(); e->Delete(); return FALSE; } int step = 0, nThreadNumber = 0; CNpcThread* pNpcThread = NULL; foreach_stlmap (itr, m_arNpc) { if (step == 0) pNpcThread = new CNpcThread; CNpc *pNpc = pNpcThread->m_pNpc[step] = itr->second; pNpc->m_sThreadNumber = nThreadNumber; pNpc->Init(); ++step; if( step == NPC_NUM ) { pNpcThread->m_sThreadNumber = nThreadNumber++; pNpcThread->m_pThread = AfxBeginThread(NpcThreadProc, &(pNpcThread->m_ThreadInfo), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); m_arNpcThread.push_back( pNpcThread ); step = 0; } } if( step != 0 ) { pNpcThread->m_sThreadNumber = nThreadNumber++; pNpcThread->m_pThread = AfxBeginThread(NpcThreadProc, &(pNpcThread->m_ThreadInfo), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); m_arNpcThread.push_back( pNpcThread ); } m_pZoneEventThread = AfxBeginThread(ZoneEventThreadProc, (LPVOID)(this), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED); //TRACE("m_TotalNPC = %d \n", m_TotalNPC); AddToList("[Monster Init - %d, threads=%d]", m_TotalNPC, m_arNpcThread.size()); return TRUE; }
void CAISocket::RecvNpcAttack(Packet & pkt) { int nHP = 0, temp_damage = 0; int16 sid, tid; BYTE type, bResult, byAttackType = 0; float fDir=0.0f; short damage = 0; CNpc* pNpc = NULL, *pMon = NULL; CUser* pUser = NULL; _OBJECT_EVENT* pEvent = NULL; pkt >> type >> bResult >> sid >> tid >> damage >> nHP >> byAttackType; //TRACE("CAISocket-RecvNpcAttack : sid=%s, tid=%d, zone_num=%d\n", sid, tid, m_iZoneNum); if(type == 0x01) // user attack -> npc { pNpc = g_pMain->m_arNpcArray.GetData(tid); if(!pNpc) return; pNpc->m_iHP -= damage; if( pNpc->m_iHP < 0 ) pNpc->m_iHP = 0; // NPC died if (bResult == 4) pNpc->OnDeath(); else { Packet result(WIZ_ATTACK, byAttackType); result << bResult << sid << tid; pNpc->SendToRegion(&result); } pUser = g_pMain->GetUserPtr(sid); if (pUser != NULL) { pUser->SendTargetHP( 0, tid, -damage ); if( byAttackType != MAGIC_ATTACK && byAttackType != DURATION_ATTACK) { pUser->ItemWoreOut(ATTACK, damage); // LEFT HAND!!! by Yookozuna temp_damage = damage * pUser->m_bMagicTypeLeftHand / 100 ; switch (pUser->m_bMagicTypeLeftHand) { // LEFT HAND!!! case ITEM_TYPE_HP_DRAIN : // HP Drain pUser->HpChange(temp_damage, 0); break; case ITEM_TYPE_MP_DRAIN : // MP Drain pUser->MSpChange(temp_damage); break; } temp_damage = 0; // reset data; // RIGHT HAND!!! by Yookozuna temp_damage = damage * pUser->m_bMagicTypeRightHand / 100 ; switch (pUser->m_bMagicTypeRightHand) { // LEFT HAND!!! case ITEM_TYPE_HP_DRAIN : // HP Drain pUser->HpChange(temp_damage, 0); break; case ITEM_TYPE_MP_DRAIN : // MP Drain pUser->MSpChange(temp_damage); break; } // } } if (bResult == 2 || bResult== 4) // npc dead { pNpc->GetMap()->RegionNpcRemove(pNpc->m_sRegion_X, pNpc->m_sRegion_Z, tid); // TRACE("--- Npc Dead : Npc�� Region���� ����ó��.. ,, region_x=%d, y=%d\n", pNpc->m_sRegion_X, pNpc->m_sRegion_Z); pNpc->m_sRegion_X = 0; pNpc->m_sRegion_Z = 0; pNpc->m_NpcState = NPC_DEAD; if( pNpc->m_byObjectType == SPECIAL_OBJECT ) { pEvent = pNpc->GetMap()->GetObjectEvent( pNpc->m_sSid ); if( pEvent ) pEvent->byLife = 0; } if (pNpc->m_tNpcType == 2 && pUser != NULL) // EXP pUser->GiveItem(900001000, 1); } } else if (type == 2) // npc attack -> user { pNpc = g_pMain->m_arNpcArray.GetData(sid); if(!pNpc) return; //TRACE("CAISocket-RecvNpcAttack 222 : sid=%s, tid=%d, zone_num=%d\n", sid, tid, m_iZoneNum); if( tid >= USER_BAND && tid < NPC_BAND) { pUser = g_pMain->GetUserPtr(tid); if(pUser == NULL) return; pUser->HpChange(-damage, 1, true); pUser->ItemWoreOut(DEFENCE, damage); Packet result(WIZ_ATTACK, byAttackType); result << uint8(bResult == 3 ? 0 : bResult) << sid << tid; pNpc->SendToRegion(&result); //TRACE("RecvNpcAttack ==> sid = %d, tid = %d, result = %d\n", sid, tid, result); // user dead if (bResult == 2) { if (pUser->m_bResHpType == USER_DEAD) return; pUser->OnDeath(); pUser->m_bResHpType = USER_DEAD; DEBUG_LOG("*** User Dead, id=%s, result=%d, AI_HP=%d, GM_HP=%d, x=%d, z=%d", pUser->m_pUserData->m_id, result, nHP, pUser->m_pUserData->m_sHp, (int)pUser->m_pUserData->m_curx, (int)pUser->m_pUserData->m_curz); if( pUser->m_pUserData->m_bFame == COMMAND_CAPTAIN ) { // ���ֱ����� �ִ� ������ �״´ٸ�,, ���� ���� ��Ż pUser->ChangeFame(CHIEF); TRACE("---> AISocket->RecvNpcAttack() Dead Captain Deprive - %s\n", pUser->m_pUserData->m_id); if (pUser->getNation() == KARUS) g_pMain->Announcement( KARUS_CAPTAIN_DEPRIVE_NOTIFY, KARUS ); else if (pUser->getNation() == ELMORAD) g_pMain->Announcement( ELMORAD_CAPTAIN_DEPRIVE_NOTIFY, ELMORAD ); } if(pNpc->m_tNpcType == NPC_PATROL_GUARD) { // ������ �״� ��������.. pUser->ExpChange( -pUser->m_iMaxExp/100 ); //TRACE("RecvNpcAttack : ����ġ�� 1%���� id = %s\n", pUser->m_pUserData->m_id); } else { // if( pUser->m_pUserData->m_bZone != pUser->m_pUserData->m_bNation && pUser->m_pUserData->m_bZone < 3) { pUser->ExpChange(-pUser->m_iMaxExp / 100); //TRACE("������ 1%�� ��ٴϱ��� ��.��"); } // else { pUser->ExpChange( -pUser->m_iMaxExp/20 ); } //TRACE("RecvNpcAttack : ����ġ�� 5%���� id = %s\n", pUser->m_pUserData->m_id); } } } else if(tid >= NPC_BAND) // npc attack -> monster { pMon = g_pMain->m_arNpcArray.GetData(tid); if(!pMon) return; pMon->m_iHP -= damage; if( pMon->m_iHP < 0 ) pMon->m_iHP = 0; Packet result(WIZ_ATTACK, byAttackType); result << bResult << sid << tid; if (bResult == 2) { // npc dead pNpc->GetMap()->RegionNpcRemove(pMon->m_sRegion_X, pMon->m_sRegion_Z, tid); // TRACE("--- Npc Dead : Npc�� Region���� ����ó��.. ,, region_x=%d, y=%d\n", pMon->m_sRegion_X, pMon->m_sRegion_Z); pMon->m_sRegion_X = 0; pMon->m_sRegion_Z = 0; pMon->m_NpcState = NPC_DEAD; if( pNpc->m_byObjectType == SPECIAL_OBJECT ) { pEvent = pNpc->GetMap()->GetObjectEvent( pMon->m_sSid ); if( pEvent ) pEvent->byLife = 0; } } pNpc->SendToRegion(&result); } } }