/*
* 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 .
*/
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 java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
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.instancemanager.QuestManager;
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.model.quest.Quest;
import com.l2jserver.gameserver.model.quest.QuestState;
import com.l2jserver.gameserver.model.quest.State;
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;
}
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 boolean isValidName(String text)
{
boolean result = true;
String test = text;
Pattern pattern;
// UnAfraid: TODO: Move that into Config
try
{
pattern = Pattern.compile(Config.CNAME_TEMPLATE);
}
catch (PatternSyntaxException e) // case of illegal pattern
{
_log.warning("ERROR : Character name pattern of config is wrong!");
pattern = Pattern.compile(".*");
}
Matcher regexp = pattern.matcher(test);
if (!regexp.matches())
{
result = false;
}
return result;
}
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();
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 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().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);
if (!Config.DISABLE_TUTORIAL)
{
startTutorialQuest(newChar);
}
EventDispatcher.getInstance().notifyEvent(new OnPlayerCreate(newChar, newChar.getObjectId(), newChar.getName(), client), Containers.Players());
newChar.setOnlineStatus(true, false);
newChar.deleteMe();
final CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1);
client.setCharSelection(cl.getCharInfo());
if (Config.DEBUG)
{
_log.fine("Character init end");
}
}
/**
* TODO: Unhardcode it using the new listeners.
* @param player
*/
public void startTutorialQuest(L2PcInstance player)
{
final QuestState qs = player.getQuestState("255_Tutorial");
Quest q = null;
if (qs == null)
{
q = QuestManager.getInstance().getQuest("255_Tutorial");
}
if (q != null)
{
q.newQuestState(player).setState(State.STARTED);
}
}
@Override
public String getType()
{
return _C__0C_CHARACTERCREATE;
}
}