Class Master

Support for the latest build of L2J Server, get help here with installations, upgrades, problems.
Do not post bugs reports here, use viewforum.php?f=77 instead.
There is no support for other server builds than the official provided by l2jserver.com
Forum rules
READ NOW: L2j Forums Rules of Conduct
User avatar
bauwbas
Posts: 60
Joined: Wed Nov 18, 2009 12:44 pm
Location: Lithuania

Class Master

Post by bauwbas »

L2J Revision 3695:
L2JDP Revision 6775:

I have question. Can some say how or give link, how to do that class master give you item (Giant Book) after 3rd class + you must give him too item (e.g. adena, or something else).

I searched in config and found only this one config :

Code: Select all

# Allow use of Event Managers for changing occupation without any quests.# Default: FalseAllowClassMasters = True

Thank you :)
User avatar
bauwbas
Posts: 60
Joined: Wed Nov 18, 2009 12:44 pm
Location: Lithuania

Re: Class Master

Post by bauwbas »

I need add reward to 3rd prof, i want add Gian book. :/ any ideas?
User avatar
NOOR
Posts: 12
Joined: Sat Dec 26, 2009 8:13 pm
Location: Russia

Re: Class Master

Post by NOOR »

JIV, please add the function of l2jo

Code: Select all

# ConfigClassMaster=1;[57(100000)];[];2;[57(1000000)];[];3;[57(10000000)],[5575(1000000)];[6622(1)]# 1st occupation change for 100.000 Adena (item id 57)# 2nd occupation change for 1.000.0000 Adena (item id 57)# 3rd occupation change for 10.000.0000 Adena (item id 57) and 1.000.000 Ancient Adena (item id 5575)# on 3rd occupation change player will be rewarded with 1 Book of Giants (item id 6622)## ConfigClassMaster=1;[];[];2;[];[];3;[];[]# 1st, 2nd, 3rd occupation change for free, without rewardsConfigClassMaster = 1;[];[];2;[];[];3;[];[]
User avatar
jurchiks
Posts: 6769
Joined: Sat Sep 19, 2009 4:16 pm
Location: Eastern Europe

Re: Class Master

Post by jurchiks »

actually, if i remember correctly, that was in l2j too, and was removed for some reason...
+1 for configurable rewards
If you have problems, FIRST TRY SOLVING THEM YOURSELF, and if you get errors, TRY TO ANALYZE THEM, and ONLY if you can't help it, THEN ask here.
Otherwise you will never learn anything if all you do is copy-paste!
Discussion breeds innovation.
User avatar
janiii
L2j Veteran
L2j Veteran
Posts: 4269
Joined: Wed May 28, 2008 3:15 pm
Location: Slovakia

Re: Class Master

Post by janiii »

jurchiks wrote:actually, if i remember correctly, that was in l2j too, and was removed for some reason...
+1 for configurable rewards
classmaster/villagemaster was totally reworked. that is why it was removed.
DO NOT EVEN TRY TO MESS WITH ME!
forum flOOder dancing dEVILoper
I don't give private support - PM will be ignored!
User avatar
jurchiks
Posts: 6769
Joined: Sat Sep 19, 2009 4:16 pm
Location: Eastern Europe

Re: Class Master

Post by jurchiks »

still, the configurable rewards should have stayed...
If you have problems, FIRST TRY SOLVING THEM YOURSELF, and if you get errors, TRY TO ANALYZE THEM, and ONLY if you can't help it, THEN ask here.
Otherwise you will never learn anything if all you do is copy-paste!
Discussion breeds innovation.
User avatar
janiii
L2j Veteran
L2j Veteran
Posts: 4269
Joined: Wed May 28, 2008 3:15 pm
Location: Slovakia

Re: Class Master

Post by janiii »

jurchiks wrote:still, the configurable rewards should have stayed...
still, you can try it yourself and contribute ;)
DO NOT EVEN TRY TO MESS WITH ME!
forum flOOder dancing dEVILoper
I don't give private support - PM will be ignored!
User avatar
Edoo
Posts: 101
Joined: Sun Sep 09, 2007 3:52 am
Location: Russia
Contact:

Re: Class Master

Post by Edoo »

NEW Class Master :)
package com.l2jserver.gameserver.model.actor.instance.L2ProfMasterInstance.java;

