void CMagicState::CharAfterFinish() { if(m_PEntity->objtype != TYPE_PC) { return; } CCharEntity* PChar = (CCharEntity*)m_PEntity; charutils::RemoveStratagems(PChar, m_PSpell); charutils::UpdateHealth(PChar); // only skill up if the effect landed if(m_PSpell->tookEffect()){ charutils::TrySkillUP(PChar, (SKILLTYPE)m_PSpell->getSkillType(), m_PTarget->GetMLevel()); if (m_PSpell->getSkillType() == SKILL_SNG) { CItemWeapon* PItem = (CItemWeapon*)PChar->getEquip(SLOT_RANGED); if (PItem && PItem->isType(ITEM_ARMOR)) { SKILLTYPE Skilltype = (SKILLTYPE)PItem->getSkillType(); if (Skilltype == SKILL_STR || Skilltype == SKILL_WND || Skilltype == SKILL_SNG) { charutils::TrySkillUP(PChar, Skilltype, m_PTarget->GetMLevel()); } } } } PChar->pushPacket(new CCharUpdatePacket(PChar)); // make wyvern use breath if(PChar->PPet!=NULL && ((CPetEntity*)PChar->PPet)->getPetType() == PETTYPE_WYVERN) { ((CAIPetDummy*)PChar->PPet->PBattleAI)->m_MasterCommand = MASTERCOMMAND_HEALING_BREATH; PChar->PPet->PBattleAI->SetCurrentAction(ACTION_MOBABILITY_START); } SetHiPCLvl(m_PTarget, PChar->GetMLevel()); }
void CParty::RefreshSync() { CCharEntity* sync = (CCharEntity*)m_PSyncTarget; uint8 syncLevel = sync->jobs.job[sync->GetMJob()]; if (syncLevel < 10) { SetSyncTarget(NULL, 554); } for (uint32 i = 0; i < members.size(); ++i) { if(members.at(i)->objtype != TYPE_PC) continue; CCharEntity* member = (CCharEntity*)members.at(i); uint8 NewMLevel = 0; if (syncLevel < member->jobs.job[member->GetMJob()]) { NewMLevel = syncLevel; }else{ NewMLevel = member->jobs.job[member->GetMJob()]; } if (member->GetMLevel() != NewMLevel) { charutils::RemoveAllEquipMods(member); member->SetMLevel(NewMLevel); member->SetSLevel(member->jobs.job[member->GetSJob()]); charutils::ApplyAllEquipMods(member); blueutils::ValidateBlueSpells(member); charutils::BuildingCharSkillsTable(member); charutils::CalculateStats(member); charutils::BuildingCharTraitsTable(member); charutils::BuildingCharAbilityTable(member); charutils::CheckValidEquipment(member); // Handles rebuilding weapon skills as well. } member->pushPacket(new CMessageBasicPacket(member, member, 0, syncLevel, 540)); } m_PSyncTarget = sync; }
void CMobEntity::DropItems() { CCharEntity* PChar = (CCharEntity*)GetEntity(m_OwnerID.targid, TYPE_PC); if (PChar != nullptr && PChar->id == m_OwnerID.id) { loc.zone->PushPacket(this, CHAR_INRANGE, new CMessageBasicPacket(PChar, this, 0, 0, MSGBASIC_DEFEATS_TARG)); if (!CalledForHelp()) { blueutils::TryLearningSpells(PChar, this); m_UsedSkillIds.clear(); if (m_giveExp) { charutils::DistributeExperiencePoints(PChar, this); } DropList_t* DropList = itemutils::GetDropList(m_DropID); //ShowDebug(CL_CYAN"DropID: %u dropping with TH Level: %u\n" CL_RESET, PMob->m_DropID, PMob->m_THLvl); if (DropList != nullptr && !getMobMod(MOBMOD_NO_DROPS) && DropList->size()) { for (uint8 i = 0; i < DropList->size(); ++i) { //THLvl is the number of 'extra chances' at an item. If the item is obtained, then break out. uint8 tries = 0; uint8 maxTries = 1 + (m_THLvl > 2 ? 2 : m_THLvl); uint8 bonus = (m_THLvl > 2 ? (m_THLvl - 2) * 10 : 0); while (tries < maxTries) { if (dsprand::GetRandomNumber(1000) < DropList->at(i).DropRate * map_config.drop_rate_multiplier + bonus) { PChar->PTreasurePool->AddItem(DropList->at(i).ItemID, this); break; } tries++; } } } // check for gil (beastmen drop gil, some NMs drop gil) if (CanDropGil() || (map_config.all_mobs_gil_bonus > 0 && getMobMod(MOBMOD_GIL_MAX) >= 0)) // Negative value of MOBMOD_GIL_MAX is used to prevent gil drops in Dynamis/Limbus. { charutils::DistributeGil(PChar, this); // TODO: REALISATION MUST BE IN TREASUREPOOL } //check for seal drops /* MobLvl >= 1 = Beastmen Seals ID=1126 >= 50 = Kindred Seals ID=1127 >= 75 = Kindred Crests ID=2955 >= 90 = High Kindred Crests ID=2956 */ uint16 Pzone = PChar->getZone(); bool validZone = ((Pzone > 0 && Pzone < 39) || (Pzone > 42 && Pzone < 134) || (Pzone > 135 && Pzone < 185) || (Pzone > 188 && Pzone < 255)); if (validZone && charutils::GetRealExp(PChar->GetMLevel(), GetMLevel()) > 0) { if (((PChar->StatusEffectContainer->HasStatusEffect(EFFECT_SIGNET) && conquest::GetInfluenceGraphics(PChar->loc.zone->GetRegionID()) < 64) || (PChar->StatusEffectContainer->HasStatusEffect(EFFECT_SANCTION) && PChar->loc.zone->GetRegionID() >= 28 && PChar->loc.zone->GetRegionID() <= 32) || (PChar->StatusEffectContainer->HasStatusEffect(EFFECT_SIGIL) && PChar->loc.zone->GetRegionID() >= 33 && PChar->loc.zone->GetRegionID() <= 40)) && m_Element > 0 && dsprand::GetRandomNumber(100) < 20) // Need to move to CRYSTAL_CHANCE constant { PChar->PTreasurePool->AddItem(4095 + m_Element, this); } // Todo: Avatarite and Geode drops during day/weather. Much higher chance during weather than day. // Item element matches day/weather element, not mob crystal. Lv80+ xp mobs can drop Avatarite. // Wiki's have conflicting info on mob lv required for Geodes. One says 50 the other 75. I think 50 is correct. if (dsprand::GetRandomNumber(100) < 20 && PChar->PTreasurePool->CanAddSeal() && !getMobMod(MOBMOD_NO_DROPS)) { //RULES: Only 1 kind may drop per mob if (GetMLevel() >= 75 && luautils::IsExpansionEnabled("ABYSSEA")) //all 4 types { switch (dsprand::GetRandomNumber(4)) { case 0: PChar->PTreasurePool->AddItem(1126, this); break; case 1: PChar->PTreasurePool->AddItem(1127, this); break; case 2: PChar->PTreasurePool->AddItem(2955, this); break; case 3: PChar->PTreasurePool->AddItem(2956, this); break; } } else if (GetMLevel() >= 70 && luautils::IsExpansionEnabled("ABYSSEA")) //b.seal & k.seal & k.crest { switch (dsprand::GetRandomNumber(3)) { case 0: PChar->PTreasurePool->AddItem(1126, this); break; case 1: PChar->PTreasurePool->AddItem(1127, this); break; case 2: PChar->PTreasurePool->AddItem(2955, this); break; } } else if (GetMLevel() >= 50) //b.seal & k.seal only { if (dsprand::GetRandomNumber(2) == 0) { PChar->PTreasurePool->AddItem(1126, this); } else { PChar->PTreasurePool->AddItem(1127, this); } } else { //b.seal only PChar->PTreasurePool->AddItem(1126, this); } } } } PChar->setWeaponSkillKill(false); StatusEffectContainer->KillAllStatusEffect(); // NOTE: this is called for all alliance / party members! luautils::OnMobDeath(this, PChar); } else { luautils::OnMobDeath(this, nullptr); } }
void TryLearningSpells(CCharEntity* PChar, CMobEntity* PMob) { if (PMob->m_UsedSkillIds.size() == 0) { // minor optimisation. return; } // prune the learnable blue spells std::vector<CSpell*> PLearnableSpells; for (std::map<uint16, uint16>::iterator i=PMob->m_UsedSkillIds.begin(); i != PMob->m_UsedSkillIds.end(); ++i) { CSpell* PSpell = spell::GetSpellByMonsterSkillId(i->first); if (PSpell != NULL) { PLearnableSpells.push_back(PSpell); } } if (PLearnableSpells.size() == 0) { return; } std::vector<CCharEntity*> PBlueMages; // populate PBlueMages if (PChar->PParty != NULL) { for (uint8 i = 0; i < PChar->PParty->members.size(); i++) { if (PChar->PParty->members[i]->GetMJob() == JOB_BLU && PChar->PParty->members[i]->objtype == TYPE_PC) { PBlueMages.push_back((CCharEntity*)PChar->PParty->members[i]); } } } else if (PChar->GetMJob() == JOB_BLU) { PBlueMages.push_back(PChar); } // loop through the list of BLUs and see if they can learn. for (int i=0; i<PBlueMages.size(); i++) { CCharEntity* PBlueMage = PBlueMages[i]; if (PBlueMage->isDead()) { // too dead to learn continue; } if (distance(PBlueMage->loc.p, PMob->loc.p) > 100) { // too far away to learn continue; } for (int spell=0; spell<PLearnableSpells.size(); spell++) { CSpell* PSpell = PLearnableSpells[spell]; if (charutils::hasSpell(PBlueMage, PSpell->getID())) { continue; } uint8 learnableLevel = PSpell->getJob(JOB_BLU); if (learnableLevel > 0 && learnableLevel < PBlueMage->GetMLevel()+7) { // TODO: Use blue magic skill check rather than level if (rand()%100 < 33) { if (charutils::addSpell(PBlueMage, PSpell->getID())) { PBlueMage->pushPacket(new CMessageBasicPacket(PBlueMage, PBlueMage, PSpell->getID(), 0, MSGBASIC_LEARNS_SPELL)); charutils::SaveSpells(PBlueMage); PBlueMage->pushPacket(new CCharSpellsPacket(PBlueMage)); } } break; // only one attempt at learning a spell, regardless of learn or not. } } } }
void CParty::SetSyncTarget(int8* MemberName, uint16 message) { CBattleEntity* PEntity = nullptr; if (MemberName) { PEntity = GetMemberByName(MemberName); } if (map_config.level_sync_enable) { if (PEntity && PEntity->objtype == TYPE_PC) { CCharEntity* PChar = (CCharEntity*)PEntity; //enable level sync if (PChar->GetMLevel() < 10) { ((CCharEntity*)GetLeader())->pushPacket(new CMessageBasicPacket((CCharEntity*)GetLeader(), (CCharEntity*)GetLeader(), 0, 10, 541)); return; } else if (PChar->getZone() != GetLeader()->getZone()) { ((CCharEntity*)GetLeader())->pushPacket(new CMessageBasicPacket((CCharEntity*)GetLeader(), (CCharEntity*)GetLeader(), 0, 0, 542)); return; } else { for (uint8 i = 0; i < members.size(); ++i) { if (members.at(i)->StatusEffectContainer->HasStatusEffect({EFFECT_LEVEL_RESTRICTION, EFFECT_LEVEL_SYNC})) { ((CCharEntity*)GetLeader())->pushPacket(new CMessageBasicPacket((CCharEntity*)GetLeader(), (CCharEntity*)GetLeader(), 0, 0, 543)); return; } } m_PSyncTarget = PChar; for (uint8 i = 0; i < members.size(); ++i) { if (members.at(i)->objtype != TYPE_PC) continue; CCharEntity* member = (CCharEntity*)members.at(i); if (member->status != STATUS_DISAPPEAR && member->getZone() == PChar->getZone()) { member->pushPacket(new CMessageStandardPacket(PChar->GetMLevel(), 0, 0, 0, message)); member->StatusEffectContainer->AddStatusEffect(new CStatusEffect( EFFECT_LEVEL_SYNC, EFFECT_LEVEL_SYNC, PChar->GetMLevel(), 0, 0), true); member->StatusEffectContainer->DelStatusEffectsByFlag(EFFECTFLAG_DISPELABLE | EFFECTFLAG_ON_ZONE); member->loc.zone->PushPacket(member, CHAR_INRANGE, new CCharSyncPacket(member)); } } Sql_Query(SqlHandle, "UPDATE accounts_parties SET partyflag = partyflag & ~%d WHERE partyid = %u AND partyflag & %d", PARTY_SYNC, m_PartyID, PARTY_SYNC); Sql_Query(SqlHandle, "UPDATE accounts_parties SET partyflag = partyflag | %d WHERE partyid = %u AND charid = '%u';", PARTY_SYNC, m_PartyID, PChar->id); } } else { if (m_PSyncTarget != nullptr) { //disable level sync for (uint8 i = 0; i < members.size(); ++i) { if (members.at(i)->objtype != TYPE_PC) continue; CCharEntity* member = (CCharEntity*)members.at(i); if (member->status != STATUS_DISAPPEAR) { CStatusEffect* sync = member->StatusEffectContainer->GetStatusEffect(EFFECT_LEVEL_SYNC); if (sync && sync->GetDuration() == 0) { member->pushPacket(new CMessageBasicPacket(member, member, 10, 30, message)); sync->SetStartTime(server_clock::now()); sync->SetDuration(30000); } } } } m_PSyncTarget = nullptr; Sql_Query(SqlHandle, "UPDATE accounts_parties SET partyflag = partyflag & ~%d WHERE partyid = %u AND partyflag & %d", PARTY_SYNC, m_PartyID, PARTY_SYNC); } } }
void CParty::SetSyncTarget(CBattleEntity* PEntity, uint16 message) { if (map_config.level_sync_enable) { if (PEntity && PEntity->objtype == TYPE_PC) { CCharEntity* PChar = (CCharEntity*)PEntity; //enable level sync if (PChar->GetMLevel() < 10 ) { ((CCharEntity*)GetLeader())->pushPacket(new CMessageBasicPacket((CCharEntity*)GetLeader(), (CCharEntity*)GetLeader(), 0, 10, 541)); return; } else if (PChar->getZone() != GetLeader()->getZone()) { ((CCharEntity*)GetLeader())->pushPacket(new CMessageBasicPacket((CCharEntity*)GetLeader(), (CCharEntity*)GetLeader(), 0, 0, 542)); return; } else { for (uint32 i = 0; i < members.size(); ++i) { if(members.at(i)->StatusEffectContainer->HasStatusEffect(EFFECT_LEVEL_RESTRICTION)) { ((CCharEntity*)GetLeader())->pushPacket(new CMessageBasicPacket((CCharEntity*)GetLeader(), (CCharEntity*)GetLeader(), 0, 0, 543)); return; } } m_PSyncTarget = PChar; for (uint32 i = 0; i < members.size(); ++i) { if(members.at(i)->objtype != TYPE_PC) continue; CCharEntity* member = (CCharEntity*)members.at(i); if (member->status != STATUS_DISAPPEAR && member->getZone() == PChar->getZone() ) { member->pushPacket(new CMessageStandardPacket(PChar->GetMLevel(), 0, 0, 0, message)); member->StatusEffectContainer->AddStatusEffect(new CStatusEffect( EFFECT_LEVEL_SYNC, EFFECT_LEVEL_SYNC, PChar->GetMLevel(), 0, 0), true); member->StatusEffectContainer->DelStatusEffectsByFlag(EFFECTFLAG_DISPELABLE); member->loc.zone->PushPacket(member, CHAR_INRANGE, new CCharSyncPacket(member)); } } } } else { if (m_PSyncTarget != NULL) { //disable level sync for (uint32 i = 0; i < members.size(); ++i) { if(members.at(i)->objtype != TYPE_PC) continue; CCharEntity* member = (CCharEntity*)members.at(i); if (member->status != STATUS_DISAPPEAR && member->getZone() == m_PSyncTarget->getZone() ) { CStatusEffect* sync = member->StatusEffectContainer->GetStatusEffect(EFFECT_LEVEL_SYNC); if (sync && sync->GetDuration() == 0) { member->pushPacket(new CMessageBasicPacket(member, member, 10, 30, message)); sync->SetStartTime(gettick()); sync->SetDuration(30000); } } } } } } }