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); } }
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; } }
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; } }
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); } }
short Unit::GetMagicDamage(int damage, Unit *pTarget) { short total_r, temp_damage = 0; if (pTarget->isDead()) return 0; if (m_bMagicTypeRightHand > 4 && m_bMagicTypeRightHand < 8) temp_damage = damage * m_sMagicAmountRightHand / 100; switch (m_bMagicTypeRightHand) { // RIGHT HAND!!! case ITEM_TYPE_FIRE : // Fire Damage total_r = pTarget->m_bFireR + pTarget->m_bFireRAmount; break; case ITEM_TYPE_COLD : // Ice Damage total_r = pTarget->m_bColdR + pTarget->m_bColdRAmount; break; case ITEM_TYPE_LIGHTNING : // Lightning Damage total_r = pTarget->m_bLightningR + pTarget->m_bLightningRAmount; break; case ITEM_TYPE_POISON : // Poison Damage total_r = pTarget->m_bPoisonR + pTarget->m_bPoisonRAmount; break; case ITEM_TYPE_HP_DRAIN : // HP Drain HpChange(temp_damage); break; case ITEM_TYPE_MP_DAMAGE : // MP Damage pTarget->MSpChange(-temp_damage); break; case ITEM_TYPE_MP_DRAIN : // MP Drain MSpChange(temp_damage); break; } total_r += pTarget->m_bResistanceBonus; if (m_bMagicTypeRightHand > 0 && m_bMagicTypeRightHand < 5) { if (total_r > 200) total_r = 200; temp_damage = m_sMagicAmountRightHand - m_sMagicAmountRightHand * total_r / 200; damage += temp_damage; } total_r = 0; // Reset all temporary data. temp_damage = 0; if (m_bMagicTypeLeftHand > 4 && m_bMagicTypeLeftHand < 8) temp_damage = damage * m_sMagicAmountLeftHand / 100; switch (m_bMagicTypeLeftHand) { // LEFT HAND!!! case ITEM_TYPE_FIRE : // Fire Damage total_r = pTarget->m_bFireR + pTarget->m_bFireRAmount; break; case ITEM_TYPE_COLD : // Ice Damage total_r = pTarget->m_bColdR + pTarget->m_bColdRAmount; break; case ITEM_TYPE_LIGHTNING : // Lightning Damage total_r = pTarget->m_bLightningR + pTarget->m_bLightningRAmount; break; case ITEM_TYPE_POISON : // Poison Damage total_r = pTarget->m_bPoisonR + pTarget->m_bPoisonRAmount; break; case ITEM_TYPE_HP_DRAIN : // HP Drain HpChange(temp_damage); break; case ITEM_TYPE_MP_DAMAGE : // MP Damage pTarget->MSpChange(-temp_damage); break; case ITEM_TYPE_MP_DRAIN : // MP Drain MSpChange(temp_damage); break; } total_r += pTarget->m_bResistanceBonus; if (m_bMagicTypeLeftHand > 0 && m_bMagicTypeLeftHand < 5) { if (total_r > 200) total_r = 200; temp_damage = m_sMagicAmountLeftHand - m_sMagicAmountLeftHand * total_r / 200; damage += temp_damage; } total_r = 0; // Reset all temporary data. temp_damage = 0; // Mirror Attack Check routine. if (pTarget->m_bMagicTypeLeftHand == ITEM_TYPE_MIRROR_DAMAGE) { temp_damage = damage * pTarget->m_sMagicAmountLeftHand / 100; HpChange(-temp_damage); // Reflective Hit. } return damage; }