void CUser::MoveProcess(Packet & pkt) { ASSERT(GetMap() != nullptr); if (m_bWarp || isDead()) return; uint16 will_x, will_z, will_y; int16 speed=0; float real_x, real_z, real_y; uint8 echo; pkt >> will_x >> will_z >> will_y >> speed >> echo; real_x = will_x/10.0f; real_z = will_z/10.0f; real_y = will_y/10.0f; if (!isGM()) { // TO-DO: Handle proper speed checks against server-side amounts. // We should also avoid relying on what the client has sent us. if (speed > 200) // What is the signifance of this number? Considering 90 is light feet... // We shouldn't be using magic numbers at all here. { Disconnect(); return; } } if (!GetMap()->IsValidPosition(real_x, real_z, real_y)) return; if (m_oldx != GetX() || m_oldz != GetZ()) { m_oldx = GetX(); m_oldy = GetY(); m_oldz = GetZ(); } // TO-DO: Ensure this is checked properly to prevent speedhacking SetPosition(real_x, real_y, real_z); if (RegisterRegion()) { g_pMain->RegionNpcInfoForMe(this); g_pMain->RegionUserInOutForMe(this); g_pMain->MerchantUserInOutForMe(this); } if (m_bInvisibilityType == INVIS_DISPEL_ON_MOVE) CMagicProcess::RemoveStealth(this, INVIS_DISPEL_ON_MOVE); Packet result(WIZ_MOVE); result << GetSocketID() << will_x << will_z << will_y << speed << echo; SendToRegion(&result); GetMap()->CheckEvent(real_x, real_z, this); result.Initialize(AG_USER_MOVE); result << GetSocketID() << m_curx << m_curz << m_cury << speed; Send_AIServer(&result); }
void CUser::SelectCharacter(Packet & pkt) { Packet result(WIZ_SEL_CHAR); uint8 bResult, bInit; if (isBanned()) { Disconnect(); return; } pkt >> bResult >> bInit; result << bResult; if (bResult == 0 || !GetZoneID()) goto fail_return; m_pMap = g_pMain->GetZoneByID(GetZoneID()); if (GetMap() == nullptr) goto fail_return; if (g_pMain->m_nServerNo != GetMap()->m_nServerNo) { _ZONE_SERVERINFO *pInfo = g_pMain->m_ServerArray.GetData(GetMap()->m_nServerNo); if (pInfo == nullptr) goto fail_return; SendServerChange(pInfo->strServerIP, bInit); return; } if (!g_pMain->isWarOpen() && GetFame() == COMMAND_CAPTAIN) m_bFame = CHIEF; // Disallow players from relogging in the opposite nation's home zone when an invasion's not running. if (((GetZoneID() != GetNation() && GetZoneID() <= ZONE_ELMORAD && !g_pMain->m_byBattleOpen) // also disallow players from logging back into war zones that aren't currently active... || (GetMap()->isWarZone() && !g_pMain->m_byBattleOpen) // Chaos, bdw and juraid montuain || isInTempleEventZone() // Ronark Land, Ardream, RLB, Bifrost, Krowaz Dominion. || (g_pMain->m_byBattleOpen && (GetZoneID() == ZONE_RONARK_LAND || GetZoneID() == ZONE_ARDREAM || GetZoneID() == ZONE_RONARK_LAND_BASE || GetZoneID() == ZONE_BIFROST || GetZoneID() == ZONE_KROWAZ_DOMINION))) && !isGM()) { NativeZoneReturn(); Disconnect(); return; } SetLogInInfoToDB(bInit); result << GetZoneID() << GetSPosX() << GetSPosZ() << GetSPosY() << g_pMain->m_byOldVictory; m_bSelectedCharacter = true; Send(&result); SetUserAbility(false); if (GetLevel() > MAX_LEVEL) { Disconnect(); return; } m_iMaxExp = g_pMain->GetExpByLevel(GetLevel()); SetRegion(GetNewRegionX(), GetNewRegionZ()); if (GetClanID() == -1) { SetClanID(0); m_bFame = 0; return; } else if (GetClanID() != 0 && GetZoneID() > 2) { result.Initialize(WIZ_KNIGHTS_PROCESS); result << uint8(KNIGHTS_LIST_REQ) << GetClanID(); g_pMain->AddDatabaseRequest(result, this); } return; fail_return: Send(&result); }
void CUser::Chat(Packet & pkt) { Packet result; uint16 sessID; uint8 type = pkt.read<uint8>(), bNation; string chatstr, finalstr, strSender, * strMessage; bool isAnnouncement = false; if (isMuted()) return; pkt >> chatstr; if (chatstr.empty() || chatstr.size() > 128) return; // Process GM commands if (isGM() && ProcessChatCommand(chatstr)) return; #if 0 // Removed this - all it seems to do is cause chat to break for GMs (is it 19xx+ only?) if( isGM() && type == GENERAL_CHAT) type = 0x14; #endif // Handle GM notice & announcement commands if (type == PUBLIC_CHAT || type == ANNOUNCEMENT_CHAT) { // Trying to use a GM command without authorisation? Bad player! if (!isGM()) return; if (type == ANNOUNCEMENT_CHAT) type = WAR_SYSTEM_CHAT; // This is horrible, but we'll live with it for now. // Pull the notice string (#### NOTICE : %s ####) from the database. // Format the chat string around it, so our chat data is within the notice g_pMain->GetServerResource(IDP_ANNOUNCEMENT, &finalstr, chatstr.c_str()); isAnnouncement = true; } if (isAnnouncement) { // GM notice/announcements show no name, so don't bother setting it. strMessage = &finalstr; // use the formatted message from the user bNation = KARUS; // arbitrary nation sessID = -1; } else { strMessage = &chatstr; // use the raw message from the user strSender = GetName(); // everything else uses a name, so set it bNation = GetNation(); sessID = GetSocketID(); } ChatPacket::Construct(&result, type, strMessage, &strSender, bNation, sessID); switch (type) { case GENERAL_CHAT: g_pMain->Send_NearRegion(&result, GetMap(), GetRegionX(), GetRegionZ(), GetX(), GetZ()); break; case PRIVATE_CHAT: { CUser *pUser = g_pMain->GetUserPtr(m_sPrivateChatUser); if (pUser != nullptr) pUser->Send(&result); } break; case PARTY_CHAT: if (isInParty()) g_pMain->Send_PartyMember(m_sPartyIndex, &result); break; case SHOUT_CHAT: if (m_sMp < (m_iMaxMp / 5)) break; // Characters under level 35 require 3,000 coins to shout. if (!isGM() && GetLevel() < 35 && !GoldLose(SHOUT_COIN_REQUIREMENT)) break; MSpChange(-(m_iMaxMp / 5)); SendToRegion(&result); break; case KNIGHTS_CHAT: if (isInClan()) g_pMain->Send_KnightsMember(GetClanID(), &result); break; case PUBLIC_CHAT: case ANNOUNCEMENT_CHAT: if (isGM()) g_pMain->Send_All(&result); break; case COMMAND_CHAT: if (GetFame() == COMMAND_CAPTAIN) g_pMain->Send_CommandChat(&result, m_bNation, this); break; case MERCHANT_CHAT: if (isMerchanting()) SendToRegion(&result); break; case ALLIANCE_CHAT: if (isInClan()) { CKnights *pKnights = g_pMain->GetClanPtr(GetClanID()); if (pKnights != nullptr && pKnights->isInAlliance()) g_pMain->Send_KnightsAlliance(pKnights->GetAllianceID(), &result); } break; case WAR_SYSTEM_CHAT: if (isGM()) g_pMain->Send_All(&result); break; } }
bool cPlayer::mount( P_NPC pMount ) { if ( !pMount ) return false; if ( isDead() ) { return false; } unsigned short mountId = pMount->mountId(); if ( !mountId ) { return false; // Not mountable } cUOSocket* socket = this->socket(); if ( !inRange( pMount, Config::instance()->mountRange() ) && !isGM() ) { if ( socket ) socket->sysMessage( 500206 ); // That is too far away to ride. return true; // Mountable, but not in range } if ( pMount->owner() == this || isGM() ) { unmount(); P_ITEM pMountItem = new cItem; pMountItem->Init(); pMountItem->setId( mountId ); pMountItem->setColor( pMount->skin() ); if ( direction() != pMount->direction() ) { setDirection( pMount->direction() ); update(); } this->addItem( cBaseChar::Mount, pMountItem ); pMountItem->setTag( "pet", cVariant( pMount->serial() ) ); pMountItem->update(); // if this is a gm lets tame the animal in the process if ( isGM() ) { pMount->setOwner( this ); pMount->setTamed( true ); } // remove it from screen! pMount->bark( Bark_Idle ); pMount->removeFromView( false ); pMount->fight( 0 ); pMount->setStablemasterSerial( serial_ ); } else if ( pMount->owner() == 0 ) { socket->clilocMessage( 501263, 0, 0x3b2, 3, this ); // That mount does not look broken! You would have to tame it to ride it. } else socket->clilocMessage( 501264, 0, 0x3b2, 3, this ); // This isn't your mount; it refuses to let you ride. return true; }
int mmo_auth_init(void) { MYSQL mysql_handle; char tmpsql[1024]; MYSQL_RES* sql_res ; MYSQL_ROW sql_row ; FILE *fp; int account_id, logincount, user_level, state, n, i; char line[2048], userid[2048], pass[2048], lastlogin[2048], sex, email[2048], error_message[2048], last_ip[2048], memo[2048]; time_t ban_until_time; time_t connect_until_time; char t_uid[256]; mysql_init(&mysql_handle); if(!mysql_real_connect(&mysql_handle, db_server_ip, db_server_id, db_server_pw, db_server_logindb ,db_server_port, (char *)NULL, 0)) { //pointer check printf("%s\n",mysql_error(&mysql_handle)); exit(1); } else { printf ("Connect: Success!\n"); } printf ("Convert start...\n"); fp=fopen("save/account.txt","r"); auth_dat = (struct auth_dat_*)malloc(sizeof(auth_dat[0])*256); if(fp==NULL) return 0; while(fgets(line,1023,fp)!=NULL) { if(line[0]=='/' && line[1]=='/') continue; i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t" "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]\t%ld%n", &account_id, userid, pass, lastlogin, &sex, &logincount, &state, email, error_message, &connect_until_time, last_ip, memo, &ban_until_time, &n); sprintf(tmpsql, "SELECT `%s`,`%s`,`%s`,`lastlogin`,`logincount`,`sex`,`connect_until`,`last_ip`,`ban_until`,`state`" " FROM `%s` WHERE `%s`='%s'", login_account_id, login_userid, login_user_pass, login_db, login_userid, t_uid); if(mysql_query(&mysql_handle, tmpsql) ) { printf("DB server Error - %s\n", mysql_error(&mysql_handle) ); } user_level = isGM(account_id); printf ("userlevel: %s (%d)- %d\n",userid, account_id, user_level); sql_res = mysql_store_result(&mysql_handle) ; sql_row = mysql_fetch_row(sql_res); //row fetching if (!sql_row) //no row -> insert sprintf(tmpsql, "INSERT INTO `login` (`account_id`, `userid`, `user_pass`, `lastlogin`, `sex`, `logincount`, `email`, `level`) VALUES (%d, '%s', '%s', '%s', '%c', %d, 'user@athena', %d);",account_id , userid, pass,lastlogin,sex,logincount, user_level); else //row reside -> updating sprintf(tmpsql, "UPDATE `login` SET `account_id`='%d', `userid`='%s', `user_pass`='%s', `lastlogin`='%s', `sex`='%c', `logincount`='%d', `email`='user@athena', `level`='%d'\nWHERE `account_id`='%d';",account_id , userid, pass,lastlogin,sex,logincount, user_level, account_id); printf ("Query: %s\n",tmpsql); mysql_free_result(sql_res) ; //resource free if(mysql_query(&mysql_handle, tmpsql) ) { printf("DB server Error - %s\n", mysql_error(&mysql_handle) ); } } fclose(fp); printf ("Convert end...\n"); return 0; }
void cPlayer::mount( P_NPC pMount ) { if ( !pMount ) return; cUOSocket* socket = this->socket(); if ( !inRange( pMount, 2 ) && !isGM() ) { if ( socket ) socket->sysMessage( tr( "You are too far away to mount!" ) ); return; } if ( pMount->owner() == this || isGM() ) { unmount(); P_ITEM pMountItem = new cItem; pMountItem->Init(); pMountItem->setId( 0x915 ); pMountItem->setColor( pMount->skin() ); switch ( static_cast<unsigned short>( pMount->body() & 0x00FF ) ) { case 0xC8: pMountItem->setId( 0x3E9F ); break; // Horse case 0xE2: pMountItem->setId( 0x3EA0 ); break; // Horse case 0xE4: pMountItem->setId( 0x3EA1 ); break; // Horse case 0xCC: pMountItem->setId( 0x3EA2 ); break; // Horse case 0xD2: pMountItem->setId( 0x3EA3 ); break; // Desert Ostard case 0xDA: pMountItem->setId( 0x3EA4 ); break; // Frenzied Ostard case 0xDB: pMountItem->setId( 0x3EA5 ); break; // Forest Ostard case 0xDC: pMountItem->setId( 0x3EA6 ); break; // LLama case 0x34: pMountItem->setId( 0x3E9F ); break; // Brown Horse case 0x4E: pMountItem->setId( 0x3EA0 ); break; // Grey Horse case 0x50: pMountItem->setId( 0x3EA1 ); break; // Tan Horse case 0x74: pMountItem->setId( 0x3EB5 ); break; // Nightmare case 0x75: pMountItem->setId( 0x3EA8 ); break; // Silver Steed case 0x72: pMountItem->setId( 0x3EA9 ); break; // Dark Steed case 0x7A: pMountItem->setId( 0x3EB4 ); break; // Unicorn case 0x84: pMountItem->setId( 0x3EAD ); break; // Kirin case 0x73: pMountItem->setId( 0x3EAA ); break; // Etheral case 0x76: pMountItem->setId( 0x3EB2 ); break; // War Horse-Brit case 0x77: pMountItem->setId( 0x3EB1 ); break; // War Horse-Mage Council case 0x78: pMountItem->setId( 0x3EAF ); break; // War Horse-Minax case 0x79: pMountItem->setId( 0x3EB0 ); break; // War Horse-Shadowlord case 0xAA: pMountItem->setId( 0x3EAB ); break; // Etheral LLama case 0x3A: pMountItem->setId( 0x3EA4 ); break; // Forest Ostard case 0x39: pMountItem->setId( 0x3EA3 ); break; // Desert Ostard case 0x3B: pMountItem->setId( 0x3EA5 ); break; // Frenzied Ostard case 0x90: pMountItem->setId( 0x3EB3 ); break; // Seahorse case 0xAB: pMountItem->setId( 0x3EAC ); break; // Etheral Ostard case 0xBB: pMountItem->setId( 0x3EB8 ); break; // Ridgeback case 0x17: pMountItem->setId( 0x3EBC ); break; // giant beetle case 0x19: pMountItem->setId( 0x3EBB ); break; // skeletal mount case 0x1a: pMountItem->setId( 0x3EBD ); break; // swamp dragon case 0x1f: pMountItem->setId( 0x3EBE ); break; // armor dragon } this->addItem( cBaseChar::Mount, pMountItem ); pMountItem->setTag( "pet", cVariant( pMount->serial() ) ); pMountItem->update(); // if this is a gm lets tame the animal in the process if ( isGM() ) { pMount->setOwner( this ); } // remove it from screen! pMount->bark( Bark_Idle ); pMount->removeFromView( false ); pMount->fight( 0 ); pMount->setStablemasterSerial( serial_ ); } else socket->sysMessage( tr( "You dont own that creature." ) ); }
int convert_login(void) { Sql* mysql_handle; SqlStmt* stmt; int line_counter = 0; FILE *fp; int account_id, logincount, user_level, state, n, i; char line[2048], userid[2048], pass[2048], lastlogin[2048], sex, email[2048], error_message[2048], last_ip[2048], memo[2048]; int ban_until_time, connect_until_time; char dummy[2048]; mysql_handle = Sql_Malloc(); if ( SQL_ERROR == Sql_Connect(mysql_handle, db_server_id, db_server_pw, db_server_ip, db_server_port, db_server_logindb) ) { Sql_ShowDebug(mysql_handle); Sql_Free(mysql_handle); exit(EXIT_FAILURE); } ShowStatus("Connect: Success!\n"); ShowStatus("Convert start...\n"); fp = fopen(ACCOUNT_TXT_NAME,"r"); if(fp == NULL) return 0; while(fgets(line,sizeof(line),fp) != NULL) { line_counter++; if(line[0]=='/' && line[1]=='/') continue; i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t%[^\t]\t%[^\t]\t%d\t%[^\t]\t%[^\t]\t%d\t%[^\r\n]%n", &account_id, userid, pass, lastlogin, &sex, &logincount, &state, email, error_message, &connect_until_time, last_ip, memo, &ban_until_time, dummy, &n); if (i < 13) { ShowWarning("Skipping incompatible data on line %d\n", line_counter); continue; } if (i > 13) ShowWarning("Reading login account variables is not implemented, data will be lost! (line %d)\n", line_counter); user_level = isGM(account_id); ShowInfo("Converting user (id: %d, name: %s, gm level: %d)\n", account_id, userid, user_level); stmt = SqlStmt_Malloc(mysql_handle); if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `login` " "(`account_id`, `userid`, `user_pass`, `lastlogin`, `sex`, `logincount`, `email`, `level`, `error_message`, `connect_until`, `last_ip`, `memo`, `ban_until`, `state`) " "VALUES " "(%d, ?, ?, '%s', '%c', %d, '%s', %d, '%s', %d, '%s', '%s', %d, %d)", account_id, lastlogin, sex, logincount, email, user_level, error_message, connect_until_time, last_ip, memo, ban_until_time, state) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_STRING, userid, strnlen(userid, 255)) || SQL_ERROR == SqlStmt_BindParam(stmt, 1, SQLDT_STRING, pass, strnlen(pass, 32)) || SQL_ERROR == SqlStmt_Execute(stmt) ) { SqlStmt_ShowDebug(stmt); } SqlStmt_Free(stmt); //TODO: parse the rest of the line to read the login-stored account variables, and import them to `global_reg_value` // then remove the 'dummy' buffer } fclose(fp); Sql_Free(mysql_handle); ShowStatus("Convert end...\n"); return 0; }
void CUser::Chat(Packet & pkt) { Packet result(WIZ_CHAT); uint8 type = pkt.read<uint8>(); char finalstr[1024] = ""; std::string buff, chatstr; bool isAnnouncement = false; if (isMuted()) return; pkt >> chatstr; if (chatstr.empty() || chatstr.size() > 128) return; // Process GM commands if (isGM() && ProcessChatCommand(chatstr)) return; #if 0 // Removed this - all it seems to do is cause chat to break for GMs (is it 19xx+ only?) if( isGM() && type == GENERAL_CHAT) type = 0x14; #endif uint8 bNation = GetNation(); uint16 sessID = GetSocketID(); // Handle GM notice & announcement commands if (type == PUBLIC_CHAT || type == ANNOUNCEMENT_CHAT) { // Trying to use a GM command without authorisation? Bad player! if (!isGM()) return; if (type == ANNOUNCEMENT_CHAT) type = WAR_SYSTEM_CHAT; // This is horrible, but we'll live with it for now. // Pull the notice string (#### NOTICE : %s ####) from the database. CString noticeText = g_pMain->GetServerResource(IDP_ANNOUNCEMENT); // Format the chat string around it, so our chat data is within the notice sprintf_s(finalstr, sizeof(finalstr), noticeText, chatstr.c_str()); bNation = KARUS; // arbitrary nation sessID = -1; isAnnouncement = true; } result.SByte(); result << type << bNation << sessID; if (isAnnouncement) { result << uint8(0); // GM notice/announcements show no name (so specify length of 0) result.DByte(); result << finalstr; // now tack on the formatted message from the user } else { result << m_pUserData.m_id; // everything else provides a name result.DByte(); result << chatstr; // now tack on the chat message from the user } switch (type) { case GENERAL_CHAT: g_pMain->Send_NearRegion(&result, GetMap(), GetRegionX(), GetRegionZ(), GetX(), GetZ()); break; case PRIVATE_CHAT: { if (m_sPrivateChatUser == GetSocketID()) break; CUser *pUser = g_pMain->GetUserPtr(m_sPrivateChatUser); if (pUser != NULL) pUser->Send(&result); } break; case PARTY_CHAT: if (isInParty()) g_pMain->Send_PartyMember(m_sPartyIndex, &result); break; case SHOUT_CHAT: if (m_pUserData.m_sMp < (m_iMaxMp / 5)) break; // Characters under level 35 require 3,000 coins to shout. if (!isGM() && GetLevel() < 35 && !GoldLose(SHOUT_COIN_REQUIREMENT)) break; MSpChange(-(m_iMaxMp / 5)); SendToRegion(&result); break; case KNIGHTS_CHAT: if (isInClan()) g_pMain->Send_KnightsMember(GetClanID(), &result); break; case PUBLIC_CHAT: case ANNOUNCEMENT_CHAT: if (isGM()) g_pMain->Send_All(&result); break; case COMMAND_CHAT: if (getFame() == COMMAND_CAPTAIN) g_pMain->Send_CommandChat(&result, m_pUserData.m_bNation, this); break; case MERCHANT_CHAT: if (isMerchanting()) SendToRegion(&result); break; case WAR_SYSTEM_CHAT: if (isGM()) g_pMain->Send_All(&result); break; } }
bool CUser::CanChangeZone(C3DMap * pTargetMap, ZoneChangeError & errorReason) { // While unofficial, game masters should be allowed to teleport anywhere. if (isGM()) return true; // Generic error reason; this should only be checked when the method returns false. errorReason = ZoneChangeErrorGeneric; // Ensure the user meets the zone's level requirements if (GetLevel() < pTargetMap->GetMinLevelReq() || GetLevel() > pTargetMap->GetMaxLevelReq()) { errorReason = ZoneChangeErrorWrongLevel; return false; } switch (pTargetMap->GetID()) { case ZONE_ELMORAD: case ZONE_KARUS: // Users may enter Luferson (1)/El Morad (2) if they are that nation, if (GetNation() == pTargetMap->GetID()) return true; // Users may also enter if there's a war invasion happening in that zone. if (GetNation() == KARUS) return g_pMain->m_byElmoradOpenFlag; else return g_pMain->m_byKarusOpenFlag; case ZONE_KARUS_ESLANT: return GetNation() == KARUS; case ZONE_ELMORAD_ESLANT: return GetNation() == ELMORAD; // Delos (30) may be entered by anybody, unless CSW is started -- in which case, it should only allow members of the clans competing for the castle (right?). case ZONE_DELOS: // TO-DO: implement CSW logic return true; // Bifrost (31) may only be entered if the zone is open by the event. // If it's open, it should only be open for the zone in control of the monument in the first stage. // After that, it's open to both zones (note: this extended logic won't be implemented until we actually implement the event -- #84). case ZONE_BIFROST: // TO-DO: implement Bifrost logic return true; case ZONE_RONARK_LAND: case ZONE_ARDREAM: // PVP zones such as Ronark Land/Ardream (do we include both?) may only be entered if a war is not started. if (g_pMain->m_byBattleOpen != NO_BATTLE) { errorReason = ZoneChangeErrorWarActive; return false; } // They may also not be entered if the user has no NP. if (GetLoyalty() <= 0) { errorReason = ZoneChangeErrorNeedLoyalty; return false; } break; default: // War zones may only be entered if that war zone is active. if (pTargetMap->isWarZone()) { if ((ZONE_BATTLE_BASE - pTargetMap->GetID()) != g_pMain->m_byBattleZone) return false; } } return true; }