Advertisement
Guest User

Untitled

a guest
Jan 28th, 2014
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 38.31 KB | None | 0 0
  1. Index: java/config/custom.properties
  2. ===================================================================
  3. --- java/config/custom.properties   (revision 470)
  4. +++ java/config/custom.properties   (working copy)
  5. @@ -139,16 +139,34 @@
  6.  # ------------------------------------------------------------
  7.  # Allow use Event Managers for changing occupation
  8.  # ------------------------------------------------------------
  9. -# If you need change occupation only use quest then set this to False
  10. -# Class transfers can also be configured seperately.
  11. -# Also, you can activate html pop up for class change
  12. -# Default = False
  13. +# Default: False
  14.  AllowClassMasters = False
  15. -AllowMobileClassChange = False
  16. -AllowFirstClass = True
  17. -AllowSecondClass = True
  18. -AllowThirdClass = True
  19.  
  20. +# ConfigClassMaster=1;[57(100000)];[];2;[57(1000000)];[];3;[57(10000000)],[5575(1000000)];[6622(1)]
  21. +# 1st occupation change for 100.000 Adena (item id 57)
  22. +# 2nd occupation change for 1.000.0000 Adena (item id 57)
  23. +# 3rd occupation change for 10.000.0000 Adena (item id 57) and 1.000.000 Ancient Adena (item id 5575)
  24. +# on 3rd occupation change player will be rewarded with 1 Book of Giants (item id 6622)
  25. +# ConfigClassMaster=1;[];[];2;[];[];3;[];[]
  26. +# 1st, 2nd, 3rd occupation change for free, without rewards.
  27. +# ConfigClassMaster=1;[];[];2;[];[]
  28. +# Allow only first and second change.
  29. +ConfigClassMaster = 1;[];[];2;[];[];3;[];[]
  30. +
  31. +# Class Masters will allow changing to any occupation on any level inside class tree
  32. +# For example, Dwarven Fighter will be able to advance to:
  33. +# Artisan, Scavenger, Warsmith, Bounty Hunter, Maestro, Fortune Seeker.
  34. +# But Warsmith will be able to change only to Maestro.
  35. +# Default = False
  36. +AllowEntireTree = False
  37. +
  38. +# When character reach levels 20,40,76 he will receive tutorial page
  39. +# with list of the all possible variants, and can select and immediately
  40. +# change to the new occupation, or decide to choose later (on next login).
  41. +# Can be used with or without classic Class Masters.
  42. +# Default = False
  43. +AlternateClassMaster = False
  44. +
  45.  #-------------------------------------------------------------
  46.  # L2J Core NPC
  47.  #-------------------------------------------------------------
  48. Index: java/net/sf/l2j/Config.java
  49. ===================================================================
  50. --- java/net/sf/l2j/Config.java (revision 470)
  51. +++ java/net/sf/l2j/Config.java (working copy)
  52. @@ -27,10 +27,13 @@
  53.  import java.util.List;
  54.  import java.util.Map;
  55.  import java.util.Properties;
  56. +import java.util.StringTokenizer;
  57.  import java.util.logging.Logger;
  58.  
  59.  import javolution.util.FastList;
  60.  import javolution.util.FastMap;
  61. +import gnu.trove.map.hash.TIntIntHashMap;
  62. +import gnu.trove.map.hash.TIntObjectHashMap;
  63.  
  64.  /**
  65.   * This class contains global server configuration.<br>
  66. @@ -753,16 +756,11 @@
  67.      /** Allow teleporting to towns that are under siege ?*/
  68.      public static boolean ALLOW_SIEGE_TELEPORT;
  69.      /** Allow use Event Managers for change occupation ?*/
  70. -    public static boolean    ALLOW_CLASS_MASTERS;
  71. -    /** Allow occupation change with html pop up?*/
  72. -    public static boolean    ALLOW_MOBILE_CLASS_CHANGE;
  73. -    /** Allow first occupation change?*/
  74. -    public static boolean    ALLOW_FIRST_CLASS;
  75. -    /** Allow second occupation change?*/
  76. -    public static boolean    ALLOW_SECOND_CLASS;
  77. -    /** Allow third occupation change?*/
  78. -    public static boolean    ALLOW_THIRD_CLASS;
  79. -
  80. +   public static boolean ALLOW_CLASS_MASTERS;
  81. +   public static ClassMasterSettings CLASS_MASTER_SETTINGS;
  82. +   public static boolean ALLOW_ENTIRE_TREE;
  83. +   public static boolean ALTERNATE_CLASS_MASTER;
  84. +  
  85.      /** Time between 2 updates of IP */
  86.      public static int        IP_UPDATE_TIME;
  87.  
  88. @@ -1885,12 +1883,14 @@
  89.                  OFFLINE_SET_NAME_COLOR       = Boolean.valueOf(customSettings.getProperty("OfflineSetNameColor", "false"));
  90.                  OFFLINE_NAME_COLOR           = Integer.decode("0x" + customSettings.getProperty("OfflineNameColor", "808080"));
  91.                  ALLOW_SIEGE_TELEPORT         = Boolean.valueOf(customSettings.getProperty("AllowSiegeTeleport", "False"));
  92. -           ALLOW_CLASS_MASTERS          = Boolean.valueOf(customSettings.getProperty("AllowClassMasters", "False"));
  93. -                ALLOW_MOBILE_CLASS_CHANGE    = Boolean.valueOf(customSettings.getProperty("AllowMobileClassChange", "False"));
  94. -                ALLOW_FIRST_CLASS            = Boolean.valueOf(customSettings.getProperty("AllowFirstClass", "True"));
  95. -                ALLOW_SECOND_CLASS           = Boolean.valueOf(customSettings.getProperty("AllowSecondClass", "True"));
  96. -                ALLOW_THIRD_CLASS            = Boolean.valueOf(customSettings.getProperty("AllowThirdClass", "True"));
  97. -            }
  98. +               ALLOW_CLASS_MASTERS = Boolean.valueOf(customSettings.getProperty("AllowClassMasters", "False"));
  99. +               ALLOW_ENTIRE_TREE = Boolean.valueOf(customSettings.getProperty("AllowEntireTree", "False"));
  100. +               ALTERNATE_CLASS_MASTER = Boolean.valueOf(customSettings.getProperty("AlternateClassMaster", "False"));
  101. +               if (ALLOW_CLASS_MASTERS || ALTERNATE_CLASS_MASTER)
  102. +               {
  103. +                   CLASS_MASTER_SETTINGS = new ClassMasterSettings(String.valueOf(customSettings.getProperty("ConfigClassMaster")));
  104. +               }
  105. +           }
  106.              catch (Exception e)
  107.         {
  108.             e.printStackTrace();
  109. @@ -2365,11 +2365,18 @@
  110.  
  111.          else if (pName.equalsIgnoreCase("AllowSiegeTeleport")) ALLOW_SIEGE_TELEPORT = Boolean.valueOf(pValue);
  112.  
  113. -        else if (pName.equalsIgnoreCase("AllowClassMasters")) ALLOW_CLASS_MASTERS = Boolean.valueOf(pValue);
  114. -        else if (pName.equalsIgnoreCase("AllowMobileClassChange")) ALLOW_MOBILE_CLASS_CHANGE = Boolean.valueOf(pValue);
  115. -        else if (pName.equalsIgnoreCase("AllowFirstClass")) ALLOW_FIRST_CLASS = Boolean.valueOf(pValue);
  116. -        else if (pName.equalsIgnoreCase("AllowSecondClass")) ALLOW_SECOND_CLASS = Boolean.valueOf(pValue);
  117. -        else if (pName.equalsIgnoreCase("AllowThirdClass")) ALLOW_THIRD_CLASS = Boolean.valueOf(pValue);
  118. +       else if (pName.equalsIgnoreCase("AllowClassMasters"))
  119. +       {
  120. +           ALLOW_CLASS_MASTERS = Boolean.valueOf(pValue);
  121. +       }
  122. +       else if (pName.equalsIgnoreCase("AllowEntireTree"))
  123. +       {
  124. +           ALLOW_ENTIRE_TREE = Boolean.valueOf(pValue);
  125. +       }
  126. +       else if (pName.equalsIgnoreCase("AlternateClassMaster"))
  127. +       {
  128. +           ALTERNATE_CLASS_MASTER = Boolean.valueOf(pValue);
  129. +       }
  130.          else if (pName.equalsIgnoreCase("AltGameFreights")) ALT_GAME_FREIGHTS = Boolean.valueOf(pValue);
  131.          else if (pName.equalsIgnoreCase("AltGameFreightPrice")) ALT_GAME_FREIGHT_PRICE = Integer.parseInt(pValue);
  132.  
  133. @@ -2452,4 +2459,103 @@
  134.              e.printStackTrace();
  135.          }
  136.     }
  137. +  
  138. +   public static class ClassMasterSettings
  139. +   {
  140. +       private final TIntObjectHashMap<TIntIntHashMap> _claimItems;
  141. +       private final TIntObjectHashMap<TIntIntHashMap> _rewardItems;
  142. +       private final TIntObjectHashMap<Boolean> _allowedClassChange;
  143. +      
  144. +       public ClassMasterSettings(String _configLine)
  145. +       {
  146. +           _claimItems = new TIntObjectHashMap<>(3);
  147. +           _rewardItems = new TIntObjectHashMap<>(3);
  148. +           _allowedClassChange = new TIntObjectHashMap<>(3);
  149. +           if (_configLine != null)
  150. +           {
  151. +               parseConfigLine(_configLine.trim());
  152. +           }
  153. +       }
  154. +      
  155. +       private void parseConfigLine(String _configLine)
  156. +       {
  157. +           StringTokenizer st = new StringTokenizer(_configLine, ";");
  158. +          
  159. +           while (st.hasMoreTokens())
  160. +           {
  161. +               // get allowed class change
  162. +               int job = Integer.parseInt(st.nextToken());
  163. +              
  164. +               _allowedClassChange.put(job, true);
  165. +              
  166. +               TIntIntHashMap _items = new TIntIntHashMap();
  167. +               // parse items needed for class change
  168. +               if (st.hasMoreTokens())
  169. +               {
  170. +                   StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");
  171. +                  
  172. +                   while (st2.hasMoreTokens())
  173. +                   {
  174. +                       StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");
  175. +                       int _itemId = Integer.parseInt(st3.nextToken());
  176. +                       int _quantity = Integer.parseInt(st3.nextToken());
  177. +                       _items.put(_itemId, _quantity);
  178. +                   }
  179. +               }
  180. +              
  181. +               _claimItems.put(job, _items);
  182. +              
  183. +               _items = new TIntIntHashMap();
  184. +               // parse gifts after class change
  185. +               if (st.hasMoreTokens())
  186. +               {
  187. +                   StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");
  188. +                  
  189. +                   while (st2.hasMoreTokens())
  190. +                   {
  191. +                       StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");
  192. +                       int _itemId = Integer.parseInt(st3.nextToken());
  193. +                       int _quantity = Integer.parseInt(st3.nextToken());
  194. +                       _items.put(_itemId, _quantity);
  195. +                   }
  196. +               }
  197. +              
  198. +               _rewardItems.put(job, _items);
  199. +           }
  200. +       }
  201. +      
  202. +       public boolean isAllowed(int job)
  203. +       {
  204. +           if (_allowedClassChange == null)
  205. +           {
  206. +               return false;
  207. +           }
  208. +           if (_allowedClassChange.containsKey(job))
  209. +           {
  210. +               return _allowedClassChange.get(job);
  211. +           }
  212. +          
  213. +           return false;
  214. +       }
  215. +      
  216. +       public TIntIntHashMap getRewardItems(int job)
  217. +       {
  218. +           if (_rewardItems.containsKey(job))
  219. +           {
  220. +               return _rewardItems.get(job);
  221. +           }
  222. +          
  223. +           return null;
  224. +       }
  225. +      
  226. +       public TIntIntHashMap getRequireItems(int job)
  227. +       {
  228. +           if (_claimItems.containsKey(job))
  229. +           {
  230. +               return _claimItems.get(job);
  231. +           }
  232. +          
  233. +           return null;
  234. +       }
  235. +   }
  236.  }
  237. \ No newline at end of file
  238. Index: java/net/sf/l2j/gameserver/clientpackets/EnterWorld.java
  239. ===================================================================
  240. --- java/net/sf/l2j/gameserver/clientpackets/EnterWorld.java    (revision 470)
  241. +++ java/net/sf/l2j/gameserver/clientpackets/EnterWorld.java    (working copy)
  242. @@ -269,15 +269,21 @@
  243.          }
  244.  
  245.          // just in case player gets disconnected
  246. -        if (Config.ALLOW_MOBILE_CLASS_CHANGE)
  247. -        {
  248. -            if (Config.ALLOW_FIRST_CLASS && activeChar.getClassId().level() == 0 && activeChar.getLevel() >= 20)
  249. -                L2ClassMasterInstance.showClassMasterWindow(activeChar, 2);
  250. -            else if (Config.ALLOW_SECOND_CLASS && activeChar.getClassId().level() == 1 && activeChar.getLevel() >= 40)
  251. -                L2ClassMasterInstance.showClassMasterWindow(activeChar, 2);
  252. -            else if (Config.ALLOW_THIRD_CLASS && activeChar.getClassId().level() == 2 && activeChar.getLevel() >= 76)
  253. -                L2ClassMasterInstance.showClassMasterWindow(activeChar, 2);
  254. -        }
  255. +       if (Config.ALTERNATE_CLASS_MASTER)
  256. +       {
  257. +           if (Config.CLASS_MASTER_SETTINGS.isAllowed(1) && (activeChar.getClassId().level() == 0) && (activeChar.getLevel() >= 20))
  258. +           {
  259. +               L2ClassMasterInstance.showHtmlMenu(activeChar, 0, 1);
  260. +           }
  261. +           else if (Config.CLASS_MASTER_SETTINGS.isAllowed(2) && (activeChar.getClassId().level() == 1) && (activeChar.getLevel() >= 40))
  262. +           {
  263. +               L2ClassMasterInstance.showHtmlMenu(activeChar, 0, 2);
  264. +           }
  265. +           else if (Config.CLASS_MASTER_SETTINGS.isAllowed(3) && (activeChar.getClassId().level() == 2) && (activeChar.getLevel() >= 76))
  266. +           {
  267. +               L2ClassMasterInstance.showHtmlMenu(activeChar, 0, 3);
  268. +           }
  269. +       }
  270.  
  271.          PetitionManager.getInstance().checkPetitionMessages(activeChar);
  272.  
  273. Index: java/net/sf/l2j/gameserver/clientpackets/RequestBypassToServer.java
  274. ===================================================================
  275. --- java/net/sf/l2j/gameserver/clientpackets/RequestBypassToServer.java (revision 470)
  276. +++ java/net/sf/l2j/gameserver/clientpackets/RequestBypassToServer.java (working copy)
  277. @@ -182,8 +182,8 @@
  278.                  Olympiad.getInstance().bypassChangeArena(_command, activeChar);
  279.              else if (_command.startsWith("change_class"))
  280.              {
  281. -                if (Config.ALLOW_CLASS_MASTERS || Config.ALLOW_MOBILE_CLASS_CHANGE)
  282. -                    L2ClassMasterInstance.changeClass(activeChar, _command);
  283. +                if (Config.ALLOW_CLASS_MASTERS || Config.ALTERNATE_CLASS_MASTER)
  284. +                    L2ClassMasterInstance.checkAndChangeClass(activeChar, Integer.valueOf(_command.substring(13)));
  285.              }
  286.          }
  287.          catch (Exception e)
  288. Index: java/net/sf/l2j/gameserver/clientpackets/RequestTutorialLinkHtml.java
  289. ===================================================================
  290. --- java/net/sf/l2j/gameserver/clientpackets/RequestTutorialLinkHtml.java   (revision 470)
  291. +++ java/net/sf/l2j/gameserver/clientpackets/RequestTutorialLinkHtml.java   (working copy)
  292. @@ -21,6 +21,7 @@
  293.  import java.nio.ByteBuffer;
  294.  
  295.  import net.sf.l2j.gameserver.ClientThread;
  296. +import net.sf.l2j.gameserver.model.actor.instance.L2ClassMasterInstance;
  297.  import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
  298.  import net.sf.l2j.gameserver.model.quest.QuestState;
  299.  
  300. @@ -42,6 +43,8 @@
  301.          if (player == null)
  302.              return;
  303.  
  304. +   L2ClassMasterInstance.onTutorialLink(player, _bypass);
  305. +
  306.          QuestState qs = player.getQuestState("255_Tutorial");
  307.          if (qs != null)
  308.              qs.getQuest().notifyEvent(_bypass, null, player);
  309. Index: java/net/sf/l2j/gameserver/model/actor/instance/L2ClassMasterInstance.java
  310. ===================================================================
  311. --- java/net/sf/l2j/gameserver/model/actor/instance/L2ClassMasterInstance.java  (revision 470)
  312. +++ java/net/sf/l2j/gameserver/model/actor/instance/L2ClassMasterInstance.java  (working copy)
  313. @@ -1,288 +1,462 @@
  314.  /*
  315. - * This program is free software; you can redistribute it and/or modify
  316. - * it under the terms of the GNU General Public License as published by
  317. - * the Free Software Foundation; either version 2, or (at your option)
  318. - * any later version.
  319. - *
  320. - * This program is distributed in the hope that it will be useful,
  321. - * but WITHOUT ANY WARRANTY; without even the implied warranty of
  322. - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  323. - * GNU General Public License for more details.
  324. - *
  325. - * You should have received a copy of the GNU General Public License
  326. - * along with this program; if not, write to the Free Software
  327. - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  328. - * 02111-1307, USA.
  329. - *
  330. - * http://www.gnu.org/copyleft/gpl.html
  331. + * This program is free software: you can redistribute it and/or modify it under
  332. + * the terms of the GNU General Public License as published by the Free Software
  333. + * Foundation, either version 3 of the License, or (at your option) any later
  334. + * version.
  335. + *
  336. + * This program is distributed in the hope that it will be useful, but WITHOUT
  337. + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  338. + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  339. + * details.
  340. + *
  341. + * You should have received a copy of the GNU General Public License along with
  342. + * this program. If not, see <http://www.gnu.org/licenses/>.
  343.   */
  344.  package net.sf.l2j.gameserver.model.actor.instance;
  345.  
  346. -import javolution.text.TextBuilder;
  347. -
  348.  import net.sf.l2j.Config;
  349. -import net.sf.l2j.gameserver.ai.CtrlIntention;
  350. +import net.sf.l2j.gameserver.cache.HtmCache;
  351.  import net.sf.l2j.gameserver.datatables.CharTemplateTable;
  352. +import net.sf.l2j.gameserver.datatables.ItemTable;
  353. +import net.sf.l2j.gameserver.instancemanager.QuestManager;
  354.  import net.sf.l2j.gameserver.model.base.ClassId;
  355. -import net.sf.l2j.gameserver.model.base.ClassLevel;
  356. -import net.sf.l2j.gameserver.model.base.PlayerClass;
  357.  import net.sf.l2j.gameserver.model.quest.Quest;
  358. -import net.sf.l2j.gameserver.serverpackets.ActionFailed;
  359. -import net.sf.l2j.gameserver.serverpackets.MyTargetSelected;
  360.  import net.sf.l2j.gameserver.serverpackets.NpcHtmlMessage;
  361. -import net.sf.l2j.gameserver.serverpackets.SystemMessage;
  362. -import net.sf.l2j.gameserver.serverpackets.ValidateLocation;
  363. +import net.sf.l2j.gameserver.serverpackets.TutorialCloseHtml;
  364. +import net.sf.l2j.gameserver.serverpackets.TutorialShowHtml;
  365. +import net.sf.l2j.gameserver.serverpackets.TutorialShowQuestionMark;
  366.  import net.sf.l2j.gameserver.templates.L2NpcTemplate;
  367.  
  368. -/**
  369. - * This class ...
  370. - *
  371. - * @version $Revision: 1.4.2.1.2.7 $ $Date: 2005/03/27 15:29:32 $
  372. - */
  373. -public final class L2ClassMasterInstance extends L2FolkInstance
  374. +public final class L2ClassMasterInstance extends L2NpcInstance
  375.  {
  376. -    private static int[] _secondClassIds =
  377. -    {
  378. -        2,3,5,6,9,8,12,13,14,16,17,20,21,23,24,27,
  379. -   28,30,33,34,36,37,40,41,43,46,48,51,52,55,57
  380. -    };
  381. -
  382. -    /**
  383. -     * @param template
  384. -     */
  385. -    public L2ClassMasterInstance(int objectId, L2NpcTemplate template)
  386. -    {
  387. -        super(objectId, template);
  388. -    }
  389. -
  390. -    public void onAction(L2PcInstance player)
  391. -    {
  392. -        if (!canTarget(player))
  393. -            return;
  394. -
  395. -        player.setLastFolkNPC(this);
  396. -
  397. -        if (getObjectId() != player.getTargetId())
  398. -        {
  399. -
  400. -            // Set the target of the L2PcInstance player
  401. -            player.setTarget(this);
  402. -
  403. -            // Send a Server->Client packet MyTargetSelected to the L2PcInstance player
  404. -            player.sendPacket(new MyTargetSelected(getObjectId(), 0));
  405. -
  406. -            // Send a Server->Client packet ValidateLocation to correct the L2NpcInstance position and heading on the client
  407. -            player.sendPacket(new ValidateLocation(this));
  408. -        }
  409. -        else
  410. -        {
  411. -            if (!canInteract(player))
  412. -            {
  413. -                player.getAI().setIntention(CtrlIntention.AI_INTENTION_INTERACT, this);
  414. -                return;
  415. -            }
  416. -
  417. -
  418. -            showClassMasterWindow(player, Config.ALLOW_CLASS_MASTERS ? 1 : 0);
  419. -        }
  420. -        player.sendPacket(new ActionFailed());
  421. -    }
  422. -
  423. -    public static void showClassMasterWindow(L2PcInstance player, int allowedState)
  424. -    {
  425. -        NpcHtmlMessage html = new NpcHtmlMessage(0);
  426. -        TextBuilder sb = new TextBuilder();
  427. -
  428. -        if (allowedState > 0)
  429. -        {
  430. -            if (Config.DEBUG)
  431. -                _log.fine("ClassMaster activated");
  432. -
  433. -            ClassId classId = player.getClassId();
  434. -
  435. -            int jobLevel = 0;
  436. -            int level = player.getLevel();
  437. -            ClassLevel lvl = PlayerClass.values()[classId.getId()].getLevel();  
  438. -            switch (lvl)
  439. -            {
  440. -                case First:
  441. -                    jobLevel = 1;
  442. -                    break;
  443. -                case Second:
  444. -                    jobLevel = 2;
  445. -                    break;
  446. -                case Third:
  447. -                    jobLevel = 3;
  448. -                    break;
  449. -                default:
  450. -                    jobLevel = 4;
  451. -                    break;
  452. -            }
  453. -
  454. -            if ((Config.ALLOW_FIRST_CLASS && level >= 20 && jobLevel == 1) || (Config.ALLOW_SECOND_CLASS && level >= 40 && jobLevel == 2))
  455. -            {
  456. -                html.setFile("data/html/classmaster/" + classId.getId() + ".htm");
  457. -                player.sendPacket(html);
  458. -            }
  459. -            else if (Config.ALLOW_THIRD_CLASS && level >= 76 && jobLevel == 3)
  460. -            {         
  461. -                for (int i = 0; i < _secondClassIds.length; i++)
  462. -                {
  463. -                    if (classId.getId() == _secondClassIds[i])
  464. -                    {
  465. -                        sb.append("<html><body<center>");
  466. -                        sb.append("<img src=\"L2UI_CH3.herotower_deco\" width=256 height=32>");
  467. -                        sb.append("<br><br><table width=200>");
  468. -                        sb.append("<tr><td>"+CharTemplateTable.getClassNameById(classId.getId())+" Class Master:</td></tr>");
  469. -                        sb.append("<tr><td><br></td></tr>");
  470. -                        sb.append("<tr><td><a action=\"bypass -h change_class "+(88+i)+"\">Advance to "+CharTemplateTable.getClassNameById(88+i)+"</a></td></tr>");
  471. -                        sb.append("<tr><td><br></td></tr></table><br><br>");
  472. -                        sb.append("<img src=\"L2UI_CH3.herotower_deco\" width=256 height=32>");
  473. -
  474. -                        sb.append("</center></body></html>");
  475. -                        html.setHtml(sb.toString());
  476. -                        player.sendPacket(html);
  477. -
  478. -                    }
  479. -                }
  480. -            }
  481. -            else if (allowedState != 2)
  482. -            {
  483. -                sb.append("<html><head><body>");
  484. -
  485. -                switch (jobLevel)
  486. -                {
  487. -                    case 1:
  488. -                        if (Config.ALLOW_FIRST_CLASS)
  489. -                            sb.append("<br>Come back here when you reach level 20 to change your class.");
  490. -                        else
  491. -                            sb.append("<br>You have to complete First Class Transfer on your own.");
  492. -                        break;
  493. -                    case 2:
  494. -                        if (Config.ALLOW_SECOND_CLASS)
  495. -                            sb.append("<br>Come back here when you reach level 40 to change your class.");
  496. -                        else
  497. -                            sb.append("<br>You have to complete Second Class Transfer on your own.");
  498. -                        break;
  499. -                    case 3:
  500. -                        if (Config.ALLOW_THIRD_CLASS)
  501. -                            sb.append("<br>Come back here when you reach level 76 to change your class.");
  502. -                        else
  503. -                            sb.append("<br>You have to complete Third Class Transfer on your own.");
  504. -                        break;
  505. -                    default:
  506. -                        sb.append("<br>There are no more classes available for you.");
  507. -                        break;
  508. -                }
  509. -                
  510. -                for (Quest q : Quest.findAllEvents())
  511. -                    sb.append("Event: <a action=\"bypass -h Quest "+q.getName()+"\">"+q.getDescr()+"</a><br>");
  512. -
  513. -                sb.append("</body></html>");
  514. -                html.setHtml(sb.toString());
  515. -                player.sendPacket(html);
  516. -            }
  517. -        }
  518. -        else
  519. -        {
  520. -            sb.append("<html><head><body>");
  521. -            sb.append("<br><center>Class Master is deactivated.</center>");
  522. -            sb.append("</body></html>");
  523. -            html.setHtml(sb.toString());
  524. -            player.sendPacket(html);
  525. -        }
  526. -    }
  527. -
  528. -    public static void changeClass(L2PcInstance player, String command)
  529. -    {
  530. -        int val = Integer.parseInt(command.substring(13));
  531. -
  532. -
  533. -        // Exploit prevention
  534. -        ClassId classId = player.getClassId();
  535. -        int level = player.getLevel();
  536. -        int jobLevel = 0;
  537. -        int newJobLevel = 0;
  538. -
  539. -
  540. -        // some protection checks, just to be sure
  541. -        ClassLevel lvlnow = PlayerClass.values()[classId.getId()].getLevel();  
  542. -        switch (lvlnow)
  543. -        {
  544. -            case First:
  545. -                if (!Config.ALLOW_FIRST_CLASS)
  546. -                    return;
  547. -                jobLevel = 1;
  548. -                break;
  549. -            case Second:
  550. -                if (!Config.ALLOW_SECOND_CLASS)
  551. -                    return;
  552. -                jobLevel = 2;
  553. -                break;
  554. -            case Third:
  555. -                if (!Config.ALLOW_THIRD_CLASS)
  556. -                    return;
  557. -                jobLevel = 3;
  558. -                break;
  559. -            default:
  560. -                jobLevel = 4;
  561. -                break;
  562. -        }
  563. -
  564. -        if (jobLevel == 4)
  565. -            return; // no more job changes
  566. -
  567. -        ClassLevel lvlnext = PlayerClass.values()[val].getLevel();  
  568. -        switch (lvlnext)
  569. -        {
  570. -            case First:
  571. -                newJobLevel = 1;
  572. -                break;
  573. -            case Second:
  574. -                newJobLevel = 2;
  575. -                break;
  576. -            case Third:
  577. -                newJobLevel = 3;
  578. -                break;
  579. -            default:
  580. -                newJobLevel = 4;
  581. -                break;
  582. -        }
  583. -
  584. -        // prevents changing between same level jobs
  585. -        if (newJobLevel != jobLevel + 1)
  586. -            return;
  587. -
  588. -        if (level < 20 && newJobLevel > 1)
  589. -            return;
  590. -        if (level < 40 && newJobLevel > 2)
  591. -            return;
  592. -        if (level < 76 && newJobLevel > 3)
  593. -            return;
  594. -        // -- prevention ends
  595. -
  596. -        if (Config.DEBUG)
  597. -            _log.fine("Changing class to ClassId:"+val);
  598. -
  599. -
  600. -        player.setClassId(val);
  601. -
  602. -
  603. -        if (player.isSubClassActive())
  604. -            player.getSubClasses().get(player.getClassIndex()).setClassId(player.getActiveClass());
  605. -        else
  606. -            player.setBaseClass(player.getActiveClass());
  607. -
  608. -
  609. -        player.broadcastUserInfo();
  610. -
  611. -
  612. -        if (val >= 88)
  613. -            player.sendPacket(new SystemMessage(1606)); // system sound 3rd occupation
  614. -        else
  615. -        {
  616. -            player.sendPacket(new SystemMessage(1308)); // system sound for 1st and 2nd occupation
  617. -            showClassMasterWindow(player, 2);
  618. -        }
  619. -    }
  620. -}
  621. \ No newline at end of file
  622. +   /**
  623. +    * @param objectId
  624. +    * @param template
  625. +    */
  626. +   public L2ClassMasterInstance(int objectId, L2NpcTemplate template)
  627. +   {
  628. +       super(objectId, template);
  629. +   }
  630. +  
  631. +   @Override
  632. +   public String getHtmlPath(int npcId, int val)
  633. +   {
  634. +       String pom = "";
  635. +      
  636. +       if (val == 0)
  637. +       {
  638. +           pom = "" + npcId;
  639. +       }
  640. +       else
  641. +       {
  642. +           pom = npcId + "-" + val;
  643. +       }
  644. +      
  645. +       return "data/html/classmaster/" + pom + ".htm";
  646. +   }
  647. +  
  648. +   @Override
  649. +   public void onBypassFeedback(L2PcInstance player, String command)
  650. +   {
  651. +       if (command.startsWith("1stClass"))
  652. +       {
  653. +           showHtmlMenu(player, getObjectId(), 1);
  654. +       }
  655. +       else if (command.startsWith("2ndClass"))
  656. +       {
  657. +           showHtmlMenu(player, getObjectId(), 2);
  658. +       }
  659. +       else if (command.startsWith("3rdClass"))
  660. +       {
  661. +           showHtmlMenu(player, getObjectId(), 3);
  662. +       }
  663. +       else if (command.startsWith("change_class"))
  664. +       {
  665. +           int val = Integer.parseInt(command.substring(13));
  666. +          
  667. +           if (checkAndChangeClass(player, val))
  668. +           {
  669. +               NpcHtmlMessage html = new NpcHtmlMessage(getObjectId());
  670. +               html.setFile("data/html/classmaster/ok.htm");
  671. +               CharTemplateTable.getInstance();
  672. +               html.replace("%name%", CharTemplateTable.getClassNameById(val));
  673. +               player.sendPacket(html);
  674. +           }
  675. +       }
  676. +       else
  677. +       {
  678. +           super.onBypassFeedback(player, command);
  679. +       }
  680. +   }
  681. +  
  682. +   public static final void onTutorialLink(L2PcInstance player, String request)
  683. +   {
  684. +       if (!Config.ALTERNATE_CLASS_MASTER || (request == null) || !request.startsWith("CO"))
  685. +       {
  686. +           return;
  687. +       }
  688. +      
  689. +       try
  690. +       {
  691. +           int val = Integer.parseInt(request.substring(2));
  692. +           checkAndChangeClass(player, val);
  693. +       }
  694. +       catch (NumberFormatException e)
  695. +       {
  696. +       }
  697. +       player.sendPacket(new TutorialCloseHtml());
  698. +   }
  699. +  
  700. +   public static final void onTutorialQuestionMark(L2PcInstance player, int number)
  701. +   {
  702. +       if (!Config.ALTERNATE_CLASS_MASTER || (number != 1001))
  703. +       {
  704. +           return;
  705. +       }
  706. +      
  707. +       showTutorialHtml(player);
  708. +   }
  709. +  
  710. +   public static final void showQuestionMark(L2PcInstance player)
  711. +   {
  712. +       if (!Config.ALTERNATE_CLASS_MASTER)
  713. +       {
  714. +           return;
  715. +       }
  716. +      
  717. +       final ClassId classId = player.getClassId();
  718. +       if (getMinLevel(classId.level()) > player.getLevel())
  719. +       {
  720. +           return;
  721. +       }
  722. +      
  723. +       if (!Config.CLASS_MASTER_SETTINGS.isAllowed(classId.level() + 1))
  724. +       {
  725. +           return;
  726. +       }
  727. +      
  728. +       player.sendPacket(new TutorialShowQuestionMark(1001));
  729. +   }
  730. +  
  731. +   public static final void showHtmlMenu(L2PcInstance player, int objectId, int level)
  732. +   {
  733. +       NpcHtmlMessage html = new NpcHtmlMessage(objectId);
  734. +      
  735. +       if (!Config.ALLOW_CLASS_MASTERS && !Config.ALTERNATE_CLASS_MASTER)
  736. +       {
  737. +           html.setFile("data/html/classmaster/disabled.htm");
  738. +       }
  739. +       else if (!Config.CLASS_MASTER_SETTINGS.isAllowed(level))
  740. +       {
  741. +           int jobLevel = player.getClassId().level();
  742. +           final StringBuilder sb = new StringBuilder(100);
  743. +           sb.append("<html><body>");
  744. +           switch (jobLevel)
  745. +           {
  746. +               case 0:
  747. +                   if (Config.CLASS_MASTER_SETTINGS.isAllowed(1))
  748. +                   {
  749. +                       sb.append("Come back here when you reached level 20 to change your class.<br>");
  750. +                   }
  751. +                   else if (Config.CLASS_MASTER_SETTINGS.isAllowed(2))
  752. +                   {
  753. +                       sb.append("Come back after your first occupation change.<br>");
  754. +                   }
  755. +                   else if (Config.CLASS_MASTER_SETTINGS.isAllowed(3))
  756. +                   {
  757. +                       sb.append("Come back after your second occupation change.<br>");
  758. +                   }
  759. +                   else
  760. +                   {
  761. +                       sb.append("I can't change your occupation.<br>");
  762. +                   }
  763. +                   break;
  764. +               case 1:
  765. +                   if (Config.CLASS_MASTER_SETTINGS.isAllowed(2))
  766. +                   {
  767. +                       sb.append("Come back here when you reached level 40 to change your class.<br>");
  768. +                   }
  769. +                   else if (Config.CLASS_MASTER_SETTINGS.isAllowed(3))
  770. +                   {
  771. +                       sb.append("Come back after your second occupation change.<br>");
  772. +                   }
  773. +                   else
  774. +                   {
  775. +                       sb.append("I can't change your occupation.<br>");
  776. +                   }
  777. +                   break;
  778. +               case 2:
  779. +                   if (Config.CLASS_MASTER_SETTINGS.isAllowed(3))
  780. +                   {
  781. +                       sb.append("Come back here when you reached level 76 to change your class.<br>");
  782. +                   }
  783. +                   else
  784. +                   {
  785. +                       sb.append("I can't change your occupation.<br>");
  786. +                   }
  787. +                   break;
  788. +               case 3:
  789. +                   sb.append("There is no class change available for you anymore.<br>");
  790. +                   break;
  791. +           }
  792. +           sb.append("</body></html>");
  793. +           html.setHtml(sb.toString());
  794. +       }
  795. +       else
  796. +       {
  797. +           final ClassId currentClassId = player.getClassId();
  798. +           if (currentClassId.level() >= level)
  799. +           {
  800. +               html.setFile("data/html/classmaster/nomore.htm");
  801. +           }
  802. +           else
  803. +           {
  804. +               final int minLevel = getMinLevel(currentClassId.level());
  805. +               if ((player.getLevel() >= minLevel) || Config.ALLOW_ENTIRE_TREE)
  806. +               {
  807. +                   final StringBuilder menu = new StringBuilder(100);
  808. +                   for (ClassId cid : ClassId.values())
  809. +                   {
  810. +                       if (validateClassId(currentClassId, cid) && (cid.level() == level))
  811. +                       {
  812. +                           if (objectId > 0)
  813. +                           {
  814. +                               menu.append("<a action=\"bypass -h npc_%objectId%_change_class ");
  815. +                           }
  816. +                           else
  817. +                           {
  818. +                               menu.append("<a action=\"bypass -h change_class ");
  819. +                           }
  820. +                           menu.append(String.valueOf(cid.getId()));
  821. +                           menu.append("\">");
  822. +                           CharTemplateTable.getInstance();
  823. +                           menu.append(CharTemplateTable.getClassNameById(cid.getId()));
  824. +                           menu.append("</a><br>");
  825. +                       }
  826. +                   }
  827. +                  
  828. +                   if (menu.length() > 0)
  829. +                   {
  830. +                       html.setFile("data/html/classmaster/template.htm");
  831. +                       CharTemplateTable.getInstance();
  832. +                       html.replace("%name%", CharTemplateTable.getClassNameById(currentClassId.getId()));
  833. +                       html.replace("%menu%", menu.toString());
  834. +                   }
  835. +                   else
  836. +                   {
  837. +                       html.setFile("data/html/classmaster/comebacklater.htm");
  838. +                       html.replace("%level%", String.valueOf(getMinLevel(level - 1)));
  839. +                   }
  840. +               }
  841. +               else
  842. +               {
  843. +                   if (minLevel < Integer.MAX_VALUE)
  844. +                   {
  845. +                       html.setFile("data/html/classmaster/comebacklater.htm");
  846. +                       html.replace("%level%", String.valueOf(minLevel));
  847. +                   }
  848. +                   else
  849. +                   {
  850. +                       html.setFile("data/html/classmaster/nomore.htm");
  851. +                   }
  852. +               }
  853. +           }
  854. +       }
  855. +      
  856. +       html.replace("%objectId%", String.valueOf(objectId));
  857. +       html.replace("%req_items%", getRequiredItems(level));
  858. +       player.sendPacket(html);
  859. +   }
  860. +  
  861. +   private static final void showTutorialHtml(L2PcInstance player)
  862. +   {
  863. +       final ClassId currentClassId = player.getClassId();
  864. +       if ((getMinLevel(currentClassId.level()) > player.getLevel()) && !Config.ALLOW_ENTIRE_TREE)
  865. +       {
  866. +           return;
  867. +       }
  868. +      
  869. +       String msg = HtmCache.getInstance().getHtm("data/html/classmaster/tutorialtemplate.htm");
  870. +      
  871. +       CharTemplateTable.getInstance();
  872. +       msg = msg.replaceAll("%name%", CharTemplateTable.getClassNameById(currentClassId.getId()));
  873. +      
  874. +       final StringBuilder menu = new StringBuilder(100);
  875. +       for (ClassId cid : ClassId.values())
  876. +       {
  877. +           if (validateClassId(currentClassId, cid))
  878. +           {
  879. +               menu.append("<a action=\"link CO");
  880. +               menu.append(String.valueOf(cid.getId()));
  881. +               menu.append("\">");
  882. +               CharTemplateTable.getInstance();
  883. +               menu.append(CharTemplateTable.getClassNameById(cid.getId()));
  884. +               menu.append("</a><br>");
  885. +           }
  886. +       }
  887. +      
  888. +       msg = msg.replaceAll("%menu%", menu.toString());
  889. +       msg = msg.replace("%req_items%", getRequiredItems(currentClassId.level() + 1));
  890. +       player.sendPacket(new TutorialShowHtml(msg));
  891. +   }
  892. +  
  893. +   public static final boolean checkAndChangeClass(L2PcInstance player, int val)
  894. +   {
  895. +       final ClassId currentClassId = player.getClassId();
  896. +       if ((getMinLevel(currentClassId.level()) > player.getLevel()) && !Config.ALLOW_ENTIRE_TREE)
  897. +       {
  898. +           return false;
  899. +       }
  900. +      
  901. +       if (!validateClassId(currentClassId, val))
  902. +       {
  903. +           return false;
  904. +       }
  905. +      
  906. +       int newJobLevel = currentClassId.level() + 1;
  907. +      
  908. +       // Weight/Inventory check
  909. +       if (!Config.CLASS_MASTER_SETTINGS.getRewardItems(newJobLevel).isEmpty())
  910. +       {
  911. +           if ((player.getWeightPenalty() >= 3) || ((player.getInventoryLimit() * 0.8) <= player.getInventory().getSize()))
  912. +           {
  913. +               player.sendMessage("Progress in a quest is possible only when your inventory's weight and volume are less than 80 percent of capacity.");
  914. +               return false;
  915. +           }
  916. +       }
  917. +      
  918. +       // check if player have all required items for class transfer
  919. +       for (int _itemId : Config.CLASS_MASTER_SETTINGS.getRequireItems(newJobLevel).keys())
  920. +       {
  921. +           int _count = Config.CLASS_MASTER_SETTINGS.getRequireItems(newJobLevel).get(_itemId);
  922. +           if (player.getInventory().getInventoryItemCount(_itemId, -1) < _count)
  923. +           {
  924. +               player.sendMessage("Incorrect item count.");
  925. +               return false;
  926. +           }
  927. +       }
  928. +      
  929. +       // get all required items for class transfer
  930. +       for (int _itemId : Config.CLASS_MASTER_SETTINGS.getRequireItems(newJobLevel).keys())
  931. +       {
  932. +           int _count = Config.CLASS_MASTER_SETTINGS.getRequireItems(newJobLevel).get(_itemId);
  933. +           if (!player.destroyItemByItemId("ClassMaster", _itemId, _count, player, true))
  934. +           {
  935. +               return false;
  936. +           }
  937. +       }
  938. +      
  939. +       // reward player with items
  940. +       for (int _itemId : Config.CLASS_MASTER_SETTINGS.getRewardItems(newJobLevel).keys())
  941. +       {
  942. +           int _count = Config.CLASS_MASTER_SETTINGS.getRewardItems(newJobLevel).get(_itemId);
  943. +           player.addItem("ClassMaster", _itemId, _count, player, true);
  944. +       }
  945. +      
  946. +       player.setClassId(val);
  947. +      
  948. +       if (player.isSubClassActive())
  949. +       {
  950. +           player.getSubClasses().get(player.getClassIndex()).setClassId(player.getActiveClass());
  951. +       }
  952. +       else
  953. +       {
  954. +           player.setBaseClass(player.getActiveClass());
  955. +       }
  956. +      
  957. +       Quest q = QuestManager.getInstance().getQuest("SkillTransfer");
  958. +       if (q != null)
  959. +       {
  960. +           q.startQuestTimer("givePormanders", 1, null, player);
  961. +       }
  962. +      
  963. +       player.broadcastUserInfo();
  964. +      
  965. +       if (Config.CLASS_MASTER_SETTINGS.isAllowed(player.getClassId().level() + 1) && Config.ALTERNATE_CLASS_MASTER && (((player.getClassId().level() == 1) && (player.getLevel() >= 40)) || ((player.getClassId().level() == 2) && (player.getLevel() >= 76))))
  966. +       {
  967. +           showQuestionMark(player);
  968. +       }
  969. +      
  970. +       return true;
  971. +   }
  972. +  
  973. +   /**
  974. +    * Returns minimum player level required for next class transfer
  975. +    * @param level - current skillId level (0 - start, 1 - first, etc)
  976. +    * @return
  977. +    */
  978. +   private static final int getMinLevel(int level)
  979. +   {
  980. +       switch (level)
  981. +       {
  982. +           case 0:
  983. +               return 20;
  984. +           case 1:
  985. +               return 40;
  986. +           case 2:
  987. +               return 76;
  988. +           default:
  989. +               return Integer.MAX_VALUE;
  990. +       }
  991. +   }
  992. +  
  993. +   /**
  994. +    * Returns true if class change is possible
  995. +    * @param oldCID current player ClassId
  996. +    * @param val new class index
  997. +    * @return
  998. +    */
  999. +   private static final boolean validateClassId(ClassId oldCID, int val)
  1000. +   {
  1001. +       try
  1002. +       {
  1003. +           return validateClassId(oldCID, ClassId.values()[val]);
  1004. +       }
  1005. +       catch (Exception e)
  1006. +       {
  1007. +           // possible ArrayOutOfBoundsException
  1008. +       }
  1009. +       return false;
  1010. +   }
  1011. +  
  1012. +   /**
  1013. +    * Returns true if class change is possible
  1014. +    * @param oldCID current player ClassId
  1015. +    * @param newCID new ClassId
  1016. +    * @return true if class change is possible
  1017. +    */
  1018. +   private static final boolean validateClassId(ClassId oldCID, ClassId newCID)
  1019. +   {
  1020. +       if ((newCID == null) || (newCID.getRace() == null))
  1021. +       {
  1022. +           return false;
  1023. +       }
  1024. +      
  1025. +       if (oldCID.equals(newCID.getParent()))
  1026. +       {
  1027. +           return true;
  1028. +       }
  1029. +      
  1030. +       if (Config.ALLOW_ENTIRE_TREE && newCID.childOf(oldCID))
  1031. +       {
  1032. +           return true;
  1033. +       }
  1034. +      
  1035. +       return false;
  1036. +   }
  1037. +  
  1038. +   private static String getRequiredItems(int level)
  1039. +   {
  1040. +       if ((Config.CLASS_MASTER_SETTINGS.getRequireItems(level) == null) || Config.CLASS_MASTER_SETTINGS.getRequireItems(level).isEmpty())
  1041. +       {
  1042. +           return "<tr><td>none</td></r>";
  1043. +       }
  1044. +       StringBuilder sb = new StringBuilder();
  1045. +       for (int _itemId : Config.CLASS_MASTER_SETTINGS.getRequireItems(level).keys())
  1046. +       {
  1047. +           int _count = Config.CLASS_MASTER_SETTINGS.getRequireItems(level).get(_itemId);
  1048. +           sb.append("<tr><td><font color=\"LEVEL\">" + _count + "</font></td><td>" + ItemTable.getInstance().getTemplate(_itemId).getName() + "</td></tr>");
  1049. +       }
  1050. +       return sb.toString();
  1051. +   }
  1052. +}
  1053. Index: java/net/sf/l2j/gameserver/model/actor/stat/PcStat.java
  1054. ===================================================================
  1055. --- java/net/sf/l2j/gameserver/model/actor/stat/PcStat.java (revision 470)
  1056. +++ java/net/sf/l2j/gameserver/model/actor/stat/PcStat.java (working copy)
  1057. @@ -164,15 +164,21 @@
  1058.          {
  1059.              // That's the best thing to do here as
  1060.              // players can increase level too fast in high rates
  1061. -            if (Config.ALLOW_MOBILE_CLASS_CHANGE)
  1062. -            {
  1063. -                if (Config.ALLOW_FIRST_CLASS && getActiveChar().getClassId().level() == 0 && getActiveChar().getLevel() >= 20)
  1064. -                    L2ClassMasterInstance.showClassMasterWindow(getActiveChar(), 2);
  1065. -                else if (Config.ALLOW_SECOND_CLASS && getActiveChar().getClassId().level() == 1 && getActiveChar().getLevel() >= 40)
  1066. -                    L2ClassMasterInstance.showClassMasterWindow(getActiveChar(), 2);
  1067. -                else if (Config.ALLOW_THIRD_CLASS && getActiveChar().getClassId().level() == 2 && getActiveChar().getLevel() >= 76)
  1068. -                    L2ClassMasterInstance.showClassMasterWindow(getActiveChar(), 2);
  1069. -            }
  1070. +           if (Config.ALTERNATE_CLASS_MASTER)
  1071. +           {
  1072. +               if (Config.CLASS_MASTER_SETTINGS.isAllowed(1) && (getActiveChar().getClassId().level() == 0) && (getActiveChar().getLevel() >= 20))
  1073. +               {
  1074. +                   L2ClassMasterInstance.showHtmlMenu(getActiveChar(), 0, 1);
  1075. +               }
  1076. +               else if (Config.CLASS_MASTER_SETTINGS.isAllowed(2) && (getActiveChar().getClassId().level() == 1) && (getActiveChar().getLevel() >= 40))
  1077. +               {
  1078. +                   L2ClassMasterInstance.showHtmlMenu(getActiveChar(), 0, 2);
  1079. +               }
  1080. +               else if (Config.CLASS_MASTER_SETTINGS.isAllowed(3) && (getActiveChar().getClassId().level() == 2) && (getActiveChar().getLevel() >= 76))
  1081. +               {
  1082. +                   L2ClassMasterInstance.showHtmlMenu(getActiveChar(), 0, 3);
  1083. +               }
  1084. +           }
  1085.  
  1086.              applyNewbieStatus();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement