Jump to content

Recommended Posts

Posted

SpellHowler:

 

Spellhowler (SH) are offensive spellcasters (nukers) of the Dark Elves. They wear Robes and can use any weapon, even if they usually prefer those with high M.Atk.

 

This class specializes in wind and dark magic.

Contents

 

Key Skills

    * Hurricane: Fast reuse and lot of damage.

 

Developement

    This section is a stub. Help us expand it, and you get a cookie.

 

Equipment

 

In general, anything that gives the SH casting speed is usually a good idea. Casting speed means your chance of getting interrupted is much lower, and it’s a huge advantage in PvP. For tattoos, the common setup for a spellhowler is +4CON-5STR, +4WIT-4MEN, +4INT-4MEN. However, if you wish to add even more the already slow casting howler, you can swap the +4CON-5STR for a +1WIT-1MEN.

 

    * C-Grade: Demon Set (or Karmian Set) with Homunkulus' Sword SA Acumen.

    * B-Grade: Avadon Set with Sword of Valhalla SA Acumen.

    * A-Grade: Dark Crystal Set with Sword of Miracles SA Acumen.

    * S-Grade: Dark Crystal Set (or Major Arcana Set) with Arcana Mace SA Acumen.

 

Magic

 

    * Hurricane: Good damage and recast time.

    * Death Spike: Good damage and recast time, low MP needed, but you must have cursed bones.

    * Vampiric Claw: Good damage, but lots of MP needed. Only use when low on HP.

    * Body To Mind: Fantastic skill for gaining mana. A good strategy is to BtM until you have low HP, then use 'Heal' on yourself until you're full. Repeat until you have lots of MP.

    * Shadow Flare: Overhit skill. Good to use when enemy is weak. Try not to use too much in case you don't have any SP when it comes to getting new skills.

    * Curse Death Link: Not as effective anymore with mobs UD'ing. Otherwise, the less HP you have, the more damage you do.

 

Adventuring

 

Nukers are loners, and the Spellhowler is even more so than elvish Spellsingers and human Sorcerers, because the latter at least have mass sleep spells.

 

Especially spellsingers can be found to almost go into melee with their spells quite often, because their fastest spells are almost uninterruptible. Spellhowlers however are slow casters, the best strategy for them is to run away until they have some distance, cast their spell, then continue running away. The Slow spell is a very important tool for the spellhowler, as are speed potions.

 

During soloplay, the spellhowler usually battles to use up his Manapool as slowly as possible. This can be done by casting the Body to Mind spell multiple times between the wind attacks, then combining them with the Vampiric Claw and Corpse Life Drain attack.

 

Dark magic is very strong, but some mobs are very resistant, and wind attacks tend to be cheaper, at least in the beginning. There is a nice combination of using Body To Mind spell that keeps Spellhowler's health at minimum and powerful Curce Death Link spell which deals great damage when caster is near death. Also, there are no dark mass attacks until top levels are reached.

 

SpellSinger:

Spellsinger is a damage dealing mage class (so-called nuker). They get a unspecific weapon skill and a skill to use robes. The spellsinger has the ability to inflict massive damage at targets from the distances.

Contents

 

 

    * 1 Key Skills

    * 2 Equipment

    * 3 Playstyle

    * 4 Class Comparison

 

Key Skills

 

    * Hydro Blast: Quick reuse time, a lot of damage, good casting speed

    * Surrender to Water: A rebuff that almost doubles damage with water spells

    * Frost Bolt: Slows the enemy causing some damage

    * Aura Flare: Extreme casting speed, good damage, melee range though.

 

Equipment

 

Spellsingers wear robes. Being the fastest of the three nukers class, but having the weakest m.atk, spellsingers prefer equipment which strengthens their spells.

 

On no-grade, all mystics except orcs will try to get the devotion set which speeds up spellcasting. On d-grade, sorcerers love to have the knowledge set for additional damage, but the gloves of that set are droponly and therefore hard to get. On c-grade the demon robe set is the favorite for very impressing damage improvements, even if the hp penalty of that set is a considerable drawback for elves (one could try to get a dye for getting more Con at cost for Str). On b-grade Doom and Zubei are good choices. On a-grade no set really has been made for the spellsinger, but anything but Tallum is probably considerable.

 

