public void HandlePacket(GameClient client, GSPacketIn packet) { ushort jumpSpotID = packet.ReadShort(); eRealm targetRealm = client.Player.Realm; if (client.Player.CurrentRegion.Expansion == (int)eClientExpansion.TrialsOfAtlantis && client.Player.CurrentZone.Realm != eRealm.None) { // if we are in TrialsOfAtlantis then base the target jump on the current region realm instead of the players realm // this is only used if zone table has the proper realms defined, otherwise it reverts to old behavior - Tolakram targetRealm = client.Player.CurrentZone.Realm; } var zonePoint = GameServer.Database.SelectObject <ZonePoint>("`Id` = '" + jumpSpotID + "' AND (`Realm` = '" + (byte)targetRealm + "' OR `Realm` = '0' OR `Realm` = NULL)"); if (zonePoint == null || zonePoint.TargetRegion == 0) { ChatUtil.SendDebugMessage(client, "Invalid Jump (ZonePoint table): [" + jumpSpotID + "]" + ((zonePoint == null) ? ". Entry missing!" : ". TargetRegion is 0!")); zonePoint = new ZonePoint(); zonePoint.Id = jumpSpotID; } if (client.Account.PrivLevel > 1) { client.Out.SendMessage("JumpSpotID = " + jumpSpotID, eChatType.CT_System, eChatLoc.CL_SystemWindow); client.Out.SendMessage("ZonePoint Target: Region = " + zonePoint.TargetRegion + ", ClassType = '" + zonePoint.ClassType + "'", eChatType.CT_System, eChatLoc.CL_SystemWindow); } //Dinberg: Fix - some jump points are handled code side, such as instances. //As such, region MAY be zero in the database, so this causes an issue. if (zonePoint.TargetRegion != 0) { Region reg = WorldMgr.GetRegion(zonePoint.TargetRegion); if (reg != null) { // check for target region disabled if player is in a standard region // otherwise the custom region should handle OnZonePoint for this check if (client.Player.CurrentRegion.IsCustom == false && reg.IsDisabled) { if ((client.Player.Mission is TaskDungeonMission && (client.Player.Mission as TaskDungeonMission).TaskRegion.Skin == reg.Skin) == false) { client.Out.SendMessage("This region has been disabled!", eChatType.CT_System, eChatLoc.CL_SystemWindow); if (client.Account.PrivLevel == 1) { return; } } } } } // Allow the region to either deny exit or handle the zonepoint in a custom way if (client.Player.CurrentRegion.OnZonePoint(client.Player, zonePoint) == false) { return; } //check caps for battleground Battleground bg = GameServer.KeepManager.GetBattleground(zonePoint.TargetRegion); if (bg != null) { if (client.Player.Level < bg.MinLevel && client.Player.Level > bg.MaxLevel && client.Player.RealmLevel >= bg.MaxRealmLevel) { return; } } IJumpPointHandler customHandler = null; if (string.IsNullOrEmpty(zonePoint.ClassType) == false) { customHandler = (IJumpPointHandler)m_customJumpPointHandlers[zonePoint.ClassType]; // check for db change to update cached handler if (customHandler != null && customHandler.GetType().FullName != zonePoint.ClassType) { customHandler = null; } if (customHandler == null) { //Dinberg - Instances need to use a special handler. This is because some instances will result //in duplicated zonepoints, such as if Tir Na Nog were to be instanced for a quest. string type = (client.Player.CurrentRegion.IsInstance) ? "DOL.GS.ServerRules.InstanceDoorJumpPoint" : zonePoint.ClassType; Type t = ScriptMgr.GetType(type); if (t == null) { Log.ErrorFormat("jump point {0}: class {1} not found!", zonePoint.Id, zonePoint.ClassType); } else if (!typeof(IJumpPointHandler).IsAssignableFrom(t)) { Log.ErrorFormat("jump point {0}: class {1} must implement IJumpPointHandler interface!", zonePoint.Id, zonePoint.ClassType); } else { try { customHandler = (IJumpPointHandler)Activator.CreateInstance(t); } catch (Exception e) { customHandler = null; Log.Error( string.Format("jump point {0}: error creating a new instance of jump point handler {1}", zonePoint.Id, zonePoint.ClassType), e); } } } if (customHandler != null) { m_customJumpPointHandlers[zonePoint.ClassType] = customHandler; } } new RegionChangeRequestHandler(client.Player, zonePoint, customHandler).Start(1); }
void Awake() { instance = this; scriptData = DataSaveLoad.LoadScript(); // 대사 XML 문서 불러오기 spokeNpc = DataSaveLoad.LoadNpcName(); // 이미 대화한 NPC 이름 불러오기 }
public static object ConvertObject(object obj, object defaultValue, Type destinationType) { object result = null; if (destinationType == typeof(Type)) { if (obj is Type) { result = obj; } else if (!String.IsNullOrEmpty(Convert.ToString(obj))) { result = ScriptMgr.GetType(Convert.ToString(obj)); } } else if (destinationType == typeof(Int32)) { result = Convert.ToInt32(obj); } else if (destinationType == typeof(Nullable <Int32>)) { result = new Nullable <Int32>(Convert.ToInt32(obj)); } else if (destinationType == typeof(Int64)) { result = Convert.ToInt64(obj); } else if (destinationType == typeof(eEmote)) { if (obj is eEmote) { result = (eEmote)obj; } else { result = (eEmote)Enum.Parse(typeof(eEmote), Convert.ToString(obj), true); } } else if (destinationType == typeof(GameLiving)) { result = QuestMgr.ResolveLiving(obj); } else if (destinationType == typeof(ItemTemplate)) { if (obj is ItemTemplate) { result = obj; } else { result = GameServer.Database.FindObjectByKey <ItemTemplate>(Convert.ToString(obj)); } } else if (destinationType == typeof(CustomDialogResponse)) { result = (CustomDialogResponse)obj; } else if (destinationType == typeof(GameLocation)) { result = (GameLocation)obj; } else if (destinationType == typeof(IPoint3D)) { result = (IPoint3D)obj; } else if (destinationType == typeof(PathPoint)) { result = (PathPoint)obj; } else { result = obj; } // handle default value if result == null if (result == null && defaultValue != null) { result = defaultValue; } return(result); }
public SpellDelve(Spell spell) { spellHandler = ScriptMgr.CreateSpellHandler(null, spell, SkillBase.GetSpellLine(GlobalSpellsLines.Reserved_Spells)); DelveType = "Spell"; Index = unchecked ((short)spellHandler.Spell.InternalID); }
public void OnAction(Hashtable parameters) { Console.WriteLine("Starting GameServer ... please wait a moment!"); FileInfo configFile; FileInfo currentAssembly = null; if (parameters["-config"] != null) { Console.WriteLine("Using config file: " + parameters["-config"]); configFile = new FileInfo((String)parameters["-config"]); } else { currentAssembly = new FileInfo(Assembly.GetEntryAssembly().Location); configFile = new FileInfo(currentAssembly.DirectoryName + Path.DirectorySeparatorChar + "config" + Path.DirectorySeparatorChar + "serverconfig.xml"); } GameServerConfiguration config = new GameServerConfiguration(); if (configFile.Exists) { config.LoadFromXMLFile(configFile); } else { if (!configFile.Directory.Exists) { configFile.Directory.Create(); } config.SaveToXMLFile(configFile); if (File.Exists(currentAssembly.DirectoryName + Path.DirectorySeparatorChar + "DOLConfig.exe")) { Console.WriteLine("No config file found, launching with default config and embedded database... (SQLite)"); /* * // Removed to allow the auto config on embedded SQLite * Console.WriteLine("No config file found, launching DOLConfig.exe..."); * System.Diagnostics.Process.Start(currentAssembly.DirectoryName + Path.DirectorySeparatorChar + "DOLConfig.exe"); * return; */ } } GameServer.CreateInstance(config); StartServer(); bool run = true; while (run) { Console.Write("> "); string line = Console.ReadLine(); switch (line.ToLower()) { case "exit": run = false; break; case "stacktrace": log.Debug(PacketProcessor.GetConnectionThreadpoolStacks()); break; case "clear": Console.Clear(); break; default: if (line.Length <= 0) { break; } if (line[0] == '/') { line = line.Remove(0, 1); line = line.Insert(0, "&"); } GameClient client = new GameClient(null); client.Out = new ConsolePacketLib(); try { bool res = ScriptMgr.HandleCommandNoPlvl(client, line); if (!res) { Console.WriteLine("Unknown command: " + line); } } catch (Exception e) { Console.WriteLine(e.ToString()); } break; } } if (GameServer.Instance != null) { GameServer.Instance.Stop(); } }
public bool OnCommand(BaseClient client, string[] args) { if (args.Length > 1) { switch (args[1]) { case "-list": foreach (Assembly ass in ScriptMgr.Scripts) { DisplayMessage(client, ass.FullName); } return(true); case "-add": if (args.Length > 2 && args[2] != null && File.Exists(args[2])) { try { Assembly ass = Assembly.LoadFile(args[2]); if (ScriptMgr.InsertAssembly(ass)) { DisplayMessage(client, "Add assembly success!"); return(true); } else { DisplayMessage(client, "Assembly already exists in the scripts array!"); return(false); } } catch (Exception ex) { DisplayMessage(client, "Add assembly error:", ex.Message); return(false); } } else { DisplayMessage(client, "Can't find add assembly!"); return(false); } case "-remove": if (args.Length > 2 && args[2] != null && File.Exists(args[2])) { try { Assembly ass = Assembly.LoadFile(args[2]); if (ScriptMgr.RemoveAssembly(ass)) { DisplayMessage(client, "Remove assembly success!"); return(true); } else { DisplayMessage(client, "Assembly didn't exist in the scripts array!"); return(false); } } catch (Exception ex) { DisplayMessage(client, "Remove assembly error:", ex.Message); return(false); } } else { DisplayMessage(client, "Can't find remove assembly!"); return(false); } default: DisplayMessage(client, "Can't fine option:{0}", args[1]); return(true); } } else { DisplaySyntax(client); } return(true); }
public override bool CastSpell() { GamePlayer caster = (GamePlayer)Caster; m_spellTarget = caster.TargetObject as GameLiving; GameSpellEffect effect = FindEffectOnTarget(caster, "Chamber", Spell.Name); if (effect != null && Spell.Name == effect.Spell.Name) { ChamberSpellHandler chamber = (ChamberSpellHandler)effect.SpellHandler; GameSpellEffect PhaseShift = FindEffectOnTarget(m_spellTarget, "Phaseshift"); SelectiveBlindnessEffect SelectiveBlindness = Caster.EffectList.GetOfType <SelectiveBlindnessEffect>(); var spellhandler = ScriptMgr.CreateSpellHandler(caster, chamber.PrimarySpell, chamber.PrimarySpellLine); int duration = caster.GetSkillDisabledDuration(Spell); if (duration > 0) { MessageToCaster($"You must wait {duration / 1000 + 1} seconds to use this spell!", eChatType.CT_System); return(false); } if (caster.IsMoving || caster.IsStrafing) { MessageToCaster("You must be standing still to cast this spell!", eChatType.CT_System); return(false); } if (caster.IsSitting) { MessageToCaster("You can't cast this spell while sitting!", eChatType.CT_System); return(false); } if (m_spellTarget == null) { MessageToCaster("You must have a target!", eChatType.CT_SpellResisted); return(false); } if (!caster.IsAlive) { MessageToCaster("You cannot cast this dead!", eChatType.CT_SpellResisted); return(false); } if (!m_spellTarget.IsAlive) { MessageToCaster("You cannot cast this on the dead!", eChatType.CT_SpellResisted); return(false); } if (caster.IsMezzed || caster.IsStunned || caster.IsSilenced) { MessageToCaster("You can't use that in your state.", eChatType.CT_System); return(false); } if (!caster.TargetInView) { MessageToCaster("Your target is not visible!", eChatType.CT_SpellResisted); return(false); } if (caster.IsObjectInFront(m_spellTarget, 180) == false) { MessageToCaster("Your target is not in view!", eChatType.CT_SpellResisted); return(false); } if (caster.IsInvulnerableToAttack) { MessageToCaster("Your invunerable at the momment and cannot use that spell!", eChatType.CT_System); return(false); } if (m_spellTarget is GamePlayer) { if ((m_spellTarget as GamePlayer).IsInvulnerableToAttack) { MessageToCaster("Your target is invunerable at the momment and cannot be attacked!", eChatType.CT_System); return(false); } } if (!caster.IsWithinRadius(m_spellTarget, ((SpellHandler)spellhandler).CalculateSpellRange())) { MessageToCaster("That target is too far away!", eChatType.CT_SpellResisted); return(false); } if (PhaseShift != null) { MessageToCaster(m_spellTarget.Name + " is Phaseshifted and can't be attacked!", eChatType.CT_System); return(false); } if (SelectiveBlindness != null) { GameLiving EffectOwner = SelectiveBlindness.EffectSource; if (EffectOwner == m_spellTarget) { ((GamePlayer)Caster).Out.SendMessage($"{m_spellTarget.GetName(0, true)} is invisible to you!", eChatType.CT_Missed, eChatLoc.CL_SystemWindow); return(false); } } if (m_spellTarget.HasAbility(Abilities.DamageImmunity)) { MessageToCaster($"{m_spellTarget.Name} is immune to this effect!", eChatType.CT_SpellResisted); return(false); } if (GameServer.ServerRules.IsAllowedToAttack(Caster, m_spellTarget, true) && chamber.PrimarySpell.Target.ToLower() == "realm") { MessageToCaster("This spell only works on friendly targets!", eChatType.CT_System); return(false); } if (!GameServer.ServerRules.IsAllowedToAttack(Caster, m_spellTarget, true) && chamber.PrimarySpell.Target.ToLower() != "realm") { MessageToCaster("That target isn't attackable at this time!", eChatType.CT_System); return(false); } spellhandler.CastSpell(); if (chamber.SecondarySpell != null) { var spellhandler2 = ScriptMgr.CreateSpellHandler(caster, chamber.SecondarySpell, chamber.SecondarySpellLine); spellhandler2.CastSpell(); } effect.Cancel(false); GamePlayer player_Caster = Caster as GamePlayer; foreach (SpellLine spellline in player_Caster.GetSpellLines()) { foreach (Spell sp in SkillBase.GetSpellList(spellline.KeyName)) { if (sp.SpellType == Spell.SpellType) { Caster.DisableSkill(sp, sp.RecastDelay); } } } } else { base.CastSpell(); int duration = caster.GetSkillDisabledDuration(Spell); if (Caster is GamePlayer player && duration == 0) { player.Out.SendMessage($"Select the first spell for your {Spell.Name}.", eChatType.CT_System, eChatLoc.CL_SystemWindow); } } return(true); }
public void OnCommand(GameClient client, string[] args) { if (args.Length == 1) { DisplaySyntax(client); return; } GamePlayer player = client.Player.TargetObject as GamePlayer; if (player == null) { player = client.Player; } ushort model; if (ushort.TryParse(args[1], out model) == false) { DisplaySyntax(client); return; } int duration = 10; if (args.Length > 2) { if (int.TryParse(args[2], out duration) == false) { duration = 10; } } DBSpell dbSpell = new DBSpell(); dbSpell.Name = "GM Morph"; dbSpell.Description = "Target has been shapechanged."; dbSpell.ClientEffect = 8000; dbSpell.Icon = 805; dbSpell.Target = "Realm"; dbSpell.Range = 4000; dbSpell.Power = 0; dbSpell.CastTime = 0; dbSpell.Type = "Morph"; dbSpell.Duration = duration * 60; dbSpell.LifeDrainReturn = model; Spell morphSpell = new Spell(dbSpell, 0); SpellLine gmLine = new SpellLine("GMSpell", "GM Spell", "none", false); ISpellHandler spellHandler = ScriptMgr.CreateSpellHandler(client.Player, morphSpell, gmLine); if (spellHandler == null) { DisplayMessage(client, "Unable to create spell handler."); } else { spellHandler.StartSpell(player); } }
public void OnAction(Hashtable parameters) { if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major >= 10) { // enable VT100 emulation var handle = GetStdHandle(-11); // STD_OUTPUT_HANDLE if (handle != IntPtr.Zero) { uint mode; if (GetConsoleMode(handle, out mode) != 0) { SetConsoleMode(handle, mode | 0x0004); // ENABLE_VIRTUAL_TERMINAL_PROCESSING } } } Console.WriteLine("Starting GameServer ... please wait a moment!"); FileInfo configFile; FileInfo currentAssembly = null; if (parameters["-config"] != null) { Console.WriteLine("Using config file: " + parameters["-config"]); configFile = new FileInfo((String)parameters["-config"]); } else { currentAssembly = new FileInfo(Assembly.GetEntryAssembly().Location); configFile = new FileInfo(currentAssembly.DirectoryName + Path.DirectorySeparatorChar + "config" + Path.DirectorySeparatorChar + "serverconfig.xml"); } if (parameters.ContainsKey("-crashonfail")) { crashOnFail = true; } var config = new GameServerConfiguration(); if (configFile.Exists) { config.LoadFromXMLFile(configFile); } else { if (!configFile.Directory.Exists) { configFile.Directory.Create(); } config.SaveToXMLFile(configFile); if (File.Exists(currentAssembly.DirectoryName + Path.DirectorySeparatorChar + "DOLConfig.exe")) { Console.WriteLine("No config file found, launching with default config and embedded database... (SQLite)"); } } GameServer.CreateInstance(config); StartServer(); if (crashOnFail && GameServer.Instance.ServerStatus == eGameServerStatus.GSS_Closed) { throw new ApplicationException("Server did not start properly."); } bool run = true; while (run) { Console.Write("> "); string line = Console.ReadLine(); switch (line.ToLower()) { case "exit": run = false; break; case "stacktrace": log.Debug(PacketProcessor.GetConnectionThreadpoolStacks()); break; case "clear": Console.Clear(); break; default: if (line.Length <= 0) { break; } if (line[0] == '/') { line = line.Remove(0, 1); line = line.Insert(0, "&"); } GameClient client = new GameClient(null); client.Out = new ConsolePacketLib(); try { bool res = ScriptMgr.HandleCommandNoPlvl(client, line); if (!res) { Console.WriteLine("Unknown command: " + line); } } catch (Exception e) { Console.WriteLine(e.ToString()); } break; } } if (GameServer.Instance != null) { GameServer.Instance.Stop(); } }
/// <summary> /// Handler fired whenever effect target is attacked /// </summary> /// <param name="e"></param> /// <param name="sender"></param> /// <param name="arguments"></param> protected override void EventHandler(DOLEvent e, object sender, EventArgs arguments) { if (!(arguments is AttackFinishedEventArgs args) || args.AttackData == null) { return; } AttackData ad = args.AttackData; if (ad.AttackResult != GameLiving.eAttackResult.HitUnstyled && ad.AttackResult != GameLiving.eAttackResult.HitStyle) { return; } int baseChance = Spell.Frequency / 100; if (ad.IsMeleeAttack) { if (sender is GamePlayer player) { InventoryItem leftWeapon = player.Inventory.GetItem(eInventorySlot.LeftHandWeapon); // if we can use left weapon, we have currently a weapon in left hand and we still have endurance, // we can assume that we are using the two weapons. if (player.CanUseLefthandedWeapon && leftWeapon != null && leftWeapon.Object_Type != (int)eObjectType.Shield) { baseChance /= 2; } } } if (baseChance < 1) { baseChance = 1; } if (Util.Chance(baseChance)) { ISpellHandler handler = ScriptMgr.CreateSpellHandler((GameLiving)sender, m_procSpell, m_procSpellLine); if (handler != null) { if (m_procSpell.Target.ToLower() == "enemy") { handler.StartSpell(ad.Target); } else if (m_procSpell.Target.ToLower() == "self") { handler.StartSpell(ad.Attacker); } else if (m_procSpell.Target.ToLower() == "group") { GamePlayer player = Caster as GamePlayer; if (Caster is GamePlayer) { if (player.Group != null) { foreach (GameLiving groupPlayer in player.Group.GetMembersInTheGroup()) { if (player.IsWithinRadius(groupPlayer, m_procSpell.Range)) { handler.StartSpell(groupPlayer); } } } else { handler.StartSpell(player); } } } else { log.Warn("Skipping " + m_procSpell.Target + " proc " + m_procSpell.Name + " on " + ad.Target.Name + "; Realm = " + ad.Target.Realm); } } } }
/// <summary> /// Check if a Character Needs update based to packet data /// </summary> /// <param name="pdata">packet data</param> /// <param name="client">client</param> /// <param name="character">db character</param> /// <returns>True if character need refreshment false if no refresh needed.</returns> private bool CheckCharacterForUpdates(CreationCharacterData pdata, GameClient client, DOLCharacters character) { int newModel = character.CurrentModel; if (pdata.CustomMode == 1 || pdata.CustomMode == 2 || pdata.CustomMode == 3) { bool flagChangedStats = false; if (Properties.ALLOW_CUSTOMIZE_FACE_AFTER_CREATION) { character.EyeSize = (byte)pdata.EyeSize; character.LipSize = (byte)pdata.LipSize; character.EyeColor = (byte)pdata.EyeColor; character.HairColor = (byte)pdata.HairColor; character.FaceType = (byte)pdata.FaceType; character.HairStyle = (byte)pdata.HairStyle; character.MoodType = (byte)pdata.MoodType; } if (pdata.CustomMode != 3 && client.Version >= GameClient.eClientVersion.Version189) { var stats = new Dictionary <eStat, int>(); stats[eStat.STR] = pdata.Strength; // Strength stats[eStat.DEX] = pdata.Dexterity; // Dexterity stats[eStat.CON] = pdata.NewConstitution; // New Constitution stats[eStat.QUI] = pdata.Quickness; // Quickness stats[eStat.INT] = pdata.Intelligence; // Intelligence stats[eStat.PIE] = pdata.Piety; // Piety stats[eStat.EMP] = pdata.Empathy; // Empathy stats[eStat.CHR] = pdata.Charisma; // Charisma // check for changed stats. flagChangedStats |= stats[eStat.STR] != character.Strength; flagChangedStats |= stats[eStat.CON] != character.Constitution; flagChangedStats |= stats[eStat.DEX] != character.Dexterity; flagChangedStats |= stats[eStat.QUI] != character.Quickness; flagChangedStats |= stats[eStat.INT] != character.Intelligence; flagChangedStats |= stats[eStat.PIE] != character.Piety; flagChangedStats |= stats[eStat.EMP] != character.Empathy; flagChangedStats |= stats[eStat.CHR] != character.Charisma; if (flagChangedStats) { ICharacterClass charClass = ScriptMgr.FindCharacterClass(character.Class); if (charClass != null) { int points; bool valid = IsCustomPointsDistributionValid(character, stats, out points); // Hacking attemp ? if (points > MAX_STARTING_BONUS_POINTS) { if ((ePrivLevel)client.Account.PrivLevel == ePrivLevel.Player) { if (ServerProperties.Properties.BAN_HACKERS) { client.BanAccount(string.Format("Autoban Hack char update : Wrong allowed points:{0}", points)); } client.Disconnect(); return(false); } } // Error in setting points if (!valid) { return(true); } if (Properties.ALLOW_CUSTOMIZE_STATS_AFTER_CREATION) { // Set Stats, valid is ok. character.Strength = stats[eStat.STR]; character.Constitution = stats[eStat.CON]; character.Dexterity = stats[eStat.DEX]; character.Quickness = stats[eStat.QUI]; character.Intelligence = stats[eStat.INT]; character.Piety = stats[eStat.PIE]; character.Empathy = stats[eStat.EMP]; character.Charisma = stats[eStat.CHR]; if (log.IsInfoEnabled) { log.InfoFormat("Character {0} Stats updated in cache!", character.Name); } if (client.Player != null) { foreach (var stat in stats.Keys) { client.Player.ChangeBaseStat(stat, (short)(stats[stat] - client.Player.GetBaseStat(stat))); } if (log.IsInfoEnabled) { log.InfoFormat("Character {0} Player Stats updated in cache!", character.Name); } } } } else if (log.IsErrorEnabled) { log.ErrorFormat("No CharacterClass with ID {0} found", character.Class); } } } if (pdata.CustomMode == 2) // change player customization { if (client.Account.PrivLevel == 1 && ((pdata.CreationModel >> 11) & 3) == 0) { if (ServerProperties.Properties.BAN_HACKERS) // Player size must be > 0 (from 1 to 3) { client.BanAccount(string.Format("Autoban Hack char update : zero character size in model:{0}", newModel)); client.Disconnect(); return(false); } return(true); } character.CustomisationStep = 2; // disable config button if (Properties.ALLOW_CUSTOMIZE_FACE_AFTER_CREATION) { if (pdata.CreationModel != character.CreationModel) { character.CurrentModel = newModel; } if (log.IsInfoEnabled) { log.InfoFormat("Character {0} face properties configured by account {1}!", character.Name, client.Account.Name); } } } else if (pdata.CustomMode == 3) //auto config -- seems someone thinks this is not possible? { character.CustomisationStep = 3; // enable config button to player } //Save the character in the database GameServer.Database.SaveObject(character); } return(false); }