private void levelSoulCrystals(L2Character attacker) { boolean success = true; int thisMobId = getNpcId(); L2PcInstance killer = (L2PcInstance)attacker; // Only L2PcInstance can absorb a soul if (!(attacker instanceof L2PcInstance)) success = false; // Fail if this L2Attackable isn't absorbed or there's no one in its _absorbersList if (!isAbsorbed() || _absorbersList == null) success = false; // Fail if the killer isn't in the _absorbersList of this L2Attackable AbsorberInfo ai = _absorbersList.get(killer); if (ai == null || ai.absorber.getObjectId() != killer.getObjectId()) success = false; // Check if the soul crystal was used when HP of this L2Attackable wasn't higher than half of it if (ai.absorbedHP > (getMaxHp()/2)) success = false; // If failed, clears the _absorbersList and just return if (!success) { _absorbed = false; _absorbersList = null; return; } // Check if this L2Attackable isn't within any of the groups of mobs that can be absorbed success = false; int maxCrystalLevel = 0; for (int mobId : _absorbingMOBS_level4) { if (thisMobId == mobId) { maxCrystalLevel = 4; success = true; break; } } if (!success) { for (int mobId : _absorbingMOBS_level8) { if (thisMobId == mobId) { maxCrystalLevel = 8; success = true; break; } } } if (!success) { for (int mobId : _absorbingMOBS_level10) { if (thisMobId == mobId) { maxCrystalLevel = 10; success = true; break; } } } // If failed, clears the _absorbersList and just return if (!success) { _absorbed = false; _absorbersList = null; return; } // Init some info Random _rnd = new Random(); int dice = _rnd.nextInt(100); int crystalId = ai.crystalId; int oldCrystalId = 0; int newCrystalId = 0; int crystalOffset = 0; int crystalsCount = 0; SystemMessage sms = new SystemMessage(SystemMessage.EARNED_ITEM); SystemMessage sm = new SystemMessage(614); success = true; final L2ItemInstance[] inv = killer.getInventory().getItems(); for (int index = 0; index < inv.length; index++) { final L2ItemInstance item = inv[index]; /** We must improve this */ if ( ((item.getItemId() >= _REDCRYSTAL_OFFSET) || (item.getItemId() >= _GREENCRYSTAL_OFFSET) || (item.getItemId() >= _BLUECRYSTAL_OFFSET)) && ((item.getItemId() <= _REDCRYSTAL_OFFSET+10) || (item.getItemId() <= _GREENCRYSTAL_OFFSET+10) || (item.getItemId() <= _BLUECRYSTAL_OFFSET+10)) ) { crystalsCount++; } if (crystalsCount > 1) { success = false; break; } } // The attacker has no crystals at all, let's just quit if (crystalsCount < 1) { _absorbed = false; _absorbersList = null; return; } // The attacker has more than one soul crystal with him, the crystal just will resonate if (!success) { sm.addString("The soul crystal resonated."); killer.sendPacket(new PlaySound("ItemSound2.broken_key")); killer.sendPacket(sm); _absorbed = false; _absorbersList = null; return; } // Now we got four choices: // 1- The Monster level is too low for the crystal. Nothing happens. // 2- Everything is correct, but it failed. Nothing happens. (50%) // 3- Everything is correct, but it failed. The crystal scatters. A sound event is played. (10%) // 4- Everything is correct, the crystal level up. A sound event is played. (40%) success = false; for (int crystalLevel = 0; crystalLevel < _MAX_CRYSTALS_LEVEL; crystalLevel++) { // Get a crystal offset to calculate the new crystal ID if (crystalId == (_REDCRYSTAL_OFFSET + crystalLevel)) crystalOffset = _REDCRYSTAL_OFFSET; if (crystalId == (_GREENCRYSTAL_OFFSET + crystalLevel)) crystalOffset = _GREENCRYSTAL_OFFSET; if (crystalId == (_BLUECRYSTAL_OFFSET + crystalLevel)) crystalOffset = _BLUECRYSTAL_OFFSET; if (crystalLevel > 9) { if (crystalId == (_REDCRYSTAL_OFFSET+10)) crystalOffset = _REDCRYSTAL_LVL11 - 11; if (crystalId == (_GREENCRYSTAL_OFFSET+10)) crystalOffset = _GREENCRYSTAL_LVL11 - 11; if (crystalId == (_BLUECRYSTAL_OFFSET+10)) crystalOffset = _BLUECRYSTAL_LVL11 - 11; if (crystalId == (_REDCRYSTAL_LVL11)) crystalOffset = _REDCRYSTAL_LVL12 - 12; if (crystalId == (_GREENCRYSTAL_LVL11)) crystalOffset = _GREENCRYSTAL_LVL12 - 12; if (crystalId == (_BLUECRYSTAL_LVL11)) crystalOffset = _BLUECRYSTAL_LVL12 - 12; } // If we have a valid offset, make the checks if (crystalOffset > 0) { // If the crystal level is way too high for this mob, then quit if (crystalLevel >= maxCrystalLevel) { sm.addString("The soul crystal has refused to absorb the soul."); break; } oldCrystalId = crystalId; newCrystalId = (crystalOffset + crystalLevel) + 1; L2ItemInstance newCrystal = ItemTable.getInstance().createItem(newCrystalId); // Crystals with level > 10 always succeed in leveling if (crystalLevel > 10) { // Manage the item exchange from killer inventory; killer.getInventory().destroyItemByItemId(oldCrystalId, 1); killer.getInventory().addItem(newCrystal); killer.sendPacket(new PlaySound("ItemSound.quest_middle")); sms.addItemName(newCrystalId); break; } // If the killer get a critical failure, break the crystal if (dice < _BREAK_CHANCE) { // Manage the item deletion from killer inventory; killer.getInventory().destroyItemByItemId(oldCrystalId, 1); killer.sendPacket(new PlaySound("ItemSound3.sys_enchant_failed")); sm.addString("The soul crystal scattered itself."); break; } // If the killer succeeds, level up the crystal if (dice < _LEVEL_CHANCE) { // Manage the item exchange from killer inventory; killer.getInventory().destroyItemByItemId(oldCrystalId, 1); killer.getInventory().addItem(newCrystal); // Update all the shortcuts to the new crystal L2ShortCut[] allShortCuts = killer.getAllShortCuts(); for (L2ShortCut sc : allShortCuts) { if (sc.id == oldCrystalId && sc.type == L2ShortCut.TYPE_ITEM) { L2ShortCut newsc = new L2ShortCut(sc.slot, sc.page, sc.type, newCrystalId, sc.level, sc.unk); killer.sendPacket(new ShortCutRegister(newsc)); killer.registerShortCut(newsc); } } // Send a sound event and text message to the player killer.sendPacket(new PlaySound("ItemSound.quest_itemget")); sms.addItemName(newCrystalId); success = true; break; } // Anything else, just fails... sm.addString("The soul crystal has failed to absorb the soul."); break; } } // Send Server->Client packets to notify the killer and update his Inventory if (success) killer.sendPacket(sms); else killer.sendPacket(sm); ItemList il = new ItemList(killer, false); killer.sendPacket(il); }