Code: Select all

 /* * 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 com.l2jserver.gameserver.model.actor.instance; import javolution.text.TextBuilder;import com.l2jserver.Config;import com.l2jserver.gameserver.ai.CtrlIntention;import com.l2jserver.gameserver.datatables.CharTemplateTable;import com.l2jserver.gameserver.datatables.ItemTable;import com.l2jserver.gameserver.model.base.ClassId;import com.l2jserver.gameserver.model.quest.Quest;import com.l2jserver.gameserver.network.SystemMessageId;import com.l2jserver.gameserver.network.serverpackets.ActionFailed;import com.l2jserver.gameserver.network.serverpackets.MyTargetSelected;import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;import com.l2jserver.gameserver.network.serverpackets.SystemMessage;import com.l2jserver.gameserver.network.serverpackets.ValidateLocation;import com.l2jserver.gameserver.templates.chars.L2NpcTemplate; import java.util.logging.Logger; /** * Class Master implementation * ths npc is used for changing character occupation * Reworked for  by -= Hell Bound project (Edoo) =- **/public final class L2ProfMasterInstance extends L2NpcInstance{    protected static final Logger _logClassMaster = Logger.getLogger(L2ProfMasterInstance.class.getName());    /**     * @param template     */    public L2ProfMasterInstance(int objectId, L2NpcTemplate template)    {        super(objectId, template);    }     @Override    public void onAction(L2PcInstance player)    {        if (!canTarget(player)) return;         // Check if the L2PcInstance already target the L2NpcInstance        if (getObjectId() != player.getTargetId())        {            // Set the target of the L2PcInstance player            player.setTarget(this);             // Send a Server->Client packet MyTargetSelected to the L2PcInstance player            player.sendPacket(new MyTargetSelected(getObjectId(), 0));             // Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client            player.sendPacket(new ValidateLocation(this));        }        else        {            if (!canInteract(player))            {                player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);                return;            }             NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());            TextBuilder sb = new TextBuilder();            sb.append("<html><body>");            sb.append(getName()+":<br>");            sb.append("<br>");             ClassId classId = player.getClassId();            int level = player.getLevel();            int jobLevel = classId.level();             int newJobLevel = jobLevel + 1;             if ((((level >= 20 && jobLevel == 0 ) || (level >= 40 && jobLevel == 1 ) || (level >= 76 && jobLevel == 2))                    && Config.CLASS_MASTER_SETTINGS2.isAllowed(newJobLevel)))            {                if (((level >= 20 && jobLevel == 0 ) || (level >= 40 && jobLevel == 1 ) || (level >= 76 && jobLevel == 2))                        && Config.CLASS_MASTER_SETTINGS2.isAllowed(newJobLevel))                {                    sb.append("You can change your occupation to following:<br>");                     for (ClassId child : ClassId.values())                        if (child.childOf(classId) && child.level() == newJobLevel)                            sb.append("<br><a action=\"bypass -h npc_" + getObjectId() + "_change_class " + (child.getId()) + "\"> " + CharTemplateTable.getInstance().getClassNameById(child.getId()) + "</a>");                     if (Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel) != null &&                            Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).size() > 0)                    {                        sb.append("<br><br>Item(s) required for class change:");                        sb.append("<table width=270>");                        for(Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).keySet())                        {                            int _count = Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).get(_itemId);                            sb.append("<tr><td><font color=\"LEVEL\">"+_count+"</font></td><td>"+ItemTable.getInstance().getTemplate(_itemId).getName()+"</td></tr>");                        }                        sb.append("</table>");                    }                }             }            else            {                switch (jobLevel)                {                    case 0:                        if (Config.CLASS_MASTER_SETTINGS2.isAllowed(1))                            sb.append("Come back here when you reached level 20 to change your class.<br>");                        else                            if (Config.CLASS_MASTER_SETTINGS2.isAllowed(2))                                sb.append("Come back after your first occupation change.<br>");                            else                                if (Config.CLASS_MASTER_SETTINGS2.isAllowed(3))                                    sb.append("Come back after your second occupation change.<br>");                                else                                    sb.append("I can't change your occupation.<br>");                        break;                    case 1:                        if (Config.CLASS_MASTER_SETTINGS2.isAllowed(2))                            sb.append("Come back here when you reached level 40 to change your class.<br>");                        else                            if (Config.CLASS_MASTER_SETTINGS2.isAllowed(3))                                sb.append("Come back after your second occupation change.<br>");                            else                                 sb.append("I can't change your occupation.<br>");                        break;                    case 2:                        if (Config.CLASS_MASTER_SETTINGS2.isAllowed(3))                            sb.append("Come back here when you reached level 76 to change your class.<br>");                        else                             sb.append("I can't change your occupation.<br>");                        break;                    case 3:                        sb.append("There is no class change available for you anymore.<br>");                        break;                }                sb.append("<br>");            }             for (Quest q : Quest.findAllEvents())                sb.append("Event: <a action=\"bypass -h Quest " + q.getName() + "\">" + q.getDescr() + "</a><br>");            sb.append("</body></html>");            html.setHtml(sb.toString());            player.sendPacket(html);         }		player.sendPacket(ActionFailed.STATIC_PACKET);    }     @Override    public void onBypassFeedback(L2PcInstance player, String command)    {        if (command.startsWith("change_class"))        {            int val = Integer.parseInt(command.substring(13));             ClassId classId = player.getClassId();            ClassId newClassId = ClassId.values()[val];             int level = player.getLevel();            int jobLevel = classId.level();            int newJobLevel = newClassId.level();             // -- exploit prevention            // prevents changing if config option disabled            if (!Config.CLASS_MASTER_SETTINGS2.isAllowed(newJobLevel)) return;             // prevents changing to class not in same class tree            if (!newClassId.childOf(classId)) return;             // prevents changing between same level jobs            if(newJobLevel != jobLevel + 1) return;             // check for player level            if (level < 20 && newJobLevel > 1) return;            if (level < 40 && newJobLevel > 2) return;            if (level < 76 && newJobLevel > 3) return;            // -- prevention ends             // check if player have all required items for class transfer            for(Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).keySet())            {                int _count = Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).get(_itemId);                if (player.getInventory().getInventoryItemCount(_itemId, -1) < _count)                {                    player.sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));                    return;                }            }             // get all required items for class transfer            for(Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).keySet())            {                int _count = Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).get(_itemId);                player.destroyItemByItemId("ClassMaster", _itemId, _count, player, true);            }             // reward player with items            for(Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRewardItems(newJobLevel).keySet())            {                int _count = Config.CLASS_MASTER_SETTINGS2.getRewardItems(newJobLevel).get(_itemId);                player.addItem("ClassMaster", _itemId, _count, player, true);            }             changeClass(player, val);             player.rewardSkills();             if(newJobLevel == 3)                // system sound 3rd occupation                player.sendPacket(new SystemMessage(SystemMessageId.THIRD_CLASS_TRANSFER));            else                // system sound for 1st and 2nd occupation                player.sendPacket(new SystemMessage(SystemMessageId.CLASS_TRANSFER));             NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());            TextBuilder sb = new TextBuilder();            sb.append("<html><body>");            sb.append(getName()+":<br>");            sb.append("<br>");                      sb.append("You have now become a <font color=\"LEVEL\">" + CharTemplateTable.getInstance().getClassNameById(player.getClassId().getId()) + "</font>.");            sb.append("</body></html>");            html.setHtml(sb.toString());            player.sendPacket(html);             // Update the overloaded status of the L2PcInstance            player.refreshOverloaded();            // Update the expertise status of the L2PcInstance            player.refreshExpertisePenalty();        }    }     private void changeClass(L2PcInstance player, int val)    {        if (Config.DEBUG) _logClassMaster.fine("Changing class to ClassId:" + val);        player.setClassId(val);         if (player.isSubClassActive()) player.getSubClasses().get(player.getClassIndex()).setClassId(player.getActiveClass());        else player.setBaseClass(player.getActiveClass());         player.broadcastUserInfo();    }}  
package com.l2jserver.Config.java

Code: Select all

     /** Class Master Configuration */    public static boolean    ALLOW_CLASS_MASTERS2;    public static boolean    CLASS_MASTER_STRIDER_UPDATE2;    public static String     CLASS_MASTER_SETTINGS_LINE2;    public static ClassMasterSettings2   CLASS_MASTER_SETTINGS2;------------------------------ 				ALLOW_CLASS_MASTERS2 = Boolean.parseBoolean(custom_system.getProperty("AllowClassMasters2", "True"));                if (!custom_system.getProperty("ConfigClassMaster2").trim().equalsIgnoreCase("False"))                    CLASS_MASTER_SETTINGS_LINE2			= custom_system.getProperty("ConfigClassMaster2");                    CLASS_MASTER_SETTINGS2				= new ClassMasterSettings2(CLASS_MASTER_SETTINGS_LINE2); ------------------------      // Class Masert Config    public static class ClassMasterSettings2    {        private FastMap<Integer, FastMap<Integer, Integer>> _claimItems;        private FastMap<Integer, FastMap<Integer, Integer>> _rewardItems;        private FastMap<Integer, Boolean>                   _allowedClassChange;        public ClassMasterSettings2(String _configLine)        {            _claimItems = new FastMap<Integer, FastMap<Integer, Integer>>();            _rewardItems = new FastMap<Integer, FastMap<Integer, Integer>>();            _allowedClassChange = new FastMap<Integer, Boolean>();            if (_configLine != null)                parseConfigLine(_configLine.trim());        }         private void parseConfigLine(String _configLine)        {            StringTokenizer st = new StringTokenizer(_configLine, ";");             while (st.hasMoreTokens())            {                // get allowed class change                int job = Integer.parseInt(st.nextToken());                 _allowedClassChange.put(job, true);                FastMap<Integer, Integer> _items = new FastMap<Integer, Integer>();                // parse items needed for class change                if (st.hasMoreTokens())                {                    StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");                    while (st2.hasMoreTokens())                    {                        StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");                        int _itemId = Integer.parseInt(st3.nextToken());                        int _quantity = Integer.parseInt(st3.nextToken());                        _items.put(_itemId, _quantity);                    }                }                _claimItems.put(job, _items);                _items = new FastMap<Integer, Integer>();                // parse gifts after class change                if (st.hasMoreTokens())                {                    StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");                    while (st2.hasMoreTokens())                    {                        StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");                        int _itemId = Integer.parseInt(st3.nextToken());                        int _quantity = Integer.parseInt(st3.nextToken());                        _items.put(_itemId, _quantity);                    }                }                _rewardItems.put(job, _items);            }        }        public boolean isAllowed(int job)        {            if (_allowedClassChange == null)                return false;            if (_allowedClassChange.containsKey(job))                return _allowedClassChange.get(job);            else                return false;        }        public FastMap<Integer, Integer> getRewardItems(int job)        {            if (_rewardItems.containsKey(job))                return _rewardItems.get(job);            else                return null;        }        public FastMap<Integer, Integer> getRequireItems(int job)        {            if (_claimItems.containsKey(job))                return _claimItems.get(job);            else                return null;       }    }  
gameserver/config/custom.properties

Code: Select all

 #============================================================##                   Мастер смен проф                         ##============================================================# # Включение мастераAllowClassMasters2 = True # Config for special Class Master npc that can change players occupation# If you need change occupation only use quest then set this to False (Default)# Syntax: occupation number;[required item id(count)],[],...;[reward item id(count)],[],...;occupation number...# Examples:## ConfigClassMaster=1;[57(100000)];[];2;[57(1000000)];[];3;[57(10000000)],[5575(1000000)];[6622(1)]# 1st occupation change for 100.000 Adena (item id 57)# 2nd occupation change for 1.000.0000 Adena (item id 57)# 3rd occupation change for 10.000.0000 Adena (item id 57) and 1.000.000 Ancient Adena (item id 5575)# on 3rd occupation change player will be rewarded with 1 Book of Giants (item id 6622)## ConfigClassMaster=1;[];[];2;[];[];3;[];[]# 1st, 2nd, 3rd occupation change for free, without rewardsConfigClassMaster2 = 1;[57(100000)];[];2;[57(2000000)];[5575(1000)];3;[57(10000000)];[5575(10000)]#ConfigClassMaster2 = False 
RUS:

Работает превосходно. Заранее извиняюсь что не по английски :oops:
Image
User avatar
jurchiks
Posts: 6769
Joined: Sat Sep 19, 2009 4:16 pm
Location: Eastern Europe

Re: Class Master

Post by jurchiks »

janiii wrote:
jurchiks wrote:still, the configurable rewards should have stayed...
still, you can try it yourself and contribute ;)
it wasn't me who removed them...
but anyway, as you can see, Edoo already made a good looking patch :)
i'm voting for it being added to svn
If you have problems, FIRST TRY SOLVING THEM YOURSELF, and if you get errors, TRY TO ANALYZE THEM, and ONLY if you can't help it, THEN ask here.
Otherwise you will never learn anything if all you do is copy-paste!
Discussion breeds innovation.
Nycs
Posts: 3
Joined: Tue Jan 12, 2010 7:50 pm

