/** * @brief Checks if all players in the party have sCount of item nItemID * and if so, removes it. * * @param nItemID Identifier for the item. * @param sCount Stack size. * * @return true if the required items were taken, false if not. */ bool CUser::RobAllItemParty(uint32 nItemID, uint16 sCount /*= 1*/) { _PARTY_GROUP * pParty = g_pMain->GetPartyPtr(GetPartyID()); if (pParty == nullptr) return RobItem(nItemID, sCount); // First check to see if all users in the party have enough of the specified item. vector<CUser *> partyUsers; for (int i = 0; i < MAX_PARTY_USERS; i++) { CUser * pUser = g_pMain->GetUserPtr(pParty->uid[i]); if (pUser != nullptr && !pUser->CheckExistItem(nItemID, sCount)) return false; partyUsers.push_back(pUser); } // Since all users have the required item, we can now remove them. foreach (itr, partyUsers) (*itr)->RobItem(nItemID, sCount); return true; }
void CUser::Regene(uint8 regene_type, uint32 magicid /*= 0*/) { ASSERT(GetMap() != nullptr); _OBJECT_EVENT* pEvent = nullptr; _HOME_INFO* pHomeInfo = nullptr; float x = 0.0f, z = 0.0f; if (!isDead()) return; if (regene_type != 1 && regene_type != 2) regene_type = 1; if (regene_type == 2) { magicid = 490041; // The Stone of Ressurection magic ID // Is our level high enough to be able to resurrect using this skill? if (GetLevel() <= 5 // Do we have enough resurrection stones? || !RobItem(379006000, 3 * GetLevel())) return; } // If we're in a home zone, we'll want the coordinates from there. Otherwise, assume our own home zone. pHomeInfo = g_pMain->m_HomeArray.GetData(GetZoneID() <= ZONE_ELMORAD ? GetZoneID() : GetNation()); if (pHomeInfo == nullptr) return; UserInOut(INOUT_OUT); pEvent = GetMap()->GetObjectEvent(m_sBind); // If we're not using a spell to resurrect. if (magicid == 0) { // Resurrect at a bind/respawn point if (pEvent != nullptr && pEvent->byLife == 1) { SetPosition(pEvent->fPosX + x, 0.0f, pEvent->fPosZ + z); } // Are we trying to respawn in a home zone? else if (GetZoneID() <= ZONE_ELMORAD) { // Use the proper respawn area for our nation, as the opposite nation can // enter this zone at a war's invasion stage. if (GetNation() == KARUS) { x = (float)(pHomeInfo->KarusZoneX + myrand(0, pHomeInfo->KarusZoneLX)); z = (float)(pHomeInfo->KarusZoneZ + myrand(0, pHomeInfo->KarusZoneLZ)); } else { x = (float)(pHomeInfo->ElmoZoneX + myrand(0, pHomeInfo->ElmoZoneLX)); z = (float)(pHomeInfo->ElmoZoneZ + myrand(0, pHomeInfo->ElmoZoneLZ)); } } else { // If we're in a war zone (aside from snow wars, which apparently use different coords), use BattleZone coordinates. if (GetZoneID() != ZONE_SNOW_BATTLE && GetZoneID() == (ZONE_BATTLE_BASE + g_pMain->m_byBattleZone)) { x = (float)(pHomeInfo->BattleZoneX + myrand(0, pHomeInfo->BattleZoneLX)); z = (float)(pHomeInfo->BattleZoneZ + myrand(0, pHomeInfo->BattleZoneLZ)); } // If we died in the Moradon arena, we need to spawn near the Arena. else if (GetZoneID() == ZONE_MORADON && isInArena()) { x = (float)(MINI_ARENA_RESPAWN_X + myrand(-MINI_ARENA_RESPAWN_RADIUS, MINI_ARENA_RESPAWN_RADIUS)); z = (float)(MINI_ARENA_RESPAWN_Z + myrand(-MINI_ARENA_RESPAWN_RADIUS, MINI_ARENA_RESPAWN_RADIUS)); } // For all else, just grab the start position (/town coordinates) from the START_POSITION table. else { short sx, sz; GetStartPosition(sx, sz); x = sx; z = sz; } } SetPosition(x, 0.0f, z); m_bResHpType = USER_STANDING; m_bRegeneType = REGENE_NORMAL; } else // we're respawning using a resurrect skill. { _MAGIC_TYPE5 * pType = g_pMain->m_Magictype5Array.GetData(magicid); if (pType == nullptr) return; MSpChange(-m_iMaxMp); // reset us to 0 MP. if (m_sWhoKilledMe == -1) ExpChange((m_iLostExp * pType->bExpRecover) / 100); // Restore m_bResHpType = USER_STANDING; m_bRegeneType = REGENE_MAGIC; } Packet result(WIZ_REGENE); result << GetSPosX() << GetSPosZ() << GetSPosY(); Send(&result); HpChange(GetMaxHealth()); m_tLastRegeneTime = UNIXTIME; m_sWhoKilledMe = -1; m_iLostExp = 0; if (magicid == 0) BlinkStart(); if (!isBlinking()) { result.Initialize(AG_USER_REGENE); result << GetSocketID() << m_sHp; Send_AIServer(&result); } SetRegion(GetNewRegionX(), GetNewRegionZ()); UserInOut(INOUT_RESPAWN); g_pMain->RegionUserInOutForMe(this); g_pMain->RegionNpcInfoForMe(this); InitializeStealth(); SendUserStatusUpdate(USER_STATUS_DOT, USER_STATUS_CURE); SendUserStatusUpdate(USER_STATUS_POISON, USER_STATUS_CURE); if (isInArena()) SendUserStatusUpdate(USER_STATUS_SPEED, USER_STATUS_CURE); RecastSavedMagic(); // If we actually respawned (i.e. we weren't resurrected by a skill)... if (magicid == 0) { // In PVP zones (not war zones), we must kick out players if they no longer // have any national points. if (GetMap()->isNationPVPZone() && GetMap()->isWarZone() && GetLoyalty() == 0) KickOutZoneUser(false); } }
BOOL CUser::RunEvent(EVENT_DATA *pEventData) { EXEC* pExec = NULL; list<EXEC*>::iterator Iter; for( Iter = pEventData->m_arExec.begin(); Iter != pEventData->m_arExec.end(); Iter++ ) { pExec = (*Iter); if( !pExec ) break; switch(pExec->m_Exec){ case EXEC_SAY: SendNpcSay( pExec ); break; case EXEC_SELECT_MSG: SelectMsg( pExec ); break; case EXEC_RUN_EVENT: { EVENT* pEvent = NULL; EVENT_DATA* pEventData = NULL; pEvent = m_pMain->m_Event.GetData(m_pUserData->m_bZone); if(!pEvent) break; pEventData = pEvent->m_arEvent.GetData(pExec->m_ExecInt[0]); if(!pEventData) break; if( !CheckEventLogic(pEventData) ) break; if( !RunEvent(pEventData) ){ return FALSE; } } break; case EXEC_GIVE_ITEM: if ( !GiveItem(pExec->m_ExecInt[0], pExec->m_ExecInt[1]) ) return FALSE; break; case EXEC_ROB_ITEM: if ( !RobItem(pExec->m_ExecInt[0], pExec->m_ExecInt[1]) ) return FALSE; break; case EXEC_GIVE_NOAH: GoldGain(pExec->m_ExecInt[0]); break; case EXEC_SAVE_COM_EVENT: SaveComEvent(pExec->m_ExecInt[0]); break; case EXEC_ROB_NOAH: GoldLose(pExec->m_ExecInt[0]); break; // case EXEC_RETURN: return FALSE; break; /* case EXEC_SAY: break; case EXEC_SELECT_MSG: SelectMsg( pExec ); break; case EXEC_RUN_EVENT: { EVENT* pEvent = NULL; pEvent = m_pMain->m_Quest.GetData(m_pUserData->m_bZone); if(!pEvent) break; EVENT_DATA* pEventData = NULL; pEventData = pEvent->m_arEvent.GetData(pExec->m_ExecInt[0]); if(!pEventData) break; if( !CheckEventLogic(pEventData) ) break; if( !RunEvent(pEventData) ) { return FALSE; } } break; case EXEC_ROB_NOAH: break; case EXEC_GIVE_QUEST: break; case EXEC_QUEST_END: break; case EXEC_QUEST_SAVE: break; case EXEC_RETURN: return FALSE; /////// These events are for the test quest. /////// case EXEC_ROB_ITEM: if (!RobItem(pExec->m_ExecInt[0], pExec->m_ExecInt[1])) { return FALSE; } break; case EXEC_GIVE_ITEM: if (!GiveItem(pExec->m_ExecInt[0], pExec->m_ExecInt[1])) { return FALSE; } break; */ default: break; } } return TRUE; }
void CUser::Regene(uint8 regene_type, uint32 magicid /*= 0*/) { ASSERT(GetMap() != NULL); CUser* pUser = NULL; _OBJECT_EVENT* pEvent = NULL; _HOME_INFO* pHomeInfo = NULL; _MAGIC_TYPE5* pType = NULL; if (!isDead()) return; InitType3(); InitType4(); if (regene_type != 1 && regene_type != 2) { regene_type = 1; } if (regene_type == 2) { magicid = 490041; // The Stone of Ressurection magic ID if (!RobItem(379006000, 3 * GetLevel())) { return; // Subtract resurrection stones. } if (GetLevel() <= 5) { return; // 5 level minimum. } } pHomeInfo = g_pMain->m_HomeArray.GetData(m_pUserData->m_bNation); if (!pHomeInfo) return; UserInOut(INOUT_OUT); float x = 0.0f, z = 0.0f; x = (float)(myrand( 0, 400 )/100.0f); z = (float)(myrand( 0, 400 )/100.0f); if( x < 2.5f ) x = 1.5f + x; if( z < 2.5f ) z = 1.5f + z; pEvent = GetMap()->GetObjectEvent(m_pUserData->m_sBind); // TO-DO: Clean this entire thing up. Wow. if (magicid == 0) { if( pEvent && pEvent->byLife == 1 ) { // Bind Point m_pUserData->m_curx = pEvent->fPosX + x; m_pUserData->m_curz = pEvent->fPosZ + z; m_pUserData->m_cury = 0; } else if( m_pUserData->m_bNation != m_pUserData->m_bZone) { // Free Zone or Opposite Zone if(m_pUserData->m_bZone > 200) { // Frontier Zone... x = (float)(pHomeInfo->FreeZoneX + myrand(0, pHomeInfo->FreeZoneLX)); z = (float)(pHomeInfo->FreeZoneZ + myrand(0, pHomeInfo->FreeZoneLZ)); } // else if(m_pUserData->m_bZone > 100 && m_pUserData->m_bZone < 200) { // Battle Zone... /* m_bResHpType = USER_STANDING; HpChange( m_iMaxHp ); KickOutZoneUser(); // Go back to your own zone! return; */ x = (float)(pHomeInfo->BattleZoneX + myrand(0, pHomeInfo->BattleZoneLX)); z = (float)(pHomeInfo->BattleZoneZ + myrand(0, pHomeInfo->BattleZoneLZ)); if (m_pUserData->m_bZone == ZONE_SNOW_BATTLE) { x = (float)(pHomeInfo->FreeZoneX + myrand(0, pHomeInfo->FreeZoneLX)); z = (float)(pHomeInfo->FreeZoneZ + myrand(0, pHomeInfo->FreeZoneLZ)); } } else if (m_pUserData->m_bZone > 10 && m_pUserData->m_bZone < 20) { x = (float)(527 + myrand(0, 10)); z = (float)(543 + myrand(0, 10)); } else if (m_pUserData->m_bZone < 3) { // Specific Lands... if (m_pUserData->m_bNation == KARUS) { x = (float)(pHomeInfo->ElmoZoneX + myrand(0, pHomeInfo->ElmoZoneLX)); z = (float)(pHomeInfo->ElmoZoneZ + myrand(0, pHomeInfo->ElmoZoneLZ)); } else if (m_pUserData->m_bNation == ELMORAD) { x = (float)(pHomeInfo->KarusZoneX + myrand(0, pHomeInfo->KarusZoneLX)); z = (float)(pHomeInfo->KarusZoneZ + myrand(0, pHomeInfo->KarusZoneLZ)); } else return; } else { short sx, sz; GetStartPosition(sx, sz); x = sx; z = sz; } m_pUserData->m_curx = x; m_pUserData->m_curz = z; } else { if (m_pUserData->m_bNation == KARUS) { x = (float)(pHomeInfo->KarusZoneX + myrand(0, pHomeInfo->KarusZoneLX)); z = (float)(pHomeInfo->KarusZoneZ + myrand(0, pHomeInfo->KarusZoneLZ)); } else if (m_pUserData->m_bNation == ELMORAD) { x = (float)(pHomeInfo->ElmoZoneX + myrand(0, pHomeInfo->ElmoZoneLX)); z = (float)(pHomeInfo->ElmoZoneZ + myrand(0, pHomeInfo->ElmoZoneLZ)); } else return; m_pUserData->m_curx = x; m_pUserData->m_curz = z; } } Packet result(WIZ_REGENE); result << GetSPosX() << GetSPosZ() << GetSPosY(); Send(&result); if (magicid > 0) { // Clerical Resurrection. pType = g_pMain->m_Magictype5Array.GetData(magicid); if ( !pType ) return; m_bResHpType = USER_STANDING; MSpChange(-m_iMaxMp); // Empty out MP. if (m_sWhoKilledMe == -1 && regene_type == 1) { ExpChange((m_iLostExp * pType->bExpRecover) / 100); // Restore Target Experience. } m_bRegeneType = REGENE_MAGIC; } else { // Normal Regene. // m_bAbnormalType = ABNORMAL_BLINKING; // m_bResHpType = USER_STANDING; m_bRegeneType = REGENE_NORMAL; } HpChange(m_iMaxHp); m_fLastRegeneTime = TimeGet(); m_sWhoKilledMe = -1; m_iLostExp = 0; if (!isBlinking()) { result.Initialize(AG_USER_REGENE); result << GetSocketID() << m_pUserData->m_sHp; g_pMain->Send_AIServer(&result); } SetRegion(GetNewRegionX(), GetNewRegionZ()); UserInOut(INOUT_RESPAWN); g_pMain->RegionUserInOutForMe(this); g_pMain->RegionNpcInfoForMe(this); BlinkStart(); if (isInParty()) { // TO-DO: Wrap these up into Party-specific methods (nothing for that yet) // UPDATE: Sticking them in the CUser class for the moment. Need to have them make sense, though. if (!m_bType3Flag) SendPartyStatusUpdate(1); if (!m_bType4Flag) SendPartyStatusUpdate(2); } }
bool CUser::RunExchange(int nExchangeID) { _ITEM_EXCHANGE * pExchange = g_pMain->m_ItemExchangeArray.GetData(nExchangeID); // Does the exchange exist? if (pExchange == nullptr // Is it a valid exchange (do we have room?) || !CheckExchange(nExchangeID) // We handle flags from 0-101 only. Anything else is broken. || pExchange->bRandomFlag > 101 // Do we have all of the required items? || !CheckExistItemAnd( pExchange->nOriginItemNum[0], pExchange->sOriginItemCount[0], pExchange->nOriginItemNum[1], pExchange->sOriginItemCount[1], pExchange->nOriginItemNum[2], pExchange->sOriginItemCount[2], pExchange->nOriginItemNum[3], pExchange->sOriginItemCount[3], pExchange->nOriginItemNum[4], pExchange->sOriginItemCount[4]) // These checks are a little pointless, but remove the required items as well. || !RobItem(pExchange->nOriginItemNum[0], pExchange->sOriginItemCount[0]) || !RobItem(pExchange->nOriginItemNum[1], pExchange->sOriginItemCount[1]) || !RobItem(pExchange->nOriginItemNum[2], pExchange->sOriginItemCount[2]) || !RobItem(pExchange->nOriginItemNum[3], pExchange->sOriginItemCount[3]) || !RobItem(pExchange->nOriginItemNum[4], pExchange->sOriginItemCount[4])) return false; // No random element? We're just exchanging x items for y items. if (!pExchange->bRandomFlag) { for (int i = 0; i < ITEMS_IN_EXCHANGE_GROUP; i++) GiveItem(pExchange->nExchangeItemNum[i], pExchange->sExchangeItemCount[i]); } // For these items the rate set by bRandomFlag. else if (pExchange->bRandomFlag <= 100) { int rand = myrand(0, 1000 * pExchange->bRandomFlag) / 1000; if (rand == 5) rand = 4; if (rand <= 4) GiveItem(pExchange->nExchangeItemNum[rand], pExchange->sExchangeItemCount[rand]); } // For 101, the rates are determined by sExchangeItemCount. else if (pExchange->bRandomFlag == 101) { uint32 nTotalPercent = 0; for (int i = 0; i < ITEMS_IN_EXCHANGE_GROUP; i++) nTotalPercent += pExchange->sExchangeItemCount[i]; // If they add up to more than 100%, if (nTotalPercent > 10000) { TRACE("Exchange %d is invalid. Rates add up to more than 100%% (%d%%)", nExchangeID, nTotalPercent / 100); return false; } // Holy stack batman! We're just going ahead and copying official for now. // NOTE: Officially they even use 2 bytes per element. Yikes. uint8 bRandArray[10000]; memset(&bRandArray, 0, sizeof(bRandArray)); // default to 0 in case it's lower than 100% (in which case, first item's rate increases) // Copy the counts, as we're going to adjust them locally. uint16 sExchangeCount[ITEMS_IN_EXCHANGE_GROUP]; memcpy(&sExchangeCount, &pExchange->sExchangeItemCount, sizeof(pExchange->sExchangeItemCount)); // Build array of exchange item slots (0-4) int offset = 0; for (int n = 0, i = 0; n < 5; n++) { if (sExchangeCount[n] > 0) { memset(&bRandArray[offset], n, sExchangeCount[n]); offset += sExchangeCount[n]; } } // Pull our exchange item slot out of our hat (the array we generated). uint8 bRandSlot = bRandArray[myrand(0, 9999)]; uint32 nItemID = pExchange->nExchangeItemNum[bRandSlot]; // Finally, give our item. GiveItem(nItemID, 1); } return true; }