/* * Copyright (C) 2004-2015 L2J Server * * This file is part of L2J Server. * * L2J Server 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. * * L2J Server 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.network.clientpackets; import java.util.List; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import com.l2jserver.Config; import com.l2jserver.gameserver.data.sql.impl.CharNameTable; import com.l2jserver.gameserver.data.xml.impl.InitialEquipmentData; import com.l2jserver.gameserver.data.xml.impl.InitialShortcutData; import com.l2jserver.gameserver.data.xml.impl.PlayerTemplateData; import com.l2jserver.gameserver.data.xml.impl.SkillTreesData; import com.l2jserver.gameserver.datatables.SkillData; import com.l2jserver.gameserver.model.L2SkillLearn; import com.l2jserver.gameserver.model.L2World; import com.l2jserver.gameserver.model.Location; import com.l2jserver.gameserver.model.actor.appearance.PcAppearance; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.actor.stat.PcStat; import com.l2jserver.gameserver.model.actor.templates.L2PcTemplate; import com.l2jserver.gameserver.model.base.ClassId; import com.l2jserver.gameserver.model.events.Containers; import com.l2jserver.gameserver.model.events.EventDispatcher; import com.l2jserver.gameserver.model.events.impl.character.player.OnPlayerCreate; import com.l2jserver.gameserver.model.items.PcItemTemplate; import com.l2jserver.gameserver.model.items.instance.L2ItemInstance; import com.l2jserver.gameserver.network.L2GameClient; import com.l2jserver.gameserver.network.serverpackets.CharCreateFail; import com.l2jserver.gameserver.network.serverpackets.CharCreateOk; import com.l2jserver.gameserver.network.serverpackets.CharSelectionInfo; import com.l2jserver.gameserver.util.Util; @SuppressWarnings("unused") public final class CharacterCreate extends L2GameClientPacket { private static final String _C__0C_CHARACTERCREATE = "[C] 0C CharacterCreate"; protected static final Logger _logAccounting = Logger.getLogger("accounting"); // cSdddddddddddd private String _name; private int _race; private byte _sex; private int _classId; private int _int; private int _str; private int _con; private int _men; private int _dex; private int _wit; private byte _hairStyle; private byte _hairColor; private byte _face; @Override protected void readImpl() { _name = readS(); _race = readD(); _sex = (byte) readD(); _classId = readD(); _int = readD(); _str = readD(); _con = readD(); _men = readD(); _dex = readD(); _wit = readD(); _hairStyle = (byte) readD(); _hairColor = (byte) readD(); _face = (byte) readD(); } @Override protected void runImpl() { // Last Verified: May 30, 2009 - Gracia Final - Players are able to create characters with names consisting of as little as 1,2,3 letter/number combinations. if ((_name.length() < 1) || (_name.length() > 16)) { if (Config.DEBUG) { _log.fine("Character Creation Failure: Character name " + _name + " is invalid. Message generated: Your title cannot exceed 16 characters in length. Please try again."); } sendPacket(new CharCreateFail(CharCreateFail.REASON_16_ENG_CHARS)); return; } if (Config.FORBIDDEN_NAMES.length > 1) { for (String st : Config.FORBIDDEN_NAMES) { if (_name.toLowerCase().contains(st.toLowerCase())) { sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME)); return; } } } // Last Verified: May 30, 2009 - Gracia Final if (!Util.isAlphaNumeric(_name) || !isValidName(_name)) { if (Config.DEBUG) { _log.fine("Character Creation Failure: Character name " + _name + " is invalid. Message generated: Incorrect name. Please try again."); } sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME)); return; } if ((_face > 2) || (_face < 0)) { _log.warning("Character Creation Failure: Character face " + _face + " is invalid. Possible client hack. " + getClient()); sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } if ((_hairStyle < 0) || ((_sex == 0) && (_hairStyle > 4)) || ((_sex != 0) && (_hairStyle > 6))) { _log.warning("Character Creation Failure: Character hair style " + _hairStyle + " is invalid. Possible client hack. " + getClient()); sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } if ((_hairColor > 3) || (_hairColor < 0)) { _log.warning("Character Creation Failure: Character hair color " + _hairColor + " is invalid. Possible client hack. " + getClient()); sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } L2PcInstance newChar = null; L2PcTemplate template = null; /* * DrHouse: Since checks for duplicate names are done using SQL, lock must be held until data is written to DB as well. */ synchronized (CharNameTable.getInstance()) { if ((CharNameTable.getInstance().getAccountCharacterCount(getClient().getAccountName()) >= Config.MAX_CHARACTERS_NUMBER_PER_ACCOUNT) && (Config.MAX_CHARACTERS_NUMBER_PER_ACCOUNT != 0)) { if (Config.DEBUG) { _log.fine("Max number of characters reached. Creation failed."); } sendPacket(new CharCreateFail(CharCreateFail.REASON_TOO_MANY_CHARACTERS)); return; } else if (CharNameTable.getInstance().doesCharNameExist(_name)) { if (Config.DEBUG) { _log.fine("Character Creation Failure: Message generated: You cannot create another character. Please delete the existing character and try again."); } sendPacket(new CharCreateFail(CharCreateFail.REASON_NAME_ALREADY_EXISTS)); return; } template = PlayerTemplateData.getInstance().getTemplate(_classId); if ((template == null) || (ClassId.getClassId(_classId).level() > 0)) { if (Config.DEBUG) { _log.fine("Character Creation Failure: " + _name + " classId: " + _classId + " Template: " + template + " Message generated: Your character creation has failed."); } sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } // Custom Feature: Disallow a race to be created. // Example: Humans can not be created if AllowHuman = False in Custom.properties switch (template.getRace()) { case HUMAN: if (!Config.ALLOW_HUMAN) { sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } break; case ELF: if (!Config.ALLOW_ELF) { sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } break; case DARK_ELF: if (!Config.ALLOW_DARKELF) { sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } break; case ORC: if (!Config.ALLOW_ORC) { sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } break; case DWARF: if (!Config.ALLOW_DWARF) { sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } break; case KAMAEL: if (!Config.ALLOW_KAMAEL) { sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } break; case ERTHEIA: if (!Config.ALLOW_ERTHEIA) { sendPacket(new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED)); return; } break; } final PcAppearance app = new PcAppearance(_face, _hairColor, _hairStyle, _sex != 0); newChar = L2PcInstance.create(template, getClient().getAccountName(), _name, app); } // HP and MP are at maximum and CP is zero by default. newChar.setCurrentHp(newChar.getMaxHp()); newChar.setCurrentMp(newChar.getMaxMp()); // newChar.setMaxLoad(template.getBaseLoad()); sendPacket(new CharCreateOk()); initNewChar(getClient(), newChar); LogRecord record = new LogRecord(Level.INFO, "Created new character"); record.setParameters(new Object[] { newChar, getClient() }); _logAccounting.log(record); } private static boolean isValidName(String text) { return Config.CHARNAME_TEMPLATE_PATTERN.matcher(text).matches(); } private void initNewChar(L2GameClient client, L2PcInstance newChar) { if (Config.DEBUG) { _log.fine("Character init start"); } L2World.getInstance().storeObject(newChar); if (Config.STARTING_ADENA > 0) { newChar.addAdena("Init", Config.STARTING_ADENA, null, false); } final L2PcTemplate template = newChar.getTemplate(); if (Config.CUSTOM_STARTING_LOC) { Location createLoc = new Location(Config.CUSTOM_STARTING_LOC_X, Config.CUSTOM_STARTING_LOC_Y, Config.CUSTOM_STARTING_LOC_Z); newChar.setXYZInvisible(createLoc.getX(), createLoc.getY(), createLoc.getZ()); } else if (Config.FACTION_SYSTEM_ENABLED) { newChar.setXYZInvisible(Config.FACTION_STARTING_LOCATION.getX(), Config.FACTION_STARTING_LOCATION.getY(), Config.FACTION_STARTING_LOCATION.getZ()); } else { Location createLoc = template.getCreationPoint(); newChar.setXYZInvisible(createLoc.getX(), createLoc.getY(), createLoc.getZ()); } newChar.setTitle(""); if (Config.ENABLE_VITALITY) { newChar.setVitalityPoints(Math.min(Config.STARTING_VITALITY_POINTS, PcStat.MAX_VITALITY_POINTS), true); } if (Config.STARTING_LEVEL > 1) { newChar.getStat().addLevel((byte) (Config.STARTING_LEVEL - 1)); } if (Config.STARTING_SP > 0) { newChar.getStat().addSp(Config.STARTING_SP); } final List<PcItemTemplate> initialItems = InitialEquipmentData.getInstance().getEquipmentList(newChar.getClassId()); if (initialItems != null) { for (PcItemTemplate ie : initialItems) { final L2ItemInstance item = newChar.getInventory().addItem("Init", ie.getId(), ie.getCount(), newChar, null); if (item == null) { _log.warning("Could not create item during char creation: itemId " + ie.getId() + ", amount " + ie.getCount() + "."); continue; } if (item.isEquipable() && ie.isEquipped()) { newChar.getInventory().equipItem(item); } } } for (L2SkillLearn skill : SkillTreesData.getInstance().getRaceSkillTree(newChar.getRace())) { newChar.addSkill(SkillData.getInstance().getSkill(skill.getSkillId(), skill.getSkillLevel()), true); } for (L2SkillLearn skill : SkillTreesData.getInstance().getAvailableSkills(newChar, newChar.getClassId(), false, true)) { if (Config.DEBUG) { _log.fine("Adding starter skill:" + skill.getSkillId() + " / " + skill.getSkillLevel()); } newChar.addSkill(SkillData.getInstance().getSkill(skill.getSkillId(), skill.getSkillLevel()), true); } // Register all shortcuts for actions, skills and items for this new character. InitialShortcutData.getInstance().registerAllShortcuts(newChar); EventDispatcher.getInstance().notifyEvent(new OnPlayerCreate(newChar, newChar.getObjectId(), newChar.getName(), client), Containers.Players()); newChar.setOnlineStatus(true, false); if (Config.SHOW_GOD_VIDEO_INTRO) { newChar.getVariables().set("intro_god_video", true); } newChar.deleteMe(); final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1); client.setCharSelection(cl.getCharInfo()); if (Config.DEBUG) { _log.fine("Character init end"); } } @Override public String getType() { return _C__0C_CHARACTERCREATE; } }