/*
* 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;
}
}