int CustomizeIcon(int startIndex, int length, byte dataKey, dynamic npc, dynamic appearence) { if (dataKey == 0) { return(0); // Custom or not specified. } for (var i = 1; i < length; i++) { var row = _sCharaMakeCustomize[startIndex + i]; if ((byte)row[0] == dataKey) { var icon = (ImageFile)row["Icon"]; var hintitem = row["HintItem"] as Saint.Item; if (hintitem != null && hintitem.Key != 0) { appearence.hairstyleItem = hintitem.Key; _builder.Db.AddReference(npc, "item", hintitem.Key, false); } return(IconDatabase.EnsureEntry("customize", icon)); } } //System.Diagnostics.Debug.WriteLine("{0} has custom hair {1}", (string)npc.name, hairstyle); return(0); // Not found - custom. }
void ImportQuestEventIcon(dynamic quest, Saint.Quest sQuest) { var sEventIconType = (Saint.IXivRow)sQuest["EventIconType"]; var baseIconIndex = (int)(UInt32)sEventIconType.GetRaw(0); // Mark function quests if (baseIconIndex == 071340) { quest.unlocksFunction = 1; } // Calculate the event icon to record. var questIconIndex = 0; if (sEventIconType.Key == 4) { questIconIndex = baseIconIndex; } else if (sQuest.IsRepeatable) { questIconIndex = baseIconIndex + 2; } else { questIconIndex = baseIconIndex + 1; } var eventIcon = SaintCoinach.Imaging.IconHelper.GetIcon(sQuest.Sheet.Collection.PackCollection, questIconIndex); quest.eventIcon = IconDatabase.EnsureEntry("event", eventIcon); }
public override void Start() { foreach (var sItem in _builder.ItemsToImport) { var sCustomizeUnlock = sItem.ItemAction as SaintCoinach.Xiv.ItemActions.CustomizeUnlock; if (sCustomizeUnlock == null) { continue; } var sCharaMakeCustomizes = sCustomizeUnlock.CustomizeRows.Where(r => (byte)r[0] != 0).ToArray(); if (sCharaMakeCustomizes.Length == 0) { continue; } var item = _builder.Db.ItemsById[sItem.Key]; item.customize = new JArray(); foreach (var sCharaMakeCustomize in sCharaMakeCustomizes) { var icon = (ImageFile)sCharaMakeCustomize["Icon"]; var id = IconDatabase.EnsureEntry("customize", icon); item.customize.Add(id); } } }
void BuildCraftingActions() { foreach (var sCraftAction in _builder.Sheet <Saint.CraftAction>()) { if (sCraftAction.Name.ToString() == "") { continue; } if (sCraftAction.ClassJob == null) { continue; // HWFIXME: This is for all DoH } dynamic action = new JObject(); action.id = sCraftAction.Key; _builder.Localize.HtmlStrings((JObject)action, sCraftAction, "Name", "Description"); action.category = 7; // DoH ability action.icon = IconDatabase.EnsureEntry("action", sCraftAction.Icon); action.job = sCraftAction.ClassJob.Key; action.affinity = sCraftAction.ClassJobCategory.Key; action.lvl = sCraftAction.ClassJobLevel; if (sCraftAction.Cost > 0) { action.resource = "CP"; action.cost = sCraftAction.Cost; } _builder.Db.Actions.Add(action); } }
void BeastTribe() { foreach (var sBeastTribe in _builder.Sheet <Saint.BeastTribe>().Skip(1)) { IconDatabase.EnsureEntry("beast", sBeastTribe.Icon, sBeastTribe.Key); } }
dynamic BuildStatus(Saint.Status sStatus) { dynamic status = new JObject(); status.id = sStatus.Key; _builder.Localize.Strings((JObject)status, sStatus, "Name"); _builder.Localize.HtmlStrings((JObject)status, sStatus, "Description"); status.patch = PatchDatabase.Get("status", sStatus.Key); status.category = sStatus.Category; status.canDispel = sStatus.CanDispel; // If the status doesn't have an icon, we probably don't want it in our data if (sStatus.Icon != null && !sStatus.Icon.Path.EndsWith("000000.tex")) { status.icon = IconDatabase.EnsureEntry("status", sStatus.Icon); } else { return(null); } _builder.Db.Statuses.Add(status); _builder.Db.StatusesById[sStatus.Key] = status; return(status); }
int GetFishIcon(UInt16 itemIconIndex) { // Replace 02 icon id with 07, eg. 029046 -> 079046 for fish rubbing image var fishIconIndex = itemIconIndex - 20000 + 70000; var icon = IconHelper.GetIcon(_builder.Realm.Packs, fishIconIndex); return(IconDatabase.EnsureEntry("fish", icon)); }
dynamic GetStatus(Saint.Status sStatus) { dynamic status = new JObject(); status.id = sStatus.Key; status.name = sStatus.Name.ToString(); status.desc = sStatus.Description.ToString(); status.icon = IconDatabase.EnsureEntry("status", sStatus.Icon); return(status); }
public override void Start() { foreach (var sItem in _builder.Sheet <Item>()) { var unlock = sItem.ItemAction as MountUnlock; if (unlock == null) { continue; } var sMount = unlock.Mount; if (string.IsNullOrEmpty(sMount.Singular.ToString())) { continue; } var sMountTransient = _builder.Sheet("MountTransient")[sMount.Key]; var item = _builder.Db.ItemsById[sItem.Key]; item.mount = new JObject(); item.mount.name = Utils.CapitalizeWords(sMount.Singular.ToString()); item.mount.action = sMountTransient[0].ToString(); item.mount.description = sMountTransient[1].ToString(); item.mount.tooltip = HtmlStringFormatter.Convert((XivString)sMountTransient[2]); // Icons var iconIndex = (UInt16)sMount.SourceRow.GetRaw("Icon"); var icon = IconHelper.GetIcon(_builder.Realm.Packs, iconIndex); item.mount.icon = IconDatabase.EnsureEntry("mount", icon); int guideIconIndex = 0; if (iconIndex < 8000) { guideIconIndex = iconIndex - 4000 + 68000; } else if (iconIndex >= 8000) // For 4.1 SB mounts. { guideIconIndex = iconIndex - 8000 + 77000; } var guideIcon = IconHelper.GetIcon(_builder.Realm.Packs, guideIconIndex); if (guideIcon == null) { DatabaseBuilder.PrintLine($"Mount {item.mount.name} #{sItem.Key} has invalid guide icon, skipping."); } else { item.mount.guideIcon = IconDatabase.EnsureEntry("mount", guideIcon); } item.models = new JArray(Utils.ModelCharaKey(sMount.ModelChara)); } }
private void ExtractIcons(List <Saint.Item> items) { foreach (var item in items) { if (_config.Extract40x) { IconDatabase.EnsureEntry("item\\40x", item.Icon); } if (_config.Extract80x) { IconDatabase.EnsureEntryHQ("item\\t", item.Icon, _realm); } } }
void ImportQuestEventIcon(dynamic quest, Saint.Quest sQuest) { var sEventIconType = (Saint.IXivRow)sQuest["EventIconType"]; if (sEventIconType == null) { byte index = (byte)sQuest.GetRaw("EventIconType"); if (index > 32) { index -= 32; sEventIconType = _builder.Sheet("EventIconType").ElementAt(index); } else { throw new NotImplementedException(); } } var baseIconIndex = (int)(UInt32)sEventIconType.GetRaw(0); // Mark function quests if (baseIconIndex == 071340) { quest.unlocksFunction = 1; } // Calculate the event icon to record. var questIconIndex = 0; if (sEventIconType.Key == 4) { questIconIndex = baseIconIndex; } else if (sQuest.IsRepeatable) { questIconIndex = baseIconIndex + 2; } else { questIconIndex = baseIconIndex + 1; } var eventIcon = SaintCoinach.Imaging.IconHelper.GetIcon(sQuest.Sheet.Collection.PackCollection, questIconIndex); quest.eventIcon = IconDatabase.EnsureEntry("event", eventIcon); }
void BuildJournalGenres() { foreach (var sJournalGenre in _builder.Sheet <Saint.JournalGenre>()) { dynamic genre = new JObject(); genre.id = sJournalGenre.Key; genre.name = sJournalGenre.Name.ToString(); if (sJournalGenre.Icon != null) { genre.icon = IconDatabase.EnsureEntry("journal", sJournalGenre.Icon); } genre.category = sJournalGenre.JournalCategory.Name.ToString(); genre.section = sJournalGenre.JournalCategory?.JournalSection?.Name?.ToString() ?? "Other Quests"; _builder.Db.QuestJournalGenres.Add(genre); } }
int CustomizeIcon(int startIndex, int length, byte dataKey, dynamic npc) { if (dataKey == 0) { return(0); // Custom or not specified. } for (var i = 1; i < length; i++) { var row = _customize[startIndex + i]; if ((byte)row[0] == dataKey) { var icon = (ImageFile)row["Icon"]; return(IconDatabase.EnsureEntry("customize", icon)); } } //System.Diagnostics.Debug.WriteLine("{0} has custom hair {1}", (string)npc.name, hairstyle); return(0); // Not found - custom. }
public override void Start() { BuildDutyRoulette(); var skippedInstances = new[] { 0, 20015, 20016, 50002, 65000, 30048 }; // Index conditions. Some PvP instances have multiple conditions, but it doesn't matter. foreach (var sContentFinderCondition in _builder.Sheet <Saint.ContentFinderCondition>()) { if (sContentFinderCondition.Key == 0) { continue; } if (sContentFinderCondition.Content is Saint.InstanceContent sInstanceContent) { _builder.ContentFinderConditionByInstanceContent[sInstanceContent] = sContentFinderCondition; } } // todo: add new player bonus currency // todo: add weekly restriction stuff? foreach (var sInstanceContent in _builder.Sheet <Saint.InstanceContent>()) { if (skippedInstances.Contains(sInstanceContent.Key)) { continue; // Skip test and fan fest instances. } // Find entry conditions. if (!_builder.ContentFinderConditionByInstanceContent.TryGetValue(sInstanceContent, out var sContentFinderCondition)) { continue; // Skip unreleased content. } // Skip some instances. switch (sContentFinderCondition.ContentType.Key) { case 3: // Guildhests case 7: // Quest Battles case 8: // FATEs case 20: // Novice Hall continue; } var name = sInstanceContent.Name.ToString(); if (name == "") { continue; } var sContentFinderConditionTransient = _builder.Sheet("ContentFinderConditionTransient")[sContentFinderCondition.Key]; dynamic instance = new JObject(); instance.id = sInstanceContent.Key; _builder.Localize.Strings((JObject)instance, sInstanceContent, Utils.SanitizeInstanceName, "Name"); instance.patch = PatchDatabase.Get("instance", sInstanceContent.Key); instance.categoryIcon = IconDatabase.EnsureEntry("instance/type", sContentFinderCondition.ContentType.Icon); _builder.Localize.Column((JObject)instance, sContentFinderCondition.ContentType, "Name", "category", x => string.IsNullOrEmpty(x) ? Hacks.GetContentTypeNameOverride(sContentFinderCondition.ContentType) : x); _builder.Localize.Strings((JObject)instance, sContentFinderConditionTransient, "Description"); instance.time = (int)sInstanceContent.TimeLimit.TotalMinutes; instance.min_lvl = sContentFinderCondition.RequiredClassJobLevel; Hacks.SetInstanceIcon(sContentFinderCondition, instance); if (sContentFinderCondition.ContentMemberType.HealersPerParty > 0) { instance.healer = sContentFinderCondition.ContentMemberType.HealersPerParty; } if (sContentFinderCondition.ContentMemberType.TanksPerParty > 0) { instance.tank = sContentFinderCondition.ContentMemberType.TanksPerParty; } if (sContentFinderCondition.ContentMemberType.RangedPerParty > 0) { instance.ranged = sContentFinderCondition.ContentMemberType.RangedPerParty; } if (sContentFinderCondition.ContentMemberType.MeleesPerParty > 0) { instance.melee = sContentFinderCondition.ContentMemberType.MeleesPerParty; } // fixme: find where this went. //if (conditions.ContentRoulette.Key > 0) // instance.roulette = conditions.ContentRoulette.Key; if (sContentFinderCondition.ClassJobLevelSync > 0) { instance.max_lvl = sContentFinderCondition.ClassJobLevelSync; } if (sContentFinderCondition.RequiredItemLevel > 0) { instance.min_ilvl = sContentFinderCondition.RequiredItemLevel; } if (sContentFinderCondition.ItemLevelSync > 0) { instance.max_ilvl = sContentFinderCondition.ItemLevelSync; } var treasureSet = new HashSet <int>(); var currency = new Dictionary <string, int>(); // Bosses var sFights = new List <Saint.InstanceContentData.Fight>(); if (sInstanceContent.Data.Boss != null) { sFights.Add(sInstanceContent.Data.Boss); } if (sInstanceContent.Data.MidBosses != null) { sFights.AddRange(sInstanceContent.Data.MidBosses); } var fights = new JArray(); foreach (var sFight in sFights) { var bossCurrency = new Dictionary <string, int>(); if (sFight.CurrencyA > 0) { currency["ClearA"] = currency.ContainsKey("ClearA") ? currency["ClearA"] + sFight.CurrencyA : sFight.CurrencyA; bossCurrency["ClearA"] = sFight.CurrencyA; } if (sFight.CurrencyB > 0) { currency["ClearB"] = currency.ContainsKey("ClearB") ? currency["ClearB"] + sFight.CurrencyB : sFight.CurrencyB; bossCurrency["ClearB"] = sFight.CurrencyB; } if (sFight.CurrencyC > 0) { currency["ClearC"] = currency.ContainsKey("ClearC") ? currency["ClearC"] + sFight.CurrencyC : sFight.CurrencyC; bossCurrency["ClearC"] = sFight.CurrencyC; } if (sFight.PrimaryBNpcs.Count() == 0 && sFight.Treasures.Count() == 0) { continue; } dynamic fight = new JObject(); fights.Add(fight); if (bossCurrency.Count > 0) { fight.currency = CreateCurrencyArray(bossCurrency); } fight.type = (sFight == sInstanceContent.Data.Boss) ? "Boss" : "MidBoss"; var fightCoffer = CreateTreasureCoffer(instance, sFight.Treasures, sInstanceContent, treasureSet); if (fightCoffer != null) { fight.coffer = fightCoffer; } var mobs = new JArray(); fight.mobs = mobs; foreach (var sBoss in sFight.PrimaryBNpcs) { _builder.InstanceIdsByMobId[sBoss.Key] = sInstanceContent.Key; if (!mobs.Any(b => ((long)b) == sBoss.Key)) { _builder.Db.AddReference(instance, "mob", sBoss.Key.ToString(), false); mobs.Add(sBoss.Key); } if (!_builder.ItemDropsByMobId.TryGetValue(sBoss.Key, out var itemIds)) { itemIds = new List <int>(); _builder.ItemDropsByMobId[sBoss.Key] = itemIds; } foreach (var sTreasureItem in sFight.Treasures.SelectMany(t => t.Items)) { if (!itemIds.Contains(sTreasureItem.Key)) { itemIds.Add(sTreasureItem.Key); } var item = _builder.Db.ItemsById[sTreasureItem.Key]; if (item.drops == null) { item.drops = new JArray(); } JArray drops = item.drops; if (!drops.Any(t => ((long)t) == sBoss.Key)) { drops.Add(sBoss.Key); _builder.Db.AddReference(instance, "item", sTreasureItem.Key, false); _builder.Db.AddReference(item, "instance", sInstanceContent.Key, true); } } if (sFight.CurrencyA > 0) { _builder.AddBossCurrency(sFight.CurrencyA, _builder.TomestoneIds[0], sBoss.Key); } if (sFight.CurrencyB > 0) { _builder.AddBossCurrency(sFight.CurrencyB, _builder.TomestoneIds[1], sBoss.Key); } if (sFight.CurrencyC > 0) { _builder.AddBossCurrency(sFight.CurrencyC, _builder.TomestoneIds[2], sBoss.Key); } } } if (fights.Count > 0) { instance.fights = fights; } // Treasures var coffers = new JArray(); if (sInstanceContent.Data.MapTreasures != null) { foreach (var sTreasure in sInstanceContent.Data.MapTreasures) { var coffer = CreateTreasureCoffer(instance, new Saint.InstanceContentData.Treasure[] { sTreasure }, sInstanceContent, treasureSet); if (coffer != null) { coffers.Add(coffer); } } if (coffers.Count > 0) { instance.coffers = coffers; } } // Some items are not referenced by the instance, but by the item itself. // This snags them. if (_builder.Db.ItemsByInstanceId.TryGetValue(sInstanceContent.Key, out var instanceItems)) { var otherItemRewards = new JArray(); foreach (var item in instanceItems) { int itemId = item.id; if (!treasureSet.Contains(itemId)) { otherItemRewards.Add(itemId); _builder.Db.AddReference(instance, "item", itemId, false); } } if (otherItemRewards.Count > 0) { instance.rewards = otherItemRewards; } } // Currency var currencyArray = CreateCurrencyArray(currency); if (currencyArray.Count > 0) { instance.currency = currencyArray; } _builder.Db.Instances.Add(instance); _builder.Db.InstancesById[sInstanceContent.Key] = instance; } }
void BuildTraits() { dynamic traitCategory = new JObject(); traitCategory.id = -1; traitCategory.name = "Trait"; _builder.Db.ActionCategories.Add(traitCategory); foreach (var sTrait in _builder.Sheet <Saint.Trait>()) { if (sTrait.ClassJob.Key == 0) { continue; // Skip adventurer traits atm. } var sTraitTransient = _builder.Sheet("TraitTransient")[sTrait.Key]; dynamic trait = new JObject(); trait.id = sTrait.Key + 50000; // Arbitrary! _builder.Localize.Strings((JObject)trait, sTrait, "Name"); _builder.Localize.HtmlStrings((JObject)trait, sTraitTransient, "Description"); trait.category = (int)traitCategory.id; trait.icon = IconDatabase.EnsureEntry("action", sTrait.Icon); trait.job = sTrait.ClassJob.Key; trait.affinity = sTrait.ClassJobCategory.Key; trait.lvl = sTrait.Level; string desc = trait.en.description; // Link traits if the action name appears somewhere in the trait description. foreach (var action in _linkingActions) { if (action.job == null) { continue; } string name = action.en.name; if (name == null || !desc.Contains(name)) { continue; } if ((int)action.job != (int)trait.job) { continue; } var actionId = (int)action.id; var traitId = (int)trait.id; if (actionId == 119 && traitId == 50065) { continue; // Graniteskin & Stone } if (actionId == 120 && traitId == 50063) { continue; // Overcure and Cure } if (trait.actions == null) { trait.actions = new JArray(); } trait.actions.Add(actionId); _builder.Db.AddReference(trait, "action", actionId, false); if (action.traits == null) { action.traits = new JArray(); } action.traits.Add(traitId); _builder.Db.AddReference(action, "action", traitId, false); } _builder.Db.Actions.Add(trait); } }
void BuildAppearanceData() { foreach (var sNpc in _builder.NpcsToImport) { var race = (Saint.Race)sNpc.Base["Race"]; var npc = _builder.GetOrCreateNpc(sNpc); if (race == null || race.Key == 0) { continue; // Unique or beast NPCs, can't do appearance now. } dynamic appearance = new JObject(); npc.appearance = appearance; var gender = (byte)sNpc.Base["Gender"]; var isMale = gender == 0; appearance.gender = isMale ? "Male" : "Female"; appearance.race = isMale ? race.Masculine.ToString() : race.Feminine.ToString(); var tribe = (Saint.Tribe)sNpc.Base["Tribe"]; appearance.tribe = isMale ? tribe.Masculine.ToString() : tribe.Feminine.ToString(); appearance.height = sNpc.Base["Height"]; var bodyType = (byte)sNpc.Base["BodyType"]; if (bodyType != 1) { appearance.bodyType = GetBodyType(bodyType); } // Faces var baseFace = (byte)sNpc.Base["Face"]; var face = baseFace % 100; // Value matches the asset number, % 100 approximate face # nicely. appearance.face = face; var isValidFace = face < 8; var isCustomFace = baseFace > 7; if (isCustomFace) { appearance.customFace = 1; } appearance.jaw = 1 + (byte)sNpc.Base["Jaw"]; appearance.eyebrows = 1 + (byte)sNpc.Base["Eyebrows"]; appearance.nose = 1 + (byte)sNpc.Base["Nose"]; appearance.skinColor = FormatColorCoordinates((byte)sNpc.Base["SkinColor"]); appearance.skinColorCode = FormatColor((byte)sNpc.Base["SkinColor"], GetSkinColorMapIndex(tribe.Key, isMale)); // Bust & Muscles - flex fields. if (race.Key == 5 || race.Key == 1) { // Roegadyn & Hyur appearance.muscle = (byte)sNpc.Base["BustOrTone1"]; if (!isMale) { appearance.bust = (byte)sNpc.Base["ExtraFeature2OrBust"]; } } else if (race.Key == 6 && isMale) { // Au Ra male muscles appearance.muscle = (byte)sNpc.Base["BustOrTone1"]; } else if (!isMale) { // Other female bust sizes appearance.bust = (byte)sNpc.Base["BustOrTone1"]; } // Hair & Highlights var hairstyle = (byte)sNpc.Base["HairStyle"]; var hairstyleIcon = CustomizeIcon(GetHairstyleCustomizeIndex(tribe.Key, isMale), 100, hairstyle, npc); if (hairstyleIcon > 0) { appearance.hairStyle = hairstyleIcon; } appearance.hairColor = FormatColorCoordinates((byte)sNpc.Base["HairColor"]); appearance.hairColorCode = FormatColor((byte)sNpc.Base["HairColor"], GetHairColorMapIndex(tribe.Key, isMale)); var highlights = Unpack2((byte)sNpc.Base["HairHighlight"]); if (highlights.Item1 == 1) { appearance.highlightColor = FormatColorCoordinates((byte)sNpc.Base["HairHighlightColor"]); appearance.highlightColorCode = FormatColor((byte)sNpc.Base["HairHighlightColor"], HairHighlightColorOffset); } // Eyes & Heterochromia var eyeShape = Unpack2((byte)sNpc.Base["EyeShape"]); appearance.eyeSize = eyeShape.Item1 == 1 ? "Small" : "Large"; appearance.eyeShape = 1 + eyeShape.Item2; var eyeColor = (byte)sNpc.Base["EyeColor"]; appearance.eyeColor = FormatColorCoordinates(eyeColor); appearance.eyeColorCode = FormatColor(eyeColor, EyeColorOffset); var heterochromia = (byte)sNpc.Base["EyeHeterochromia"]; if (heterochromia != eyeColor) { appearance.heterochromia = FormatColorCoordinates(heterochromia); appearance.heterochromiaCode = FormatColor(heterochromia, EyeColorOffset); } // Mouth & Lips var mouth = Unpack2((byte)sNpc.Base["Mouth"]); appearance.mouth = 1 + mouth.Item2; if (mouth.Item1 == 1) { var lipColor = Unpack2((byte)sNpc.Base["LipColor"]); appearance.lipShade = lipColor.Item1 == 1 ? "Light" : "Dark"; appearance.lipColor = FormatColorCoordinates(lipColor.Item2); appearance.lipColorCode = FormatColor(lipColor.Item2, lipColor.Item1 == 1 ? LightLipFacePaintColorOffset : DarkLipFacePaintColorOffset); } // Extra Features var extraFeatureName = ExtraFeatureName(race.Key); if (extraFeatureName != null) { appearance.extraFeatureName = extraFeatureName; appearance.extraFeatureShape = (byte)sNpc.Base["ExtraFeature1"]; appearance.extraFeatureSize = (byte)sNpc.Base["ExtraFeature2OrBust"]; } // Facepaint var facepaint = Unpack2((byte)sNpc.Base["FacePaint"]); var facepaintIcon = CustomizeIcon(GetFacePaintCustomizeIndex(tribe.Key, isMale), 50, facepaint.Item2, npc); if (facepaintIcon > 0) { appearance.facepaint = facepaintIcon; if (facepaint.Item1 == 1) { appearance.facepaintReverse = 1; } var facepaintColor = Unpack2((byte)sNpc.Base["FacePaintColor"]); appearance.facepaintShade = facepaintColor.Item1 == 1 ? "Light" : "Dark"; appearance.facepaintColor = FormatColorCoordinates(facepaintColor.Item2); appearance.facepaintColorCode = FormatColor(facepaintColor.Item2, facepaintColor.Item1 == 1 ? LightLipFacePaintColorOffset : DarkLipFacePaintColorOffset); } // Facial Features var facialfeature = (byte)sNpc.Base["FacialFeature"]; if (facialfeature != 0 && isValidFace) { var type = CharaMakeTypeRow(tribe.Key, gender); appearance.facialfeatures = new JArray(); // There are only 7 groups of facial features at the moment. var facialfeatures = new System.Collections.BitArray(new byte[] { facialfeature }); for (var i = 0; i < 7; i++) { if (!facialfeatures[i]) { continue; } // Columns are split into groups of 6, 1 for each face type. var iconIndex = (i * 6) + face - 1; var icon = (ImageFile)type["FacialFeatureIcon[" + iconIndex + "]"]; appearance.facialfeatures.Add(IconDatabase.EnsureEntry("customize", icon)); } appearance.facialfeatureColor = FormatColorCoordinates((byte)sNpc.Base["FacialFeatureColor"]); appearance.facialfeatureColorCode = FormatColor((byte)sNpc.Base["FacialFeatureColor"], 0); } // todo: CharaMakeType ExtraFeatureData for faces, extra feature icons. } }
dynamic BuildAction(Saint.Action sAction) { dynamic action = new JObject(); action.id = sAction.Key; _builder.Localize.Strings((JObject)action, sAction, "Name"); _builder.Localize.HtmlStrings((JObject)action, sAction.ActionTransient, "Description"); action.patch = PatchDatabase.Get("action", sAction.Key); action.category = sAction.ActionCategory.Key; if (!sAction.Icon.Path.EndsWith("000000.tex")) { action.icon = IconDatabase.EnsureEntry("action", sAction.Icon); } if (sAction.ClassJobCategory.Key > 0) { action.affinity = sAction.ClassJobCategory.Key; } action.lvl = sAction.ClassJobLevel; action.range = sAction.Range; // -1 = melee, 0 = self action.cast = sAction.CastTime.TotalMilliseconds; action.recast = sAction.RecastTime.TotalMilliseconds; // This is needed for ninja and pet actions. var sClassJob = sAction.ClassJob; if (sClassJob == null || (sClassJob.Key == 0 && sAction.ClassJobCategory.ClassJobs.Count() == 1)) { if (sAction.ClassJobCategory.Key > 0) { action.job = sAction.ClassJobCategory.ClassJobs.First().Key; } } else { action.job = sClassJob.Key; } if (sAction.ComboFrom.Key > 0) { action.comboFrom = sAction.ComboFrom.Key; _builder.Db.AddReference(action, "action", sAction.ComboFrom.Key, false); } if (sAction.GainedStatus.Key != 0) { action.gainedStatus = GetStatus(sAction.GainedStatus); } if (sAction.EffectRange > 1) { action.size = sAction.EffectRange; } BuildActionCost(action, sAction); var cooldownGroup = (byte)sAction["CooldownGroup"]; if (cooldownGroup == 58) { action.gcd = 1; } // Not very useful. //if (gameData.CanTargetSelf) // action.self = 1; //if (gameData.CanTargetParty) // action.party = 1; //if (gameData.CanTargetFriendly) // action.friendly = 1; //if (gameData.CanTargetHostile) // action.hostile = 1; //if (gameData.TargetArea) // action.aoe = 1; _builder.Db.Actions.Add(action); _builder.Db.ActionsById[sAction.Key] = action; return(action); }
void BuildCards() { foreach (var sItem in _builder.ItemsToImport) { var unlock = sItem.ItemAction as SaintCoinach.Xiv.ItemActions.TripleTriadCardUnlock; if (unlock == null) { continue; } var item = _builder.Db.ItemsById[sItem.Key]; if (item.tripletriad != null) { throw new InvalidOperationException(); } var sCard = unlock.TripleTriadCard; var sResident = unlock.TripleTriadCard.TripleTriadCardResident; item.tripletriad = new JObject(); _builder.Localize.Strings(item.tripletriad, unlock.TripleTriadCard, "Description"); var type = sResident.TripleTriadCardType.Name.ToString(); if (!string.IsNullOrEmpty(type)) { item.tripletriad.type = type; } if (sResident.SaleValue > 0) { item.tripletriad.sellMgp = sResident.SaleValue; } // unlock.TripleTriadCard.Icon is only 40x40 and looks awful. item.tripletriad.plate = IconDatabase.EnsureEntry("triad\\plate", sCard.PlateIcon); item.tripletriad.rarity = sResident.TripleTriadCardRarity.Key; if (sResident.Top == 10) { item.tripletriad.top = "A"; } else { item.tripletriad.top = sResident.Top; } if (sResident.Bottom == 10) { item.tripletriad.bottom = "A"; } else { item.tripletriad.bottom = sResident.Bottom; } if (sResident.Left == 10) { item.tripletriad.left = "A"; } else { item.tripletriad.left = sResident.Left; } if (sResident.Right == 10) { item.tripletriad.right = "A"; } else { item.tripletriad.right = sResident.Right; } _itemsByTripleTriadCardId[sCard.Key] = item; } }
void BuildQuests() { var lQuestsByKey = _builder.Libra.Table <Libra.Quest>().ToDictionary(q => q.Key); foreach (var sQuest in _builder.Sheet <Saint.Quest>()) { if (sQuest.Key == 65536 || sQuest.Name == "") { continue; // Test quests } dynamic quest = new JObject(); quest.id = sQuest.Key; _builder.Localize.Strings((JObject)quest, sQuest, Utils.SanitizeQuestName, "Name"); quest.patch = PatchDatabase.Get("quest", sQuest.Key); quest.sort = sQuest.SortKey; // Quest location var questIssuer = (sQuest.IssuingENpc?.Locations?.Count() ?? 0) > 0 ? sQuest.IssuingENpc : null; var sPlaceName = sQuest.PlaceName; if (sPlaceName.Name == "" && questIssuer != null) { sPlaceName = questIssuer.Locations.First().PlaceName; } _builder.Localize.Column((JObject)quest, sPlaceName, "Name", "location", x => x == "" ? "???" : x.ToString()); // Repeatability if (sQuest.RepeatInterval == Saint.QuestRepeatInterval.Daily) { quest.interval = "daily"; } else if (sQuest.RepeatInterval == Saint.QuestRepeatInterval.Weekly) { quest.interval = "weekly"; } if (sQuest.IsRepeatable) { quest.repeatable = 1; } // Miscellaneous if (sQuest.Icon != null) { quest.icon = IconDatabase.EnsureEntry("quest", sQuest.Icon); } if (sQuest.BeastTribe.Key != 0) { quest.beast = sQuest.BeastTribe.Key; } ImportQuestEventIcon(quest, sQuest); // Quest issuer if (questIssuer != null) { var npc = AddQuestNpc(quest, questIssuer); if (npc != null) { quest.issuer = questIssuer.Key; } } // Quest target var questTarget = sQuest.TargetENpc; if (questTarget != null) { var npc = AddQuestNpc(quest, questTarget); if (npc != null) { quest.target = questTarget.Key; } } // Involved if (_npcsByQuestKey.TryGetValue(sQuest.Key, out var involvedNpcKeys)) { foreach (var npcKey in involvedNpcKeys) { var sInvolvedEnpc = _builder.Realm.GameData.ENpcs[npcKey]; if (sInvolvedEnpc == null || sInvolvedEnpc == questTarget || sInvolvedEnpc == questIssuer) { continue; } var npc = AddQuestNpc(quest, sInvolvedEnpc); if (npc == null) { continue; } if (quest.involved == null) { quest.involved = new JArray(); } quest.involved.Add(npcKey); } } // Journal Genre quest.genre = sQuest.JournalGenre.Key; // Rewards dynamic rewards = new JObject(); if (sQuest.Rewards.Gil > 0) { rewards.gil = sQuest.Rewards.Gil; } if (sQuest.Rewards.Emote.Key > 0) { rewards.emote = sQuest.Rewards.Emote.Name.ToString(); } if (sQuest.Rewards.ClassJob.Key > 0) { rewards.job = sQuest.Rewards.ClassJob.Key; } if (sQuest.AsInt32("CurrencyRewardCount") > 0) { rewards.gcseal = sQuest.AsInt32("CurrencyRewardCount"); } if (sQuest.Rewards.Action.Key > 0) { rewards.action = sQuest.Rewards.Action.Key; _builder.Db.AddReference(quest, "action", sQuest.Rewards.Action.Key, false); } var sInstanceContentReward = sQuest.Rewards.InstanceContent; if (sInstanceContentReward.Key > 0) { var instance = _builder.Db.Instances.FirstOrDefault(i => i.id == sInstanceContentReward.Key); if (instance != null) { instance.unlockedByQuest = sQuest.Key; rewards.instance = sInstanceContentReward.Key; _builder.Db.AddReference(quest, "instance", sInstanceContentReward.Key, false); _builder.Db.AddReference(instance, "quest", sQuest.Key, false); } } if (sQuest.Rewards.Reputation > 0) { rewards.reputation = sQuest.Rewards.Reputation; } if (sQuest.Rewards.QuestRewardOther.Name == "Aether Current") { rewards.aetherCurrent = 1; } foreach (var sQuestRewardItemGroup in sQuest.Rewards.Items) { foreach (var sQuestRewardItem in sQuestRewardItemGroup.Items) { if (rewards.items == null) { rewards.items = new JArray(); } var maxCount = sQuestRewardItem.Counts.Max(); dynamic o = new JObject(); if (maxCount > 1) { o.num = maxCount; } o.id = sQuestRewardItem.Item.Key; if (sQuestRewardItemGroup.Type == Saint.QuestRewardGroupType.One) { o.one = 1; } if (sQuestRewardItem.IsHq) { o.hq = 1; } rewards.items.Add(o); try { var item = _builder.Db.ItemsById[sQuestRewardItem.Item.Key]; if (item.quests == null) { item.quests = new JArray(); } JArray quests = item.quests; if (!quests.Any(id => ((int)id) == sQuest.Key)) { quests.Add(sQuest.Key); } _builder.Db.AddReference(item, "quest", sQuest.Key, false); } catch (KeyNotFoundException ignored) { DatabaseBuilder.PrintLine($"Reward item '{sQuestRewardItem.Item.Key}' not found for Quest '{quest.Key}'."); } _builder.Db.AddReference(quest, "item", sQuestRewardItem.Item.Key, false); } } // Libra supplemental rewards. if (lQuestsByKey.TryGetValue(sQuest.Key, out var lQuest)) { dynamic data = JsonConvert.DeserializeObject(lQuest.data); int xp = 0; if (data.exp != null && int.TryParse((string)data.exp, out xp)) { rewards.xp = xp; } } // Scripts var instructions = ScriptInstruction.Read(sQuest, 50); // Script instance unlocks. if (!sQuest.IsRepeatable) { var instanceReferences = instructions.Where(i => i.Label.StartsWith("INSTANCEDUNGEON")).ToArray(); foreach (var instanceReference in instanceReferences) { var key = (int)instanceReference.Argument; var instance = _builder.Db.Instances.FirstOrDefault(i => ((int)i.id) == key); if (instance == null) { continue; // Probably a guildhest. } if (instance.unlockedByQuest != null) { continue; } if (!instructions.Any(i => i.Label == "UNLOCK_ADD_NEW_CONTENT_TO_CF" || i.Label.StartsWith("UNLOCK_DUNGEON"))) { // Some quests reference instances for the retrieval of items. // Don't treat these as unlocks. if (instructions.Any(i => i.Label.StartsWith("LOC_ITEM"))) { continue; } } instance.unlockedByQuest = sQuest.Key; rewards.instance = key; _builder.Db.AddReference(quest, "instance", key, false); _builder.Db.AddReference(instance, "quest", sQuest.Key, false); } } // Used items. foreach (var instruction in instructions) { if (!instruction.Label.StartsWith("RITEM") && !instruction.Label.StartsWith("QUEST_ITEM")) { continue; } var key = (int)instruction.Argument; if (_builder.Db.ItemsById.TryGetValue(key, out var item)) { if (item.usedInQuest == null) { item.usedInQuest = new JArray(); } JArray usedInQuest = item.usedInQuest; if (usedInQuest.Any(i => (int)i == sQuest.Key)) { continue; } item.usedInQuest.Add(sQuest.Key); if (quest.usedItems == null) { quest.usedItems = new JArray(); } quest.usedItems.Add(key); _builder.Db.AddReference(item, "quest", sQuest.Key, false); _builder.Db.AddReference(quest, "item", key, false); } } ImportQuestLore(quest, sQuest, instructions); if (((JObject)rewards).Count > 0) { quest.reward = rewards; } ImportQuestRequirements(quest, sQuest); _builder.Db.Quests.Add(quest); _builder.Db.QuestsById[sQuest.Key] = quest; } }
void BuildLeve(Game.Leve sLeve) { if (sLeve.Key <= 20 || sLeve.Name == "") { return; } dynamic leve = new JObject(); leve.id = sLeve.Key; _builder.Localize.HtmlStrings((JObject)leve, sLeve, "Name", "Description"); leve.patch = PatchDatabase.Get("leve", sLeve.Key); leve.client = sLeve.LeveClient.Name.ToString().Replace("Client: ", ""); leve.lvl = sLeve.ClassJobLevel; leve.jobCategory = sLeve.ClassJobCategory.Key; var sNpc = _builder.Realm.GameData.ENpcs[sLeve.LevemeteLevel.Object.Key]; var levemete = _builder.Db.NpcsById[sNpc.Key]; leve.levemete = sNpc.Key; _builder.Db.AddReference(leve, "npc", sNpc.Key, false); if (sLeve.StartLevel != null && sLeve.StartLevel.Key != 0) { leve.coords = _builder.GetCoords(sLeve.StartLevel); var locationInfo = _builder.LocationInfoByMapId[sLeve.StartLevel.Map.Key]; leve.zoneid = locationInfo.PlaceName.Key; } leve.areaid = sLeve.PlaceNameStart.Key; _builder.Db.AddLocationReference(sLeve.PlaceNameStart.Key); if (sLeve.ExpReward > 0) { leve.xp = sLeve.ExpReward; } else if (sLeve.ClassJobCategory.Name.Equals("MIN") || sLeve.ClassJobCategory.Name.Equals("BTN") || sLeve.ClassJobCategory.Name.Equals("FSH")) { if ((float)sLeve["ExpFactor"] > 0) { leve.xp = ((float)sLeve["ExpFactor"]) * _gatherExpByLvl[leve.lvl.Value].Exp; } } if (sLeve.GilReward > 0) { leve.gil = sLeve.GilReward; } switch (sLeve.LeveAssignmentType.Key) { case 16: // Maelstrom case 17: // Adders case 18: // Flames leve.gc = sLeve.LeveAssignmentType.Key - 15; break; } if (sLeve.LeveRewardItem.ItemGroups.Any(ig => ig.Value.Key > 0)) { // Embed the rewards, as they will be kept in separate files. leve.rewards = sLeve.LeveRewardItem.Key; foreach (var group in sLeve.LeveRewardItem.ItemGroups.SelectMany(g => g.Value.Items)) { var item = _builder.Db.ItemsById[group.Item.Key]; if (item.category == 59) // Crystal { continue; // Skip these, there are too many. } if (item.leves == null) { item.leves = new JArray(); } JArray leves = item.leves; if (!leves.Any(l => (int)l == sLeve.Key)) { leves.Add(sLeve.Key); _builder.Db.AddReference(item, "leve", sLeve.Key, false); _builder.Db.AddReference(leve, "item", group.Item.Key, false); } } } leve.plate = IconDatabase.EnsureEntry("leve\\plate", sLeve.PlateIcon); leve.frame = IconDatabase.EnsureEntry("leve\\frame", sLeve.FrameIcon); leve.areaicon = IconDatabase.EnsureEntry("leve\\area", sLeve.IssuerIcon); // Find turn-ins for crafting and fisher leves. if (_craftLevesByLeve.TryGetValue(sLeve, out var sCraftLeve)) { if (sCraftLeve.Repeats > 0) { leve.repeats = sCraftLeve.Repeats; } JArray requires = new JArray(); leve.requires = requires; foreach (var sCraftLeveItem in sCraftLeve.Items) { dynamic entry = requires.FirstOrDefault(t => (int)t["item"] == sCraftLeveItem.Item.Key); if (entry != null) { if (entry.amount == null) { entry.amount = 1; } entry.amount += sCraftLeveItem.Count; continue; } dynamic requireItem = new JObject(); requireItem.item = sCraftLeveItem.Item.Key; if (sCraftLeveItem.Count > 1) { requireItem.amount = sCraftLeveItem.Count; } leve.requires.Add(requireItem); var item = _builder.Db.ItemsById[sCraftLeveItem.Item.Key]; if (item.requiredByLeves == null) { item.requiredByLeves = new JArray(); } item.requiredByLeves.Add(sLeve.Key); _builder.Db.AddReference(item, "leve", sLeve.Key, false); _builder.Db.AddReference(leve, "item", sCraftLeveItem.Item.Key, false); } } // TODO: CompanyLeve sheet for seal rewards and stuff? _builder.Db.Leves.Add(leve); }
public override void Start() { foreach (var sAchievement in _builder.Sheet <Game.Achievement>()) { if (sAchievement.Key == 0 || sAchievement.AchievementCategory.Key == 0) { continue; } if (sAchievement.AchievementCategory.AchievementKind.Name == "Legacy") { continue; } dynamic achievement = new JObject(); achievement.id = sAchievement.Key; _builder.Localize.Strings((JObject)achievement, sAchievement, "Name", "Description"); achievement.patch = PatchDatabase.Get("achievement", sAchievement.Key); achievement.points = sAchievement.Points; achievement.category = sAchievement.AchievementCategory.Key; if (sAchievement.Title.Key != 0) { if (sAchievement.Title.Feminine == sAchievement.Title.Masculine) { achievement.title = sAchievement.Title.Masculine.ToString(); } else { achievement.title = sAchievement.Title.ToString(); } } if (sAchievement.Item.Key != 0) { achievement.item = sAchievement.Item.Key; var item = _builder.Db.ItemsById[sAchievement.Item.Key]; if (item.achievements == null) { item.achievements = new JArray(); } item.achievements.Add(sAchievement.Key); _builder.Db.AddReference(achievement, "item", sAchievement.Item.Key, false); _builder.Db.AddReference(item, "achievement", sAchievement.Key, false); } achievement.icon = IconDatabase.EnsureEntry("achievement", sAchievement.Icon); _builder.Db.Achievements.Add(achievement); } foreach (var sAchievementCategory in _builder.Sheet <Game.AchievementCategory>()) { if (sAchievementCategory.Key == 0 || sAchievementCategory.Name == "") { continue; } dynamic category = new JObject(); category.id = sAchievementCategory.Key; category.name = sAchievementCategory.Name.ToString(); category.kind = sAchievementCategory.AchievementKind.Name.ToString(); _builder.Db.AchievementCategories.Add(category); } }