Jump to content

Recommended Posts

Posted

Creating new Npc Instance

 


 

Hello, someone sent me request via pm, thats why I decided to post this Guide.

 

I will show you, and explain few simple steps about how to create own Npc Instance, how does it work etc.

 

It may be useful for someone who would like to create new kinds of L2 Npc Types.

 

Of course, for single/simple tasks handling, it would be better to make quest bassed Npc instead of new Instance.

 

Hope you know how to compile/use eclipse generaly because I won't explain basic steps here.

 

Guide created with latest Freya clean L2JServer source.

 


 

1. Firstly, it would be good to analyze code:

 

  • L2Npc class at least, available functions etc.

 

2. Create new class:

 

(com/l2jserver/gameserver/model/actor/instance package)

 

  • You will have to add "Instance" word at the end of class name
  • Sample: L2TestNpcInstance.java

 

3. Class body, at begining:

 

package com.l2jserver.gameserver.model.actor.instance;

public class L2TestNpcInstance
{

}

 

4. Select extender of your new Npc Instance:

 

  • You will have to select proper extender - superclass.
  • A Java superclass is a class which gives a method or methods to a Java subclass.
  • A Java class may be either a subclass, a superclass, both, or neither.

 

Lets say you want to create some kind of Monster Npc type, so you should choose L2Attackable for example.

 

For educational purposes, we will extend basic Npc Type class - L2Npc (by using extends L2Npc)

 

package com.l2jserver.gameserver.model.actor.instance;

import com.l2jserver.gameserver.model.actor.L2Npc;

public class L2TestNpcInstance extends L2Npc
{

}

 

Now you will have to add constructor:

 

package com.l2jserver.gameserver.model.actor.instance;

import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;

public class L2TestNpcInstance extends L2Npc
{
public L2TestNpcInstance(int objectId, L2NpcTemplate template)
{
	super(objectId, template);
}
}

 

Even now you would be able to use this Npc Instance (it would work as a standard L2Npc type, nothing changed, nothing new)

 

Its up to you, to choice what exactly this NPC should do, for example handle some kind of event etc.

 

Since you extended L2Npc class, you may use functions/booleans etc from this class. Most important:

 

  • onSpawn()  - actions after NPC ingame spawn
  • onBypassFeedback() - handling html bypass functions
  • showChatWindow - handle showing chat window
  • onAction() - determinate what exactly should happen while clicking at Npc, for example show chat/attack etc
  • doDie() - handle NPC death, for example what should happen after npc death

 

Of course, there are plenty of useful codes (...) simply check L2Npc class.

 

Now, I will show few example, about how to use those things from extended class.

 


 

5. Handling NPC spawn:

 

Lets say, we will create npc, which will say something after his spawn, for example "Hello World!"

 

You will have to use and Override onSpawn() function by adding @Override addannotation.

 

And use proper code to broadcast NPC say packet. Take a look at code:

 

package com.l2jserver.gameserver.model.actor.instance;

import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.network.serverpackets.NpcSay;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;

public class L2TestNpcInstance extends L2Npc
{
public L2TestNpcInstance(int objectId, L2NpcTemplate template)
{
	super(objectId, template);
}

@Override
public void onSpawn()
{
	super.onSpawn();
	// Broadcast new Npc Say Packet
	this.broadcastPacket(new NpcSay(this.getObjectId(), 0, this.getNpcId(),"Hello World!"));
}
}

 


 

6. Bypass Handling:

 

Its important, when for example you want to handle bypass actions from npc html window.

 

Lets say, you want to add new button in npc chat, and after pressing it, player will receive short message.

 

	@Override
public void onBypassFeedback(L2PcInstance player, String command)
{
	if (player == null || player.getLastFolkNPC() == null || player.getLastFolkNPC().getObjectId() != this.getObjectId()) 
	{
		return;
	}
	if (command.startsWith("showMessage"))
	{	
		player.sendMessage("Hello " + player.getName());
	}
}

 

By adding this code (guess its self explanatory), you may use button bypass with bypass "etiquette" - showMessage

 

You will receive message after pressing button with this bypass (of course, while using this NPC type)

 

bypass -h npc_objectId_mainWindow

 

