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);
}