inline int32 CLuaItem::getMod(lua_State* L) { DSP_DEBUG_BREAK_IF(m_PLuaItem == nullptr); DSP_DEBUG_BREAK_IF(lua_isnil(L, 1) || !lua_isnumber(L, 1)); CItemArmor* PItem = (CItemArmor*)m_PLuaItem; uint16 mod = lua_tointeger(L, 1); lua_pushinteger(L, PItem->getModifier(mod)); return 1; }
int8 CCharEntity::getShieldSize() { CItemArmor* PItem = (CItemArmor*)(getStorage(LOC_INVENTORY)->GetItem(equip[SLOT_SUB])); if(PItem == NULL){ return 0; } if(!PItem->IsShield()){ return 0; } return PItem->getShieldSize(); }
inline int32 CLuaItem::delMod(lua_State* L) { DSP_DEBUG_BREAK_IF(m_PLuaItem == nullptr); DSP_DEBUG_BREAK_IF(lua_isnil(L, 1) || !lua_isnumber(L, 1)); DSP_DEBUG_BREAK_IF(lua_isnil(L, 2) || !lua_isnumber(L, 2)); CItemArmor* PItem = (CItemArmor*)m_PLuaItem; uint32 mod = lua_tointeger(L, 1); int32 power = lua_tointeger(L, 2); PItem->addModifier(new CModifier(mod, -power)); return 0; }
inline int32 CLuaItem::getAugment(lua_State* L) { DSP_DEBUG_BREAK_IF(m_PLuaItem == nullptr); DSP_DEBUG_BREAK_IF(lua_isnil(L, 1) || !lua_isnumber(L, 1)); CItemArmor* PItem = (CItemArmor*)m_PLuaItem; uint8 slot = lua_tointeger(L, 1); uint16 augment = PItem->getAugment(slot); uint16 augmentid = unpackBitsBE((uint8*)(&augment), 0, 11); uint8 augmentVal = unpackBitsBE((uint8*)(&augment), 11, 5); lua_pushinteger(L, augmentid); lua_pushinteger(L, augmentVal); return 2; }
void CAIPetDummy::ActionAbilityStart() { if (m_PPet->StatusEffectContainer->HasPreventActionEffect()) { return; } if (m_PPet->objtype == TYPE_MOB && m_PPet->PMaster->objtype == TYPE_PC) { if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr) { m_MasterCommand = MASTERCOMMAND_NONE; CMobEntity* PMob = (CMobEntity*)m_PPet->PMaster->PPet; std::vector<CMobSkill*> MobSkills = battleutils::GetMobSkillsByFamily(PMob->m_Family); if (MobSkills.size() > 0) { int maxSearch = 10; // keep looking for an ability until one is valid do { SetCurrentMobSkill(MobSkills.at(dsprand::GetRandomNumber(MobSkills.size()))); } while (luautils::OnMobSkillCheck(m_PBattleTarget, m_PPet, GetCurrentMobSkill()) != 0 && maxSearch--); // could not find skill if (maxSearch == 0) { TransitionBack(true); return; } preparePetAbility(m_PBattleTarget); return; } return; } } if (m_PPet->getPetType() == PETTYPE_JUG_PET){ if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr){ //choose random tp move m_MasterCommand = MASTERCOMMAND_NONE; if (m_PPet->PetSkills.size() > 0){ SetCurrentMobSkill(m_PPet->PetSkills.at(dsprand::GetRandomNumber(m_PPet->PetSkills.size()))); preparePetAbility(m_PBattleTarget); return; } } } else if (m_PPet->getPetType() == PETTYPE_AVATAR){ for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getAnimationTime() == m_MasterCommand){ SetCurrentMobSkill(m_PPet->PetSkills[i]); m_MasterCommand = MASTERCOMMAND_NONE; preparePetAbility(m_PPet); return; } } m_MasterCommand = MASTERCOMMAND_NONE; } else if (m_PPet->getPetType() == PETTYPE_WYVERN){ WYVERNTYPE wyverntype = m_PPet->getWyvernType(); if (m_MasterCommand == MASTERCOMMAND_ELEMENTAL_BREATH && (wyverntype == WYVERNTYPE_MULTIPURPOSE || wyverntype == WYVERNTYPE_OFFENSIVE)){ m_MasterCommand = MASTERCOMMAND_NONE; //offensive or multipurpose wyvern if (m_PBattleTarget != nullptr){ //prepare elemental breaths int skip = dsprand::GetRandomNumber(6); int hasSkipped = 0; for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getValidTargets() == TARGET_ENEMY){ if (hasSkipped == skip){ SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else{ hasSkipped++; } } } preparePetAbility(m_PBattleTarget); return; } } else if (m_MasterCommand == MASTERCOMMAND_HEALING_BREATH && (wyverntype == WYVERNTYPE_DEFENSIVE || wyverntype == WYVERNTYPE_MULTIPURPOSE)) { m_MasterCommand = MASTERCOMMAND_NONE; m_PBattleSubTarget = nullptr; //TODO: CHECK FOR STATUS EFFECTS FOR REMOVE- BREATH (higher priority than healing breaths) // if(m_PPet->PMaster->PParty==nullptr){//solo with master-kun CItemArmor* masterHeadItem = ((CCharEntity*)(m_PPet->PMaster))->getEquip(SLOT_HEAD); uint16 masterHead = masterHeadItem ? masterHeadItem->getID() : 0; // Determine what the required HP percentage will need to be // at or under in order for healing breath to activate. uint8 requiredHPP = 0; if (((CCharEntity*)(m_PPet->PMaster))->objtype == TYPE_PC && (masterHead == 12519 || masterHead == 15238)) { //Check for player & AF head, or +1 if (wyverntype == WYVERNTYPE_DEFENSIVE) { //healer wyvern requiredHPP = 50; } else if (wyverntype == WYVERNTYPE_MULTIPURPOSE) { //hybrid wyvern requiredHPP = 33; } } else { if (wyverntype == WYVERNTYPE_DEFENSIVE) { //healer wyvern requiredHPP = 33; } else if (wyverntype == WYVERNTYPE_MULTIPURPOSE) { //hybrid wyvern requiredHPP = 25; } } // Only attempt to find a target if there is an HP percentage to calculate. if (requiredHPP) { CBattleEntity* master = m_PPet->PMaster; // Check the master first. if (master->GetHPP() <= requiredHPP) { m_PBattleSubTarget = master; } // Otherwise if this is a healer wyvern, and the member is in a party // check all of the party members who qualify. else if (wyverntype == WYVERNTYPE_DEFENSIVE && master->PParty != nullptr) { master->ForParty([this, requiredHPP](CBattleEntity* PTarget){ if (PTarget->GetHPP() <= requiredHPP) { m_PBattleSubTarget = PTarget; } }); } } if (m_PBattleSubTarget != nullptr){ //target to heal //get highest breath for wyverns level m_PMobSkill = nullptr; for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getValidTargets() == TARGET_PLAYER_PARTY){ if (m_PPet->PetSkills[i]->getID() == 638 && m_PPet->PMaster->GetMLevel() < 20){ //can only using hb1 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else if (m_PPet->PetSkills[i]->getID() == 639 && m_PPet->PMaster->GetMLevel() < 40){ //can only using hb2 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else if (m_PPet->PetSkills[i]->getID() == 640 && m_PPet->PMaster->GetMLevel() >= 40){ //can only using hb3 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } } } preparePetAbility(m_PBattleSubTarget); return; } } } TransitionBack(true); }
/************************************************************************ * * * 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); }
void CAIPetDummy::ActionAbilityStart() { if (m_PPet->StatusEffectContainer->HasPreventActionEffect()) { return; } if (m_PPet->objtype == TYPE_MOB && m_PPet->PMaster->objtype == TYPE_PC) { if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr) { m_MasterCommand = MASTERCOMMAND_NONE; CMobEntity* PMob = (CMobEntity*)m_PPet->PMaster->PPet; std::vector<CMobSkill*> MobSkills = battleutils::GetMobSkillsByFamily(PMob->m_Family); if (MobSkills.size() > 0) { int maxSearch = 10; // keep looking for an ability until one is valid do { SetCurrentMobSkill(MobSkills.at(WELL512::irand() % MobSkills.size())); } while (luautils::OnMobSkillCheck(m_PBattleTarget, m_PPet, GetCurrentMobSkill()) != 0 && maxSearch--); // could not find skill if (maxSearch == 0) { TransitionBack(true); return; } preparePetAbility(m_PBattleTarget); return; } return; } } if (m_PPet->getPetType() == PETTYPE_JUG_PET){ if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr){ //choose random tp move m_MasterCommand = MASTERCOMMAND_NONE; if (m_PPet->PetSkills.size() > 0){ SetCurrentMobSkill(m_PPet->PetSkills.at(WELL512::irand() % m_PPet->PetSkills.size())); preparePetAbility(m_PBattleTarget); return; } } } else if (m_PPet->getPetType() == PETTYPE_AVATAR){ for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getAnimationTime() == m_MasterCommand){ SetCurrentMobSkill(m_PPet->PetSkills[i]); m_MasterCommand = MASTERCOMMAND_NONE; preparePetAbility(m_PPet); return; } } m_MasterCommand = MASTERCOMMAND_NONE; } else if (m_PPet->getPetType() == PETTYPE_WYVERN){ WYVERNTYPE wyverntype = m_PPet->getWyvernType(); if (m_MasterCommand == MASTERCOMMAND_ELEMENTAL_BREATH && (wyverntype == WYVERNTYPE_MULTIPURPOSE || wyverntype == WYVERNTYPE_OFFENSIVE)){ m_MasterCommand = MASTERCOMMAND_NONE; //offensive or multipurpose wyvern if (m_PBattleTarget != nullptr){ //prepare elemental breaths int skip = WELL512::irand() % 6; int hasSkipped = 0; for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getValidTargets() == TARGET_ENEMY){ if (hasSkipped == skip){ SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else{ hasSkipped++; } } } preparePetAbility(m_PBattleTarget); return; } } else if (m_MasterCommand == MASTERCOMMAND_HEALING_BREATH && (wyverntype == WYVERNTYPE_DEFENSIVE || wyverntype == WYVERNTYPE_MULTIPURPOSE)) { m_MasterCommand = MASTERCOMMAND_NONE; m_PBattleSubTarget = nullptr; //TODO: CHECK FOR STATUS EFFECTS FOR REMOVE- BREATH (higher priority than healing breaths) // if(m_PPet->PMaster->PParty==nullptr){//solo with master-kun CItemArmor* masterHeadItem = ((CCharEntity*)(m_PPet->PMaster))->getEquip(SLOT_HEAD); uint16 masterHead = masterHeadItem ? masterHeadItem->getID() : 0; if (((CCharEntity*)(m_PPet->PMaster))->objtype == TYPE_PC && (masterHead == 12519 || masterHead == 15238)) { //Check for player & AF head, or +1 if (m_PPet->PMaster->GetHPP() <= 50 && wyverntype == WYVERNTYPE_DEFENSIVE){//healer wyvern m_PBattleSubTarget = m_PPet->PMaster; } else if (m_PPet->PMaster->GetHPP() <= 33 && wyverntype == WYVERNTYPE_MULTIPURPOSE){//hybrid wyvern m_PBattleSubTarget = m_PPet->PMaster; } } else { if (m_PPet->PMaster->GetHPP() <= 33 && wyverntype == WYVERNTYPE_DEFENSIVE) {//healer wyvern m_PBattleSubTarget = m_PPet->PMaster; } else if (m_PPet->PMaster->GetHPP() <= 25 && wyverntype == WYVERNTYPE_MULTIPURPOSE) {//hybrid wyvern m_PBattleSubTarget = m_PPet->PMaster; } } // } // else{ //group play // //for( int i=0; i< // } if (m_PBattleSubTarget != nullptr){ //target to heal //get highest breath for wyverns level m_PMobSkill = nullptr; for (int i = 0; i < m_PPet->PetSkills.size(); i++){ if (m_PPet->PetSkills[i]->getValidTargets() == TARGET_PLAYER_PARTY){ if (m_PPet->PetSkills[i]->getID() == 638 && m_PPet->PMaster->GetMLevel() < 20){ //can only using hb1 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else if (m_PPet->PetSkills[i]->getID() == 639 && m_PPet->PMaster->GetMLevel() < 40){ //can only using hb2 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } else if (m_PPet->PetSkills[i]->getID() == 640 && m_PPet->PMaster->GetMLevel() >= 40){ //can only using hb3 SetCurrentMobSkill(m_PPet->PetSkills[i]); break; } } } preparePetAbility(m_PBattleSubTarget); return; } } } TransitionBack(true); }