/// <summary> /// Check if Custom Creation Points Distribution is Valid. /// </summary> /// <param name="character"></param> /// <param name="stats"></param> /// <param name="points"></param> /// <returns></returns> public static bool IsCustomPointsDistributionValid(DOLCharacters character, IDictionary <eStat, int> stats, out int points) { ICharacterClass charClass = ScriptMgr.FindCharacterClass(character.Class); if (charClass != null) { points = 0; // check if each stat is valid. foreach (var stat in stats.Keys) { int raceAmount = GlobalConstants.STARTING_STATS_DICT[(eRace)character.Race][stat]; int classAmount = 0; for (int level = character.Level; level > 5; level--) { if (charClass.PrimaryStat != eStat.UNDEFINED && charClass.PrimaryStat == stat) { classAmount++; } if (charClass.SecondaryStat != eStat.UNDEFINED && charClass.SecondaryStat == stat && (level - 6) % 2 == 0) { classAmount++; } if (charClass.TertiaryStat != eStat.UNDEFINED && charClass.TertiaryStat == stat && (level - 6) % 3 == 0) { classAmount++; } } int above = stats[stat] - raceAmount - classAmount; // Miss Some points... if (above < 0) { return(false); } points += above; points += Math.Max(0, above - 10); // two points used points += Math.Max(0, above - 15); // three points used } return(points == MaxStartingBonusPoints); } points = -1; return(false); }
/// <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); }