Re: Class Master

Post by Nycs »

I'm voting for it being added to svn too. Why not? ;)
User avatar
janiii
L2j Veteran
L2j Veteran
Posts: 4269
Joined: Wed May 28, 2008 3:15 pm
Location: Slovakia

Re: Class Master

Post by janiii »

jurchiks wrote:it wasn't me who removed them...
but anyway, as you can see, Edoo already made a good looking patch :)
i'm voting for it being added to svn
- it isn't a real patch, so applying will be probably a bit harder for you
- not even reviewed by you
- not even applied and compiled by you
- not even tested by you
- same for devs, and at the end it is up to them if they commit it or do own work on this

first at least look at the code, apply the "patch", test it and report here issues. then we can talk about something.

my comments to Edoo's code:
- interesting approach to create a new npc type and not implement it to existing one
- mostly copy of l2jo class master without the gm handling
- not compilable
- config ALLOW_CLASS_MASTERS2 not used anywhere (should be used to spawn the new classmaster)
- no npc and no spawnlist for new classmaster
- config CLASS_MASTER_STRIDER_UPDATE2 only declared, but not defined and not used anywhere
- no gm handling
DO NOT EVEN TRY TO MESS WITH ME!
forum flOOder dancing dEVILoper
I don't give private support - PM will be ignored!
User avatar
janiii
L2j Veteran
L2j Veteran
Posts: 4269
Joined: Wed May 28, 2008 3:15 pm
Location: Slovakia

