public static void ReloadParams() { BND4 paramBnd = SFUtil.DecryptDS3Regulation(DarkSoulsTools.GetOverridenPath(ParamPath)); DS3Param = PARAM64.Read(paramBnd.Files.Find(x => Path.GetFileName(x.Name) == "ItemLotParam.param").Bytes); PARAM64.Layout layout = PARAM64.Layout.ReadXMLFile($@"{Application.dataPath.Replace('/', '\\')}\dstools\ParamLayouts\DS3\{DS3Param.ID}.xml"); DS3Param.SetLayout(layout); // Build and cache the item name list HashSet <int> usedItemIds = new HashSet <int>(); ItemNameList = new List <Tuple <int, string> >(); foreach (var row in DS3Param.Rows) { ItemLotParam param = new ItemLotParam(row); foreach (int id in param.ItemID) { if (!usedItemIds.Contains(id)) { usedItemIds.Add(id); ItemNameList.Add(new Tuple <int, string>(id, FMGUtils.LookupItemName(id))); } } } ItemNameList.Sort((a, b) => StringComparer.InvariantCulture.Compare(a.Item2, b.Item2)); }
private void LoadRegulation(string path) { BND4 bnd; try { bnd = SFUtil.DecryptDS3Regulation(path); } catch (Exception ex) { ShowError($"Failed to load regulation file:\r\n\r\n{path}\r\n\r\n{ex}"); return; } paramFiles = new List <ParamFile>(); foreach (BinderFile file in bnd.Files) { if (Path.GetExtension(file.Name) == ".param") { try { PARAM64 param = PARAM64.Read(file.Bytes); paramFiles.Add(new ParamFile(Path.GetFileNameWithoutExtension(file.Name), param, layouts)); } catch { } } } paramFiles.Sort((p1, p2) => p1.Name.CompareTo(p2.Name)); dgvParams.DataSource = paramFiles; }
public ParamWrapper(string name, PARAM64 param, PARAM64.Layout layout, string description) { Name = name; Param = param; Layout = layout; Param.SetLayout(layout); Description = description; }
public ParamFile(string name, PARAM64 param, Dictionary <string, PARAM64.Layout> layouts) { Name = name; Param = param; string format = Param.ID; if (!layouts.ContainsKey(format)) { layouts[format] = new PARAM64.Layout(); } try { Layout = layouts[format]; Param.SetLayout(Layout); Rows = Param.Rows; } catch (Exception ex) { Rows = new List <PARAM64.Row>(); ShowError($"Error in layout {format}, please try again.\r\n\r\n{ex}"); } }
private void Randomize(IProgress <string> progress) { progress.Report("Loading regulation..."); string regPath = Path.Combine(txtGameDir.Text, "Data0.bdt"); if (!File.Exists(regPath)) { progress.Report("Aborted."); ShowError($"Regulation file not found in game directory:\n{regPath}\nPlease make sure the path is correct."); return; } try { if (!File.Exists(regPath + ".bak")) { File.Copy(regPath, regPath + ".bak"); } } catch (Exception ex) { progress.Report("Aborted."); ShowError($"Failed to back up regulation file:\n{regPath}\n\n{ex}"); return; } BND4 regulation; var paramDict = new Dictionary <string, PARAM64>(); try { regulation = Util.DecryptDS3Regulation(regPath); foreach (BND4.File f in regulation.Files) { if (f.Name.EndsWith(".param")) { PARAM64 param = PARAM64.Read(f.Bytes); PARAM64.Layout layout = PARAM64.Layout.ReadXMLFile($"Layouts\\{param.ID}.xml"); param.SetLayout(layout); paramDict[Path.GetFileNameWithoutExtension(f.Name)] = param; } } } catch (Exception ex) { progress.Report("Aborted."); ShowError($"Failed to load regulation file:\n{regPath}\n\n{ex}"); return; } progress.Report("Randomizing..."); try { bool[] weaponOptions = { radDefault.Checked, radBalanced.Checked, radNoShields.Checked }; Irregulator irreg = new Irregulator(txtSeed.Text); irreg.Randomize(paramDict, cbxArmor.Checked, cbxWeapons.Checked, weaponOptions, cbxRings.Checked, cbxGoods.Checked, cbxSpells.Checked, cbxBullets.Checked, cbxBulletsPlus.Checked, cbxHumans.Checked, cbxOther.Checked, cbxTesting.Checked); } catch (Exception ex) { progress.Report("Aborted."); ShowError($"Failed to randomize regulation file:\n{regPath}\n\n{ex}"); return; } progress.Report("Saving regulation..."); try { foreach (BND4.File f in regulation.Files) { if (paramDict.ContainsKey(Path.GetFileNameWithoutExtension(f.Name))) { f.Bytes = paramDict[Path.GetFileNameWithoutExtension(f.Name)].Write(); } } Util.EncryptDS3Regulation(regPath, regulation); } catch (Exception ex) { progress.Report("Aborted."); ShowError($"Failed to save regulation file:\n{regPath}\n\n{ex}"); return; } progress.Report("Finished!"); SystemSounds.Asterisk.Play(); }
public static LoadParamsResult LoadParams(string paramPath, Dictionary <string, ParamInfo> paramInfo, Dictionary <string, PARAM64.Layout> layouts, bool hideUnusedParams) { if (!File.Exists(paramPath)) { ShowError($"Parambnd not found:\r\n{paramPath}\r\nPlease browse to the Data0.bdt or parambnd you would like to edit."); return(null); } var result = new LoadParamsResult(); try { if (BND4.Is(paramPath)) { result.ParamBND = BND4.Read(paramPath); result.Encrypted = false; } else { result.ParamBND = SFUtil.DecryptDS3Regulation(paramPath); result.Encrypted = true; } } catch (DllNotFoundException ex) when(ex.Message.Contains("oo2core_6_win64.dll")) { ShowError("In order to load Sekiro params, you must copy oo2core_6_win64.dll from Sekiro into Yapped's lib folder."); return(null); } catch (Exception ex) { ShowError($"Failed to load parambnd:\r\n{paramPath}\r\n\r\n{ex}"); return(null); } result.ParamWrappers = new List <ParamWrapper>(); foreach (BinderFile file in result.ParamBND.Files.Where(f => f.Name.EndsWith(".param"))) { string name = Path.GetFileNameWithoutExtension(file.Name); if (paramInfo.ContainsKey(name)) { if (paramInfo[name].Blocked || paramInfo[name].Hidden && hideUnusedParams) { continue; } } try { PARAM64 param = PARAM64.Read(file.Bytes); if (layouts.ContainsKey(param.ID)) { PARAM64.Layout layout = layouts[param.ID]; if (layout.Size == param.DetectedSize) { string description = null; if (paramInfo.ContainsKey(name)) { description = paramInfo[name].Description; } var wrapper = new ParamWrapper(name, param, layout, description); result.ParamWrappers.Add(wrapper); } else { } } } catch (Exception ex) { ShowError($"Failed to load param file: {name}.param\r\n\r\n{ex}"); } } result.ParamWrappers.Sort(); return(result); }
public void Randomize(Dictionary <string, PARAM64> paramDict, bool doArmor, bool doWeapons, bool doRings, bool doGoods, bool doSpells, bool doBullets, bool bulletsPlus, bool doHumans, bool doOthers) { if (doBullets) { PARAM64 param = paramDict["Bullet"]; RandomizeAll(param.Rows, bulletsPlus); } if (doRings) { PARAM64 param = paramDict["EquipParamAccessory"]; var rings = param.Rows.Where(row => (byte)row["accessoryCategory"].Value == 0 && row.ID < 900000); RandomizeSome(rings, "weight", "refId0"); } if (doGoods) { PARAM64 param = paramDict["EquipParamGoods"]; // Skip estus flask and some other stuff var usable = param.Rows.Where(row => (byte)row["goodsType"].Value == 0 && row.ID >= 240); RandomizeSome(usable, "sfxVariationId", "goodsUseAnim"); RandomizePair <byte, int>(usable, "refCategory", "refId1"); } if (doArmor) { PARAM64 param = paramDict["EquipParamProtector"]; var valid = param.Rows.Where(row => row.ID >= 1000000); RandomizeSome(valid, "weight", "residentSpEffectId1", "residentSpEffectId2", "residentSpEffectId3", "resistPoison", "resistBlood", "resistCurse", "resistFrost", "Poise", "PhysDamageCutRate", "SlashDamageCutRate", "StrikeDamageCutRate", "ThrustDamageCutRate", "MagicDamageCutRate", "FireDamageCutRate", "ThunderDamageCutRate", "DarkDamageCutRate"); } if (doWeapons) { RandomizeAll(paramDict["HitEffectSfxParam"].Rows); PARAM64 param = paramDict["EquipParamWeapon"]; // Get rid of test and ghost stuff var valid = param.Rows.Where(row => row.ID >= 100000 && row.ID < 30000000 && !(row.ID >= 409900 && row.ID <= 933900)); RandomizeSome(valid, "weight", "correctStrength", "correctAgility", "corretMagic", "corretFaith", "physGuardCutRate", "magGuardCutRate", "fireGuardCutRate", "thunGuardCutRate", "residentSpEffectId0", "residentSpEffectId1", "residentSpEffectId2", "parryDamageLife", "atkBasePhysics", "atkBaseMagic", "atkBaseFire", "atkBaseThunder", "atkBaseDark", "atkBaseStamina", "saWeaponDamage", "saDurability", "guardAngle", "staminaGuardDef", "properStrength", "properAgility", "properMagic", "properFaith", "correctLuck"); for (int i = 0; i < 24; i++) { RandomizeOne <int>(valid, "HitSfx" + i); } for (int i = 0; i < 8; i++) { RandomizeOne <int>(valid, "weaponVfx" + i); } var weapons = valid.Where(row => weaponCats.Contains((byte)row["weaponCategory"].Value)); RandomizeSome(weapons, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); var bows = valid.Where(row => bowCats.Contains((byte)row["weaponCategory"].Value)); RandomizeSome(bows, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); var catalysts = valid.Where(row => catalystCats.Contains((byte)row["weaponCategory"].Value)); RandomizeSome(catalysts, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); } if (doSpells) { PARAM64 param = paramDict["Magic"]; RandomizeSome(param.Rows, "refIdFpCost1", "refIdSpCost1", "sfxVariationId", "slotLength", "requirementIntellect", "requirementFaith", "analogDexterityMin", "analogDexterityMax", "spEffectCategory", "refType", "CastSfx1", "CastSfx2", "CastSfx3", "refIdFpCost2", "refIdSpCost2", "refIdFpCost3", "refIdSpCost3", "refIdFpCost4", "refIdSpCost4"); RandomizePair <byte, int>(param.Rows, "refCategory1", "refId1"); RandomizePair <byte, int>(param.Rows, "refCategory2", "refId2"); RandomizePair <byte, int>(param.Rows, "refCategory3", "refId3"); RandomizePair <byte, int>(param.Rows, "refCategory4", "refId4"); } if (doHumans) { PARAM64 param = paramDict["CharaInitParam"]; RandomizeSome(param.Rows, "equip_Helm", "equip_Armor", "equip_Gaunt", "equip_Leg", "equip_Wep_Right", "equip_Subwep_Right", "equip_Wep_Left", "equip_Subwep_Left", "equip_Accessory1", "equip_Accessory2", "equip_Accessory3", "equip_Accessory4", "bodyScaleHead", "bodyScaleBreast", "BodyScaleAbdomen", "BodyScaleArm", "BodyScaleLeg"); } //{ // PARAM64 param = paramDict["NpcParam"]; // foreach (var cell in param.Rows[0].Cells) // { // if (cell.Name != "teamType" && !cell.Name.StartsWith("ModelDispMask")) // RandomizeSome(param.Rows, cell.Name); // } //} if (doOthers) { //RandomizeAll(paramDict["AtkParam_Npc"].Rows); //RandomizeAll(paramDict["AtkParam_Pc"].Rows); //RandomizeAll(paramDict["AttackElementCorrectParam"].Rows); //RandomizeAll(paramDict["BehaviorParam"].Rows); //RandomizeAll(paramDict["BehaviorParam_PC"].Rows); RandomizeAll(paramDict["DecalParam"].Rows); //RandomizeAll(paramDict["HitEffectSfxConceptParam"].Rows); //RandomizeAll(paramDict["ModelSfxParam"].Rows); //RandomizeAll(paramDict["NpcThinkParam"].Rows); //RandomizeAll(paramDict["ObjectMaterialSfxParam"].Rows); RandomizeAll(paramDict["PhantomParam"].Rows); //RandomizeAll(paramDict["SwordArtsParam"].Rows); //RandomizeAll(paramDict["UpperArmParam"].Rows); //RandomizeAll(paramDict["WepAbsorpPosParam"].Rows); RandomizeAll(paramDict["WetAspectParam"].Rows); RandomizeAll(paramDict["Wind"].Rows); } }
private void btnDump_Click(object sender, EventArgs e) { BND4 bnd; try { bnd = SFUtil.DecryptDS3Regulation(txtRegulation.Text); } catch (Exception ex) { MessageBox.Show($"Failed to load regulation:\r\n\r\n{txtRegulation.Text}\r\n\r\n{ex}"); return; } var translations = new Dictionary <string, string>(); var xml = new XmlDocument(); xml.Load("translations.xml"); foreach (XmlNode text in xml.SelectNodes("translations/text")) { string jp = text.SelectSingleNode("jp").InnerText; string en = text.SelectSingleNode("en").InnerText; translations[WebUtility.HtmlDecode(jp)] = WebUtility.HtmlDecode(en); } var package = new ExcelPackage(); foreach (BinderFile file in bnd.Files) { if (Path.GetExtension(file.Name) == ".param") { PARAM64 param = PARAM64.Read(file.Bytes); string layoutPath = $"Layouts\\{param.ID}.xml"; txtStatus.AppendText(file.Name + "\r\n"); var worksheet = package.Workbook.Worksheets.Add(Path.GetFileNameWithoutExtension(file.Name)); PARAM64.Layout layout; if (File.Exists(layoutPath)) { layout = PARAM64.Layout.ReadXMLFile(layoutPath); if (layout.Size != param.DetectedSize) { layout = new PARAM64.Layout(); for (int i = 0; i < param.DetectedSize / 4; i++) { layout.Add(new PARAM64.Layout.Entry(CellType.u32, $"unk0x{i * 4:X4}", (uint)0)); } for (int i = 0; i < param.DetectedSize % 4; i++) { layout.Add(new PARAM64.Layout.Entry(CellType.u8, "unkb" + i, (byte)0)); } } } else { layout = new PARAM64.Layout(); } param.SetLayout(layout); List <PARAM64.Row> rows = param.Rows; worksheet.Cells[1, 1].Value = "ID"; worksheet.Cells[1, 2].Value = "Name"; worksheet.Cells[1, 3].Value = "Translated"; int columnCount = 3; foreach (PARAM64.Layout.Entry lv in layout) { if (lv.Type != CellType.dummy8) { worksheet.Cells[1, ++columnCount].Value = lv.Name; } } for (int i = 0; i < rows.Count; i++) { PARAM64.Row row = rows[i]; worksheet.Cells[i + 2, 1].Value = row.ID; if (row.Name != null) { if (translations.ContainsKey(row.Name)) { worksheet.Cells[i + 2, 2].Value = row.Name; worksheet.Cells[i + 2, 3].Value = translations[row.Name]; } else if (row.Name.Contains(" -- ")) { worksheet.Cells[i + 2, 2].Value = row.Name.Substring(row.Name.IndexOf(" -- ") + 4); worksheet.Cells[i + 2, 3].Value = row.Name.Substring(0, row.Name.IndexOf(" -- ")); } } else { worksheet.Cells[i + 2, 2].Value = row.Name; } columnCount = 3; foreach (PARAM64.Cell cell in row.Cells) { CellType type = cell.Type; if (type != CellType.dummy8) { var range = worksheet.Cells[i + 2, ++columnCount]; if (type == CellType.f32) { range.Value = (double)(float)cell.Value; } else if (type == CellType.b8 || type == CellType.b32) { bool b = (bool)cell.Value; range.Value = b.ToString(); range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; range.Style.Fill.BackgroundColor.SetColor(b ? Color.LightGreen : Color.LightPink); } else if (type == CellType.x8) { range.Value = $"0x{cell.Value:X2}"; range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Right; } else if (type == CellType.x16) { range.Value = $"0x{cell.Value:X4}"; range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Right; } else if (type == CellType.x32) { range.Value = $"0x{cell.Value:X8}"; range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Right; } else { range.Value = cell.Value; } } } } worksheet.Row(1).Style.Font.Bold = true; worksheet.Column(1).Style.Font.Bold = true; worksheet.View.FreezePanes(2, 4); worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns(); } } FileInfo f = new FileInfo(Path.Combine(txtOutput.Text, "dump.xlsx")); package.SaveAs(f); }
public void Randomize(Dictionary <string, PARAM64> paramDict, bool doArmor, bool doWeapons, bool[] weaponStyle, bool doRings, bool doGoods, bool doSpells, bool doBullets, bool bulletsPlus, bool doHumans, bool doOthers, bool doTesting) { if (doBullets) { PARAM64 param = paramDict["Bullet"]; RandomizeAll(param.Rows, bulletsPlus); } if (doRings) { PARAM64 param = paramDict["EquipParamAccessory"]; var rings = param.Rows.Where(row => (byte)row["accessoryCategory"].Value == 0 && row.ID < 900000); RandomizeSome(rings, false, "weight", "refId0"); } if (doGoods) { PARAM64 goods = paramDict["EquipParamGoods"]; var usable = goods.Rows.Where(row => (byte)row["goodsType"].Value == 0 && //Is a consumable (?) type good row.ID >= 240 && !(row.ID >= 712 && row.ID <= 747) && //Not boss souls or estus (int)row["refId1"].Value > 0); //Has an effect // Doing these sets of parameters together ensures an item can be used properly // for example, an effect that needs a text box will open that text box string[] goodsLockedParams = { "refId1", "refCategory", "opmeMenuType", "yesNoDialogMessageId", "isEnhance", "useBulletMaxNum", "useHpCureMaxNum", "isEnchantLeftHand", "isApplySpecialEffect", "refVirtualWepId", "replaceItemId_BySpEffect", "replaceTriggerSpEffectId", "reinforceParamWeapon" }; RandomizeSomeTogether(usable, goodsLockedParams); RandomizeSome(usable, false, "sfxVariationId", "goodsUseAnim"); // These do not affect the effect } if (doArmor) { PARAM64 param = paramDict["EquipParamProtector"]; var valid = param.Rows.Where(row => row.ID >= 1000000); RandomizeSome(valid, false, "weight", "residentSpEffectId1", "residentSpEffectId2", "residentSpEffectId3", "resistPoison", "resistBlood", "resistCurse", "resistFrost", "Poise", "PhysDamageCutRate", "SlashDamageCutRate", "StrikeDamageCutRate", "ThrustDamageCutRate", "MagicDamageCutRate", "FireDamageCutRate", "ThunderDamageCutRate", "DarkDamageCutRate"); } if (doWeapons) { bool flatten = weaponStyle[1]; // Chose Balanced bool separate = weaponStyle[2]; // Chose No Shields RandomizeAll(paramDict["HitEffectSfxParam"].Rows); PARAM64 param = paramDict["EquipParamWeapon"]; // Get rid of test and ghost stuff var valid = param.Rows.Where(row => row.ID >= 100000 && row.ID < 30000000 && !(row.ID >= 409900 && row.ID <= 933900)); RandomizeSome(valid, false, "weight", "correctStrength", "correctAgility", "corretMagic", "corretFaith", "physGuardCutRate", "magGuardCutRate", "fireGuardCutRate", "thunGuardCutRate", "residentSpEffectId0", "residentSpEffectId1", "residentSpEffectId2", "parryDamageLife", "atkBasePhysics", "atkBaseMagic", "atkBaseFire", "atkBaseThunder", "atkBaseDark", "atkBaseStamina", "saWeaponDamage", "saDurability", "guardAngle", "staminaGuardDef", "properStrength", "properAgility", "properMagic", "properFaith", "correctLuck"); for (int i = 0; i < 24; i++) { RandomizeOne <int>(valid, "HitSfx" + i, true); } for (int i = 0; i < 8; i++) { RandomizeOne <int>(valid, "weaponVfx" + i, true); } if (separate) // If wanting to remove shield movesets from the weapon's pool { var weapons = valid.Where(row => weaponCats.Contains((byte)row["weaponCategory"].Value)); RandomizeSome(weapons, false, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); var shields = valid.Where(row => shieldCats.Contains((byte)row["weapnCategory"].Value)); RandomizeSome(weapons, false, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); } else { var weapons = valid.Where(row => swingableCats.Contains((byte)row["weaponCategory"].Value)); RandomizeSome(weapons, flatten, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); } var bows = valid.Where(row => bowCats.Contains((byte)row["weaponCategory"].Value)); RandomizeSome(bows, false, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); var catalysts = valid.Where(row => catalystCats.Contains((byte)row["weaponCategory"].Value)); RandomizeSome(catalysts, false, "wepmotionCategory", "guardmotionCategory", "spAtkCategory", "wepmotionOneHandId", "wepmotionBothHandId", "swordArtId", "wepAbsorpPosId"); } if (doSpells) { PARAM64 param = paramDict["Magic"]; RandomizeSome(param.Rows, false, "refIdFpCost1", "refIdSpCost1", "sfxVariationId", "slotLength", "requirementIntellect", "requirementFaith", "analogDexterityMin", "analogDexterityMax", "spEffectCategory", "refType", "CastSfx1", "CastSfx2", "CastSfx3", "refIdFpCost2", "refIdSpCost2", "refIdFpCost3", "refIdSpCost3", "refIdFpCost4", "refIdSpCost4"); RandomizePair <byte, int>(param.Rows, "refCategory1", "refId1"); RandomizePair <byte, int>(param.Rows, "refCategory2", "refId2"); RandomizePair <byte, int>(param.Rows, "refCategory3", "refId3"); RandomizePair <byte, int>(param.Rows, "refCategory4", "refId4"); } if (doHumans) { PARAM64 param = paramDict["CharaInitParam"]; RandomizeSome(param.Rows, false, "equip_Helm", "equip_Armor", "equip_Gaunt", "equip_Leg", "equip_Wep_Right", "equip_Subwep_Right", "equip_Wep_Left", "equip_Subwep_Left", "equip_Accessory1", "equip_Accessory2", "equip_Accessory3", "equip_Accessory4", "bodyScaleHead", "bodyScaleBreast", "BodyScaleAbdomen", "BodyScaleArm", "BodyScaleLeg"); } //{ // PARAM64 param = paramDict["NpcParam"]; // foreach (var cell in param.Rows[0].Cells) // { // if (cell.Name != "teamType" && !cell.Name.StartsWith("ModelDispMask")) // RandomizeSome(param.Rows, cell.Name); // } //} if (doOthers) { //TEXTURE RandomizeAll(paramDict["DecalParam"].Rows); // Like bloody footprints? RandomizeAll(paramDict["PhantomParam"].Rows); // Phantom Texture RandomizeAll(paramDict["WetAspectParam"].Rows); // Liquid Colors RandomizeAll(paramDict["Wind"].Rows); // Wind directions and strengths? RandomizeAll(paramDict["HitEffectSfxParam"].Rows); RandomizeAll(paramDict["ObjectMaterialSfxParam"].Rows); RandomizeAll(paramDict["HitEffectSfxConceptParam"].Rows); RandomizeAll(paramDict["ModelSfxParam"].Rows); //SOUND RandomizeAll(paramDict["FootSfxParam"].Rows); RandomizeAll(paramDict["HitEffectSeParam"].Rows); RandomizeAll(paramDict["SeMaterialConvertParam"].Rows); IEnumerable <PARAM64.Row> breakables = paramDict["ObjectParam"].Rows.Where(row => (short)row["HP"].Value > 0 && !(bool)row["isAnimBreak"].Value); RandomizeAll(breakables, true); //ENEMY ATTACLS String[] some = { "KnockbackDist", "HitStopTime", "spEffect0", "spEffect1", "spEffect2", "spEffect3", "spEffect4", "AtkPhys", "AtkMag", "AtkFire", "AtkThun", "AtkStam", "GuardAtkRate", "GuardBreakRate","AtkSuperArmor", "AtkThrowEscape", "damageLevel", "mapHitType", "AtkAttribute", "atkPowForSfxSe", "atkDirForSfxSe" }; PARAM64 param = paramDict["AtkParam_Npc"]; List <long> oldIDs = new List <long>(); oldIDs.Add(0); for (int i = 3; i >= 0; i--) { String toCheck = "Hit" + i + "_Radius"; var xhit = param.Rows.Where(row => (float)row[toCheck].Value > 0 && !oldIDs.Contains(row.ID)); RandomizeSome(xhit, false, some); List <long> newIDs = xhit.Select(row => (long)row.ID).ToList(); Console.Out.WriteLine("Randomized " + newIDs.Count + " attacks with " + (i + 1) + " hits."); oldIDs.AddRange(newIDs); } } if (doTesting) { //TODO: //SHIELDS AS WEAPONS //SWAMP NO HURT ENEMY //spEffectParam, row 4001-4004, set effectTargetFriend to no // AFAICT There's no way to stop the ground from affecting the NPCs // Turn off for Ash and Stone to protect shrine at least? IEnumerable <PARAM64.Row> materials = paramDict["HitMtrlParam"].Rows.Where(row => !dangerFloors.Contains(row.ID)); string[] effect0 = { "spEffectIdOnHit0", "spEffectIdOnHit3", "spEffectIdOnHit4", "spEffectIdOnHit5", "spEffectIdOnHit6", "spEffectIdOnHit7", "spEffectIdOnHit8", "spEffectIdOnHit9" }; string[] effect1 = { "spEffectIdOnHit1", "newSpType0", "spEffectIdOnHit10", "spEffectIdOnHit11", "spEffectIdOnHit12", "spEffectIdOnHit13", "spEffectIdOnHit14", "spEffectIdOnHit15", "spEffectIdOnHit16" }; string[] effect2 = { "spEffectIdOnHit2", "FootEffectHeightType0", "FootEffectHeightType1" }; string[] unlocked = { "HitMtrlType0", "HitMtrlType1", "HitMtrlType2" }; RandomizeSomeTogether(materials, effect0); RandomizeSomeTogether(materials, effect1); RandomizeSomeTogether(materials, effect2); RandomizeSome(materials, false, unlocked); bool done = true; if (done) { //BREAKABLES //BALANCE // This block randomizes enemy attack effects // but we can only randomize between attack entries with the same number of attacks } } }