private static void UnlockItemByResearch(List <GeoFactionDef> factions, ResearchElement tech, TacticalItemDef item) { if (tech.Rewards.Any(e => (e.BaseDef as ManufactureResearchRewardDef)?.Items?.Contains(item) ?? false)) { return; } Verbo("Adding {0} to {1} ({2})", item.name, tech.ResearchDef.name, (Func <string>)tech.GetLocalizedName); if (Shared == null) { Shared = GameUtl.GameComponent <SharedData>(); } if (!item.Tags.Any(e => e == Shared.SharedGameTags.ManufacturableTag)) { item.Tags.Add(Shared.SharedGameTags.ManufacturableTag); } var rewards = tech.Rewards.ToList(); var items = new List <ItemDef> { item }; if (item.CompatibleAmmunition != null) { items.AddRange(item.CompatibleAmmunition); } rewards.Add(new ManufactureResearchReward(new ManufactureResearchRewardDef() { Items = items.ToArray(), ValidForFactions = factions })); typeof(ResearchElement).GetProperty("Rewards").SetValue(tech, rewards.ToArray()); }
private static void UnlockItem(TacticalItemDef item) { if (Shared == null) { Shared = GameUtl.GameComponent <SharedData>(); } var manufacturableTag = Shared.SharedGameTags.ManufacturableTag; if (!item.Tags.Any(e => e == manufacturableTag)) { item.Tags.Add(manufacturableTag); } if (Manufacture.ManufacturableItems.Any(e => e.RelatedItemDef == item)) { Verbo("Already unlocked: {0}", item.name); return; } else { AddItem(item); } if (item.CompatibleAmmunition?.Length > 0 && item.CompatibleAmmunition[0] != item) { UnlockItem(item.CompatibleAmmunition[0]); } }
private static void LoadVehicleDefs() { try { if (planeDefs != null) { return; } planeDefs = new Dictionary <GeoVehicleDef, VehicleItemDef>(3); tankDefs = new Dictionary <TacUnitClassDef, GroundVehicleItemDef>(3); Verbo("Loading vehicles for scrap screen"); DefRepository defRepo = GameUtl.GameComponent <DefRepository>(); foreach (BaseDef def in defRepo.GetAllDefs <ItemDef>()) { if (def is GroundVehicleItemDef tankDef) { TacUnitClassDef chrDef = tankDef.VehicleClassDef; if (chrDef != null && (chrDef.IsVehicle || chrDef.IsMutog)) { tankDefs[chrDef] = tankDef; } } else if (def is VehicleItemDef planeDef) { GeoVehicleDef vDef = planeDef.ComponentSetDef?.GetComponentDef <GeoVehicleDef>(); if (vDef != null) { planeDefs[vDef] = planeDef; } } } Verbo("Mapped {0} types of airplanes, {1} types of tanks", planeDefs.Count, tankDefs.Count); } catch (Exception ex) { Error(ex); } }
private static TacticalItemDef FindTacItem(string key) { if (Repo == null) { Repo = GameUtl.GameComponent <DefRepository>(); } return(Repo.GetDef(key) as TacticalItemDef ?? Repo.GetAllDefs <TacticalItemDef>().FirstOrDefault(e => e.name == key)); }
/// <summary> /// Called very early, just after main assemblies are loaded, before logos. Saves have not been scanned and most game data are unavailable. /// Full info at https://github.com/Sheep-y/Modnix/wiki/DLL-Specs#SplashMod /// </summary> /// <param name="api">First param (string) is the query/action. Second param (object) and result (object) varies by action.</param> public void SplashMod(ModnixCallback api = null) { // Technically, SplashMod isn't the right place to init this mod. However, it ensures a VERY // early load, and it doesn't cause any issues. This means PPDefModifier can modify it. harmInst = HarmonyInstance.Create(typeof(MyMod).FullName); harmInst.PatchAll(); FileLog.logPath = "./Mods/PPWB_Harmony.log"; FileLog.Log("PPWB..."); BasicUtil.EnsureAPI(ref api); BasicUtil.GetConfig(ref Config, api); storedAPI = api; DefRepository definitions_repo = GameUtl.GameComponent<DefRepository>(); List<WeaponDef> WeaponList = definitions_repo.GetAllDefs<WeaponDef>().ToList(); List<DamageKeywordDef> damageKeywords = definitions_repo.GetAllDefs<DamageKeywordDef>().ToList(); BasicUtil.Log($"Found {WeaponList.Count} weapons loaded into the game.", api); BasicUtil.Log($"Found {damageKeywords.Count} damage types loaded into the game.", api); #region DamageTypeSetup List<DamageKeywordPair> damageKeywordPairsToAdd = new List<DamageKeywordPair>(); if (Config.add_bleed) { damageKeywordPairsToAdd.Add(new DamageKeywordPair() { Value = 0, DamageKeywordDef = damageKeywords.Find(x => x.name.Contains("Bleed")) }); } if (Config.add_pierce) { damageKeywordPairsToAdd.Add(new DamageKeywordPair() { Value = 0, DamageKeywordDef = damageKeywords.Find(x => x.name.Contains("Pierc")) // Because it's truncated "Piercing" }); } if (Config.add_shred) { damageKeywordPairsToAdd.Add(new DamageKeywordPair() { Value = 0, DamageKeywordDef = damageKeywords.Find(x => x.name.Contains("Shred")) }); }; #endregion BasicUtil.Log("Adding damage types to all weapons.", api); foreach (WeaponDef weapon in WeaponList) { foreach (DamageKeywordPair dkp in damageKeywordPairsToAdd) { if (!weapon.DamagePayload.DamageKeywords.Exists(x => x.DamageKeywordDef == dkp.DamageKeywordDef)) { weapon.DamagePayload.DamageKeywords.Add(dkp.Clone()); #if DEBUG BasicUtil.Log($"Had to add damage type {dkp.DamageKeywordDef.Visuals.DisplayName1.Localize()} to {weapon.GetDisplayName().Localize()}", api); #endif } } weapon.DamagePayload.DamageKeywords.Sort( (x, y) => x.CompareTo(y)); } BasicUtil.Log("Done adding damage types.", api); }
private static void AfterAddTravelSite_RestorePause(UIStateVehicleSelected __instance, ref bool __state) { try { var craft_count = GameUtl.CurrentLevel().GetComponent <GeoLevelController>().ViewerFaction.Vehicles.Count(); //Verbo( "Craft count = {0}", craft_count ); if ((craft_count <= 1 && Mod.Config.Auto_Unpause_Single) || (craft_count > 1 && Mod.Config.Auto_Unpause_Multiple)) { return; } Verbo("New vehicle travel plan. Setting time to {0}.", __state ? "Paused" : "Running"); getContext(__instance).Level.Timing.Paused = __state; } catch (Exception ex) { Error(ex); } }
public void GeoscapeMod(Func <string, object, object> api = null) { SetApi(api, out Config).Upgrade(); if (Config.Augments.Enabled) { var sharedData = GameUtl.GameComponent <SharedData>(); AugInfo.AnuMutation = sharedData.SharedGameTags.AnuMutationTag; AugInfo.BioAugTag = sharedData.SharedGameTags.BionicalTag; } if (Config.Skills.Enabled || Config.Augments.Enabled || Config.Equipments.Enabled) { Patch(typeof(HavenFacilityItemController), "SetRecruitmentGroup", postfix: nameof(AfterSetRecruitment_ListPerks)); } }
private static bool CreateCache() { lock ( ByType ) { if (Repo != null) { return(false); } Verbo("Building BaseDef cache"); Repo = GameUtl.GameComponent <DefRepository>(); ByType[typeof(BaseDef)] = new List <BaseDef>(AllDefs); ByName = new SimpleCache(); ByPath = new SimpleCache(); foreach (var def in AllDefs) { AddToCache(def); } Info("Built cache from {0} BaseDef", ByType[typeof(BaseDef)].Count); return(true); } }
private static Component DefaultDumpSubject() { var level = GameUtl.CurrentLevel(); if (level == null || level.CurrentState != Level.State.Playing) { return(level.gameObject.transform); } if (level.GetComponent <MenuLevelController>() != null) { return(level.GetComponent <HomeScreenView>()?.HomeScreenModules); } if (level.GetComponent <GeoLevelController>() != null) { return(level.GetComponent <GeoscapeView>()?.GeoscapeModules); } if (level.GetComponent <TacticalLevelController>() != null) { return(level.GetComponent <TacticalView>()?.TacticalModules); } return(null); }
public static void MainMod() { // Opt out of tele GameUtl.GameComponent <OptionsComponent>().Options.Set("TelemetryInformationAccepted", 0); }
/// <summary> /// Construct a new mod file object from the given filename. /// </summary> /// <param name="fileName">Path to the mod config file</param> /// <param name="api">A (possibly null) callback object for Modnix.</param> public ModFile(string fileName) { this.fileName = fileName; this.repo = new PPDefRepository(GameUtl.GameComponent <DefRepository>()); this.logger = PPDefLogger.logger; }
/// <summary> /// Called after basic assets are loaded, before the hottest year cinematic. Virtually the same time as PPML. /// Full info at https://github.com/Sheep-y/Modnix/wiki/DLL-Specs#MainMod /// </summary> /// <param name="api">First param (string) is the query/action. Second param (object) and result (object) varies by action.</param> public static void MainMod(ModnixCallback api = null) { BasicUtil.EnsureAPI(ref api); BasicUtil.GetConfig(ref Config, api); api("log info", "New MainMod initialized"); DefRepository gameRootDef = GameUtl.GameComponent <DefRepository>(); List <TacticalItemDef> tacticalItems = gameRootDef.GetAllDefs <TacticalItemDef>().ToList().FindAll( new Predicate <TacticalItemDef>(FilterDefList) ); BasicUtil.Log($"Readied {tacticalItems.Count} Independent tactical items.", api); string guid = ""; I2.Loc.LanguageSourceData langDB = I2.Loc.LocalizationManager.Sources[0]; int englishKey = langDB.GetLanguageIndex("English"); foreach (ItemDef item in tacticalItems) { bool isWeapon = item.GetType() == typeof(WeaponDef); #if DEBUG BasicUtil.Log($"Making Reverse Engineer for: {item.GetDisplayName().Localize()} - {item}", api); #endif ResearchTagDef optional = (ResearchTagDef)gameRootDef.GetDef("08191866-ff38-9e74-abd7-cb484188911a"); GeoFactionDef PhoenixPointFaction = (GeoFactionDef)gameRootDef.GetDef("8be7e872-0ad2-a2a4-7bee-c980ed304a8a"); GeoFactionDef DisciplesOfAnuFaction = (GeoFactionDef)gameRootDef.GetDef("edc6783a-be00-1a84-2b97-2fe1e0fc5448"); GeoFactionDef NewJerichoFaction = (GeoFactionDef)gameRootDef.GetDef("d31c78b9-ff0e-8b94-ab96-9672da73da54"); GeoFactionDef SynedrionFaction = (GeoFactionDef)gameRootDef.GetDef("0e6dc218-e157-5954-c9ab-1a0606e0d914"); // 1 + length of compatible ammo list int researchUnlockLength = 1 + ((isWeapon) ? ((WeaponDef)item).CompatibleAmmunition.Length : 0); ItemDef[] researchUnocks = new ItemDef[researchUnlockLength]; researchUnocks[0] = item; for (int i = 1; i < researchUnlockLength; i++) { researchUnocks[i] = ((WeaponDef)item).CompatibleAmmunition[i - 1]; } string[] guidparts = item.Guid.Split('-'); string guidBase = string.Join("-", guidparts.Take(3)); string guidTail = "deadbeefbabe"; int typeInt; #region Generate reverse engineering def typeInt = (int)ResearchGUIDSegments.ReceiveItemResearchRequirement; ReceiveItemResearchRequirementDef rirrDef = ScriptableObject.CreateInstance <ReceiveItemResearchRequirementDef>(); rirrDef.name = item.name + "_ReceiveItemResearchRequirementDef"; rirrDef.Guid = $"{guidBase}-{typeInt:x4}-{guidTail}"; rirrDef.ItemDef = item; typeInt = (int)ResearchGUIDSegments.ItemResearchCost; string I2Key = $"REVERSE_ENGINEER_COSTDEF_{item.name}"; ItemResearchCostDef ircDef = ScriptableObject.CreateInstance <ItemResearchCostDef>(); ircDef.name = item.name + "_ItemResearchCostDef"; ircDef.Guid = $"{guidBase}-{typeInt:x4}-{guidTail}"; ircDef.ItemDef = item; ircDef.Amount = 1; ircDef.LocalizationText = new Base.UI.LocalizedTextBind() { LocalizationKey = I2Key }; langDB.AddTerm($"REVERSE_ENGINEER_COSTDEF_{item.name}", I2.Loc.eTermType.Text); langDB.GetTermData(I2Key).Languages[englishKey] = "Needed items {0}/{1}"; typeInt = (int)ResearchGUIDSegments.ManufactureResearchReward; ManufactureResearchRewardDef mrdDef = ScriptableObject.CreateInstance <ManufactureResearchRewardDef>(); mrdDef.name = item.name + "_ManufactureResearchRewardDef"; mrdDef.Guid = $"{guidBase}-{typeInt:x4}-{guidTail}"; mrdDef.Items = researchUnocks; typeInt = (int)ResearchGUIDSegments.Research; string rName = item.name + "_ResearchDef"; ResearchDef reverseEngineerDef = ScriptableObject.CreateInstance <ResearchDef>(); reverseEngineerDef.name = rName; reverseEngineerDef.Guid = $"{guidBase}-{typeInt:X4}-{guidTail}"; reverseEngineerDef.Id = rName; reverseEngineerDef.Faction = PhoenixPointFaction; reverseEngineerDef.Costs = new ResearchCostDef[] { ircDef }; reverseEngineerDef.ResearchCost = 100; reverseEngineerDef.Tags = new ResearchTagDef[] { optional }; reverseEngineerDef.ValidForFactions = new List <GeoFactionDef> { PhoenixPointFaction }; reverseEngineerDef.Unlocks = new ResearchRewardDef[] { mrdDef }; reverseEngineerDef.InitialStates = new ResearchDef.InitialResearchState[] { new ResearchDef.InitialResearchState { Faction = PhoenixPointFaction, State = ResearchState.Hidden }, new ResearchDef.InitialResearchState { Faction = DisciplesOfAnuFaction, State = ResearchState.Hidden }, new ResearchDef.InitialResearchState { Faction = NewJerichoFaction, State = ResearchState.Hidden }, new ResearchDef.InitialResearchState { Faction = SynedrionFaction, State = ResearchState.Hidden } }; reverseEngineerDef.RevealRequirements.Container = new ReseachRequirementDefOpContainer[] { new ReseachRequirementDefOpContainer() { Operation = ResearchContainerOperation.ALL, Requirements = new ResearchRequirementDef[] { rirrDef } } }; #if DEBUG BasicUtil.Log($"{researchUnocks.Length} items prepared for the rDef.", api); BasicUtil.Log(ircDef.LocalizationText.Localize(), api); #if NOISY BasicUtil.Log(reverseEngineerDef.Repr(), api); #endif #endif #endregion gameRootDef.CreateRuntimeDef(rirrDef, rirrDef.GetType(), rirrDef.Guid); gameRootDef.CreateRuntimeDef(ircDef, ircDef.GetType(), ircDef.Guid); gameRootDef.CreateRuntimeDef(mrdDef, mrdDef.GetType(), mrdDef.Guid); gameRootDef.CreateRuntimeDef(reverseEngineerDef, guid: reverseEngineerDef.Guid); guid = reverseEngineerDef.Guid; } #if DEBUG foreach (GeoFactionDef fact in gameRootDef.GetAllDefs <GeoFactionDef>().ToList()) { BasicUtil.Log(fact.Render(), api); } BasicUtil.Log($"Looking for GUID: {guid}", api); DefRepository temp = GameUtl.GameComponent <DefRepository>(); ResearchDef rDef = (ResearchDef)temp.GetDef(guid); BasicUtil.Log(rDef.name, api); BasicUtil.Log(rDef.Guid, api); BasicUtil.Log(rDef.Costs[0].Guid, api); BasicUtil.Log(rDef.Unlocks[0].Guid, api); BasicUtil.Log(rDef.RevealRequirements.Container[0].Requirements[0].Guid, api); BasicUtil.Log( rDef.Repr(), api); BasicUtil.Log( // Reverse Engineering example ((ResearchDef)temp.GetDef("15d2170b-469b-0341-22d4-a8b4d90eefb8")).Repr(), api); #if COMPAREMANY BasicUtil.Log( // Capture research ((ResearchDef)temp.GetDef("c7b3f8ab-8c90-0343-823b-c966d2c4edb8")).Repr(), api); BasicUtil.Log( // Research that rewards multiple resources temp.GetAllDefs <ResearchDef>().ToList().Find(x => x.Resources.Count > 1).Repr(), api); #endif #endif }