Re: Class Master

Post by janiii »

Edoo's code reworked and a real patch..

- todo: needs a npc of type L2ProfMaster and spawns
- todo: gm handling

http://www.pastebin.cz/30223

Code: Select all

Index: java/com/l2jserver/Config.java===================================================================--- java/com/l2jserver/Config.java	(revision 3799)+++ java/com/l2jserver/Config.java	(working copy)@@ -29,9 +29,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List;+import java.util.StringTokenizer; import java.util.logging.Logger;  import javolution.util.FastList;+import javolution.util.FastMap;  import com.l2jserver.gameserver.util.FloodProtectorConfig; import com.l2jserver.gameserver.util.StringUtil;@@ -104,6 +106,9 @@ 	public static boolean ALT_GAME_SHIELD_BLOCKS; 	public static int ALT_PERFECT_SHLD_BLOCK; 	public static boolean ALLOW_CLASS_MASTERS;+	public static boolean ALLOW_CLASS_MASTERS2;+	public static String CLASS_MASTER_SETTINGS_LINE2;+	public static ClassMasterSettings2 CLASS_MASTER_SETTINGS2; 	public static boolean ALLOW_ENTIRE_TREE; 	public static boolean ALTERNATE_CLASS_MASTER; 	public static boolean LIFE_CRYSTAL_NEEDED;@@ -1308,6 +1313,10 @@ 					ALT_GAME_SHIELD_BLOCKS = Boolean.parseBoolean(Character.getProperty("AltShieldBlocks", "false")); 					ALT_PERFECT_SHLD_BLOCK = Integer.parseInt(Character.getProperty("AltPerfectShieldBlockRate", "10")); 					ALLOW_CLASS_MASTERS = Boolean.parseBoolean(Character.getProperty("AllowClassMasters", "False"));+					ALLOW_CLASS_MASTERS2 = Boolean.parseBoolean(Character.getProperty("AllowClassMasters2", "False"));+					if (!Character.getProperty("ConfigClassMaster2").trim().equalsIgnoreCase("False"))+						CLASS_MASTER_SETTINGS_LINE2 = Character.getProperty("ConfigClassMaster2");+					CLASS_MASTER_SETTINGS2 = new ClassMasterSettings2(CLASS_MASTER_SETTINGS_LINE2); 					ALLOW_ENTIRE_TREE = Boolean.parseBoolean(Character.getProperty("AllowEntireTree", "False")); 					ALTERNATE_CLASS_MASTER = Boolean.parseBoolean(Character.getProperty("AlternateClassMaster", "False")); 					LIFE_CRYSTAL_NEEDED = Boolean.parseBoolean(Character.getProperty("LifeCrystalNeeded", "true"));@@ -2856,4 +2865,86 @@ 		config.PUNISHMENT_TYPE = properties.getProperty(StringUtil.concat("FloodProtector", configString, "PunishmentType"), "none"); 		config.PUNISHMENT_TIME = Integer.parseInt(properties.getProperty(StringUtil.concat("FloodProtector", configString, "PunishmentTime"), "0")); 	}+	+	// Class Master Config+	public static class ClassMasterSettings2+	{+		private FastMap<Integer, FastMap<Integer, Integer>> _claimItems;+		private FastMap<Integer, FastMap<Integer, Integer>> _rewardItems;+		private FastMap<Integer, Boolean> _allowedClassChange;+		+		public ClassMasterSettings2(String _configLine)+		{+			_claimItems = new FastMap<Integer, FastMap<Integer, Integer>>();+			_rewardItems = new FastMap<Integer, FastMap<Integer, Integer>>();+			_allowedClassChange = new FastMap<Integer, Boolean>();+			if (_configLine != null)+				parseConfigLine(_configLine.trim());+		}+		+		private void parseConfigLine(String _configLine)+		{+			StringTokenizer st = new StringTokenizer(_configLine, ";");+			while (st.hasMoreTokens())+			{+				// get allowed class change+				int job = Integer.parseInt(st.nextToken());+				_allowedClassChange.put(job, true);+				FastMap<Integer, Integer> _items = new FastMap<Integer, Integer>();+				// parse items needed for class change+				if (st.hasMoreTokens())+				{+					StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");+					while (st2.hasMoreTokens())+					{+						StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");+						int _itemId = Integer.parseInt(st3.nextToken());+						int _quantity = Integer.parseInt(st3.nextToken());+						_items.put(_itemId, _quantity);+					}+				}+				_claimItems.put(job, _items);+				_items = new FastMap<Integer, Integer>();+				// parse gifts after class change+				if (st.hasMoreTokens())+				{+					StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");+					while (st2.hasMoreTokens())+					{+						StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");+						int _itemId = Integer.parseInt(st3.nextToken());+						int _quantity = Integer.parseInt(st3.nextToken());+						_items.put(_itemId, _quantity);+					}+				}+				_rewardItems.put(job, _items);+			}+		}+		+		public boolean isAllowed(int job)+		{+			if (_allowedClassChange == null)+				return false;+			if (_allowedClassChange.containsKey(job))+				return _allowedClassChange.get(job);+			else+				return false;+		}+		+		public FastMap<Integer, Integer> getRewardItems(int job)+		{+			if (_rewardItems.containsKey(job))+				return _rewardItems.get(job);+			else+				return null;+		}+		+		public FastMap<Integer, Integer> getRequireItems(int job)+		{+			if (_claimItems.containsKey(job))+				return _claimItems.get(job);+			else+				return null;+		}+	} }Index: java/com/l2jserver/gameserver/model/actor/instance/L2ProfMasterInstance.java===================================================================--- java/com/l2jserver/gameserver/model/actor/instance/L2ProfMasterInstance.java	(revision 0)+++ java/com/l2jserver/gameserver/model/actor/instance/L2ProfMasterInstance.java	(revision 0)@@ -0,0 +1,253 @@+/*+ * 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 com.l2jserver.gameserver.model.actor.instance;++import java.util.logging.Logger;++import javolution.text.TextBuilder;++import com.l2jserver.Config;+import com.l2jserver.gameserver.ai.CtrlIntention;+import com.l2jserver.gameserver.datatables.CharTemplateTable;+import com.l2jserver.gameserver.datatables.ItemTable;+import com.l2jserver.gameserver.model.base.ClassId;+import com.l2jserver.gameserver.model.quest.Quest;+import com.l2jserver.gameserver.network.SystemMessageId;+import com.l2jserver.gameserver.network.serverpackets.ActionFailed;+import com.l2jserver.gameserver.network.serverpackets.MyTargetSelected;+import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;+import com.l2jserver.gameserver.network.serverpackets.SystemMessage;+import com.l2jserver.gameserver.network.serverpackets.ValidateLocation;+import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;++/**+ * Class Master implementation+ * the npc is used for changing character occupation+ * Reworked for  by -= Hell Bound project (Edoo) =-+ **/+public final class L2ProfMasterInstance extends L2NpcInstance+{+	protected static final Logger _logClassMaster = Logger.getLogger(L2ProfMasterInstance.class.getName());+	+	public L2ProfMasterInstance(int objectId, L2NpcTemplate template)+	{+		super(objectId, template);+	}+	+	@Override+	public void onAction(L2PcInstance player, boolean interact)+	{+		if (!canTarget(player))+			return;+		+		player.setLastFolkNPC(this);+		+		// Check if the L2PcInstance already target the L2NpcInstance+		if (getObjectId() != player.getTargetId())+		{+			// Set the target of the L2PcInstance player+			player.setTarget(this);+			+			// Send a Server->Client packet MyTargetSelected to the L2PcInstance player+			player.sendPacket(new MyTargetSelected(getObjectId(), 0));+			+			// Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client+			player.sendPacket(new ValidateLocation(this));+		}+		else if (interact)+		{+			// Calculate the distance between the L2PcInstance and the L2NpcInstance+			if (!canInteract(player))+			{+				// Notify the L2PcInstance AI with AI_INTENTION_INTERACT+				player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);+				return;+			}+			+			NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());+			TextBuilder sb = new TextBuilder();+			sb.append("<html><body>");+			sb.append(getName() + ":<br>");+			sb.append("<br>");+			+			ClassId classId = player.getClassId();+			int level = player.getLevel();+			int jobLevel = classId.level();+			+			int newJobLevel = jobLevel + 1;+			+			if (((level >= 20 && jobLevel == 0) || (level >= 40 && jobLevel == 1) || (level >= 76 && jobLevel == 2)) && Config.CLASS_MASTER_SETTINGS2.isAllowed(newJobLevel))+			{+				sb.append("You can change your occupation to following:<br>");+				+				for (ClassId child : ClassId.values())+				{+					if (child.childOf(classId) && child.level() == newJobLevel)+						sb.append("<br><a action=\"bypass -h npc_" + getObjectId() + "_change_class " + (child.getId()) + "\"> " + CharTemplateTable.getInstance().getClassNameById(child.getId()) + "</a>");+				}+				+				if (Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel) != null && !Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).isEmpty())+				{+					sb.append("<br><br>Item(s) required for class change:");+					sb.append("<table width=270>");+					for (Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).keySet())+					{+						int _count = Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).get(_itemId);+						sb.append("<tr><td><font color=\"LEVEL\">" + _count + "</font></td><td>" + ItemTable.getInstance().getTemplate(_itemId).getName() + "</td></tr>");+					}+					sb.append("</table>");+				}+			}+			else+			{+				switch (jobLevel)+				{+					case 0:+						if (Config.CLASS_MASTER_SETTINGS2.isAllowed(1))+							sb.append("Come back here when you reached level 20 to change your class.<br>");+						else if (Config.CLASS_MASTER_SETTINGS2.isAllowed(2))+							sb.append("Come back after your first occupation change.<br>");+						else if (Config.CLASS_MASTER_SETTINGS2.isAllowed(3))+							sb.append("Come back after your second occupation change.<br>");+						else+							sb.append("I can't change your occupation.<br>");+						break;+					case 1:+						if (Config.CLASS_MASTER_SETTINGS2.isAllowed(2))+							sb.append("Come back here when you reached level 40 to change your class.<br>");+						else if (Config.CLASS_MASTER_SETTINGS2.isAllowed(3))+							sb.append("Come back after your second occupation change.<br>");+						else+							sb.append("I can't change your occupation.<br>");+						break;+					case 2:+						if (Config.CLASS_MASTER_SETTINGS2.isAllowed(3))+							sb.append("Come back here when you reached level 76 to change your class.<br>");+						else+							sb.append("I can't change your occupation.<br>");+						break;+					case 3:+						sb.append("There is no class change available for you anymore.<br>");+						break;+				}+				sb.append("<br>");+			}+			+			for (Quest q : Quest.findAllEvents())+				sb.append("Event: <a action=\"bypass -h Quest " + q.getName() + "\">" + q.getDescr() + "</a><br>");+			sb.append("</body></html>");+			html.setHtml(sb.toString());+			player.sendPacket(html);+		}+		player.sendPacket(ActionFailed.STATIC_PACKET);+	}+	+	@Override+	public void onBypassFeedback(L2PcInstance player, String command)+	{+		if (command.startsWith("change_class"))+		{+			int val = Integer.parseInt(command.substring(13));+			+			ClassId classId = player.getClassId();+			ClassId newClassId = ClassId.values()[val];+			+			int level = player.getLevel();+			int jobLevel = classId.level();+			int newJobLevel = newClassId.level();+			+			// -- exploit prevention+			// prevents changing if config option disabled+			if (!Config.CLASS_MASTER_SETTINGS2.isAllowed(newJobLevel))+				return;+			+			// prevents changing to class not in same class tree+			if (!newClassId.childOf(classId))+				return;+			+			// prevents changing between same level jobs+			if (newJobLevel != jobLevel + 1)+				return;+			+			// check for player level+			if (level < 20 && newJobLevel > 1)+				return;+			if (level < 40 && newJobLevel > 2)+				return;+			if (level < 76 && newJobLevel > 3)+				return;+			// -- prevention ends+			+			// check if player have all required items for class transfer+			for (Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).keySet())+			{+				int _count = Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).get(_itemId);+				if (player.getInventory().getInventoryItemCount(_itemId, -1) < _count)+				{+					player.sendPacket(new SystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS));+					return;+				}+			}+			+			// get all required items for class transfer+			for (Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).keySet())+			{+				int _count = Config.CLASS_MASTER_SETTINGS2.getRequireItems(newJobLevel).get(_itemId);+				player.destroyItemByItemId("ClassMaster", _itemId, _count, player, true);+			}+			+			// reward player with items+			for (Integer _itemId : Config.CLASS_MASTER_SETTINGS2.getRewardItems(newJobLevel).keySet())+			{+				int _count = Config.CLASS_MASTER_SETTINGS2.getRewardItems(newJobLevel).get(_itemId);+				player.addItem("ClassMaster", _itemId, _count, player, true);+			}+			+			changeClass(player, val);+			+			player.rewardSkills();+			+			NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());+			TextBuilder sb = new TextBuilder();+			sb.append("<html><body>");+			sb.append(getName() + ":<br>");+			sb.append("<br>");+			sb.append("You have now become a <font color=\"LEVEL\">" + CharTemplateTable.getInstance().getClassNameById(player.getClassId().getId()) + "</font>.");+			sb.append("</body></html>");+			html.setHtml(sb.toString());+			player.sendPacket(html);+			+			// Update the overloaded status of the L2PcInstance+			player.refreshOverloaded();+			// Update the expertise status of the L2PcInstance+			player.refreshExpertisePenalty();+		}+	}+	+	private void changeClass(L2PcInstance player, int val)+	{+		if (Config.DEBUG)+			_logClassMaster.fine("Changing class to ClassId:" + val);+		+		player.setClassId(val);+		+		if (player.isSubClassActive())+			player.getSubClasses().get(player.getClassIndex()).setClassId(player.getActiveClass());+		else+			player.setBaseClass(player.getActiveClass());+		+		player.broadcastUserInfo();+	}+}Index: java/config/Character.properties===================================================================--- java/config/Character.properties	(revision 3799)+++ java/config/Character.properties	(working copy)@@ -150,6 +150,23 @@ # Default: False AllowClassMasters = False +# Class master with configurable price and reward+AllowClassMasters2 = False+ +# Config for special Class Master npc that can change players occupation+# If you need change occupation only use quest then set this to False (Default)+# Syntax: occupation number;[required item id(count)],[],...;[reward item id(count)],[],...;occupation number...+# Examples:+# ConfigClassMaster = 1;[57(100000)];[];2;[57(1000000)];[];3;[57(10000000)],[5575(1000000)];[6622(1)]+# 1st occupation change for 100.000 Adena (item id 57)+# 2nd occupation change for 1.000.0000 Adena (item id 57)+# 3rd occupation change for 10.000.0000 Adena (item id 57) and 1.000.000 Ancient Adena (item id 5575)+# on 3rd occupation change player will be rewarded with 1 Book of Giants (item id 6622)+# ConfigClassMaster = 1;[];[];2;[];[];3;[];[]+# 1st, 2nd, 3rd occupation change for free, without rewards+ConfigClassMaster2 = 1;[57(100000)];[];2;[57(2000000)];[5575(1000)];3;[57(10000000)];[5575(10000)]+#ConfigClassMaster2 = False+ # Class Masters will allow changing to any occupation on any level inside class tree # For example, Dwarven Fighter will be able to advance to: # Artisan, Scavenger, Warsmith, Bounty Hunter, Maestro, Fortune Seeker.
dp part (need to enable custom_npc table in config!), e.g.