Naturally, nukers prefer mage weapons with high matk and magic effects like Empower, Mana Up, UpDown, Acumen etc. For no-grade, the Voodoo Doll and the Crucifix of Blessing are best (and both can be combined with a shield). On d-grade, the Staff of Life would be optimal (but very hard to get) as it is again one-handed; otherwise the Ghost Staff and the Atuba Mace/Hammer all offer the same m.atk. On c-grade, the Homunkulus Sword would be the best onehanded weapon, which also can have two very good SA's, too (Acumen and UpDown). Otherwise, the Ghoul/Demon/Deadmans staff offer more matk, but their SA's are not that great (Ghoul Staff can have Mana Up, however).

 

On b-grade the Hell Knife (Magic Regeneration, Magic Mental Shield, Magic Weakness) and the Sword of Valhalla (Acumen, Magic Weakness, Magic Regeneration) are options for people who prefer to play with a shield. Otherwise there is of course the Staff of Evil Spirits (only crappy magic SAs). On a-grade, the favorite weapon of all mystics (except orcs) is definitely the Sword of Miracles with SA Acumen. Alternatively nukers can use the Branch of The World Tree with either Acumen, Empower or UpDown; spellsingers will probably prefer to get Empower.

 

Sacrificing Str for more Con is an absolutely natural choice for spellsingers, they have no use for Str. They will often also want to sacrifice either Men or Wis for more Int to get more matk.

Playstyle

 

Nukers tend to be loners. However, spellsingers still can get a party once in a while, because their mass sleep effects are welcomed for tight situations. Inside a party, nukers have to step careful. If they are the first ones who attack mobs, they will have to use the same techniques as in solo play (hit and run) while the rest of the party runs after them. Therefore it is best to wait for the party to attack first, so the focus of the mob is already focussed on someone else when the nuker uses his high damage spells.

 

On their own, nukers typically use hit and run techniques - they attack a mob with their highest range spell, run until it has recharged, then attack again. With this technique, nukers can kill even red mobs. Spellsingers are best at this technique, as they are both the fastest runners and the fastest spellcasters.

 

All nukers make good two people parties with Shillien Elders who can empower them and give them Mana, a feature which becomes very important on high levels with the Seal of Element spells which suck endless Mana away. Elven Elders work also - they can't empower, but can give Mana.

Class Comparison

 

Elves are the fastest spellcasters, but have worse matk than Humans and especially Darkelves.

 

Spellsingers are definitely an elven class which can at least keep up with their human and elven counterparts (Sorcerer and Spellhowler). In fact, they are easiest to play, as they are the fastest runners and fastest spellcasters; hardly do they ever get interrupted or even get hit at all. If you love elves, but want a strong class, spellsinger is definitely a good choice.

 

Sorceror:

 

Sorcerer (female: Sorceress) is a damage dealing mage class (so-called nuker). They get an unspecific weapon skill and a skill to use robes. The sorcerer has the ability to inflict massive damage at targets from the distances.

Contents

 

 

    * 1 Key Skills

    * 2 Equipment

    * 3 Playstyle

    * 4 Class Comparison

 

Key Skills

 

To be added

Equipment

 

Sorcerers wear robes. Being the most balanced of the three nukers class, they are relatively free to choose if they prefer robes which offer more spellcasting speed, or robes which offer higher m.atk; most players prefer the later.

 

On no-grade, all mystics except orcs will try to get the devotion set which speeds up spellcasting. On d-grade, sorcerers love to have the knowledge set for additional damage, but the gloves of that set are droponly and therefore hard to get. On c-grade the demon robe set is the favorite for very impressing damage improvements, the hp penalty of that set is no problem for sorcerers. That set is so good that temptation is high to keep it until a-grade, while both Zubei and Avadon robes are not bad to have for more mp and better p.def. Preferences on a-grade is for the Dark Cristal set robe.

 

Naturally, sorcerers prefer mage weapons with high matk and magic effects like Empower, Mana Up, UpDown, Acumen etc. For no-grade, the Voodoo Doll and the Crucifix of Blessing are best (and both can be combined with a shield). On d-grade, the Staff of Life would be optimal (but very hard to get) as it is again one-handed; otherwise the Ghost Staff and the Atuba Mace/Hammer all offer the same m.atk. On c-grade, the Homunkulus Sword would be the best onehanded weapon, which also can have two very good SA's, too (Acumen and UpDown). Otherwise, the Ghoul/Demon/Deadmans staff offer more matk, but their SA's are not that great (Ghoul Staff can have Mana Up, however).

 

