void CGameSocket::RecvUserInfoAllData(char* pBuf) { int index = 0; BYTE byCount = 0; // 마리수 short uid=-1, sHp, sMp, len; BYTE bNation, bLevel, bZone, bAuthority=1; short sDamage, sAC, sPartyIndex=0; float fHitAgi, fAvoidAgi; TRACE(" ***** 유저의 모든 정보를 받기 시작합니다 ****** \n"); byCount = GetByte(pBuf, index); for(int i=0; i<byCount; i++) { char strName[MAX_ID_SIZE+1] = ""; len = 0; uid = GetShort( pBuf, index ); len = GetShort( pBuf, index ); GetString(strName, pBuf, len, index); bZone = GetByte( pBuf, index ); bNation = GetByte( pBuf, index ); bLevel = GetByte( pBuf, index ); sHp = GetShort( pBuf, index ); sMp = GetShort( pBuf, index ); sDamage = GetShort( pBuf, index ); sAC = GetShort( pBuf, index ); fHitAgi = Getfloat( pBuf, index ); fAvoidAgi = Getfloat( pBuf, index ); sPartyIndex = GetShort( pBuf, index ); bAuthority = GetByte( pBuf, index ); if( len > MAX_ID_SIZE || len <= 0 ) { TRACE("### RecvUserInfoAllData() Fail ---> uid = %d, name=%s, len=%d ### \n", uid, strName, len); continue; } //CUser* pUser = m_pMain->GetActiveUserPtr(uid); //if(pUser == NULL) continue; CUser* pUser = new CUser; pUser->Initialize(); pUser->m_iUserId = uid; strcpy(pUser->m_strUserID, strName); pUser->m_curZone = bZone; pUser->m_pMap = m_pMain->GetZoneByID(bZone); pUser->m_bNation = bNation; pUser->m_bLevel = bLevel; pUser->m_sHP = sHp; pUser->m_sMP = sMp; //pUser->m_sSP = sSp; pUser->m_sHitDamage = sDamage; pUser->m_fHitrate = fHitAgi; pUser->m_fAvoidrate = fAvoidAgi; pUser->m_sAC = sAC; pUser->m_byIsOP = bAuthority; pUser->m_bLive = USER_LIVE; if(sPartyIndex != -1) { pUser->m_byNowParty = 1; // 파티중 pUser->m_sPartyNumber = sPartyIndex; // 파티 번호 셋팅 } TRACE("**** RecvUserInfoAllData()---> uid = %d, %s, party_number=%d ******\n", uid, strName, pUser->m_sPartyNumber); if(uid >= USER_BAND && uid < MAX_USER) { m_pMain->m_pUser[uid] = pUser; } } TRACE(" ***** 유저의 모든 정보를 다 받았습니다 ****** \n"); }
void CGameSocket::RecvAttackReq(char* pBuf) { int index = 0; int sid = -1, tid = -1; BYTE type, result; float rx=0.0f, ry=0.0f, rz=0.0f; float fDir = 0.0f; short sDamage, sAC; float fHitAgi, fAvoidAgi; // short sItemAC; BYTE bTypeLeft; BYTE bTypeRight; short sAmountLeft; short sAmountRight; // type = GetByte(pBuf,index); result = GetByte(pBuf,index); sid = GetShort(pBuf,index); tid = GetShort(pBuf,index); sDamage = GetShort( pBuf, index ); sAC = GetShort( pBuf, index ); fHitAgi = Getfloat( pBuf, index ); fAvoidAgi = Getfloat( pBuf, index ); // sItemAC = GetShort(pBuf, index); bTypeLeft = GetByte(pBuf, index); bTypeRight = GetByte(pBuf, index); sAmountLeft = GetShort(pBuf, index); sAmountRight = GetShort(pBuf, index); // //TRACE("RecvAttackReq : [sid=%d, tid=%d, zone_num=%d] \n", sid, tid, m_sSocketID); CUser* pUser = m_pMain->GetUserPtr(sid); if(pUser == NULL) return; //TRACE("RecvAttackReq 222 : [id=%d, %s, bLive=%d, zone_num=%d] \n", pUser->m_iUserId, pUser->m_strUserID, pUser->m_bLive, m_sSocketID); if(pUser->m_bLive == USER_DEAD || pUser->m_sHP <= 0) { if(pUser->m_sHP > 0) { pUser->m_bLive = USER_LIVE; TRACE("##### CGameSocket-Attack Fail : User가 Heal된 경우.. [id=%d, %s, bLive=%d, hp=%d] ######\n", pUser->m_iUserId, pUser->m_strUserID, pUser->m_bLive, pUser->m_sHP); } else { TRACE("##### CGameSocket-Attack Fail : UserDead [id=%d, %s, bLive=%d, hp=%d] ######\n", pUser->m_iUserId, pUser->m_strUserID, pUser->m_bLive, pUser->m_sHP); // 죽은 유저이므로 게임서버에 죽은 처리를 한다... Send_UserError(sid, tid); return; } } pUser->m_sHitDamage = sDamage; pUser->m_fHitrate = fHitAgi; pUser->m_fAvoidrate = fAvoidAgi; pUser->m_sAC = sAC; // pUser->m_sItemAC = sItemAC; pUser->m_bMagicTypeLeftHand = bTypeLeft; pUser->m_bMagicTypeRightHand = bTypeRight; pUser->m_sMagicAmountLeftHand = sAmountLeft; pUser->m_sMagicAmountRightHand = sAmountRight; // pUser->Attack(sid, tid); }
void CGameSocket::RecvUserUpdate(char* pBuf) { int index = 0; short uid=-1, sHP=0, sMP=0, sSP=0; BYTE byLevel; short sDamage, sAC; float fHitAgi, fAvoidAgi; // short sItemAC; BYTE bTypeLeft; BYTE bTypeRight; short sAmountLeft; short sAmountRight; // uid = GetShort( pBuf, index ); byLevel = GetByte(pBuf, index); sHP = GetShort( pBuf, index ); sMP = GetShort( pBuf, index ); sDamage = GetShort( pBuf, index ); sAC = GetShort( pBuf, index ); fHitAgi = Getfloat( pBuf, index ); fAvoidAgi = Getfloat( pBuf, index ); // sItemAC = GetShort( pBuf, index ) ; bTypeLeft = GetByte(pBuf, index); bTypeRight = GetByte(pBuf, index); sAmountLeft = GetShort(pBuf, index); sAmountRight = GetShort(pBuf, index); // // User List에서 User정보,, 삭제... CUser* pUser = m_pMain->GetUserPtr(uid); if(pUser == NULL) return; if(pUser->m_bLevel < byLevel) // level up { pUser->m_sHP = sHP; pUser->m_sMP = sMP; //pUser->m_sSP = sSP; _USERLOG* pUserLog = NULL; pUserLog = new _USERLOG; pUserLog->t = CTime::GetCurrentTime(); pUserLog->byFlag = USER_LEVEL_UP; pUserLog->byLevel = byLevel; strcpy( pUserLog->strUserID, pUser->m_strUserID ); pUser->m_UserLogList.push_back( pUserLog ); } pUser->m_bLevel = byLevel; pUser->m_sHitDamage = sDamage; pUser->m_fHitrate = fHitAgi; pUser->m_fAvoidrate = fAvoidAgi; pUser->m_sAC = sAC; // pUser->m_sItemAC = sItemAC ; pUser->m_bMagicTypeLeftHand = bTypeLeft; pUser->m_bMagicTypeRightHand = bTypeRight; pUser->m_sMagicAmountLeftHand = sAmountLeft; pUser->m_sMagicAmountRightHand = sAmountRight; // //char buff[256]; //sprintf_s(buff, sizeof(buff), "**** RecvUserUpdate -- uid = (%s,%d), HP = %d, level=%d->%d", pUser->m_strUserID, pUser->m_iUserId, pUser->m_sHP, byLevel, pUser->m_bLevel); //TimeTrace(buff); //TRACE("**** RecvUserUpdate -- uid = (%s,%d), HP = %d\n", pUser->m_strUserID, pUser->m_iUserId, pUser->m_sHP); }
void CGameSocket::RecvUserInfo(char* pBuf) { // TRACE("RecvUserInfo()\n"); int index = 0; short uid=-1, sHp, sMp, sLength = 0; BYTE bNation, bLevel, bZone, bAuthority=1; short sDamage, sAC; float fHitAgi, fAvoidAgi; char strName[MAX_ID_SIZE+1]; short sItemAC, sAmountLeft, sAmountRight; BYTE bTypeLeft, bTypeRight; uid = GetShort( pBuf, index ); sLength = GetShort( pBuf, index ); if( sLength > MAX_ID_SIZE || sLength <= 0 ) { char countstr[256]; CTime cur = CTime::GetCurrentTime(); sprintf_s( countstr, "RecvUserInfo() Fail : %02d/%02d %02d:%02d - uid=%d, name=%s\r\n", cur.GetMonth(), cur.GetDay(), cur.GetHour(), cur.GetMinute(), uid, strName); LogFileWrite( countstr ); TRACE("### RecvUserInfo() Fail ---> uid = %d, name=%s ### \n", uid, strName); return; } GetString(strName, pBuf, sLength, index); bZone = GetByte( pBuf, index ); bNation = GetByte( pBuf, index ); bLevel = GetByte( pBuf, index ); sHp = GetShort( pBuf, index ); sMp = GetShort( pBuf, index ); sDamage = GetShort( pBuf, index ); sAC = GetShort( pBuf, index ); fHitAgi = Getfloat( pBuf, index ); fAvoidAgi = Getfloat( pBuf, index ); // sItemAC = GetShort(pBuf, index); bTypeLeft = GetByte(pBuf, index); bTypeRight = GetByte(pBuf, index); sAmountLeft = GetShort(pBuf, index); sAmountRight = GetShort(pBuf, index); bAuthority = GetByte(pBuf, index); // //CUser* pUser = m_pMain->GetActiveUserPtr(uid); //if( pUser == NULL ) return; CUser* pUser = new CUser; pUser->Initialize(); pUser->m_iUserId = uid; strcpy(pUser->m_strUserID, strName); pUser->m_curZone = bZone; pUser->m_pMap = m_pMain->GetZoneByID(bZone); pUser->m_bNation = bNation; pUser->m_bLevel = bLevel; pUser->m_sHP = sHp; pUser->m_sMP = sMp; //pUser->m_sSP = sSp; pUser->m_sHitDamage = sDamage; pUser->m_fHitrate = fHitAgi; pUser->m_fAvoidrate = fAvoidAgi; pUser->m_sAC = sAC; pUser->m_bLive = USER_LIVE; // pUser->m_sItemAC = sItemAC; pUser->m_bMagicTypeLeftHand = bTypeLeft; pUser->m_bMagicTypeRightHand = bTypeRight; pUser->m_sMagicAmountLeftHand = sAmountLeft; pUser->m_sMagicAmountRightHand = sAmountRight; pUser->m_byIsOP = bAuthority; // TRACE("**** RecvUserInfo()---> uid = %d, name=%s, leng=%d ******\n", uid, strName, sLength); if(uid >= USER_BAND && uid < MAX_USER) { m_pMain->m_pUser[uid] = pUser; } _USERLOG* pUserLog = NULL; pUserLog = new _USERLOG; pUserLog->t = CTime::GetCurrentTime(); pUserLog->byFlag = USER_LOGIN; pUserLog->byLevel = pUser->m_bLevel; strcpy( pUserLog->strUserID, pUser->m_strUserID ); pUser->m_UserLogList.push_back( pUserLog ); }
void CGameSocket::RecvUserInOut(char* pBuf) { int index = 0; BYTE bType=-1; short uid=-1, len=0; char strName[MAX_ID_SIZE+1] = ""; float fX=-1, fZ=-1; bType = GetByte( pBuf, index ); uid = GetShort( pBuf, index ); len = GetShort( pBuf, index ); GetString(strName, pBuf, len, index); fX = Getfloat(pBuf, index); fZ = Getfloat(pBuf, index); if(fX < 0 || fZ < 0) { TRACE("Error:: RecvUserInOut(),, uid = %d, fX=%.2f, fZ=%.2f\n", uid, fX, fZ); return; } // TRACE("RecvUserInOut(),, uid = %d\n", uid); int region_x = 0, region_z=0; int x1 = (int)fX / TILE_SIZE; int z1 = (int)fZ / TILE_SIZE; region_x = (int)fX / VIEW_DIST; region_z = (int)fZ / VIEW_DIST; // 수정할것,,, : 지금 존 번호를 0으로 했는데.. 유저의 존 정보의 번호를 읽어야,, 함,, MAP* pMap = NULL; //m_pMain->g_arZone[pUser->m_curZone]; CUser* pUser = m_pMain->GetUserPtr(uid); // TRACE("^^& RecvUserInOut( type=%d )-> User(%s, %d),, zone=%d, index=%d, region_x=%d, y=%d\n", bType, pUser->m_strUserID, pUser->m_iUserId, pUser->m_curZone, pUser->m_sZoneIndex, region_x, region_z); if(pUser != NULL) { // TRACE("##### Fail : ^^& RecvUserInOut() [name = %s]. state=%d, hp=%d\n", pUser->m_strUserID, pUser->m_bLive, pUser->m_sHP); BOOL bFlag = FALSE; if(pUser->m_bLive == USER_DEAD || pUser->m_sHP <= 0) { if(pUser->m_sHP > 0) { pUser->m_bLive = TRUE; TRACE("##### CGameSocket-RecvUserInOut Fail : UserHeal [id=%s, bLive=%d, hp=%d], fX=%.2f, fZ=%.2f ######\n", pUser->m_strUserID, pUser->m_bLive, pUser->m_sHP, fX, fZ); } else { TRACE("##### CGameSocket-RecvUserInOut Fail : UserDead [id=%s, bLive=%d, hp=%d], fX=%.2f, fZ=%.2f ######\n", pUser->m_strUserID, pUser->m_bLive, pUser->m_sHP, fX, fZ); // 죽은 유저이므로 게임서버에 죽은 처리를 한다... //Send_UserError(uid); //return; } } pMap = pUser->GetMap(); if(pMap == NULL) { TRACE("#### Fail : pMap == NULL ####\n"); return; } if(x1 < 0 || z1 < 0 || x1 > pMap->m_sizeMap.cx || z1 > pMap->m_sizeMap.cy) { TRACE("#### RecvUserInOut Fail : [name=%s], x1=%d, z1=%d #####\n", pUser->m_strUserID, region_x, region_z); return; } // map 이동이 불가능이면 User등록 실패.. //if(pMap->m_pMap[x1][z1].m_sEvent == 0) return; if(region_x > pMap->GetXRegionMax() || region_z > pMap->GetZRegionMax()) { TRACE("#### GameSocket-RecvUserInOut() Fail : [name=%s], nRX=%d, nRZ=%d #####\n", pUser->m_strUserID, region_x, region_z); return; } //strcpy(pUser->m_strUserID, strName); pUser->m_curx = pUser->m_fWill_x = fX; pUser->m_curz = pUser->m_fWill_z = fZ; //bFlag = pUser->IsOpIDCheck(strName); //if(bFlag) pUser->m_byIsOP = 1; if(bType == 2) { // region out // 기존의 region정보에서 User의 정보 삭제.. pMap->RegionUserRemove(region_x, region_z, uid); //TRACE("^^& RecvUserInOut()-> User(%s, %d)를 Region에서 삭제..,, zone=%d, index=%d, region_x=%d, y=%d\n", pUser->m_strUserID, pUser->m_iUserId, pUser->m_curZone, pUser->m_sZoneIndex, region_x, region_z); } else { // region in if(pUser->m_sRegionX != region_x || pUser->m_sRegionZ != region_z) { pUser->m_sRegionX = region_x; pUser->m_sRegionZ = region_z; pMap->RegionUserAdd(region_x, region_z, uid); //TRACE("^^& RecvUserInOut()-> User(%s, %d)를 Region에 등록,, zone=%d, index=%d, region_x=%d, y=%d\n", pUser->m_strUserID, pUser->m_iUserId, pUser->m_curZone, pUser->m_sZoneIndex, region_x, region_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::RecvNpcGiveItem(char* pBuf) { int index = 0, send_index = 0; char send_buff[1024]; short sUid, sNid, sZone, regionx, regionz; float fX, fZ, fY; BYTE byCount; int nItemNumber[NPC_HAVE_ITEM_LIST]; short sCount[NPC_HAVE_ITEM_LIST]; _ZONE_ITEM* pItem = NULL; C3DMap* pMap = NULL; CUser* pUser = NULL; sUid = GetShort(pBuf,index); // Item을 가져갈 사람의 아이디... (이것을 참조해서 작업하셈~) sNid = GetShort(pBuf,index); sZone = GetShort(pBuf, index); regionx = GetShort( pBuf, index ); regionz = GetShort( pBuf, index ); fX = Getfloat(pBuf,index); fZ = Getfloat(pBuf,index); fY = Getfloat(pBuf,index); byCount = GetByte(pBuf,index); for(int i=0; i<byCount; i++) { nItemNumber[i] = GetDWORD(pBuf, index); sCount[i] = GetShort(pBuf,index); } if( sUid < 0 || sUid >= MAX_USER ) return; pMap = m_pMain->GetZoneByID(sZone); if (pMap == NULL) return; pItem = new _ZONE_ITEM; for(int i=0; i<6; i++) { pItem->itemid[i] = 0; pItem->count[i] = 0; } pItem->bundle_index = pMap->m_wBundle; pItem->time = TimeGet(); pItem->x = fX; pItem->z = fZ; pItem->y = fY; for(int i=0; i<byCount; i++) { if( m_pMain->m_ItemtableArray.GetData(nItemNumber[i]) ) { pItem->itemid[i] = nItemNumber[i]; pItem->count[i] = sCount[i]; } } if (!pMap->RegionItemAdd(regionx, regionz, pItem )) { delete pItem; return; } pUser = m_pMain->GetUserPtr(sUid); if (pUser == NULL) return; send_index = 0; SetByte( send_buff, WIZ_ITEM_DROP, send_index ); SetShort( send_buff, sNid, send_index ); SetDWORD( send_buff, pItem->bundle_index, send_index ); if( pUser->m_sPartyIndex == -1 ) pUser->Send( send_buff, send_index ); else m_pMain->Send_PartyMember( pUser->m_sPartyIndex, 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); } } }
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); } } }
/*** * We've been told from another server that a user's status in the clan has changed. ***/ void CUdpSocket::RecvModifyFame(char* pBuf, BYTE command) { CString clanNotice; int index = 0, knightsindex = 0, vicechief = 0; char userid[MAX_ID_SIZE+1]; knightsindex = GetShort(pBuf, index); if (!GetKOString(pBuf, userid, index, MAX_ID_SIZE)) return; CUser *pTUser = g_pMain->GetUserPtr(userid, TYPE_CHARACTER); CKnights *pKnights = g_pMain->GetClanPtr(knightsindex); if (pKnights == NULL) return; switch (command) { case KNIGHTS_REMOVE: case KNIGHTS_REJECT: if (pTUser) { pTUser->SetClanID(0); pTUser->m_pUserData->m_bFame = 0; if (command == KNIGHTS_REMOVE) clanNotice = g_pMain->GetServerResource(IDS_KNIGHTS_REMOVE); } g_pMain->m_KnightsManager.RemoveKnightsUser(knightsindex, userid); break; case KNIGHTS_ADMIT: if (pTUser) pTUser->m_pUserData->m_bFame = KNIGHT; break; case KNIGHTS_CHIEF+0x10: if (pTUser) { pTUser->m_pUserData->m_bFame = CHIEF; clanNotice = g_pMain->GetServerResource(IDS_KNIGHTS_CHIEF); } break; case KNIGHTS_VICECHIEF+0x10: if (pTUser) { pTUser->m_pUserData->m_bFame = VICECHIEF; clanNotice = g_pMain->GetServerResource(IDS_KNIGHTS_VICECHIEF); } break; case KNIGHTS_OFFICER+0x10: if (pTUser) pTUser->m_pUserData->m_bFame = OFFICER; break; case KNIGHTS_PUNISH+0x10: if (pTUser) pTUser->m_pUserData->m_bFame = PUNISH; break; } if (pTUser != NULL) pTUser->SendClanUserStatusUpdate(command == KNIGHTS_REMOVE); if (clanNotice.GetLength() == 0) return; Packet result; // Construct the clan system chat packet pKnights->ConstructChatPacket(result, clanNotice, pTUser != NULL ? pTUser->m_pUserData->m_id : userid); // If we've been removed from a clan, tell the user as well (since they're no longer in the clan) if (command == KNIGHTS_REMOVE && pTUser != NULL) pTUser->Send(&result); // Otherwise, since we're actually in the clan, we don't need to be explicitly told what happened. if (pKnights != NULL) pKnights->Send(&result); }
// 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 CUdpSocket::RecvBattleEvent(char *pBuf) { int index = 0, send_index = 0, udp_index = 0; int nType = 0, nResult = 0, nLen = 0, nKillKarus = 0, nElmoKill = 0; char strMaxUserName[MAX_ID_SIZE+1], strKnightsName[MAX_ID_SIZE+1]; char finalstr[1024]; std::string buff; nType = GetByte( pBuf, index ); nResult = GetByte(pBuf, index); if( nType == BATTLE_EVENT_OPEN ) { } else if( nType == BATTLE_MAP_EVENT_RESULT ) { if( g_pMain->m_byBattleOpen == NO_BATTLE ) { TRACE("#### UDP RecvBattleEvent Fail : battleopen = %d, type = %d\n", g_pMain->m_byBattleOpen, nType); return; } if( nResult == KARUS ) { //TRACE("--> UDP RecvBattleEvent : 카루스 땅으로 넘어갈 수 있어\n"); g_pMain->m_byKarusOpenFlag = 1; // 카루스 땅으로 넘어갈 수 있어 } else if( nResult == ELMORAD ) { //TRACE("--> UDP RecvBattleEvent : 엘모 땅으로 넘어갈 수 있어\n"); g_pMain->m_byElmoradOpenFlag = 1; // 엘모 땅으로 넘어갈 수 있어 } } else if( nType == BATTLE_EVENT_RESULT ) { if( g_pMain->m_byBattleOpen == NO_BATTLE ) { TRACE("#### UDP RecvBattleEvent Fail : battleopen = %d, type=%d\n", g_pMain->m_byBattleOpen, nType); return; } if( nResult == KARUS ) { //TRACE("--> UDP RecvBattleEvent : 카루스가 승리하였습니다.\n"); } else if( nResult == ELMORAD ) { //TRACE("--> UDP RecvBattleEvent : 엘모라드가 승리하였습니다.\n"); } g_pMain->m_bVictory = nResult; g_pMain->m_byOldVictory = nResult; g_pMain->m_byKarusOpenFlag = 0; // 카루스 땅으로 넘어갈 수 없도록 g_pMain->m_byElmoradOpenFlag = 0; // 엘모 땅으로 넘어갈 수 없도록 g_pMain->m_byBanishFlag = 1; } else if( nType == BATTLE_EVENT_MAX_USER ) { nLen = GetByte(pBuf, index); if (!GetKOString(pBuf, strKnightsName, index, MAX_ID_SIZE) || GetKOString(pBuf, strMaxUserName, index, MAX_ID_SIZE)) return; int nResourceID = 0; switch (nResult) { case 1: // captain nResourceID = IDS_KILL_CAPTAIN; break; case 2: // keeper case 7: // warders? case 8: nResourceID = IDS_KILL_GATEKEEPER; break; case 3: // Karus sentry nResourceID = IDS_KILL_KARUS_GUARD1; break; case 4: // Karus sentry nResourceID = IDS_KILL_KARUS_GUARD2; break; case 5: // El Morad sentry nResourceID = IDS_KILL_ELMO_GUARD1; break; case 6: // El Morad sentry nResourceID = IDS_KILL_ELMO_GUARD2; break; } if (nResourceID == 0) { TRACE("RecvBattleEvent: could not establish resource for result %d", nResult); return; } _snprintf(finalstr, sizeof(finalstr), g_pMain->GetServerResource(nResourceID), strKnightsName, strMaxUserName); #if 0 SetByte( send_buff, WIZ_CHAT, send_index ); SetByte( send_buff, WAR_SYSTEM_CHAT, send_index ); SetByte( send_buff, 1, send_index ); SetShort( send_buff, -1, send_index ); SetKOString( send_buff, finalstr, send_index ); g_pMain->Send_All( send_buff, send_index ); send_index = 0; SetByte( send_buff, WIZ_CHAT, send_index ); SetByte( send_buff, PUBLIC_CHAT, send_index ); SetByte( send_buff, 1, send_index ); SetShort( send_buff, -1, send_index ); SetKOString( send_buff, finalstr, send_index ); g_pMain->Send_All( send_buff, send_index ); #endif } else if( nType == BATTLE_EVENT_KILL_USER ) { if( nResult == 1 ) { nKillKarus = GetShort( pBuf, index ); nElmoKill = GetShort( pBuf, index ); g_pMain->m_sKarusDead = g_pMain->m_sKarusDead + nKillKarus; g_pMain->m_sElmoradDead = g_pMain->m_sElmoradDead + nElmoKill; //TRACE("--> UDP RecvBattleEvent type = 1 : 적국 유저 죽인수 : karus=%d->%d, elmo=%d->%d\n", nKillKarus, g_pMain->m_sKarusDead, nElmoKill, g_pMain->m_sElmoradDead); Packet result(UDP_BATTLE_EVENT_PACKET, uint8(BATTLE_EVENT_KILL_USER)); result << uint8(2) << g_pMain->m_sKarusDead << g_pMain->m_sElmoradDead; g_pMain->Send_UDP_All(&result); } else if( nResult == 2 ) { nKillKarus = GetShort( pBuf, index ); nElmoKill = GetShort( pBuf, index ); //TRACE("--> UDP RecvBattleEvent type = 2 : 적국 유저 죽인수 : karus=%d->%d, elmo=%d->%d\n", g_pMain->m_sKarusDead, nKillKarus, g_pMain->m_sElmoradDead, nElmoKill); g_pMain->m_sKarusDead = nKillKarus; g_pMain->m_sElmoradDead = nElmoKill; } } }
void CUser::MoveProcess(char *pBuf ) { ASSERT(GetMap() != NULL); if( m_bWarp ) return; int index = 0, send_index = 0, region = 0; WORD will_x, will_z; short will_y, speed=0; float real_x, real_z, real_y; BYTE echo; char send_buff[32]; will_x = GetShort( pBuf, index ); will_z = GetShort( pBuf, index ); will_y = GetShort( pBuf, index ); speed = GetShort( pBuf, index ); echo = GetByte( pBuf, index ); real_x = will_x/10.0f; real_z = will_z/10.0f; real_y = will_y/10.0f; if (GetMap()->IsValidPosition(real_x, real_z, real_y) == FALSE) return; if (isDead() && speed != 0) TRACE("### MoveProcess Fail : name=%s(%d), m_bResHpType=%d, hp=%d, speed=%d, x=%d, z=%d ###\n", m_pUserData->m_id, m_Sid, m_bResHpType, m_pUserData->m_sHp, speed, (int)m_pUserData->m_curx, (int)m_pUserData->m_curz); if( speed != 0 ) { m_pUserData->m_curx = m_fWill_x; // ????? ??? ?????g?? ??????g?? ????... m_pUserData->m_curz = m_fWill_z; m_pUserData->m_cury = m_fWill_y; m_fWill_x = will_x/10.0f; // ?????g?? ???.... m_fWill_z = will_z/10.0f; m_fWill_y = will_y/10.0f; } else { m_pUserData->m_curx = m_fWill_x = will_x/10.0f; // ?????g == ???? ??g... m_pUserData->m_curz = m_fWill_z = will_z/10.0f; m_pUserData->m_cury = m_fWill_y = will_y/10.0f; } SetByte( send_buff, WIZ_MOVE, send_index ); SetShort( send_buff, m_Sid, send_index ); SetShort( send_buff, will_x, send_index ); SetShort( send_buff, will_z, send_index ); SetShort( send_buff, will_y, send_index ); SetShort( send_buff, speed, send_index ); SetByte( send_buff, echo, send_index ); RegisterRegion(); m_pMain->Send_Region( send_buff, send_index, GetMap(), m_RegionX, m_RegionZ, NULL, false ); GetMap()->CheckEvent( real_x, real_z, this ); send_index = 0; SetByte( send_buff, AG_USER_MOVE, send_index ); SetShort( send_buff, m_Sid, send_index ); Setfloat( send_buff, m_fWill_x, send_index ); Setfloat( send_buff, m_fWill_z, send_index ); Setfloat( send_buff, m_fWill_y, send_index ); SetShort( send_buff, speed, send_index ); m_pMain->Send_AIServer(send_buff, send_index); }
void HMISong::SetupForHMI(int len) { int i, p; ReadVarLen = ReadVarLenHMI; NumTracks = GetShort(MusHeader + HMI_TRACK_COUNT_OFFSET); if (NumTracks <= 0) { return; } // The division is the number of pulses per quarter note (PPQN). // HMI files have two values here, a full value and a quarter value. Some games, // notably Quarantines, have identical values for some reason, so it's safer to // use the quarter value and multiply it by four than to trust the full value. Division = GetShort(MusHeader + HMI_DIVISION_OFFSET) << 2; Tempo = InitialTempo = 4000000; Tracks = new TrackInfo[NumTracks + 1]; int track_dir = GetInt(MusHeader + HMI_TRACK_DIR_PTR_OFFSET); // Gather information about each track for (i = 0, p = 0; i < NumTracks; ++i) { int start = GetInt(MusHeader + track_dir + i*4); int tracklen, datastart; if (start > len - HMITRACK_DESIGNATION_OFFSET - 4) { // Track is incomplete. continue; } // BTW, HMI does not actually check the track header. if (memcmp(MusHeader + start, TRACK_MAGIC, 13) != 0) { continue; } // The track ends where the next one begins. If this is the // last track, then it ends at the end of the file. if (i == NumTracks - 1) { tracklen = len - start; } else { tracklen = GetInt(MusHeader + track_dir + i*4 + 4) - start; } // Clamp incomplete tracks to the end of the file. tracklen = MIN(tracklen, len - start); if (tracklen <= 0) { continue; } // Offset to actual MIDI events. datastart = GetInt(MusHeader + start + HMITRACK_DATA_PTR_OFFSET); tracklen -= datastart; if (tracklen <= 0) { continue; } // Store track information Tracks[p].TrackBegin = MusHeader + start + datastart; Tracks[p].TrackP = 0; Tracks[p].MaxTrackP = tracklen; // Retrieve track designations. We can't check them yet, since we have not yet // connected to the MIDI device. for (int ii = 0; ii < NUM_HMI_DESIGNATIONS; ++ii) { Tracks[p].Designation[ii] = GetShort(MusHeader + start + HMITRACK_DESIGNATION_OFFSET + ii*2); } p++; } // In case there were fewer actual chunks in the file than the // header specified, update NumTracks with the current value of p. NumTracks = p; }
// //AbilityActiveMessage // int AbilityActiveMessage::handleMessage(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { creatureInstance->RemoveNoncombatantStatus("abilityActivate"); // Flags appears to be intended for party casting, but isn't used outside the /do command. // We don't use it in the server, but we still need to read it from the message. short aID = GetShort(&sim->readPtr[sim->ReadPos], sim->ReadPos); //Ability ID // Unused? GetByte(&sim->readPtr[sim->ReadPos], sim->ReadPos); //unsigned char flags = GetByte(&sim->readPtr[sim->ReadPos], sim->ReadPos); //flags unsigned char ground = GetByte(&sim->readPtr[sim->ReadPos], sim->ReadPos); //ground float x, y, z; //LogMessageL(MSG_SHOW, "abilityActivate: %d, flags: %d", aID, flags); if (ground != 0) { x = GetFloat(&sim->RecBuf[sim->ReadPos], sim->ReadPos); y = GetFloat(&sim->RecBuf[sim->ReadPos], sim->ReadPos); z = GetFloat(&sim->RecBuf[sim->ReadPos], sim->ReadPos); creatureInstance->ab[0].SetPosition(x, y, z); //LogMessageL(MSG_DIAGV, "ground: %d, x: %g, y: %g, z: %g", ground, x, y, z); } if (creatureInstance->serverFlags & ServerFlags::IsTransformed) { const Ability2::AbilityEntry2 *abData = g_AbilityManager.GetAbilityPtrByID(aID); if (abData != NULL) { /* TODO: old junk, update or remove this if(abData->isMagic == true) { sim->SendInfoMessage("You may not use elemental abilities while transformed.", INFOMSG_INFO); return; } if(abData->isRanged == true) { sim->SendInfoMessage("You may not use ranged abilities while transformed.", INFOMSG_INFO); return; } */ } } if (aID == g_JumpConstant) { if (sim->IsGMInvisible() == false) sim->AddMessage(pld->CreatureID, 0, BCM_ActorJump); } else { bool allow = false; if (sim->CheckPermissionSimple(Perm_Account, Permission_Debug | Permission_Admin | Permission_Developer) == true) allow = true; else if (pld->charPtr->abilityList.GetAbilityIndex(aID) >= 0) allow = true; else { if (g_AbilityManager.IsGlobalIntrinsicAbility(aID) == true) allow = true; } if (allow == true) { creatureInstance->RequestAbilityActivation(aID); if (sim->TargetRarityAboveNormal() == false) { if (pld->NotifyCast(creatureInstance->CurrentX, creatureInstance->CurrentZ, aID) == true) { CreatureInstance *target = creatureInstance->CurrentTarget.targ; const char *targetName = "no target"; int targetID = 0; if (target != NULL) { targetID = target->CreatureID; targetName = target->css.display_name; } g_Logs.cheat->info( "[BOT] Attacks in area by %s @ %d:%d,%d(%d) (%d:%s) [%s:%d]", creatureInstance->css.display_name, pld->CurrentZoneID, creatureInstance->CurrentX, creatureInstance->CurrentZ, creatureInstance->Rotation, aID, g_AbilityManager.GetAbilityNameByID(aID), targetName, targetID); } } } } return 0; }
// //UpdateVelocityMessage // int UpdateVelocityMessage::handleMessage(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { if (g_ServerTime < pld->MovementBlockTime) { creatureInstance->Speed = 0; return 0; } //When entering a new zone from a portal, a velocity update always seems to be sent. //This is designed to block that message from interrupting the noncombat status. if (pld->IgnoreNextMovement == true) pld->IgnoreNextMovement = false; else creatureInstance->RemoveNoncombatantStatus("updateVelocity"); int x = GetShort(&sim->readPtr[sim->ReadPos], sim->ReadPos); int z = GetShort(&sim->readPtr[sim->ReadPos], sim->ReadPos); int y = GetShort(&sim->readPtr[sim->ReadPos], sim->ReadPos); creatureInstance->Heading = GetByte(&sim->readPtr[sim->ReadPos], sim->ReadPos); creatureInstance->Rotation = GetByte(&sim->readPtr[sim->ReadPos], sim->ReadPos); int speed = GetByte(&sim->readPtr[sim->ReadPos], sim->ReadPos); // LogMessageL(MSG_SHOW, "Heading:%d, Rot:%d, Spd:%d, X: %d, Y: %d, Z: %d", creatureInstance->Heading, creatureInstance->Rotation, speed, x, y, z); if (g_Config.FallDamage && !creatureInstance->actInst->mZoneDefPtr->mGrove) { int deltaY = creatureInstance->CurrentY - y; if (deltaY >= 30) pld->bFalling = true; if (pld->bFalling == true) { pld->DeltaY += deltaY; g_Logs.simulator->debug("[%v] Delta: %v, %v", sim->InternalID, deltaY, pld->DeltaY); } if (deltaY < 30) { if (pld->bFalling == true) { creatureInstance->CheckFallDamage(pld->DeltaY); g_Logs.simulator->debug("[%v] Damage: %v", sim->InternalID, pld->DeltaY); pld->bFalling = false; } pld->DeltaY = 0; } } if (g_Config.HasAdministrativeBehaviorFlag(ADMIN_BEHAVIOR_VERIFYSPEED) == true) { if (sim->CheckPermissionSimple(Perm_Account, Permission_Debug | Permission_Admin | Permission_Developer) == false) { int xlen = abs(x - (creatureInstance->CurrentX & 0xFFFF)); int zlen = abs(z - (creatureInstance->CurrentZ & 0xFFFF)); if (xlen < SimulatorThread::OverflowThreshold && zlen < SimulatorThread::OverflowThreshold) { int pspeed = 120 + creatureInstance->css.mod_movement; int distPerSecond = (int) (((float) pspeed / 100.0F) * 40.0F); //The number of units to move for this update. if (speed > pspeed || xlen > distPerSecond || zlen > distPerSecond) { g_Logs.cheat->warn( "[SPEED] Spd: %d / %d, xlen: %d, zlen: %d (%d)", speed, pspeed, xlen, zlen, distPerSecond); return PrepExt_GeneralMoveUpdate(sim->SendBuf, creatureInstance); } } } } creatureInstance->Speed = speed; int oldX = creatureInstance->CurrentX; int oldZ = creatureInstance->CurrentZ; int newX = oldX; int newZ = oldZ; //Since these updates are unsigned short, the maximum value they can relay //is 65535. Some maps are much larger (Europe), thus some kind of overflow //handling must be supplied to prevent characters from having their //position reach 0. Check for an overflow by comparing the new location //with the last location. If the distance is too great, a rollover //must've happened (although coordinate warping might be a possibility //too?) If the resulting short value is small, it means it overflowed //into a higher value. If not, it underflowed into a smaller value. if (abs(x - (oldX & 0xFFFF)) >= SimulatorThread::OverflowThreshold) { if (x < SimulatorThread::OverflowThreshold) newX += SimulatorThread::OverflowAdditive; else newX -= SimulatorThread::OverflowAdditive; } if (abs(z - (oldZ & 0xFFFF)) >= SimulatorThread::OverflowThreshold) { if (z < SimulatorThread::OverflowThreshold) newZ += SimulatorThread::OverflowAdditive; else newZ -= SimulatorThread::OverflowAdditive; } //Zero out the lower short, then OR it back with the short coords we received from the client. newX = (newX ^ (newX & 0xFFFF)) | x; newZ = (newZ ^ (newZ & 0xFFFF)) | z; creatureInstance->CurrentX = newX; creatureInstance->CurrentY = y; creatureInstance->CurrentZ = newZ; //LogMessageL(MSG_SHOW, "Loc: X:%d, Y:%d, Z:%d", x, y, z); //LogMessageL(MSG_SHOW, "Vel: Hd:%d, Rot:%d, Spd:%d", creatureInstance->Heading, creatureInstance->Rotation, creatureInstance->Speed); if (creatureInstance->Speed != 0) { //Check movement timers. int xlen = newX - oldX; int zlen = newZ - oldZ; float offset = sqrt((float) ((xlen * xlen) + (zlen * zlen))); creatureInstance->CheckMovement(offset); pld->TotalDistanceMoved += (int) offset; //Movement data verification against cheats. Only run it for normal players. //If administrative /setstat command was used to increase speed above 255 (speed is 1 byte) //the expected velocity won't match. //The client uses a recurring event pulse to send the avatar's velocity updates to the server. //The pulse activates at 0.25 second intervals, regardless of whether movement occurred. //If the client's update flag is true (at least some movement happened), the update is sent //with the player's current position and rotation, then the update flag is cleared. The //closed beta does not use any forced updates, although the client function allows that as //an optional parameter (forced updating would send the velocity update immediately, //independently from the update pulse, and would not trigger the update flag. //The pulse is not always accurate, and can vary with framerate. Also, when first logging in //the pulse seems to be ignored, instead sending sporadic updates whenever required. For example, //autorunning into a hill too steep to climb produces an indefinite flood of updates. At some //currently unknown point, the pulse seems to take over and subsequent floods will stop. //There are tons of weird cases where verification fails on legit movement, so it may be necessary //to just disable it entirely. if(g_Config.VerifyMovement == true && !sim->CheckPermissionSimple(Perm_Account, Permission_Admin | Permission_Developer)) { int expectedSpeed = 100 + creatureInstance->css.base_movement + creatureInstance->css.mod_movement; //The heading and rotation fields use only a single byte (0 to 255) to represent 360 degree //rotation. So 90 degrees (360/4) -> (255/4) = 64. //Usually if we're moving backward in a single direction (pressing Backward only) //then the difference is almost always ~128. However, if we're moving Left or Right while //moving backward, sometimes heading and rotation is the same so we can't judge by that. //Instead we have to look at the incoming speed. Since moving backward is half speed, //division may be off slightly so we allow a small tolerance. int halfExpected = abs(speed - (expectedSpeed / 2)); if ((speed != expectedSpeed) && (halfExpected > 3)) { g_Logs.cheat->info( "[SPEED] Unexpected speed by %s @ Zn:%d,X%d,Y%d, Spd:%d, Expected:%d", creatureInstance->css.display_name, pld->CurrentZoneID, newX, newZ, speed, expectedSpeed); } else { //Moving backwards, change to half speed for distance calculations. if ((speed != expectedSpeed) && (halfExpected <= 3)) expectedSpeed /= 2; } //Movement updates are typically every 250 milliseconds, but even on localhost can vary a bit. //Using the client, update intervals of ~218ms were semi common. unsigned long timeSinceLastMovement = g_ServerTime - pld->MovementTime; /* Removed: natural latency triggers this so often that it spams too many logs messages. if(timeSinceLastMovement < 200) { Debug::cheatLogger.Log("[SPEED] Rapid request by %s @ Zn:%d,X%d,Y%d, Spd:%d, Time:%lu", creatureInstance->css.display_name, pld->CurrentZoneID, newX, newZ, speed, timeSinceLastMovement); LogMessageL(MSG_SHOW, "[SPEED] Rapid request by %s @ Zn:%d,X%d,Y%d, Spd:%d, Time:%lu", creatureInstance->css.display_name, pld->CurrentZoneID, newX, newZ, speed, timeSinceLastMovement); } */ //We want to limit this to a quarter second so that we can calculate our expected //distance correctly, accepting lower update intervals but not large intervals which //would otherwise translate to potentially huge gaps with spoofed movement. //if(timeSinceLastMovement > 250) timeSinceLastMovement = 250; //Calculate how far the creature should have moved. Default speed is 100, so //convert that into an expected distance while factoring the incoming time interval //and a 50% tolerance. float expectedOffset = ((expectedSpeed / 100.0F) * DEFAULT_CREATURE_SPEED) * (timeSinceLastMovement / 1000.0F) * 1.5F; // Disabled: was testing incoming movement for verification but it doesn't really help. /* Sleep(1); g_Log.AddMessageFormat("Offset:%g, Expected:%g", offset, expectedOffset); */ if (offset > expectedOffset) { g_Logs.cheat->info( "[SPEED] Moved too far by %s @ Zn:%d,X%d,Z%d, Spd:%d, Offset X:%d,Z:%d Moved:%g/Expected:%g", creatureInstance->css.display_name, pld->CurrentZoneID, newX, newZ, speed, xlen, zlen, offset, expectedOffset); } } //Check our current position against any quest objective locations. //The movement counter will help us check every other step instead as a small optimization. if ((pld->PendingMovement & 1) && (pld->charPtr != NULL)) { int r = pld->charPtr->questJournal.CheckTravelLocations( creatureInstance->CreatureID, sim->Aux1, creatureInstance->CurrentX, creatureInstance->CurrentY, creatureInstance->CurrentZ, pld->CurrentZoneID); if (r > 0) sim->AttemptSend(sim->Aux1, r); } if (pld->PendingMovement >= 10) { pld->PendingMovement = 0; } } if (creatureInstance->actInst != NULL) { creatureInstance->actInst->PlayerMovement(creatureInstance); } //Check for zone boundaries, if a player is trying to go somewhere they should not be able to access. if (g_ZoneBarrierManager.CheckCollision(pld->CurrentZoneID, creatureInstance->CurrentX, creatureInstance->CurrentZ) == true) sim->AddMessage((long) creatureInstance, 0, BCM_UpdateFullPosition); int wpos = 0; //If GM invisible, send the update to ourself. Otherwise broadcast it. if (sim->IsGMInvisible() == true) { wpos = PrepExt_GeneralMoveUpdate(sim->SendBuf, creatureInstance); } else { sim->AddMessage((long) creatureInstance, 0, BCM_UpdateVelocity); sim->AddMessage((long) creatureInstance, 0, BCM_UpdatePosInc); } pld->PendingMovement++; pld->MovementTime = g_ServerTime; sim->CheckSpawnTileUpdate(false); sim->CheckMapUpdate(false); return wpos; }