Of course, you can easily add new bypasses by using else if (command.startsWith("blabla")

 


 

7. Showing Chat Window:

 

First of all, since you extended L2Npc class, you really don't have to create any methods to show npc html window.

 

Why? Because this code already exist in L2Npc class (which is our extender in this sample)

 

But lets say, you would like to modify it a little bit (for example using html generated with java instead of showing htm file from DP)

 

It may be pointless sample, but its just to explain about how does it work.

 

You will have to Override showChatWindow() method.

 

	@Override
public void showChatWindow(L2PcInstance player, int val)
{
	TextBuilder tb = new TextBuilder();
	tb.append("<html><title>Test Npc</title><body><center><br>");

	if (player.getLevel() > 60)
		tb.append("Hello " + player.getName() + "! How are you?");
	else
		tb.append("Sorry " + player.getName() + "! You need level 60 or above!");

	NpcHtmlMessage msg = new NpcHtmlMessage(this.getObjectId());
	msg.setHtml(tb.toString());
	msg.replace("%objectId%", String.valueOf(this.getObjectId()));
	player.sendPacket(msg);
}	

 

While using this sample code, after talking with NPC, there will be window, and If player is level 60 or above, he will see this:

 

Hello 'playerNameHere'! How are you?

 

And if player is level > 60

 

Sorry 'playerNameHere'! ! You need level 60 or above!

 


 

8. How to use new Npc Instance:

 

Lets say to made it, and you already compiled it. Now you will have to create new Npc (new npc in database)

 

With proper NPC type, its simple, since our class name is: L2TestNpcInstance so type is L2TestNpc

 

Its like L2Npc, L2Buffer, L2Merchant, L2Teleporter etc.

 


 

This is just a basic introduction, hope you find it useful. Of course its for beginners.

 

So posts like "Lol, I know it already" or "Nothing new for master of java like me" are pointless..

 

Thanks, if there is something wrong, leave reply, something could go wrong.

 

Posted

A perfect guide for L2NPC Intances with too much details about all,step by step.

These kind of guides need l2jsections and thanks that you are improving them again & again ;) .

You are not doing for karma but +1 from me.

Keep up.

 

Posted

Awesome guide and really helpful. Thanks Matim!

 

Btw...

	if (player.getLevel() < 60)
		tb.append("Hello " + player.getName() + "! How are you?");
	else
		tb.append("Sorry " + player.getName() + "! You need level 60 or above!");

I think here if player is lower level than 60, then "Hello playername! How are you?" message will appear to him, and not that he needs to be lvl 60 or above :S I might be wrong, but that's what i read :P

Posted

Awesome guide and really helpful. Thanks Matim!

 

Btw...

	if (player.getLevel() < 60)
		tb.append("Hello " + player.getName() + "! How are you?");
	else
		tb.append("Sorry " + player.getName() + "! You need level 60 or above!");

I think here if player is lower level than 60, then "Hello playername! How are you?" message will appear to him, and not that he needs to be lvl 60 or above :S I might be wrong, but that's what i read :P

else

You read that?

Posted

If player is less than 60 level, then show him message, if he is not, then show him the other message.

Oh,you have right.

So it might be like that

if (player.getLevel() >= 60)
		tb.append("Hello " + player.getName() + "! How are you?");
	else
		tb.append("Sorry " + player.getName() + "! You need level 60 or above!");

With this if he is 60 level or more,it will show him the message "Hello Player!How are you?

if he is less than 60 Sorry Player! You need level 60 or above!

right?

Posted

Oh,you have right.

So it might be like that

if (player.getLevel() >= 60)
		tb.append("Hello " + player.getName() + "! How are you?");
	else
		tb.append("Sorry " + player.getName() + "! You need level 60 or above!");

With this if he is 60 level or more,it will show him the message "Hello Player!How are you?

if he is less than 60 Sorry Player! You need level 60 or above!

right?

yeah, i think :P

Posted

Right, there was mistake, fixed thanks.

No problem.

 

Btw, i have a problem, i hope you can help me. I created a new instance of npc, L2TownTeleporterInstance, i want it to be like when you talk to it, a html will appear that will be located in data/html/teleporter, and in there there will be a list to choose, and a button Teleport. The list will be like combobox (ex. in l2essiel when you pressed .color a window with combo box list appeared). And with Teleport button, you will be teleported to the selected town. Check what i've done:

