Hello, good afternoon, friends. I am currently working under the free version of Mobius., I found that Symbol and other abilities didn't require Spellforce and Battleforce charges to be used; they could only be used by having the item.
After much reading and searching for information, I managed to solve my problem. (This applies to my free version.)
To correct this, the following patch must be applied. Please verify the IDs against the charges.
The following skills are affected
<skill id="454" levels="1" name="Symbol of Defense">
<skill id="455" levels="1" name="Symbol of Noise">
<skill id="456" levels="1" name="Symbol of Resistance">
<skill id="457" levels="1" name="Symbol of Honor">
<skill id="458" levels="1" name="Symbol of Energy">
<skill id="459" levels="1" name="Symbol of the Sniper">
<skill id="460" levels="1" name="Symbol of the Assassin">
--------------------------------------------------------------------------------------------------------
<skill id="1419" levels="1" name="Volcano">
<skill id="1420" levels="1" name="Cyclone">
<skill id="1421" levels="1" name="Raging Waves">
<skill id="1422" levels="1" name="Day of Doom">
<skill id="1423" levels="1" name="Gehenna">
<skill id="1424" levels="1" name="Anti-Summoning Field">
<skill id="1425" levels="1" name="Purification Field">
<skill id="1426" levels="1" name="Miracle">
<skill id="1427" levels="1" name="Flames of Invincibility">
<skill id="1428" levels="1" name="Mass Recharge">
--------------------------------------------------------------------------------------------------------
Path of the Original code that needs to be corrected.
Route : java\org\l2jmobius\gameserver\network\clientpackets\RequestMagicSkillUse
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.clientpackets;
import org.l2jmobius.Config;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.effects.EffectType;
import org.l2jmobius.gameserver.model.skill.CommonSkill;
import org.l2jmobius.gameserver.model.skill.Skill;
import org.l2jmobius.gameserver.model.skill.targets.TargetType;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.ActionFailed;
public class RequestMagicSkillUse extends ClientPacket
{
private int _magicId;
private boolean _ctrlPressed;
private boolean _shiftPressed;
[member=79]override[/member]
protected void readImpl()
{
_magicId = readInt(); // Identifier of the used skill
_ctrlPressed = readInt() != 0; // True if it's a ForceAttack : Ctrl pressed
_shiftPressed = readByte() != 0; // True if Shift pressed
}
[member=79]override[/member]
protected void runImpl()
{
final Player player = getPlayer();
if (player == null)
{
return;
}
if (player.isDead())
{
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
if (player.isFakeDeath())
{
if (_magicId != CommonSkill.FAKE_DEATH.getId())
{
player.sendPacket(SystemMessageId.YOU_CANNOT_MOVE_WHILE_SITTING);
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
else if (player.isSkillDisabled(CommonSkill.FAKE_DEATH.getSkill()))
{
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
// Get the level of the used skill
Skill skill = player.getKnownSkill(_magicId);
if (skill == null)
{
// Player doesn't know this skill, maybe it's the display Id.
skill = player.getCustomSkill(_magicId);
if (skill == null)
{
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
// If Alternate rule Karma punishment is set to true, forbid skill Return to player with Karma
if (!Config.ALT_GAME_KARMA_PLAYER_CAN_TELEPORT && (player.getKarma() > 0) && skill.hasEffectType(EffectType.TELEPORT))
{
return;
}
// players mounted on pets cannot use any toggle skills
if (skill.isToggle() && player.isMounted())
{
return;
}
player.onActionRequest();
// Stop if use self-buff (except if on Boat).
if ((skill.isContinuous() && !skill.isDebuff() && (skill.getTargetType() == TargetType.SELF)) && !player.isInBoat())
{
player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, player.getLocation());
}
player.useMagic(skill, _ctrlPressed, _shiftPressed);
}
}
Here we have the corrected version, which allows us to make the skills work in retail mode.
Here I have my method for my version, which corrects this lack of charges to be able to use the skills corresponding to the IDs shown.
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.clientpackets;
import java.util.Set;
import org.l2jmobius.Config;
import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.effects.EffectType;
import org.l2jmobius.gameserver.model.skill.Skill;
import org.l2jmobius.gameserver.model.skill.targets.TargetType;
import org.l2jmobius.gameserver.network.serverpackets.ActionFailed;
public class RequestMagicSkillUse extends ClientPacket
{
private int _magicId;
private boolean _ctrlPressed;
private boolean _shiftPressed;
[member=79]override[/member]
protected void readImpl()
{
_magicId = readInt();
_ctrlPressed = readInt() != 0;
_shiftPressed = readInt() != 0;
readInt();
}
[member=79]override[/member]
protected void runImpl()
{
final Player player = getPlayer();
// Verificación completa de null y estados del jugador
if ((player == null) || player.isDead() || player.isFakeDeath())
{
if (player != null)
{
player.sendPacket(ActionFailed.STATIC_PACKET);
}
return;
}
final int BATTLE_FORCE_ID = 5104; // ID de Battle Force
final int SPELL_FORCE_ID = 5105; // ID de Spell Force
// Skills that require Battle Force level 2
final Set<Integer> SKILLS_REQ_BATTLE_FORCE_LVL2 = Set.of(457, //
458, 454, 460, 459, 455, 456); // 454 Symbol of Defense , 455 Symbol of Noise , 456 Symbol of Resistance, 457 Symbol of Honor
// 459 Symbol of the Sniper , 460 Symbol of the Assassin , 458 Symbol of Energy
// Skills that require Spell Force level 3
final Set<Integer> SKILLS_REQ_SPELL_FORCE_LVL3 = Set.of(1427, //
1419, 1422, 1423, 1421, 1420 // 1419 Volcano, 1420 Cyclone, 1421 Raging Waves, 1422 Day of Doom, 1423 Gehenna, 1424 Anti-Summoning Field
// 1425 Purification Field, 1426 Miracle, 1427 Flames of Invincibility, 1428 Mass Recharge
);
// Skills that require Spell Force level 2
final Set<Integer> SKILLS_REQ_SPELL_FORCE_LVL2 = Set.of(1420, // 1420 Cyclone, 1421 Raging Waves, 1424 Anti-Summoning Field
1421, 1424);
// Battle Force Level 2 Validation
if (SKILLS_REQ_BATTLE_FORCE_LVL2.contains(_magicId))
{
boolean hasBattleForce = player.getEffectList().getBuffs().stream().anyMatch(buff -> (buff.getSkill().getId() == BATTLE_FORCE_ID) && (buff.getSkill().getLevel() >= 2));
if (!hasBattleForce)
{
player.sendMessage("You need Battle Force level 2 to use this ability");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
// Spell Force Level 3 Validation
if (SKILLS_REQ_SPELL_FORCE_LVL3.contains(_magicId))
{
boolean hasSpellForce = player.getEffectList().getBuffs().stream().anyMatch(buff -> (buff.getSkill().getId() == SPELL_FORCE_ID) && (buff.getSkill().getLevel() >= 3));
if (!hasSpellForce)
{
player.sendMessage("You need Spell Force level 3 to use this ability");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
// Spell Force Level 2 Validation
if (SKILLS_REQ_SPELL_FORCE_LVL2.contains(_magicId))
{
boolean hasSpellForce = player.getEffectList().getBuffs().stream().anyMatch(buff -> (buff.getSkill().getId() == SPELL_FORCE_ID) && (buff.getSkill().getLevel() >= 2));
if (!hasSpellForce)
{
player.sendMessage("You need Spell Force level 2 to use this ability");
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
Skill skill = player.getKnownSkill(_magicId);
if (skill == null)
{
skill = player.getCustomSkill(_magicId);
if (skill == null)
{
player.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
}
if (!Config.ALT_GAME_KARMA_PLAYER_CAN_TELEPORT && (player.getKarma() > 0) && skill.hasEffectType(EffectType.TELEPORT))
{
return;
}
if (skill.isToggle() && player.isMounted())
{
return;
}
player.onActionRequest();
if ((skill.isContinuous() && !skill.isDebuff() && (skill.getTargetType() == TargetType.SELF)) && !player.isInBoat())
{
player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, player.getLocation());
}
player.useMagic(skill, _ctrlPressed, _shiftPressed);
}
}
My code currently works under JDK21; adjustments will likely be needed for the new version, but it's just a matter of adapting if there are errors.
My solution may not be the correct one, but I'm trying to contribute to development.