On b-grade, there is a special weapon, the Hell Knife, a dagger. Has the highest matk of all daggers and can be combined with a shield; unfortunately it doesn't have magic SAs, which is a shame, because it would be the most stylish weapon for a necromancer. There is also the Sword of Valhalla, which is very beautiful, but cannot have any SAs at all. The b-grade staffs have only crappy magic SA's, too.

 

On a-grade, the favorite weapon of all mystics (except orcs) is definitely the Sword of Miracles with SA Acumen. Alternatively the sorcerer can use the Branch of The World Tree with either Acumen, Empower or UpDown. Also is good Elemental Sword vith SA Empower.

 

Nukers will naturally want to sacrifice Men for Wis or Int - or both. Also, giving Str for Con or Dex or both is done very easily, as Nukers naturally have no use for Str at all.

[edit] Playstyle

 

Nukers tend to be loners. However, sorcerers still can get a party once in a while, because their mass sleep effects are welcomed for tight situations. Inside a party, sorcerers have to step careful. If they are the first ones who attack mobs, they will have to use the same techniques as in solo play (hit and run) while the rest of the party runs uselessly after them. Therefore it is best to wait for the party to attack first, so the focus of the mob is already focussed on someone else when the nuker uses his high damage spells.

 

On their own, nukers typically use hit and run techniques - they attack a mob with their highest range spell, run until it has recharged, then attack again. With this technique, nukers can kill even red mobs.

 

However, all nukers make good two people parties with Shillien Elders who can empower them and give them Mana, a feature which becomes very important on high levels with the Seal of Element spells which suck endless Mana away. Elven Elders work also - they can't empower, but can give Mana.

[edit] Class Comparison

 

Unlike Necromancers, Sorcerers are mainly focused on elemental spells instead of the use of black magic.

 

Unlike spellsingers, a class which uses no black magic at all, Sorcerers have the ability to use slow, one of the black magic necromancer have.

 

-MariniS

 

P.S.:Credits To Strategy Wiki

Posted

Well I would want to >.< And yes I think you coppied that from old topic. Shame man, shame...

 

lol thats why moderator exist ( they have to say what its double post or not)..if u like it just say thx

 

btw good job marinish...and if its double u will be punished xD LOL

Posted

Key skills for Sorc is

 

Prominance

Surrender to Fire

Aura Flare

[Decoy when in pvp the enemy keeps distance]

And Fire Vortex...

 

Fire the one of the 3 earth sings and one of the strongest as well, Sorceress as well as the SpellSinger has a good casting speed but low m atk. although when fire and water are againts each other, the duel is quite fearsome [ tho i never loose when im on sorc]

 

I can make a perfect guide for sorc but i don't have the time for it :).

 

 

PS: -1 For lying :).

Posted

OmG,i didn't said that i made i the guide but that i didn't copy that from here....btw if u are that bad with me then i'll make my own and share it with u!!Stay tuned

Posted

http://www.maxcheaters.com/forum/index.php?topic=48042.msg337983#msg337983...It's greek but i will translate it when i have some free time.....

I start changing my opinion about u :P

