bool CLatentEffect::Deactivate() { if (IsActivated()) { //remove the modifier from weapon, not player if (GetModValue() == Mod::ADDITIONAL_EFFECT || GetModValue() == Mod::DMG) { CCharEntity* PChar = (CCharEntity*)m_POwner; CItemWeapon* weapon = (CItemWeapon*)PChar->getEquip((SLOTTYPE)GetSlot()); int16 modPower = GetModPower(); if (weapon != nullptr && (weapon->isType(ITEM_ARMOR) || weapon->isType(ITEM_WEAPON))) { if (GetModValue() == Mod::ADDITIONAL_EFFECT) { for (uint8 i = 0; i < weapon->modList.size(); ++i) { //ensure the additional effect is fully removed from the weapon if (weapon->modList.at(i).getModID() == Mod::ADDITIONAL_EFFECT) { weapon->modList.at(i).setModAmount(0); } } } else { weapon->addModifier(CModifier(GetModValue(), -modPower)); } } } else { m_POwner->delModifier(m_ModValue, m_ModPower); } m_Activated = false; //printf("LATENT DEACTIVATED: %d\n", m_ModValue); return true; } return false; }
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 CLatentEffect::Activate() { if( !IsActivated() ) { //additional effect/dmg latents add mod to weapon, not player if (GetModValue() == MOD_ADDITIONAL_EFFECT || GetModValue() == MOD_DMG) { CCharEntity* PChar = (CCharEntity*)m_POwner; CItemWeapon* weapon = (CItemWeapon*)PChar->getEquip((SLOTTYPE)GetSlot()); weapon->addModifier(new CModifier(GetModValue(), GetModPower())); } else { m_POwner->addModifier(m_ModValue, m_ModPower); } m_Activated = true; //printf("LATENT ACTIVATED: %d, Current value: %d\n", m_ModValue, m_POwner->getMod(m_ModValue)); } }
void CStatusEffectContainer::CheckRegen(uint32 tick) { DSP_DEBUG_BREAK_IF(m_POwner == nullptr); if (!m_POwner->isDead()) { if ((tick - m_RegenCheckTime) < 3000 ) { return; } CCharEntity* PChar = nullptr; if(m_POwner->objtype == TYPE_PC) { PChar = (CCharEntity*)m_POwner; } m_RegenCheckTime = tick; int16 regen = m_POwner->getMod(MOD_REGEN); int16 poison = m_POwner->getMod(MOD_REGEN_DOWN); int16 refresh = m_POwner->getMod(MOD_REFRESH) - m_POwner->getMod(MOD_REFRESH_DOWN); int16 regain = m_POwner->getMod(MOD_REGAIN) - m_POwner->getMod(MOD_REGAIN_DOWN); bool update = false; if (m_POwner->addHP(regen)) update = true; if(poison) { int16 damage = battleutils::HandleStoneskin(m_POwner, poison); if(damage > 0) { DelStatusEffectSilent(EFFECT_HEALING); m_POwner->addHP(-damage); WakeUp(); update = true; } } if (m_POwner->getMod(MOD_AVATAR_PERPETUATION) > 0 && (m_POwner->objtype == TYPE_PC)) { int16 perpetuation = m_POwner->getMod(MOD_AVATAR_PERPETUATION); if (m_POwner->StatusEffectContainer->HasStatusEffect(EFFECT_ASTRAL_FLOW)) perpetuation = 0; else { if (m_POwner->PPet != nullptr && PChar != nullptr) { if(m_POwner->PPet->objtype == TYPE_PET) { CPetEntity* PPet = (CPetEntity*)m_POwner->PPet; CItem* hands = PChar->getEquip(SLOT_HANDS); // carbuncle mitts only work on carbuncle if (hands && hands->getID() == 14062 && PPet->name == "Carbuncle"){ perpetuation /= 2; } } perpetuation -= charutils::AvatarPerpetuationReduction(PChar); if( perpetuation < 1 ) perpetuation = 1; } } if (m_POwner->addMP(refresh - perpetuation)) update = true; if( m_POwner->health.mp == 0 && m_POwner->PPet != nullptr && m_POwner->PPet->objtype == TYPE_PET) { CPetEntity* PPet = (CPetEntity*)m_POwner->PPet; if (PPet->getPetType() == PETTYPE_AVATAR) { petutils::DespawnPet(m_POwner); } } } else { if (m_POwner->addMP(refresh)) update = true; } if (m_POwner->addTP(regain)) update = true; if (m_POwner->PPet && ((CPetEntity*)(m_POwner->PPet))->getPetType() == PETTYPE_AUTOMATON) { ((CAutomatonEntity*)(m_POwner->PPet))->burdenTick(); } if( m_POwner->status != STATUS_DISAPPEAR && (m_POwner->objtype == TYPE_PC) && update) { charutils::UpdateHealth((CCharEntity*)m_POwner); } } }
/************************************************************************ * * * Creates up to many attacks for a particular hand. * * * ************************************************************************/ void CAttackRound::CreateAttacks(CItemWeapon* PWeapon, PHYSICAL_ATTACK_DIRECTION direction) { uint8 num = 1; bool isPC = m_attacker->objtype == TYPE_PC; // Checking the players weapon hit count if (PWeapon->getReqLvl() <= m_attacker->GetMLevel()) { num = PWeapon->getHitCount(); } // If the attacker is a mobentity or derived from mobentity, check to see if it has any special mutli-hit capabilties if (dynamic_cast<CMobEntity*>(m_attacker)) { auto multiHitMax = static_cast<CMobEntity*>(m_attacker)->getMobMod(MOBMOD_MULTI_HIT); if (multiHitMax > 0) num = 1 + battleutils::getHitCount(multiHitMax); } AddAttackSwing(PHYSICAL_ATTACK_TYPE::NORMAL, direction, num); // Checking the players triple, double and quadruple attack int16 tripleAttack = m_attacker->getMod(Mod::TRIPLE_ATTACK); int16 doubleAttack = m_attacker->getMod(Mod::DOUBLE_ATTACK); int16 quadAttack = m_attacker->getMod(Mod::QUAD_ATTACK); //check for merit upgrades if (isPC) { CCharEntity* PChar = (CCharEntity*)m_attacker; //merit chance only applies if player has the job trait if (charutils::hasTrait(PChar, TRAIT_TRIPLE_ATTACK)) tripleAttack += PChar->PMeritPoints->GetMeritValue(MERIT_TRIPLE_ATTACK_RATE, PChar); if (charutils::hasTrait(PChar, TRAIT_DOUBLE_ATTACK)) doubleAttack += PChar->PMeritPoints->GetMeritValue(MERIT_DOUBLE_ATTACK_RATE, PChar); // TODO: Quadruple attack merits when SE release them. } quadAttack = dsp_cap(quadAttack, 0, 100); doubleAttack = dsp_cap(doubleAttack, 0, 100); tripleAttack = dsp_cap(tripleAttack, 0, 100); // Checking Mikage Effect - Hits Vary With Num of Utsusemi Shadows for Main Weapon if (m_attacker->StatusEffectContainer->HasStatusEffect(EFFECT_MIKAGE) && m_attacker->m_Weapons[SLOT_MAIN]->getID() == PWeapon->getID()) { int16 shadows = m_attacker->getMod(Mod::UTSUSEMI); //ShowDebug(CL_CYAN"Create Attacks: Mikage Active, Rolling Attack Chance for %d Shadowss...\n" CL_RESET, shadows); AddAttackSwing(PHYSICAL_ATTACK_TYPE::NORMAL, direction, shadows); } else if (num == 1 && dsprand::GetRandomNumber(100) < quadAttack) AddAttackSwing(PHYSICAL_ATTACK_TYPE::QUAD, direction, 3); else if (num == 1 && dsprand::GetRandomNumber(100) < tripleAttack) AddAttackSwing(PHYSICAL_ATTACK_TYPE::TRIPLE, direction, 2); else if (num == 1 && dsprand::GetRandomNumber(100) < doubleAttack) AddAttackSwing(PHYSICAL_ATTACK_TYPE::DOUBLE, direction, 1); // Ammo extra swing - players only if (isPC && m_attacker->getMod(Mod::AMMO_SWING) > 0) { // Check for ammo CCharEntity* PChar = (CCharEntity*)m_attacker; CItemArmor* PAmmo = PChar->getEquip(SLOT_AMMO); CItemArmor* PMain = PChar->getEquip(SLOT_MAIN); CItemArmor* PSub = PChar->getEquip(SLOT_SUB); uint8 slot = PChar->equip[SLOT_AMMO]; uint8 loc = PChar->equipLoc[SLOT_AMMO]; uint8 ammoCount = 0; // Handedness check, checking mod of the weapon for the purposes of level scaling if (battleutils::GetScaledItemModifier(PChar, PMain, Mod::AMMO_SWING_TYPE) == 2 && dsprand::GetRandomNumber(100) < m_attacker->getMod(Mod::AMMO_SWING) && PAmmo != nullptr && ammoCount < PAmmo->getQuantity()) { AddAttackSwing(PHYSICAL_ATTACK_TYPE::NORMAL, direction, 1); ammoCount += 1; } else { if (direction == RIGHTATTACK && battleutils::GetScaledItemModifier(PChar, PMain, Mod::AMMO_SWING_TYPE) == 1 && dsprand::GetRandomNumber(100) < m_attacker->getMod(Mod::AMMO_SWING) && PAmmo != nullptr && ammoCount < PAmmo->getQuantity()) { AddAttackSwing(PHYSICAL_ATTACK_TYPE::NORMAL, RIGHTATTACK, 1); ammoCount += 1; } if (direction == LEFTATTACK && PSub != nullptr && battleutils::GetScaledItemModifier(PChar, PSub, Mod::AMMO_SWING_TYPE) == 1 && dsprand::GetRandomNumber(100) < m_attacker->getMod(Mod::AMMO_SWING) && PAmmo != nullptr && ammoCount < PAmmo->getQuantity()) { AddAttackSwing(PHYSICAL_ATTACK_TYPE::NORMAL, LEFTATTACK, 1); ammoCount += 1; } } if (PAmmo != nullptr) { if (PAmmo->getQuantity() == ammoCount) { charutils::UnequipItem(PChar, SLOT_AMMO); charutils::SaveCharEquip(PChar); } charutils::UpdateItem(PChar, loc, slot, -ammoCount); PChar->pushPacket(new CInventoryFinishPacket()); } } // TODO: Possible Lua function for the nitty gritty stuff below. // Iga mod: Extra attack chance whilst dual wield is on. if (direction == LEFTATTACK && dsprand::GetRandomNumber(100) < m_attacker->getMod(Mod::EXTRA_DUAL_WIELD_ATTACK)) AddAttackSwing(PHYSICAL_ATTACK_TYPE::NORMAL, RIGHTATTACK, 1); }
/************************************************************************ * * * Creates up to many attacks for a particular hand. * * * ************************************************************************/ void CAttackRound::CreateAttacks(CItemWeapon* PWeapon, PHYSICAL_ATTACK_DIRECTION direction) { uint8 num = 1; // Checking the players weapon hit count if (PWeapon->getReqLvl() <= m_attacker->GetMLevel()) { num = PWeapon->getHitCount(); } AddAttackSwing(ATTACK_NORMAL, direction, num); // Checking the players triple, double and quadruple attack int16 tripleAttack = m_attacker->getMod(MOD_TRIPLE_ATTACK); int16 doubleAttack = m_attacker->getMod(MOD_DOUBLE_ATTACK); int16 quadAttack = m_attacker->getMod(MOD_QUAD_ATTACK); //check for merit upgrades if (m_attacker->objtype == TYPE_PC) { CCharEntity* PChar = (CCharEntity*)m_attacker; //merit chance only applies if player has the job trait if (charutils::hasTrait(PChar, TRAIT_TRIPLE_ATTACK)) tripleAttack += PChar->PMeritPoints->GetMeritValue(MERIT_TRIPLE_ATTACK_RATE, PChar); if (charutils::hasTrait(PChar, TRAIT_DOUBLE_ATTACK)) doubleAttack += PChar->PMeritPoints->GetMeritValue(MERIT_DOUBLE_ATTACK_RATE, PChar); // TODO: Quadruple attack merits when SE release them. } quadAttack = dsp_cap(quadAttack,0,100); doubleAttack = dsp_cap(doubleAttack,0,100); tripleAttack = dsp_cap(tripleAttack,0,100); // Checking Mikage Effect - Hits Vary With Num of Utsusemi Shadows for Main Weapon if (m_attacker->StatusEffectContainer->HasStatusEffect(EFFECT_MIKAGE) && m_attacker->m_Weapons[SLOT_MAIN]->getID() == PWeapon->getID()) { int16 shadows = m_attacker->getMod(MOD_UTSUSEMI); //ShowDebug(CL_CYAN"Create Attacks: Mikage Active, Rolling Attack Chance for %d Shadowss...\n" CL_RESET, shadows); AddAttackSwing(ATTACK_NORMAL, direction, shadows); } else if (num == 1 && dsprand::GetRandomNumber(100) < quadAttack) AddAttackSwing(QUAD_ATTACK, direction, 3); else if (num == 1 && dsprand::GetRandomNumber(100) < tripleAttack) AddAttackSwing(TRIPLE_ATTACK, direction, 2); else if (num == 1 && dsprand::GetRandomNumber(100) < doubleAttack) AddAttackSwing(DOUBLE_ATTACK, direction, 1); // Ammo extra swing - players only if (m_attacker->objtype == TYPE_PC && m_attacker->getMod(MOD_AMMO_SWING) > 0) { // Check for ammo CCharEntity* PChar = (CCharEntity*)m_attacker; CItemArmor* PAmmo = PChar->getEquip(SLOT_AMMO); uint8 slot = PChar->equip[SLOT_AMMO]; uint8 loc = PChar->equipLoc[SLOT_AMMO]; if (dsprand::GetRandomNumber(100) < m_attacker->getMod(MOD_AMMO_SWING)) { // Add swing, then subtract an ammo item, unequip if there's one left. AddAttackSwing(ATTACK_NORMAL, direction, 1); if (PAmmo->getQuantity() == 1) { charutils::UnequipItem(PChar, SLOT_AMMO); charutils::SaveCharEquip(PChar); } charutils::UpdateItem(PChar, loc, slot, -1); PChar->pushPacket(new CInventoryFinishPacket()); } } // TODO: Possible Lua function for the nitty gritty stuff below. // Iga mod: Extra attack chance whilst dual wield is on. if (direction == LEFTATTACK && dsprand::GetRandomNumber(100) < m_attacker->getMod(MOD_EXTRA_DUAL_WIELD_ATTACK)) AddAttackSwing(ATTACK_NORMAL, RIGHTATTACK, 1); }
/************************************************************************ * * * Tick regen/refresh/regain effects * * * ************************************************************************/ void CStatusEffectContainer::CheckRegen(uint32 tick) { DSP_DEBUG_BREAK_IF(m_POwner == NULL); if (!m_POwner->isDead()) { if ((tick - m_RegenCheckTime) < 3000 ) { return; } CCharEntity* PChar = NULL; if(m_POwner->objtype == TYPE_PC) { PChar = (CCharEntity*)m_POwner; } m_RegenCheckTime = tick; int8 regen = m_POwner->getMod(MOD_REGEN); int8 poison = m_POwner->getMod(MOD_REGEN_DOWN); int8 refresh = m_POwner->getMod(MOD_REFRESH) - m_POwner->getMod(MOD_REFRESH_DOWN); int16 regain = m_POwner->getMod(MOD_REGAIN) - m_POwner->getMod(MOD_REGAIN_DOWN); m_POwner->addHP(regen); if(poison) { int16 damage = battleutils::HandleStoneskin(m_POwner, poison); if(damage > 0) { DelStatusEffectSilent(EFFECT_HEALING); m_POwner->addHP(-damage); WakeUp(); } } if (m_POwner->getMod(MOD_AVATAR_PERPETUATION) > 0 && (m_POwner->objtype == TYPE_PC)) { int8 perpetuation = m_POwner->getMod(MOD_AVATAR_PERPETUATION); if (m_POwner->StatusEffectContainer->HasStatusEffect(EFFECT_ASTRAL_FLOW)) perpetuation = 0; else { if (m_POwner->PPet != NULL && PChar != NULL) { if(m_POwner->PPet->objtype == TYPE_PET) { CPetEntity* PPet = (CPetEntity*)m_POwner->PPet; CItem* hands = PChar->getEquip(SLOT_HANDS); // carbuncle mitts only work on carbuncle if (hands && hands->getID() == 14062 && PPet->name == "Carbuncle"){ perpetuation /= 2; } } perpetuation -= charutils::AvatarPerpetuationReduction(PChar); if( perpetuation < 1 ) perpetuation = 1; } } m_POwner->addMP(refresh - perpetuation); if( m_POwner->health.mp == 0 && m_POwner->PPet != NULL && m_POwner->PPet->objtype == TYPE_PET) { CPetEntity* PPet = (CPetEntity*)m_POwner->PPet; if (PPet->getPetType() == PETTYPE_AVATAR) { petutils::DespawnPet(m_POwner); } } } else { m_POwner->addMP(refresh); } if(PChar != NULL && IsAsleep()) { CItem* neck = PChar->getEquip(SLOT_NECK); // opo-opo necklace if(neck != NULL && neck->getID() == 13143) { // add tp regain += 2.5f; } } m_POwner->addTP(regain); if( m_POwner->status != STATUS_DISAPPEAR && (m_POwner->objtype == TYPE_PC)) { charutils::UpdateHealth((CCharEntity*)m_POwner); } } }
void CLinkshell::RemoveMemberByName(int8* MemberName) { for (uint32 i = 0; i < members.size(); ++i) { if (strcmp(MemberName, members.at(i)->GetName()) == 0) { CCharEntity* PMember = (CCharEntity*)members.at(i); CItemLinkshell* PItemLinkshell = (CItemLinkshell*)PMember->getEquip(SLOT_LINK1); SLOTTYPE slot = SLOT_LINK1; int lsNum = 1; if (PItemLinkshell->GetLSID() != this->getID()) { PItemLinkshell = (CItemLinkshell*)PMember->getEquip(SLOT_LINK2); slot = SLOT_LINK2; lsNum = 2; } if (PItemLinkshell != nullptr && PItemLinkshell->isType(ITEM_LINKSHELL)) { linkshell::DelOnlineMember(PMember, PItemLinkshell); PItemLinkshell->setSubType(ITEM_UNLOCKED); PMember->equip[slot] = 0; if (slot == SLOT_LINK1) { PMember->nameflags.flags &= ~FLAG_LINKSHELL; PMember->updatemask |= UPDATE_HP; } PMember->pushPacket(new CInventoryAssignPacket(PItemLinkshell, INV_NORMAL)); PMember->pushPacket(new CLinkshellEquipPacket(PMember,lsNum)); } CItemContainer* Inventory = PMember->getStorage(LOC_INVENTORY); for (uint8 SlotID = 0; SlotID < Inventory->GetSize(); ++SlotID) { CItemLinkshell* PItemLinkshell = (CItemLinkshell*)Inventory->GetItem(SlotID); if (PItemLinkshell != nullptr && PItemLinkshell->isType(ITEM_LINKSHELL) && PItemLinkshell->GetLSID() == m_id) { const int8* Query = "UPDATE char_inventory SET itemid = (itemid+2) WHERE charid = %u AND location = %u AND slot = %u LIMIT 1"; Sql_Query(SqlHandle, Query, PMember->id, LOC_INVENTORY, SlotID); PItemLinkshell->SetLSID(0); PItemLinkshell->setID(PItemLinkshell->getID() + 2); PMember->pushPacket(new CInventoryItemPacket(PItemLinkshell, LOC_INVENTORY, SlotID)); } } charutils::SaveCharStats(PMember); charutils::SaveCharEquip(PMember); PMember->pushPacket(new CInventoryFinishPacket()); PMember->pushPacket(new CCharUpdatePacket(PMember)); PMember->pushPacket(new CMessageSystemPacket(0,0,109)); return; } } }
void CLinkshell::ChangeMemberRank(int8* MemberName, uint8 toSack) { //topearl = 3 //tosack = 2 int newId = 512 + toSack; if (newId == 514 || newId == 515) { for (uint32 i = 0; i < members.size(); ++i) { if (strcmp(MemberName, members.at(i)->GetName()) == 0) { CCharEntity* PMember = (CCharEntity*)members.at(i); SLOTTYPE slot = SLOT_LINK1; int lsID = 1; if (PMember->PLinkshell2 == this) { lsID = 2; slot = SLOT_LINK2; } CItemLinkshell* PItemLinkshell = (CItemLinkshell*)PMember->getEquip(slot); if (PItemLinkshell != nullptr && PItemLinkshell->isType(ITEM_LINKSHELL)) { PItemLinkshell->setID(newId); PMember->pushPacket(new CInventoryAssignPacket(PItemLinkshell, INV_NORMAL)); PMember->pushPacket(new CLinkshellEquipPacket(PMember, lsID)); } CItemContainer* Inventory = PMember->getStorage(LOC_INVENTORY); for (uint8 SlotID = 0; SlotID < Inventory->GetSize(); ++SlotID) { CItemLinkshell* PItemLinkshell = (CItemLinkshell*)Inventory->GetItem(SlotID); if (PItemLinkshell != nullptr && PItemLinkshell->isType(ITEM_LINKSHELL) && PItemLinkshell->GetLSID() == m_id) { const int8* Query = "UPDATE char_inventory SET itemid = %u WHERE charid = %u AND location = %u AND slot = %u LIMIT 1"; Sql_Query(SqlHandle, Query, PItemLinkshell->getID(),PMember->id, LOC_INVENTORY, SlotID); if (lsID == 1) { Sql_Query(SqlHandle, "UPDATE accounts_sessions SET linkshellid1 = %u , linkshellrank1 = %u WHERE charid = %u", m_id, PItemLinkshell->GetLSType(), PMember->id); } else if (lsID == 2) { Sql_Query(SqlHandle, "UPDATE accounts_sessions SET linkshellid2 = %u , linkshellrank2 = %u WHERE charid = %u", m_id, PItemLinkshell->GetLSType(), PMember->id); } PMember->pushPacket(new CInventoryItemPacket(PItemLinkshell, LOC_INVENTORY, SlotID)); } } charutils::SaveCharStats(PMember); charutils::SaveCharEquip(PMember); PMember->pushPacket(new CInventoryFinishPacket()); PMember->pushPacket(new CCharUpdatePacket(PMember)); return; } } } }