/*
* 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 2, 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* http://www.gnu.org/copyleft/gpl.html
*/
package net.sf.l2j.gameserver.model.actor.instance;

import java.util.StringTokenizer;

import net.sf.l2j.Config;
import net.sf.l2j.gameserver.datatables.TeleportLocationTable;
import net.sf.l2j.gameserver.instancemanager.CastleManager;
import net.sf.l2j.gameserver.instancemanager.SiegeManager;
import net.sf.l2j.gameserver.instancemanager.TownManager;
import net.sf.l2j.gameserver.model.L2TeleportLocation;
import net.sf.l2j.gameserver.model.actor.L2Character;
import net.sf.l2j.gameserver.network.SystemMessageId;
import net.sf.l2j.gameserver.network.serverpackets.ActionFailed;
import net.sf.l2j.gameserver.network.serverpackets.NpcHtmlMessage;
import net.sf.l2j.gameserver.network.serverpackets.SystemMessage;
import net.sf.l2j.gameserver.templates.chars.L2NpcTemplate;

/**
* @author 
*
*/
public final class L2TownTeleporterInstance extends L2NpcInstance
{

   public L2TownTeleporterInstance(int objectId, L2NpcTemplate template)
   {
       super(objectId, template);
   }

@Override
public void onBypassFeedback(L2PcInstance player, String command)
{
	if (player == null || player.getLastFolkNPC() == null || player.getLastFolkNPC().getObjectId() != this.getObjectId()) 
	{
		return;
	}
       if (command.equalsIgnoreCase("Giran"))
	{	
		player.teleToLocation(83400, 147943, -3404);
		player.sendMessage("You have been teleported to Giran!");
	}
       if (command.equalsIgnoreCase("Aden"))
	{	
		player.teleToLocation(146331, 25762, -2018);
		player.sendMessage("You have been teleported to Aden!");
	}
}
   @Override
public String getHtmlPath(int npcId, int val)
   {
       String pom = "";
       if (val == 0)
       {
           pom = "" + npcId;
       }
       else
       {
           pom = npcId + "-" + val;
       }

       return "data/html/teleporter/" + pom + ".htm";
   }
   @Override
public void showChatWindow(L2PcInstance player)
   {
       NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
       html.replace("%objectId%", String.valueOf(getObjectId()));
       html.replace("%npcname%", getName());
       player.sendPacket(html);
   }
}

 

The problem is that, when i select my town(in this case i have only Giran and Aden), i press Teleport but nothing happens. I am working on Interlude, L2JaCis latest rev(54).

 

Check my html too:

<html>
<body>
<table width=270 cellpadding="4">
<tr>
<td>Select Town:</td>
<td><combobox width=120 height=17 var=ebox list=Giran;Aden></td>
</tr>
<tr>
<td></td>
<td><button value="Teleport" action="bypass -h npc_objectId_mainWindow $ebox" width=140 height=21 back="L2UI_ct1.button_df" fore="L2UI_ct1.button_df"></td>
</tr>
</table>
</html>
</body>

Posted

~OlyMpuS~ look at your extender ..

 

You are trying something like new type of Gatekeeper.

 

Now think, use L2TeleporterInstance as a extender (teleport bypasse will work then)

Posted

~OlyMpuS~ look at your extender ..

 

You are trying something like new type of Gatekeeper.

 

Now think, use L2TeleporterInstance as a extender (teleport bypasse will work then)

If i use as extender L2TeleporterInstance, i get tons of errors. Also L2TeleporterInstance uses as extender L2NpcInstance.

 

 

EDIT: I removed final modifier from L2TeleporterInstance, and the errors are gone. Let me test it again...

 

EDIT2: Still nothing. I press Teleport but nothing. Any ideas? Maybe if i avoid making a new Instance and just copy my 2 commands in L2TeleporterInstance?

 

I mean these:

        if (command.equalsIgnoreCase("Giran"))
	{	
		player.teleToLocation(83400, 147943, -3404);
		player.sendMessage("You have been teleported to Giran!");
	}
        if (command.equalsIgnoreCase("Aden"))
	{	
		player.teleToLocation(146331, 25762, -2018);
		player.sendMessage("You have been teleported to Aden!");
	}

Posted