That looks better then this topic. :D Anyway it's for kamael++? I don't understand what is writed here but I see in screens....

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.




  • Posts

    • [Release] Solo PvP Zone System 🔹 Compatible with: aCis 401+ 📜 Features: ✅ Automatic Exit on Restart: Players are removed from the zone if a restart occurs or logout. ✅ Custom Exit Command: Players can exit the Solo Zone with the voice command .exit. ✅ Teleport NPC Command: new bypass solopvp for gatekeeper. ✅ Random Name Generator: Generates random names. ✅ PvP Flag: The players are flagged within this zone.   xml preview & java code backup code -> https://pastebin.com/974V2p2p   SoloZone.xml <?xml version="1.0" encoding="UTF-8"?> <list> <zone shape="NPoly" minZ="-5200" maxZ="-4680"><!-- Frintezza Solo Zone --> <stat name="name" val="Solo PvP Zone" /> <stat name="locs" val="174244,-89089,-5112;174260,-86881,-5112;173184,-88090,-5112;175309,-88018,-5112;174231,-88019,-5112;175136,-88828,-5104;174962,-87025,-5104;173149,-87142,-5104;173470,-88908,-5112" /> <stat name="restrictedClasses" val="15,16,97" /> <node x="172031" y="-90127"/> <node x="176428" y="-90089"/> <node x="176428" y="-74051"/> <node x="172057" y="-74108"/> </zone> </list> SoloZone Code: diff --git a/java/net/sf/l2j/gameserver/taskmanager/SoloZoneTaskManager.java b/java/net/sf/l2j/gameserver/taskmanager/SoloZoneTaskManager.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/taskmanager/SoloZoneTaskManager.java @@ -0,0 +1,98 @@ +package net.sf.l2j.gameserver.taskmanager; + +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.logging.Logger; + +import net.sf.l2j.commons.random.Rnd; + +import net.sf.l2j.gameserver.data.manager.ZoneManager; +import net.sf.l2j.gameserver.enums.ZoneId; +import net.sf.l2j.gameserver.handler.voicecommandhandlers.VoiceExitSoloZone; +import net.sf.l2j.gameserver.model.World; +import net.sf.l2j.gameserver.model.actor.Player; +import net.sf.l2j.gameserver.model.location.Location; +import net.sf.l2j.gameserver.model.zone.type.SoloZone; + + +/** + * @author MarGaZeaS + */ +public class SoloZoneTaskManager implements Runnable { + + private static final Location EXIT_LOCATION = VoiceExitSoloZone.getExitLocation(); // Λαμβάνουμε την έξοδο από το VoiceExitSoloZone + + @Override + public void run() + { + // Διασχίζουμε όλους τους παίκτες του κόσμου + for (Player player : World.getInstance().getPlayers()) + { + // Ελέγχουμε αν ο παίκτης είναι στο SoloZone + if (player.isInsideZone(ZoneId.SOLO)) + { + // Μεταφέρουμε τον παίκτη στην έξοδο + player.teleportTo(EXIT_LOCATION.getX(), EXIT_LOCATION.getY(), EXIT_LOCATION.getZ(), 0); + player.sendMessage("The server is restarting, you have been moved out of the Solo Zone."); + } + } + } + + private int _id; + + private static final Logger _log = Logger.getLogger(SoloZoneTaskManager.class.getName()); + private static final ArrayList<String> _rndNames = new ArrayList<>(); + private static final int RANDOM_NAMES = 500; + private static final String CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + private int _playersInSoloZone = 0; + + public int getPlayersInside() { + return _playersInSoloZone; + } + + public void setPlayersInside(int val) { + _playersInSoloZone = val; + } + + public SoloZoneTaskManager() { + _log.info("Solo Zone System: Loading..."); + for (int i = 0; i < RANDOM_NAMES; i++) { + String name = generateName(); + _rndNames.add(name); + _log.info("Generated name: " + name); + } + _log.info("Solo Zone System: Loaded " + _rndNames.size() + " names."); + } + + public String getAName() { + if (_rndNames.isEmpty()) { + _log.warning("SoloZoneManager: No random names available."); + return "Unknown"; + } + return _rndNames.get(Rnd.get(5, RANDOM_NAMES - 5)); + } + + private static String generateName() { + SecureRandom rnd = new SecureRandom(); + StringBuilder sb = new StringBuilder(15); + for (int i = 0; i < 15; i++) { + sb.append(CHARS.charAt(rnd.nextInt(CHARS.length()))); + } + return sb.toString(); + } + + public int getZoneId() + { + return _id; + } + + public final static SoloZone getCurrentZone() { + return ZoneManager.getInstance().getAllZones(SoloZone.class) + .stream() + .findFirst() // Επιστρέφει την πρώτη SoloZone (αν υπάρχει μόνο μία) + .orElse(null); + } + + public static SoloZoneTaskManager getInstance() { + return SingletonHolder._instance; + } + + private static class SingletonHolder { + private static final SoloZoneTaskManager _instance = new SoloZoneTaskManager(); + } +} diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/taskmanager/PvpFlagTaskManager.java b/aCis_gameserver/java/net/sf/l2j/gameserver/taskmanager/PvpFlagTaskManager.java index a707ce5..d247e2e 100644 --- a/aCis_gameserver/java/net/sf/l2j/gameserver/taskmanager/PvpFlagTaskManager.java final Player player = entry.getKey(); final long timeLeft = entry.getValue(); + if(player.isInsideZone(ZoneId.SOLO)) + continue; if(player.isInsideZone(ZoneId.BOSS)) continue; // Time is running out, clear PvP flag and remove from list. if (currentTime > timeLeft) diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestCharacterCreate.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestCharacterCreate.java index a707ce5..d247e2e 100644 +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestCharacterCreate.java if (Config.ALLOW_FISH_CHAMPIONSHIP) FishingChampionshipManager.getInstance(); + if (Config.ENABLE_STARTUP) + StartupManager.getInstance(); diff --git a/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminMaintenance.java b/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminMaintenance.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminMaintenance.java if (!st.hasMoreTokens()) { sendHtmlForm(player); return; } try { switch (st.nextToken()) { case "shutdown": + SoloZoneTaskManager exitTask = new SoloZoneTaskManager(); + ThreadPool.schedule(exitTask, 0); Shutdown.getInstance().startShutdown(player, null, Integer.parseInt(st.nextToken()), false); break; case "restart": + exitTask = new SoloZoneTaskManager(); + ThreadPool.schedule(exitTask, 0); Shutdown.getInstance().startShutdown(player, null, Integer.parseInt(st.nextToken()), true); break; case "abort": Shutdown.getInstance().abort(player); break; diff --git a/java/net/sf/l2j/gameserver/handler/voicecommandhandlers/VoiceExitSoloZone.java b/java/net/sf/l2j/gameserver/handler/voicecommandhandlers/VoiceExitSoloZone.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/handler/voicecommandhandlers/VoiceExitSoloZone.java +package net.sf.l2j.gameserver.handler.voicecommandhandlers; + +import net.sf.l2j.commons.pool.ThreadPool; + +import net.sf.l2j.gameserver.enums.ZoneId; +import net.sf.l2j.gameserver.handler.IVoiceCommandHandler; +import net.sf.l2j.gameserver.model.actor.Player; +import net.sf.l2j.gameserver.model.location.Location; +import net.sf.l2j.gameserver.network.serverpackets.MagicSkillUse; + +/** + * Handles the voice command for exiting the Solo Zone with delay and effects. + * + * @author MarGaZeaS + */ +public class VoiceExitSoloZone implements IVoiceCommandHandler +{ + private static final String[] VOICE_COMMANDS = + { + "exit" + }; + + // Default location to teleport players when exiting the Solo Zone + private static final Location EXIT_LOCATION = new Location(81318, 148064, -3464); // Replace with your desired coordinates + + // Προσθήκη της μεθόδου για να πάρουμε την τοποθεσία εξόδου + public static Location getExitLocation() { + return EXIT_LOCATION; + } + + @Override + public void useVoiceCommand(Player player, String command) + { + if (command.equalsIgnoreCase("exit")) + { + if (!player.isInsideZone(ZoneId.SOLO)) + { + player.sendMessage("You are not inside the Solo Zone."); + return; + } + + // Notify the player about the delay + player.sendMessage("You will be teleported out of the Solo Zone in 2 seconds."); + + // Cast skill effect (Skill ID: 2100, Level: 1) + player.broadcastPacket(new MagicSkillUse(player, player, 2100, 1, 2000, 0)); + + // Schedule the teleportation after a 2-second delay + ThreadPool.schedule(() -> { + // Teleport the player to the designated exit location + player.teleportTo(EXIT_LOCATION.getX(), EXIT_LOCATION.getY(), EXIT_LOCATION.getZ(), 0); + + // Inform the player + player.sendMessage("You have exited the Solo Zone."); + }, 2000); // Delay in milliseconds (2000ms = 2 seconds) + } + } + + @Override + public String[] getVoiceCommandList() + { + return VOICE_COMMANDS; + } +} diff --git a/java/net/sf/l2j/gameserver/handler/VoiceCommandHandler.java b/java/net/sf/l2j/gameserver/handler/VoiceCommandHandler.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/handler/VoiceCommandHandler.java public class VoiceCommandHandler { private final Map<String, IVoiceCommandHandler> _entries = new HashMap<>(); protected VoiceCommandHandler() { ............ ............ + registerHandler(new VoiceExitSoloZone()); } public void registerHandler(IVoiceCommandHandler handler) { for (String command : handler.getVoiceCommandList()) _entries.put(command, handler); } diff --git a/java/net/sf/l2j/gameserver/model/actor/Npc.java b/java/net/sf/l2j/gameserver/model/actor/Npc.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/model/actor/Npc.java else if (command.startsWith("Chat")) { int val = 0; try { val = Integer.parseInt(command.substring(5)); } catch (final IndexOutOfBoundsException ioobe) { } catch (final NumberFormatException nfe) { } showChatWindow(player, val); + ) + else if (command.startsWith("solopvp")) + { + SoloZoneTaskManager.getInstance(); + player.teleportTo(SoloZoneTaskManager.getCurrentZone().getLoc(), 25); + } else if (command.startsWith("Link")) { final String path = command.substring(5).trim(); if (path.indexOf("..") != -1) return; final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); html.setFile("data/html/" + path); html.replace("%objectId%", getObjectId()); player.sendPacket(html); } diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestartPoint.java b/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestartPoint.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestartPoint.java // Fixed. - else if (_requestType == 4) - { - if (!player.isGM() && !player.isFestivalParticipant()) - return; - - loc = player.getPosition(); - } + if (_requestType == 4) + { + // Έλεγχος αν ο παίκτης δεν είναι GM, δεν είναι μέρος του φεστιβάλ και δεν είναι στην Solo Zone + if (!player.isGM() && !player.isFestivalParticipant() && !player.isInsideZone(ZoneId.SOLO)) + { + return; + } + + SoloZoneTaskManager.getInstance(); + SoloZone currentZone = SoloZoneTaskManager.getCurrentZone(); + if (currentZone != null && currentZone.getLoc() != null) + { + // Αν υπάρχει ζώνη και οι τοποθεσίες δεν είναι κενές, χρησιμοποιούμε τυχαία τοποθεσία από την ζώνη + loc = currentZone.getLoc(); + } else + { + // Διαφορετικά, κάνουμε respawn στην τρέχουσα θέση του παίκτη + loc = player.getPosition(); + } + } diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestart.java b/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestart.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestart.java if (player.isFestivalParticipant() && FestivalOfDarknessManager.getInstance().isFestivalInitialized()) { player.sendPacket(SystemMessageId.NO_RESTART_HERE); sendPacket(RestartResponse.valueOf(false)); return; } + if (player.isInsideZone(ZoneId.SOLO)) + { + player.sendMessage("You cannot restart your character while in Solo Zone. Use .exit to leave"); + player.setFakeName(null); + sendPacket(RestartResponse.valueOf(false)); + return; + } player.removeFromBossZone(); diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/Logout.java b/java/net/sf/l2j/gameserver/network/clientpackets/Logout.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/Logout.java player.removeFromBossZone(); player.logout(true); } } + + if (player.isInsideZone(ZoneId.SOLO)) + { + player.sendMessage("You cannot logout or restart your character while in Solo Zone. Use .exit to leave"); + player.setFakeName(null); + player.sendPacket(ActionFailed.STATIC_PACKET); + return; + } + player.removeFromBossZone(); player.logout(true); } } diff --git a/java/net/sf/l2j/gameserver/model/zone/type/SoloZone.java b/java/net/sf/l2j/gameserver/model/zone/type/SoloZone.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/model/zone/type/SoloZone.java +package net.sf.l2j.gameserver.model.zone.type; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.sf.l2j.commons.random.Rnd; + +import net.sf.l2j.Config; +import net.sf.l2j.gameserver.enums.MessageType; +import net.sf.l2j.gameserver.enums.ZoneId; +import net.sf.l2j.gameserver.handler.voicecommandhandlers.VoiceExitSoloZone; +import net.sf.l2j.gameserver.model.World; +import net.sf.l2j.gameserver.model.actor.Creature; +import net.sf.l2j.gameserver.model.actor.Player; +import net.sf.l2j.gameserver.model.location.Location; +import net.sf.l2j.gameserver.model.zone.type.subtype.ZoneType; +import net.sf.l2j.gameserver.network.SystemMessageId; +import net.sf.l2j.gameserver.network.serverpackets.EtcStatusUpdate; +import net.sf.l2j.gameserver.taskmanager.PvpFlagTaskManager; +import net.sf.l2j.gameserver.taskmanager.SoloZoneTaskManager; + +/** + * @author MarGaZeaS + * + */ +public class SoloZone extends ZoneType +{ + private String _name; + private List<Location> _locations = new ArrayList<>(); + + public SoloZone(int id) + { + super(id); + } + + @Override + public void setParameter(String name, String value) + { + if (name.equals("name")) + _name = value; + else if (name.equals("locs")) + { + for (String locs : value.split(";")) + { + String[] coordinates = locs.split(","); + if (coordinates.length == 3) + { + int x = Integer.parseInt(coordinates[0]); + int y = Integer.parseInt(coordinates[1]); + int z = Integer.parseInt(coordinates[2]); + _locations.add(new Location(x, y, z)); + } + else + { + LOGGER.warn("Invalid location format: " + locs); + } + } + } + } + + + @Override + protected void onEnter(Creature character) + { + if (character instanceof Player) + { + final Player player = (Player) character; + + if ((player.getClassId().getId() == 15 || player.getClassId().getId() == 16 || player.getClassId().getId() == 97)) + { + Location respawnLocation = VoiceExitSoloZone.getExitLocation(); + player.instantTeleportTo(respawnLocation, 20); + player.sendMessage("Your class is not allowed in this zone."); + return; + } + + String randomName = SoloZoneTaskManager.getInstance().getAName(); + if (randomName == null || randomName.isEmpty() || !isValidName(randomName)) + { + randomName = generateRandomName(); + } + if (isNameAlreadyTaken(randomName)) + { + randomName = generateRandomName(); + } + player.setFakeName(randomName); + player.sendMessage("Welcome to the Solo Zone, your random name is: " + randomName); + player.sendPacket(SystemMessageId.ENTERED_COMBAT_ZONE); + character.setInsideZone(ZoneId.SOLO, true); + character.setInsideZone(ZoneId.NO_STORE, true); + character.setInsideZone(ZoneId.NO_SUMMON_FRIEND, true); + + if (player.getParty() != null) + { + player.getParty().removePartyMember(player, MessageType.DISCONNECTED); + } + + if (player.getPvpFlag() > 0) + PvpFlagTaskManager.getInstance().remove(player, true); + + player.updatePvPStatus(); + player.broadcastUserInfo(); + } + } + + private static boolean isValidName(String name) { + return name.matches("[a-zA-Z0-9_]+"); + } + + private static String generateRandomName() { + Random rand = new Random(); + int nameLength = rand.nextInt(12) + 4; + StringBuilder nameBuilder = new StringBuilder(); + + for (int i = 0; i < nameLength; i++) { + char randomChar = (char) (rand.nextInt(26) + 'a'); + nameBuilder.append(randomChar); + } + + return nameBuilder.toString(); + } + + private static boolean isNameAlreadyTaken(String name) { + return World.getInstance().getPlayers().stream().anyMatch(player -> player.getFakeName().equals(name)); + } + + @Override + protected void onExit(Creature character) + { + character.setInsideZone(ZoneId.SOLO, false); // Solo zone + character.setInsideZone(ZoneId.NO_STORE, false); // Allow making a store + character.setInsideZone(ZoneId.NO_SUMMON_FRIEND, false); // Allow summon + + if (character instanceof Player) + { + final Player player = (Player) character; + + if (player.getFakeName() != null) + { + player.setFakeName(null); + } + + player.sendPacket(SystemMessageId.LEFT_COMBAT_ZONE); + { + if(!player.isInObserverMode() && player.getPvpFlag() > 0) + PvpFlagTaskManager.getInstance().add(player, Config.PVP_NORMAL_TIME); + + player.sendPacket(new EtcStatusUpdate(player)); + player.broadcastUserInfo(); + } + } + } + + public String getName() + { + return _name; + } + + public Location getLoc() + { + if (_locations.isEmpty()) + { + return null; // Αν η λίστα είναι κενή, επιστρέφουμε null + } + return _locations.get(Rnd.get(0, _locations.size() - 1)); // Επιλέγουμε τυχαία τοποθεσία + } +} diff --git a/java/net/sf/l2j/gameserver/GameServer.java b/java/net/sf/l2j/gameserver/GameServer.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/GameServer.java if (Config.ALLOW_FISH_CHAMPIONSHIP) FishingChampionshipManager.getInstance(); + StringUtil.printSection("Custom Features"); + SoloZoneTaskManager.getInstance(); StringUtil.printSection("Handlers"); LOGGER.info("Loaded {} admin command handlers.", AdminCommandHandler.getInstance().size()); diff --git a/java/net/sf/l2j/gameserver/GameServer.java b/java/net/sf/l2j/gameserver/Shutdown.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/Shutdown.java // disconnect players try { disconnectAllPlayers(); LOGGER.info("All players have been disconnected."); } catch (Exception e) { // Silent catch. } + // Restore real names for players in SoloZone + restoreRealNamesInSoloZone(); // stop all threadpolls ThreadPool.shutdown(); try { LoginServerThread.getInstance().interrupt(); } catch (Exception e) { // Silent catch. } // avoids new players from logging in if (_secondsShut <= 60 && LoginServerThread.getInstance().getServerType() != ServerType.DOWN) LoginServerThread.getInstance().setServerType(ServerType.DOWN); _secondsShut--; Thread.sleep(1000); } } catch (InterruptedException e) { } } + // This method restores the real names of players in SoloZone + private static void restoreRealNamesInSoloZone() + { + for (Player player : World.getInstance().getPlayers()) + { + // Check if player is inside the SoloZone + if (player.isInsideZone(ZoneId.SOLO)) + { + // Restore the real name by removing the fake name + if (player.getFakeName() != null) + { + player.setFakeName(null); // Restore the real name + LOGGER.info("Player {}'s fake name has been removed and real name restored.", player.getName()); + } + } + } + } private static void sendServerQuit(int seconds) { World.toAllOnlinePlayers(SystemMessage.getSystemMessage(SystemMessageId.THE_SERVER_WILL_BE_COMING_DOWN_IN_S1_SECONDS).addNumber(seconds)); } diff --git a/java/net/sf/l2j/gameserver/enums/ZoneId.java b/java/net/sf/l2j/gameserver/enums/ZoneId.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/enums/ZoneId.java public enum ZoneId { PVP(0), PEACE(1), SIEGE(2), MOTHER_TREE(3), CLAN_HALL(4), NO_LANDING(5), WATER(6), JAIL(7), MONSTER_TRACK(8), CASTLE(9), SWAMP(10), NO_SUMMON_FRIEND(11), NO_STORE(12), TOWN(13), HQ(14), DANGER_AREA(15), CAST_ON_ARTIFACT(16), NO_RESTART(17), SCRIPT(18), - BOSS(19), + BOSS(19), + SOLO(20); private final int _id; private ZoneId(int id) { _id = id; } diff --git a/java/net/sf/l2j/gameserver/network/serverpackets/Die.java b/java/net/sf/l2j/gameserver/network/serverpackets/Die.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/serverpackets/Die.java if (creature instanceof Player) { Player player = (Player) creature; - _allowFixedRes = player.getAccessLevel().allowFixedRes(); + _allowFixedRes = player.getAccessLevel().allowFixedRes() || player.isInsideZone(ZoneId.SOLO); _clan = player.getClan(); } diff --git a/java/net/sf/l2j/gameserver/model/actor/Player.java b/java/net/sf/l2j/gameserver//model/actor/Player.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java // Attacker or spectator logging into a siege zone will be ported at town. if (player.isInsideZone(ZoneId.SIEGE) && player.getSiegeState() < 2) player.teleportTo(TeleportType.TOWN); + if (player.isInsideZone(ZoneId.SOLO)) + { + ThreadPool.schedule(() -> { + Location exitLocation = VoiceExitSoloZone.getExitLocation(); + + if (exitLocation != null) + { + player.teleportTo(exitLocation.getX(), exitLocation.getY(), exitLocation.getZ(), 0); + player.sendMessage("You have been moved to the exit of the SoloZone."); + } + }, 5000); // 5000 milliseconds (5sec) + } diff --git a/java/net/sf/l2j/gameserver/model/actor/Player.java b/java/net/sf/l2j/gameserver/model/actor/Player.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/model/actor/Player.java @Override public void doRevive() { super.doRevive(); stopEffects(EffectType.CHARM_OF_COURAGE); sendPacket(new EtcStatusUpdate(this)); getStatus().setCpHpMp(getStatus().getMaxCp(), getStatus().getMaxHp(), getStatus().getMaxMp()); _reviveRequested = 0; _revivePower = 0; if (isMounted()) startFeed(_mountNpcId); + if (isInsideZone(ZoneId.SOLO)) + { + // Give Nobless (1323 ID) + L2Skill no = SkillTable.getInstance().getInfo(1323, 1); + no.getEffects(this, this); + sendMessage("You have received the Nobless status in the Solo Zone."); + } + }   If anyone thinks the code is wrong, please make an update and upload it here so I can update the post. A part was edited with chatgpt
    • Always remember, when you buy files, just compare with my files that I publish for free. and you will know that you are being ripped off. Greetings to all community!!! 🙂
    • Thank you for sharing. You are a capable and skilled person. Thank you again for your selfless dedication, Guytis🫡
    • he kept his promise! i think it's a good idea to unban his old account. he shares files with the community and could help both new and veteran l2off users! good job, Guytis!
  • Topics

×
×
  • Create New...