Code: Select all

INSERT INTO `custom_npc` VALUES ('90001', '31756', 'Mr. Cat', '0', 'Test Server Helper', '0', 'LineageMonster.cat_the_cat', '9.00', '16.00', '70', 'male', 'L2ProfMaster', '40', '3862', '1493', '11.85', '2.78', '40', '43', '30', '21', '20', '10', '0', '0', '1314', '470', '780', '382', '278', '0', '333', '0', '0', '0', '0', '80', '120', 'NULL', '0', '0', '0', 'LAST_HIT', '0', '0', '0', 'fighter', 'false');INSERT INTO `custom_npc` VALUES ('90002', '31757', 'Miss Queen', '0', 'Test Server Helper', '0', 'LineageMonster2.queen_of_cat', '8.00', '15.00', '70', 'female', 'L2ProfMaster', '40', '3862', '1493', '11.85', '2.78', '40', '43', '30', '21', '20', '10', '0', '0', '1314', '470', '780', '382', '278', '0', '333', '0', '0', '0', '0', '26', '120', 'NULL', '0', '0', '0', 'LAST_HIT', '0', '0', '0', 'fighter', 'false');
and then spawn the classmaster with //spawn 90001 or //spawn 90002
DO NOT EVEN TRY TO MESS WITH ME!
forum flOOder dancing dEVILoper
I don't give private support - PM will be ignored!
User avatar
Edoo
Posts: 101
Joined: Sun Sep 09, 2007 3:52 am
Location: Russia
Contact:

Re: Class Master

Post by Edoo »

ENG:
Why not to inject data Of СlassЬaster's as alternative?

RUS:
Почему бы не внедрить данного Class Mastera как альтернативу?
Image
User avatar
janiii
L2j Veteran
L2j Veteran
Posts: 4269
Joined: Wed May 28, 2008 3:15 pm
Location: Slovakia

Re: Class Master

Post by janiii »

Edoo wrote:ENG:
Why not to inject data Of СlassЬaster's as alternative?

RUS:
Почему бы не внедрить данного Class Mastera как альтернативу?
first, it has to be tested. second, who want to add it, can add it on his server by his own.

i don't like the idea very much to have two different npc types and classes for class master.
DO NOT EVEN TRY TO MESS WITH ME!
forum flOOder dancing dEVILoper
I don't give private support - PM will be ignored!
User avatar
Edoo
Posts: 101
Joined: Sun Sep 09, 2007 3:52 am
Location: Russia
Contact:

Re: Class Master

Post by Edoo »

I nothing have against :) simply in me he stands already from the chronicles Of Kamael
Image
Post Reply