public static Container CreateCorpse(Creature template, Position newPosition) { ushort wcidCorpse = 21; WeenieHeaderFlag weenie = WeenieHeaderFlag.ItemsCapacity | WeenieHeaderFlag.ContainersCapacity | WeenieHeaderFlag.Usable | WeenieHeaderFlag.UseRadius | WeenieHeaderFlag.Burden; ObjectDescriptionFlag objDesc = ObjectDescriptionFlag.Openable | ObjectDescriptionFlag.Stuck | ObjectDescriptionFlag.Attackable | ObjectDescriptionFlag.Corpse; // = bitfield 8213 string name = $"Corpse of {template.Name}"; Container wo = new Container(template.AceCorpse, GuidManager.NewItemGuid(), name, wcidCorpse, objDesc, weenie, newPosition); // TODO: Find the correct motionstate to create a corpse with. For now only the dead motionstate works // wo.CurrentMotionState = new GeneralMotion(MotionStance.Standing); wo.CurrentMotionState = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.Dead)); wo.SoundTableId = 536871106; // SoundTableId in DB - constant value according to pcap wo.PhysicsTableId = 872415342; // phstableid in DB - constant value according to pcap wo.PhysicsDescriptionFlag = PhysicsDescriptionFlag.CSetup | PhysicsDescriptionFlag.MTable | PhysicsDescriptionFlag.ObjScale | PhysicsDescriptionFlag.STable | PhysicsDescriptionFlag.PeTable | PhysicsDescriptionFlag.Position | PhysicsDescriptionFlag.Movement; // 104579 - according to pcap wo.PhysicsState = PhysicsState.Ethereal | PhysicsState.IgnoreCollision | PhysicsState.Gravity; // 1044 - according to pcap uint tmpIcon = 100667504; wo.IconId = tmpIcon; wo.ItemCapacity = 120; // constant value according to pcap wo.ContainerCapacity = 10; // constant value according to pcap wo.Usable = Usable.ViewedRemote; // constant value according to pcap wo.UseRadius = 2.0f; // constant value according to pcap wo.Burden = 6000; // Testdata, has to be set as the sum of the spawned items in the corpse // Calculation of the TTL: 5 real time minutes * player level with a minimum of 1 hour, so we set the minimum here wo.DespawnTime = 360 + WorldManager.PortalYearTicks; return(wo); }
public static WorldObject CreateNewWorldObject(string weenieClassDescription, int palette = 0, float shade = 0, int stackSize = 1) { uint weenieClassId = DatabaseManager.World.GetWeenieClassIdByWeenieClassDescription(weenieClassDescription); if (weenieClassId < 1 && weenieClassId > AceObject.WEENIE_MAX) { return(null); } WorldObject wo = CreateWorldObject(weenieClassId, GuidManager.NewItemGuid(), palette, shade, stackSize); return(wo); }
/// <summary> /// creates a portal of the specified weenie at the position provided /// </summary> public static void SpawnPortal(PortalWcid weenieClassId, Position newPosition, float despawnTime) { AceObject aceO = DatabaseManager.World.GetAceObjectByWeenie((ushort)weenieClassId); aceO.AceObjectPropertiesPositions.Add(PositionType.Location, newPosition); WorldObject portal = new Portal(aceO); portal.Guid = GuidManager.NewItemGuid(); LandblockManager.AddObject(portal); // Create portal decay ActionChain despawnChain = new ActionChain(); despawnChain.AddDelaySeconds(despawnTime); despawnChain.AddAction(portal, () => portal.CurrentLandblock.RemoveWorldObject(portal.Guid, false)); despawnChain.EnqueueChain(); }
private static void CharacterCreateEx(ClientMessage message, Session session, uint id) { CharGen cg = CharGen.ReadFromDat(); var reader = message.Payload; AceCharacter character = new AceCharacter(id); reader.Skip(4); /* Unknown constant (1) */ character.Heritage = reader.ReadUInt32(); character.HeritageGroup = cg.HeritageGroups[(int)character.Heritage].Name; character.Gender = reader.ReadUInt32(); if (character.Gender == 1) { character.Sex = "Male"; } else { character.Sex = "Female"; } Appearance appearance = Appearance.FromNetwork(reader); // character.IconId = cg.HeritageGroups[(int)character.Heritage].IconImage; // pull character data from the dat file SexCG sex = cg.HeritageGroups[(int)character.Heritage].SexList[(int)character.Gender]; character.MotionTableId = sex.MotionTable; character.SoundTableId = sex.SoundTable; character.PhysicsTableId = sex.PhysicsTable; character.SetupTableId = sex.SetupID; character.PaletteId = sex.BasePalette; character.CombatTableId = sex.CombatTable; // Check the character scale if (sex.Scale != 100u) { character.DefaultScale = (sex.Scale / 100f); // Scale is stored as a percentage } // Get the hair first, because we need to know if you're bald, and that's the name of that tune! HairStyleCG hairstyle = sex.HairStyleList[Convert.ToInt32(appearance.HairStyle)]; bool isBald = hairstyle.Bald; // Certain races (Undead, Tumeroks, Others?) have multiple body styles available. This is controlled via the "hair style". if (hairstyle.AlternateSetup > 0) { character.SetupTableId = hairstyle.AlternateSetup; } character.EyesTexture = sex.GetEyeTexture(appearance.Eyes, isBald); character.DefaultEyesTexture = sex.GetDefaultEyeTexture(appearance.Eyes, isBald); character.NoseTexture = sex.GetNoseTexture(appearance.Nose); character.DefaultNoseTexture = sex.GetDefaultNoseTexture(appearance.Nose); character.MouthTexture = sex.GetMouthTexture(appearance.Mouth); character.DefaultMouthTexture = sex.GetDefaultMouthTexture(appearance.Mouth); character.HairTexture = sex.GetHairTexture(appearance.HairStyle); character.DefaultHairTexture = sex.GetDefaultHairTexture(appearance.HairStyle); character.HeadObject = sex.GetHeadObject(appearance.HairStyle); // Skin is stored as PaletteSet (list of Palettes), so we need to read in the set to get the specific palette PaletteSet skinPalSet = PaletteSet.ReadFromDat(sex.SkinPalSet); character.SkinPalette = skinPalSet.GetPaletteID(appearance.SkinHue); // Hair is stored as PaletteSet (list of Palettes), so we need to read in the set to get the specific palette PaletteSet hairPalSet = PaletteSet.ReadFromDat(sex.HairColorList[Convert.ToInt32(appearance.HairColor)]); character.HairPalette = hairPalSet.GetPaletteID(appearance.HairHue); // Eye Color character.EyesPalette = sex.EyeColorList[Convert.ToInt32(appearance.EyeColor)]; if (appearance.HeadgearStyle < 0xFFFFFFFF) // No headgear is max UINT { uint headgearWeenie = sex.GetHeadgearWeenie(appearance.HeadgearStyle); ClothingTable headCT = ClothingTable.ReadFromDat(sex.GetHeadgearClothingTable(appearance.HeadgearStyle)); uint headgearIconId = headCT.GetIcon(appearance.HeadgearColor); var hat = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(headgearWeenie).Clone(GuidManager.NewItemGuid().Full); hat.PaletteOverrides = new List <PaletteOverride>(); // wipe any existing overrides hat.TextureOverrides = new List <TextureMapOverride>(); hat.AnimationOverrides = new List <AnimationOverride>(); hat.SpellIdProperties = new List <AceObjectPropertiesSpell>(); hat.IconDID = headgearIconId; hat.Placement = 0; hat.CurrentWieldedLocation = hat.ValidLocations; hat.WielderIID = id; if (headCT.ClothingBaseEffects.ContainsKey(sex.SetupID)) { // Add the model and texture(s) ClothingBaseEffect headCBE = headCT.ClothingBaseEffects[sex.SetupID]; for (int i = 0; i < headCBE.CloObjectEffects.Count; i++) { byte partNum = (byte)headCBE.CloObjectEffects[i].Index; hat.AnimationOverrides.Add(new AnimationOverride() { AceObjectId = hat.AceObjectId, AnimationId = headCBE.CloObjectEffects[i].ModelId, Index = (byte)headCBE.CloObjectEffects[i].Index }); for (int j = 0; j < headCBE.CloObjectEffects[i].CloTextureEffects.Count; j++) { hat.TextureOverrides.Add(new TextureMapOverride() { AceObjectId = hat.AceObjectId, Index = (byte)headCBE.CloObjectEffects[i].Index, OldId = (ushort)headCBE.CloObjectEffects[i].CloTextureEffects[j].OldTexture, NewId = (ushort)headCBE.CloObjectEffects[i].CloTextureEffects[j].NewTexture }); } } // Apply the proper palette(s). Unlike character skin/hair, clothes can have several palette ranges! CloSubPalEffect headSubPal = headCT.ClothingSubPalEffects[appearance.HeadgearColor]; for (int i = 0; i < headSubPal.CloSubPalettes.Count; i++) { PaletteSet headgearPalSet = PaletteSet.ReadFromDat(headSubPal.CloSubPalettes[i].PaletteSet); ushort headgearPal = (ushort)headgearPalSet.GetPaletteID(appearance.HeadgearHue); for (int j = 0; j < headSubPal.CloSubPalettes[i].Ranges.Count; j++) { uint palOffset = headSubPal.CloSubPalettes[i].Ranges[j].Offset / 8; uint numColors = headSubPal.CloSubPalettes[i].Ranges[j].NumColors / 8; hat.PaletteOverrides.Add(new PaletteOverride() { AceObjectId = hat.AceObjectId, SubPaletteId = headgearPal, Length = (ushort)(numColors), Offset = (ushort)(palOffset) }); } } } character.WieldedItems.Add(new ObjectGuid(hat.AceObjectId), hat); } uint shirtWeenie = sex.GetShirtWeenie(appearance.ShirtStyle); ClothingTable shirtCT = ClothingTable.ReadFromDat(sex.GetShirtClothingTable(appearance.ShirtStyle)); uint shirtIconId = shirtCT.GetIcon(appearance.ShirtColor); var shirt = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(shirtWeenie).Clone(GuidManager.NewItemGuid().Full); shirt.PaletteOverrides = new List <PaletteOverride>(); // wipe any existing overrides shirt.TextureOverrides = new List <TextureMapOverride>(); shirt.AnimationOverrides = new List <AnimationOverride>(); shirt.SpellIdProperties = new List <AceObjectPropertiesSpell>(); shirt.IconDID = shirtIconId; shirt.Placement = 0; shirt.CurrentWieldedLocation = shirt.ValidLocations; shirt.WielderIID = id; if (shirtCT.ClothingBaseEffects.ContainsKey(sex.SetupID)) { ClothingBaseEffect shirtCBE = shirtCT.ClothingBaseEffects[sex.SetupID]; for (int i = 0; i < shirtCBE.CloObjectEffects.Count; i++) { byte partNum = (byte)shirtCBE.CloObjectEffects[i].Index; shirt.AnimationOverrides.Add(new AnimationOverride() { AceObjectId = shirt.AceObjectId, AnimationId = shirtCBE.CloObjectEffects[i].ModelId, Index = (byte)shirtCBE.CloObjectEffects[i].Index }); for (int j = 0; j < shirtCBE.CloObjectEffects[i].CloTextureEffects.Count; j++) { shirt.TextureOverrides.Add(new TextureMapOverride() { AceObjectId = shirt.AceObjectId, Index = (byte)shirtCBE.CloObjectEffects[i].Index, OldId = (ushort)shirtCBE.CloObjectEffects[i].CloTextureEffects[j].OldTexture, NewId = (ushort)shirtCBE.CloObjectEffects[i].CloTextureEffects[j].NewTexture }); } } // Apply the proper palette(s). Unlike character skin/hair, clothes can have several palette ranges! if (shirtCT.ClothingSubPalEffects.ContainsKey(appearance.ShirtColor)) { CloSubPalEffect shirtSubPal = shirtCT.ClothingSubPalEffects[appearance.ShirtColor]; for (int i = 0; i < shirtSubPal.CloSubPalettes.Count; i++) { PaletteSet shirtPalSet = PaletteSet.ReadFromDat(shirtSubPal.CloSubPalettes[i].PaletteSet); ushort shirtPal = (ushort)shirtPalSet.GetPaletteID(appearance.ShirtHue); if (shirtPal > 0) // shirtPal will be 0 if the palette set is empty/not found { for (int j = 0; j < shirtSubPal.CloSubPalettes[i].Ranges.Count; j++) { uint palOffset = shirtSubPal.CloSubPalettes[i].Ranges[j].Offset / 8; uint numColors = shirtSubPal.CloSubPalettes[i].Ranges[j].NumColors / 8; shirt.PaletteOverrides.Add(new PaletteOverride() { AceObjectId = shirt.AceObjectId, SubPaletteId = shirtPal, Offset = (ushort)palOffset, Length = (ushort)numColors }); } } } } } character.WieldedItems.Add(new ObjectGuid(shirt.AceObjectId), shirt); uint pantsWeenie = sex.GetPantsWeenie(appearance.PantsStyle); ClothingTable pantsCT = ClothingTable.ReadFromDat(sex.GetPantsClothingTable(appearance.PantsStyle)); uint pantsIconId = pantsCT.GetIcon(appearance.PantsColor); var pants = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(pantsWeenie).Clone(GuidManager.NewItemGuid().Full); pants.PaletteOverrides = new List <PaletteOverride>(); // wipe any existing overrides pants.TextureOverrides = new List <TextureMapOverride>(); pants.AnimationOverrides = new List <AnimationOverride>(); pants.SpellIdProperties = new List <AceObjectPropertiesSpell>(); pants.IconDID = pantsIconId; pants.Placement = 0; pants.CurrentWieldedLocation = pants.ValidLocations; pants.WielderIID = id; // Get the character's initial pants if (pantsCT.ClothingBaseEffects.ContainsKey(sex.SetupID)) { ClothingBaseEffect pantsCBE = pantsCT.ClothingBaseEffects[sex.SetupID]; for (int i = 0; i < pantsCBE.CloObjectEffects.Count; i++) { byte partNum = (byte)pantsCBE.CloObjectEffects[i].Index; pants.AnimationOverrides.Add(new AnimationOverride() { AceObjectId = pants.AceObjectId, AnimationId = pantsCBE.CloObjectEffects[i].ModelId, Index = (byte)pantsCBE.CloObjectEffects[i].Index }); for (int j = 0; j < pantsCBE.CloObjectEffects[i].CloTextureEffects.Count; j++) { pants.TextureOverrides.Add(new TextureMapOverride() { AceObjectId = pants.AceObjectId, Index = (byte)pantsCBE.CloObjectEffects[i].Index, OldId = (ushort)pantsCBE.CloObjectEffects[i].CloTextureEffects[j].OldTexture, NewId = (ushort)pantsCBE.CloObjectEffects[i].CloTextureEffects[j].NewTexture }); } } // Apply the proper palette(s). Unlike character skin/hair, clothes can have several palette ranges! CloSubPalEffect pantsSubPal = pantsCT.ClothingSubPalEffects[appearance.PantsColor]; for (int i = 0; i < pantsSubPal.CloSubPalettes.Count; i++) { PaletteSet pantsPalSet = PaletteSet.ReadFromDat(pantsSubPal.CloSubPalettes[i].PaletteSet); ushort pantsPal = (ushort)pantsPalSet.GetPaletteID(appearance.PantsHue); for (int j = 0; j < pantsSubPal.CloSubPalettes[i].Ranges.Count; j++) { uint palOffset = pantsSubPal.CloSubPalettes[i].Ranges[j].Offset / 8; uint numColors = pantsSubPal.CloSubPalettes[i].Ranges[j].NumColors / 8; pants.PaletteOverrides.Add(new PaletteOverride() { AceObjectId = pants.AceObjectId, SubPaletteId = pantsPal, Offset = (ushort)palOffset, Length = (ushort)numColors }); } } } // end pants character.WieldedItems.Add(new ObjectGuid(pants.AceObjectId), pants); uint footwearWeenie = sex.GetFootwearWeenie(appearance.FootwearStyle); ClothingTable footwearCT = ClothingTable.ReadFromDat(sex.GetFootwearClothingTable(appearance.FootwearStyle)); uint footwearIconId = footwearCT.GetIcon(appearance.FootwearColor); var shoes = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(footwearWeenie).Clone(GuidManager.NewItemGuid().Full); shoes.PaletteOverrides = new List <PaletteOverride>(); // wipe any existing overrides shoes.TextureOverrides = new List <TextureMapOverride>(); shoes.AnimationOverrides = new List <AnimationOverride>(); shoes.SpellIdProperties = new List <AceObjectPropertiesSpell>(); shoes.IconDID = footwearIconId; shoes.Placement = 0; shoes.CurrentWieldedLocation = shoes.ValidLocations; shoes.WielderIID = id; if (footwearCT.ClothingBaseEffects.ContainsKey(sex.SetupID)) { ClothingBaseEffect footwearCBE = footwearCT.ClothingBaseEffects[sex.SetupID]; for (int i = 0; i < footwearCBE.CloObjectEffects.Count; i++) { byte partNum = (byte)footwearCBE.CloObjectEffects[i].Index; shoes.AnimationOverrides.Add(new AnimationOverride() { AceObjectId = shoes.AceObjectId, AnimationId = footwearCBE.CloObjectEffects[i].ModelId, Index = (byte)footwearCBE.CloObjectEffects[i].Index }); for (int j = 0; j < footwearCBE.CloObjectEffects[i].CloTextureEffects.Count; j++) { shoes.TextureOverrides.Add(new TextureMapOverride() { AceObjectId = shoes.AceObjectId, Index = (byte)footwearCBE.CloObjectEffects[i].Index, OldId = (ushort)footwearCBE.CloObjectEffects[i].CloTextureEffects[j].OldTexture, NewId = (ushort)footwearCBE.CloObjectEffects[i].CloTextureEffects[j].NewTexture }); } } // Apply the proper palette(s). Unlike character skin/hair, clothes can have several palette ranges! CloSubPalEffect footwearSubPal = footwearCT.ClothingSubPalEffects[appearance.FootwearColor]; for (int i = 0; i < footwearSubPal.CloSubPalettes.Count; i++) { PaletteSet footwearPalSet = PaletteSet.ReadFromDat(footwearSubPal.CloSubPalettes[i].PaletteSet); ushort footwearPal = (ushort)footwearPalSet.GetPaletteID(appearance.FootwearHue); for (int j = 0; j < footwearSubPal.CloSubPalettes[i].Ranges.Count; j++) { uint palOffset = footwearSubPal.CloSubPalettes[i].Ranges[j].Offset / 8; uint numColors = footwearSubPal.CloSubPalettes[i].Ranges[j].NumColors / 8; pants.PaletteOverrides.Add(new PaletteOverride() { AceObjectId = shoes.AceObjectId, SubPaletteId = footwearPal, Offset = (ushort)palOffset, Length = (ushort)numColors }); } } } // end footwear character.WieldedItems.Add(new ObjectGuid(shoes.AceObjectId), shoes); // Profession (Adventurer, Bow Hunter, etc) // TODO - Add this title to the available titles for this character. var templateOption = reader.ReadInt32(); string templateName = cg.HeritageGroups[(int)character.Heritage].TemplateList[templateOption].Name; character.Title = templateName; character.Template = templateName; character.CharacterTitleId = cg.HeritageGroups[(int)character.Heritage].TemplateList[templateOption].Title; character.NumCharacterTitles = 1; // stats uint totalAttributeCredits = cg.HeritageGroups[(int)character.Heritage].AttributeCredits; uint usedAttributeCredits = 0; // Validate this is equal to actual attribute credits (330 for all but "Olthoi", which have 60 character.StrengthAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.StrengthAbility.Base; character.EnduranceAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.EnduranceAbility.Base; character.CoordinationAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.CoordinationAbility.Base; character.QuicknessAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.QuicknessAbility.Base; character.FocusAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.FocusAbility.Base; character.SelfAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.SelfAbility.Base; // data we don't care about uint characterSlot = reader.ReadUInt32(); uint classId = reader.ReadUInt32(); // characters start with max vitals character.Health.Current = character.Health.MaxValue; character.Stamina.Current = character.Stamina.MaxValue; character.Mana.Current = character.Mana.MaxValue; // set initial skill credit amount. 52 for all but "Olthoi", which have 68 character.AvailableSkillCredits = cg.HeritageGroups[(int)character.Heritage].SkillCredits; uint numOfSkills = reader.ReadUInt32(); Skill skill; SkillStatus skillStatus; SkillCostAttribute skillCost; for (uint i = 0; i < numOfSkills; i++) { skill = (Skill)i; skillCost = skill.GetCost(); skillStatus = (SkillStatus)reader.ReadUInt32(); if (skillStatus == SkillStatus.Specialized) { character.TrainSkill(skill, skillCost.TrainingCost); character.SpecializeSkill(skill, skillCost.SpecializationCost); // oddly enough, specialized skills don't get any free ranks like trained do } if (skillStatus == SkillStatus.Trained) { character.TrainSkill(skill, skillCost.TrainingCost); character.AceObjectPropertiesSkills[skill].Ranks = 5; character.AceObjectPropertiesSkills[skill].ExperienceSpent = 526; } if (skillCost != null && skillStatus == SkillStatus.Untrained) { character.UntrainSkill(skill, skillCost.TrainingCost); } } // grant starter items based on skills var starterGearConfig = StarterGearFactory.GetStarterGearConfiguration(); List <uint> grantedItems = new List <uint>(); foreach (var skillGear in starterGearConfig.Skills) { var charSkill = character.AceObjectPropertiesSkills[(Skill)skillGear.SkillId]; if (charSkill.Status == SkillStatus.Trained || charSkill.Status == SkillStatus.Specialized) { foreach (var item in skillGear.Gear) { if (grantedItems.Contains(item.WeenieId)) { var existingItem = character.Inventory.Values.FirstOrDefault(i => i.WeenieClassId == item.WeenieId); if ((existingItem?.MaxStackSize ?? 1) <= 1) { continue; } existingItem.StackSize += item.StackSize; continue; } var loot = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(item.WeenieId).Clone(GuidManager.NewItemGuid().Full); loot.Placement = 0; loot.ContainerIID = id; loot.StackSize = item.StackSize > 1 ? (ushort?)item.StackSize : null; character.Inventory.Add(new ObjectGuid(loot.AceObjectId), loot); grantedItems.Add(item.WeenieId); } var heritageLoot = skillGear.Heritage.FirstOrDefault(sh => sh.HeritageId == character.Heritage); if (heritageLoot != null) { foreach (var item in heritageLoot.Gear) { if (grantedItems.Contains(item.WeenieId)) { var existingItem = character.Inventory.Values.FirstOrDefault(i => i.WeenieClassId == item.WeenieId); if ((existingItem?.MaxStackSize ?? 1) <= 1) { continue; } existingItem.StackSize += item.StackSize; continue; } var loot = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(item.WeenieId).Clone(GuidManager.NewItemGuid().Full); loot.Placement = 0; loot.ContainerIID = id; loot.StackSize = item.StackSize > 1 ? (ushort?)item.StackSize : null; character.Inventory.Add(new ObjectGuid(loot.AceObjectId), loot); grantedItems.Add(item.WeenieId); } } foreach (var spell in skillGear.Spells) { character.SpellIdProperties.Add(new AceObjectPropertiesSpell() { AceObjectId = id, SpellId = spell.SpellId }); } } } character.Name = reader.ReadString16L(); character.DisplayName = character.Name; // unsure // currently not used uint startArea = reader.ReadUInt32(); character.IsAdmin = Convert.ToBoolean(reader.ReadUInt32()); character.IsEnvoy = Convert.ToBoolean(reader.ReadUInt32()); DatabaseManager.Shard.IsCharacterNameAvailable(character.Name, ((bool isAvailable) => { if (!isAvailable) { SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.NameInUse); return; } character.AccountId = session.Id; CharacterCreateSetDefaultCharacterOptions(character); CharacterCreateSetDefaultCharacterPositions(character); // We must await here -- DatabaseManager.Shard.SaveObject(character, ((bool saveSuccess) => { if (!saveSuccess) { SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.DatabaseDown); return; } // DatabaseManager.Shard.SaveCharacterOptions(character); // DatabaseManager.Shard.InitCharacterPositions(character); var guid = new ObjectGuid(character.AceObjectId); session.AccountCharacters.Add(new CachedCharacter(guid, (byte)session.AccountCharacters.Count, character.Name, 0)); SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.Ok, guid, character.Name); })); })); }
private static void CreateIOU(AceCharacter character, uint missingWeenieId) { var iouObj = (AceObject)DatabaseManager.World.GetAceObjectByWeenie("parchment").Clone(GuidManager.NewItemGuid().Full); iouObj.Name = "IOU"; iouObj.EncumbranceVal = 0; iouObj.Value = 0; iouObj.ShortDesc = "An IOU for a missing database object."; iouObj.Inscription = "Sorry about that chief..."; iouObj.ScribeName = "Ripley"; iouObj.ScribeAccount = "prewritten"; iouObj.IgnoreAuthor = false; iouObj.AppraisalPages = 1; iouObj.AppraisalMaxPages = 1; iouObj.ContainerIID = character.AceObjectId; // FIXME: This is wrong and should also be unnecessary but we're not handling storing and reading back object placement within a container correctly so this is here to make it work. // TODO: fix placement (order or slot) issues within containers. iouObj.Placement = 0; var bookProperties = new AceObjectPropertiesBook(); bookProperties.AceObjectId = iouObj.AceObjectId; bookProperties.AuthorName = "Ripley"; bookProperties.AuthorAccount = "prewritten"; bookProperties.Page = 0; bookProperties.PageText = $"{missingWeenieId}\n\nSorry but the database does not have a weenie for weenieClassId #{missingWeenieId} so in lieu of that here is an IOU for that item."; iouObj.BookProperties.Add(bookProperties.Page, bookProperties); if (iouObj != null) { character.Inventory.Add(new ObjectGuid(iouObj.AceObjectId), iouObj); } }
private static AceObject GetClothingObject(uint playerIID, uint weenieClassId, uint palette, double shade) { AceObject clothingObj; try { clothingObj = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(weenieClassId).Clone(GuidManager.NewItemGuid().Full); } catch (NullReferenceException) { return(null); } clothingObj.IconDID = DatManager.PortalDat.ReadFromDat <ClothingTable>(clothingObj.ClothingBaseDID.Value).GetIcon(palette); clothingObj.PaletteBaseDID = palette; clothingObj.Shade = shade; clothingObj.CurrentWieldedLocation = clothingObj.ValidLocations; clothingObj.WielderIID = playerIID; //if (shirtCT.ClothingBaseEffects.ContainsKey(sex.SetupID)) //{ // ClothingBaseEffect shirtCBE = shirtCT.ClothingBaseEffects[sex.SetupID]; // for (int i = 0; i < shirtCBE.CloObjectEffects.Count; i++) // { // byte partNum = (byte)shirtCBE.CloObjectEffects[i].Index; // shirt.AnimationOverrides.Add(new AnimationOverride() // { // AceObjectId = shirt.AceObjectId, // AnimationId = shirtCBE.CloObjectEffects[i].ModelId, // Index = (byte)shirtCBE.CloObjectEffects[i].Index // }); // for (int j = 0; j < shirtCBE.CloObjectEffects[i].CloTextureEffects.Count; j++) // { // shirt.TextureOverrides.Add(new TextureMapOverride() // { // AceObjectId = shirt.AceObjectId, // Index = (byte)shirtCBE.CloObjectEffects[i].Index, // OldId = (ushort)shirtCBE.CloObjectEffects[i].CloTextureEffects[j].OldTexture, // NewId = (ushort)shirtCBE.CloObjectEffects[i].CloTextureEffects[j].NewTexture // }); // } // } // // Apply the proper palette(s). Unlike character skin/hair, clothes can have several palette ranges! // if (shirtCT.ClothingSubPalEffects.ContainsKey(appearance.ShirtColor)) // { // CloSubPalEffect shirtSubPal = shirtCT.ClothingSubPalEffects[appearance.ShirtColor]; // for (int i = 0; i < shirtSubPal.CloSubPalettes.Count; i++) // { // PaletteSet shirtPalSet = PaletteSet.ReadFromDat(shirtSubPal.CloSubPalettes[i].PaletteSet); // ushort shirtPal = (ushort)shirtPalSet.GetPaletteID(appearance.ShirtHue); // if (shirtPal > 0) // shirtPal will be 0 if the palette set is empty/not found // { // for (int j = 0; j < shirtSubPal.CloSubPalettes[i].Ranges.Count; j++) // { // uint palOffset = shirtSubPal.CloSubPalettes[i].Ranges[j].Offset / 8; // uint numColors = shirtSubPal.CloSubPalettes[i].Ranges[j].NumColors / 8; // shirt.PaletteOverrides.Add(new PaletteOverride() // { // AceObjectId = shirt.AceObjectId, // SubPaletteId = shirtPal, // Offset = (ushort)palOffset, // Length = (ushort)numColors // }); // } // } // } // } //} return(clothingObj); }
private static void CharacterCreateEx(ClientMessage message, Session session, uint id) { var cg = DatManager.PortalDat.CharGen; var reader = message.Payload; AceCharacter character = new AceCharacter(id); reader.Skip(4); /* Unknown constant (1) */ character.Heritage = (int)reader.ReadUInt32(); // Disable OlthoiPlay characters for now. They're not implemented yet. // FIXME: Restore OlthoiPlay characters when properly handled. if (character.Heritage == (int)HeritageGroup.Olthoi || character.Heritage == (int)HeritageGroup.OlthoiAcid) { SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.Pending); return; } character.HeritageGroup = cg.HeritageGroups[(uint)character.Heritage].Name; character.Gender = (int)reader.ReadUInt32(); if (character.Gender == 1) { character.Sex = "Male"; } else { character.Sex = "Female"; } Appearance appearance = Appearance.FromNetwork(reader); // character.IconId = cg.HeritageGroups[(int)character.Heritage].IconImage; // pull character data from the dat file SexCG sex = cg.HeritageGroups[(uint)character.Heritage].Genders[(int)character.Gender]; character.MotionTableId = sex.MotionTable; character.SoundTableId = sex.SoundTable; character.PhysicsTableId = sex.PhysicsTable; character.SetupTableId = sex.SetupID; character.PaletteId = sex.BasePalette; character.CombatTableId = sex.CombatTable; // Check the character scale if (sex.Scale != 100u) { character.DefaultScale = (sex.Scale / 100f); // Scale is stored as a percentage } // Get the hair first, because we need to know if you're bald, and that's the name of that tune! HairStyleCG hairstyle = sex.HairStyleList[Convert.ToInt32(appearance.HairStyle)]; bool isBald = hairstyle.Bald; // Certain races (Undead, Tumeroks, Others?) have multiple body styles available. This is controlled via the "hair style". if (hairstyle.AlternateSetup > 0) { character.SetupTableId = hairstyle.AlternateSetup; } character.EyesTexture = sex.GetEyeTexture(appearance.Eyes, isBald); character.DefaultEyesTexture = sex.GetDefaultEyeTexture(appearance.Eyes, isBald); character.NoseTexture = sex.GetNoseTexture(appearance.Nose); character.DefaultNoseTexture = sex.GetDefaultNoseTexture(appearance.Nose); character.MouthTexture = sex.GetMouthTexture(appearance.Mouth); character.DefaultMouthTexture = sex.GetDefaultMouthTexture(appearance.Mouth); character.HairTexture = sex.GetHairTexture(appearance.HairStyle); character.DefaultHairTexture = sex.GetDefaultHairTexture(appearance.HairStyle); character.HeadObject = sex.GetHeadObject(appearance.HairStyle); // Skin is stored as PaletteSet (list of Palettes), so we need to read in the set to get the specific palette var skinPalSet = DatManager.PortalDat.ReadFromDat <PaletteSet>(sex.SkinPalSet); character.SkinPalette = skinPalSet.GetPaletteID(appearance.SkinHue); character.Shade = appearance.SkinHue; // Hair is stored as PaletteSet (list of Palettes), so we need to read in the set to get the specific palette var hairPalSet = DatManager.PortalDat.ReadFromDat <PaletteSet>(sex.HairColorList[Convert.ToInt32(appearance.HairColor)]); character.HairPalette = hairPalSet.GetPaletteID(appearance.HairHue); // Eye Color character.EyesPalette = sex.EyeColorList[Convert.ToInt32(appearance.EyeColor)]; if (appearance.HeadgearStyle < 0xFFFFFFFF) // No headgear is max UINT { var hat = GetClothingObject(id, sex.GetHeadgearWeenie(appearance.HeadgearStyle), appearance.HeadgearColor, appearance.HeadgearHue); if (hat != null) { character.WieldedItems.Add(new ObjectGuid(hat.AceObjectId), hat); } else { CreateIOU(character, sex.GetHeadgearWeenie(appearance.HeadgearStyle)); } } var shirt = GetClothingObject(id, sex.GetShirtWeenie(appearance.ShirtStyle), appearance.ShirtColor, appearance.ShirtHue); if (shirt != null) { character.WieldedItems.Add(new ObjectGuid(shirt.AceObjectId), shirt); } else { CreateIOU(character, sex.GetShirtWeenie(appearance.ShirtStyle)); } var pants = GetClothingObject(id, sex.GetPantsWeenie(appearance.PantsStyle), appearance.PantsColor, appearance.PantsHue); if (pants != null) { character.WieldedItems.Add(new ObjectGuid(pants.AceObjectId), pants); } else { CreateIOU(character, sex.GetPantsWeenie(appearance.PantsStyle)); } var shoes = GetClothingObject(id, sex.GetFootwearWeenie(appearance.FootwearStyle), appearance.FootwearColor, appearance.FootwearHue); if (shoes != null) { character.WieldedItems.Add(new ObjectGuid(shoes.AceObjectId), shoes); } else { CreateIOU(character, sex.GetFootwearWeenie(appearance.FootwearStyle)); } // Profession (Adventurer, Bow Hunter, etc) // TODO - Add this title to the available titles for this character. var templateOption = reader.ReadInt32(); string templateName = cg.HeritageGroups[(uint)character.Heritage].Templates[templateOption].Name; character.Title = templateName; character.Template = templateName; character.CharacterTitleId = (int)cg.HeritageGroups[(uint)character.Heritage].Templates[templateOption].Title; character.NumCharacterTitles = 1; // stats uint totalAttributeCredits = cg.HeritageGroups[(uint)character.Heritage].AttributeCredits; uint usedAttributeCredits = 0; // Validate this is equal to actual attribute credits (330 for all but "Olthoi", which have 60 character.StrengthAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.StrengthAbility.Base; character.EnduranceAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.EnduranceAbility.Base; character.CoordinationAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.CoordinationAbility.Base; character.QuicknessAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.QuicknessAbility.Base; character.FocusAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.FocusAbility.Base; character.SelfAbility.Base = ValidateAttributeCredits(reader.ReadUInt32(), usedAttributeCredits, totalAttributeCredits); usedAttributeCredits += character.SelfAbility.Base; // data we don't care about uint characterSlot = reader.ReadUInt32(); uint classId = reader.ReadUInt32(); // characters start with max vitals character.Health.Current = character.Health.MaxValue; character.Stamina.Current = character.Stamina.MaxValue; character.Mana.Current = character.Mana.MaxValue; // set initial skill credit amount. 52 for all but "Olthoi", which have 68 character.AvailableSkillCredits = (int)cg.HeritageGroups[(uint)character.Heritage].SkillCredits; uint numOfSkills = reader.ReadUInt32(); for (uint i = 0; i < numOfSkills; i++) { var skill = (Skill)i; var skillCost = skill.GetCost(); var skillStatus = (SkillStatus)reader.ReadUInt32(); if (skillStatus == SkillStatus.Specialized) { character.TrainSkill(skill, skillCost.TrainingCost); character.SpecializeSkill(skill, skillCost.SpecializationCost); // oddly enough, specialized skills don't get any free ranks like trained do } if (skillStatus == SkillStatus.Trained) { character.TrainSkill(skill, skillCost.TrainingCost); character.AceObjectPropertiesSkills[skill].Ranks = 5; character.AceObjectPropertiesSkills[skill].ExperienceSpent = 526; } if (skillCost != null && skillStatus == SkillStatus.Untrained) { character.UntrainSkill(skill, skillCost.TrainingCost); } } // grant starter items based on skills var starterGearConfig = StarterGearFactory.GetStarterGearConfiguration(); List <uint> grantedItems = new List <uint>(); foreach (var skillGear in starterGearConfig.Skills) { var charSkill = character.AceObjectPropertiesSkills[(Skill)skillGear.SkillId]; if (charSkill.Status == SkillStatus.Trained || charSkill.Status == SkillStatus.Specialized) { foreach (var item in skillGear.Gear) { if (grantedItems.Contains(item.WeenieId)) { var existingItem = character.Inventory.Values.FirstOrDefault(i => i.WeenieClassId == item.WeenieId); if ((existingItem?.MaxStackSize ?? 1) <= 1) { continue; } existingItem.StackSize += item.StackSize; continue; } var loot = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(item.WeenieId).Clone(GuidManager.NewItemGuid().Full); loot.Placement = 0; loot.ContainerIID = id; loot.StackSize = item.StackSize > 1 ? (ushort?)item.StackSize : null; character.Inventory.Add(new ObjectGuid(loot.AceObjectId), loot); grantedItems.Add(item.WeenieId); } var heritageLoot = skillGear.Heritage.FirstOrDefault(sh => sh.HeritageId == character.Heritage); if (heritageLoot != null) { foreach (var item in heritageLoot.Gear) { if (grantedItems.Contains(item.WeenieId)) { var existingItem = character.Inventory.Values.FirstOrDefault(i => i.WeenieClassId == item.WeenieId); if ((existingItem?.MaxStackSize ?? 1) <= 1) { continue; } existingItem.StackSize += item.StackSize; continue; } var loot = (AceObject)DatabaseManager.World.GetAceObjectByWeenie(item.WeenieId).Clone(GuidManager.NewItemGuid().Full); loot.Placement = 0; loot.ContainerIID = id; loot.StackSize = item.StackSize > 1 ? (ushort?)item.StackSize : null; character.Inventory.Add(new ObjectGuid(loot.AceObjectId), loot); grantedItems.Add(item.WeenieId); } } foreach (var spell in skillGear.Spells) { // Olthoi Spitter is a special case if (character.Heritage == (int)HeritageGroup.OlthoiAcid) { character.SpellIdProperties.Add(new AceObjectPropertiesSpell() { AceObjectId = id, SpellId = spell.SpellId }); // Continue to next spell as Olthoi spells do not have the SpecializedOnly field continue; } if (charSkill.Status == SkillStatus.Trained && spell.SpecializedOnly == false) { character.SpellIdProperties.Add(new AceObjectPropertiesSpell() { AceObjectId = id, SpellId = spell.SpellId }); } else if (charSkill.Status == SkillStatus.Specialized) { character.SpellIdProperties.Add(new AceObjectPropertiesSpell() { AceObjectId = id, SpellId = spell.SpellId }); } } } } character.Name = reader.ReadString16L(); character.DisplayName = character.Name; // unsure // Index used to determine the starting location uint startArea = reader.ReadUInt32(); character.IsAdmin = Convert.ToBoolean(reader.ReadUInt32()); character.IsEnvoy = Convert.ToBoolean(reader.ReadUInt32()); DatabaseManager.Shard.IsCharacterNameAvailable(character.Name, ((bool isAvailable) => { if (!isAvailable) { SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.NameInUse); return; } character.AccountId = session.Id; CharacterCreateSetDefaultCharacterOptions(character); CharacterCreateSetDefaultCharacterPositions(character, startArea); // We must await here -- DatabaseManager.Shard.SaveObject(character, ((bool saveSuccess) => { if (!saveSuccess) { SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.DatabaseDown); return; } // DatabaseManager.Shard.SaveCharacterOptions(character); // DatabaseManager.Shard.InitCharacterPositions(character); var guid = new ObjectGuid(character.AceObjectId); session.AccountCharacters.Add(new CachedCharacter(guid, (byte)session.AccountCharacters.Count, character.Name, 0)); SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.Ok, guid, character.Name); })); })); }
public static WorldObject CreateNewWorldObject(uint weenieId) { WorldObject wo = CreateWorldObject(weenieId, GuidManager.NewItemGuid()); return(wo); }
/// <summary> /// Create WorldObjects by ObjectType from a generator. /// </summary> /// <param name="generatorObject"></param> /// <returns>List of created WorldObjects</returns> public static List <WorldObject> CreateWorldObjectsFromGenerator(AceObject generator) { List <WorldObject> results = new List <WorldObject>(); DerethDateTime currentTime = new DerethDateTime(WorldManager.PortalYearTicks); Position pos = null; Random random = new Random((int)DateTime.UtcNow.Ticks); // Check if the current generator is meant to spawn objects at this time of the day switch (generator.GeneratorTimeType) { case (int)GeneratorTimeType.Day: if (currentTime.IsNight) { return(null); } break; case (int)GeneratorTimeType.Night: if (currentTime.IsDaytime) { return(null); } break; } // Check the probability of this generator spawning something at all if (random.Next(1, 100) >= generator.GeneratorProbability) { return(null); } // Generate objects from this generator #MaxGeneratedObjects times for (int i = 0; i < generator.MaxGeneratedObjects; i++) { switch (generator.GeneratorType) { // Use the position of the generator as a static position case (int)GeneratorType.Absolute: pos = generator.Location.InFrontOf(2.0); pos.PositionZ = pos.PositionZ - 0.5f; break; // Generate a random position inside the landblock case (int)GeneratorType.Relative: pos = GetRandomLocInLandblock(random, generator.Location.Cell); break; } // If this generator has linked generators use those for spawning objects if (generator.ActivationCreateClass == 0) { // Spawn this generator if it's not the top-level generator if (generator.GeneratorIID != null) { results.Add(new Generator(GuidManager.NewGeneratorGuid(), generator)); generator.GeneratorEnteredWorld = true; } // Get a random generator from the weighted list of linked generators and read it's AceObject from the DB if (generator.GeneratorLinks.Count == 0) { return(null); } uint linkId = GetRandomGeneratorIdFromGeneratorList(random, generator.GeneratorLinks); AceObject newGen = DatabaseManager.World.GetAceObjectByWeenie(linkId); // The linked generator is at the same location as the top generator and references its parent newGen.Location = pos; newGen.GeneratorIID = generator.AceObjectId; newGen.GeneratorEnteredWorld = true; // Recursively call this method again with the just read generatorObject List <WorldObject> objectList = CreateWorldObjectsFromGenerator(newGen); objectList?.ForEach(o => results.Add(o)); } // else spawn the objects directly from this generator else { WorldObject wo = WorldObjectFactory.CreateWorldObject((uint)generator.ActivationCreateClass); if (wo != null) { wo.Location = pos; if (wo.WeenieType == WeenieType.Creature || wo.WeenieType == WeenieType.Cow) { wo.Guid = GuidManager.NewNonStaticGuid(); } else { wo.Guid = GuidManager.NewItemGuid(); } wo.GeneratorId = generator.AceObjectId; results.Add(wo); } } } return(results); }
public static WorldObject CreateNewWorldObject(uint weenieClassId, int palette = 0, float shade = 0, int stackSize = 1) { WorldObject wo = CreateWorldObject(weenieClassId, GuidManager.NewItemGuid(), palette, shade, stackSize); return(wo); }