Wonder why you can't use goto bypass.

 

L2NpcInstance doesn't support this bypass.

You mean to use goto bypass in another instance? Or in L2TeleporterInstance?

Posted

You mean to use goto bypass in another instance? Or in L2TeleporterInstance?

 

First of all tell me what exactly would you like to code.

 

For now, its looks like you want standard Gatekeeper (so its pointless to create new instance, sine there is L2Teleporter)

 

You can also modify L2TeleportInstance aswell (just to add some small things or something)

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Posts

    • ⚡ 5TB Storage + Gemini Advanced 12-18M upgrade active! Keeps your personal files 100% private with instant automated setup.     FINAL CALL: Google is Shutting This Down After October 2026! Google will NEVER bring back this window of opportunity again. Once this month ends, this massive backdoor upgrade is gone permanently!  BUY 2, GET 1 FREE IS STILL LIVE! Stock up now for yourself, your family, your business, and your friends! Think about it: Every single person you know uses a Gmail account, and everyone is running out of storage. Don't let your loved ones get trapped paying $20–$30 every single month when you can set them up with 5TB Cloud Storage + Gemini Advanced (12–18 Months) right now for only $15! Why Buy Bulk Activations Today? Instant Gift Value: Perfect lifetime-style gift for clients, family, or team members. 100% Private & Safe: Activates on personal Gmails—zero passwords or logins required. Global Access: Works worldwide with zero VPN hassles. Instant Automated Delivery: Receive your activation links in seconds 24/7! ‍ Time is running out fast—secure your extra free licenses before the October deadline hits! Order Your Bundle Now on the Website
    • Since technical talk offends people, I believe I should return back to writting my Lineage 2 lore stories. Here's the next one:   Once upon a time, there was a boy and a small adorable wolf.    The boy really loved the wolf but as the wolf grow older and bigger, it became agressive and would bite the boy. One day the boy and the wolf decided to go to the city to buy potions. The road was long and hilly so the boy moved all his adena to the wolf bags to help his legs and reach the city easier.   When they reached the city, the boy tried to take the adena out of the wolf's bags. But the wolf would not ! He bit the boy and said "You will not get this adena back, this is my adena". The boy got angry. He decided to go to the pet master and ask for help.    "Pet master, pet master ! My wolf is big, bad and angry and it won't obey me. I want my adena back and it bites me. "   The pet master looked at the big angry wolf, then looked at the boy and said. "I have a solution for your problem young one. I have magic. Dark magic. I can turn your big bad elder wolf into a younger puppy for free, all you have to do is spell the magic chants. Nothing more, no wolf modifying wands, just your say".   The boy thought about it for a bit, and decided that he indeed wanted to turn things back. But when he was about to spell the magic words, guards arrived at the pet master.    The city guard captain said "Is this the big bad angry wolf that bites people and doesn't give back his adena ? We will kill this wolf !"    For a moment the boy hesitated but he said "This wolf is big bad and angry, but I love this wolf and I dont want it to die ! Please don't kill the big bad angry wolf." But the boy was not fast enough. The guards jumped the wolf and started slashing on him with their swords. The boy didn't know what to do, so in it its final moments right as the wolf was about to die, it spelled the magic words. "Pet master, make my wolf young and adorable again !"   But he was not fast enough. The wolf got slashed and killed by the guards just one moment before the boy could finish his last word.    But as the words came out of his mouth, with the wolf's dead body on the floor, a younger wolf manifested out of thin air. The magic was real. The guards got scared and run away. Now the boy was left with a dead old bad angry wolf and next to him an alive younger version.    The boys joy was even bigger when it opened the new wolfs bags and his adena was finally there. He took the adena and went back to buy potions in the city.   Twenty four hours later, the boy couldn't believe how his fortune would change ...   (No AI was used to write this story)
    • This is like 2017 MaxCheaters. i love it.
    • NEW SEASON GRAND OPENING FROM - 30 OCTOBER 2026, FRIDAY, 20:00 +2 GMT !
    • My bug report was a proper submission. I shouldn't have shown the exploit, I will accept that. Let's end it here. 
  • Topics

×
×
  • Create New...

Important Information

This community uses essential cookies to function properly. Non-essential cookies and third-party services are used only with your consent. Read our Privacy Policy and We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue..