private static DialogueContent BuildContent(CastDef castDef, List <string> quips) { string quip = quips[Mod.Random.Next(0, quips.Count)]; string localizedQuip = new Localize.Text(quip).ToString(); return(Coordinator.BuildDialogueContent(castDef, localizedQuip, Color.white)); }
// Generates a random quip and publishes it public static void PlayQuip(AbstractActor source, List <string> quips, float showDuration = 3) { CastDef castDef = Coordinator.CreateCast(source); DialogueContent content = BuildContent(castDef, quips); source.Combat.MessageCenter.PublishMessage(new CustomDialogMessage(source, content, showDuration)); }
public static DialogueContent BuildDialogueContent(CastDef castDef, string dialogue, Color dialogueColor) { if (castDef == null || String.IsNullOrEmpty(castDef.id) || castDef.defaultEmotePortrait == null || String.IsNullOrEmpty(castDef.defaultEmotePortrait.portraitAssetPath)) { Mod.Log.Warn?.Write("Was passed a castDef with an empty ID - we can't handle this!"); return(null); } Mod.Log.Info?.Write($"Creating dialogueContent for castDef: {castDef.id}"); DialogueContent content = new DialogueContent(dialogue, dialogueColor, castDef.id, null, null, DialogCameraDistance.Medium, DialogCameraHeight.Default, 0); // ContractInitialize normally sets the castDef on the content... no need, since we have the actual ref Traverse castDefT = Traverse.Create(content).Field("castDef"); castDefT.SetValue(castDef); // Initialize the active contract's team settings ApplyCastDef(content); // Load the default emote portrait Traverse dialogueSpriteCacheT = Traverse.Create(content).Field("dialogueSpriteCache"); Dictionary <string, Sprite> dialogueSpriteCache = dialogueSpriteCacheT.GetValue <Dictionary <string, Sprite> >(); Mod.Log.Debug?.Write($"Populating dialogueContent with sprite from path: {castDef.defaultEmotePortrait.portraitAssetPath}"); dialogueSpriteCache[castDef.defaultEmotePortrait.portraitAssetPath] = ModState.Portraits[castDef.defaultEmotePortrait.portraitAssetPath]; return(content); }
public static CastDef CreateCast(CombatGameState combat, string sourceGUID, Team team, string employerFactionName = "Support") { string castDefId = $"castDef_{sourceGUID}"; if (combat.DataManager.CastDefs.Exists(castDefId)) { return(combat.DataManager.CastDefs.Get(castDefId)); } FactionValue actorFaction = team?.FactionValue; bool factionExists = actorFaction.Name != "INVALID_UNSET" && actorFaction.Name != "NoFaction" && actorFaction.FactionDefID != null && actorFaction.FactionDefID.Length != 0 ? true : false; if (factionExists) { Mod.Log.Debug?.Write($"Found factionDef for id:{actorFaction}"); string factionId = actorFaction?.FactionDefID; FactionDef employerFactionDef = UnityGameInstance.Instance.Game.DataManager.Factions.Get(factionId); if (employerFactionDef == null) { Mod.Log.Error?.Write($"Error finding FactionDef for faction with id '{factionId}'"); } else { employerFactionName = employerFactionDef.Name.ToUpper(); } } else { Mod.Log.Debug?.Write($"FactionDefID does not exist for faction: {actorFaction}"); } CastDef newCastDef = new CastDef { // Temp test data FactionValue = actorFaction, firstName = $"{employerFactionName} -", showRank = false, showCallsign = true, showFirstName = true, showLastName = false }; // DisplayName order is first, callsign, lastname newCastDef.id = castDefId; string portraitPath = GetRandomPortraitPath(); newCastDef.callsign = GetRandomCallsign(); Mod.Log.Debug?.Write($" Generated cast with callsign: {newCastDef.callsign} and DisplayName: {newCastDef.DisplayName()} using portrait: '{portraitPath}'"); // Load the associated portrait newCastDef.defaultEmotePortrait.portraitAssetPath = portraitPath; Mod.Log.Debug?.Write($"Generated random portrait: {portraitPath}."); ((DictionaryStore <CastDef>)UnityGameInstance.BattleTechGame.DataManager.CastDefs).Add(newCastDef.id, newCastDef); return(newCastDef); }
public static void PlayQuip(CombatGameState combat, string sourceGUID, Team team, string employerFactionName, List <string> quips, float showDuration = 3) { CastDef castDef = Coordinator.CreateCast(combat, sourceGUID, team, employerFactionName); DialogueContent content = BuildContent(castDef, quips); combat.MessageCenter.PublishMessage(new CustomDialogMessage(sourceGUID, content, showDuration)); }
public static CastDef CreateCast() { Contract contract = MissionControl.Instance.CurrentContract; FactionValue employerFaction = contract.GetTeamFaction(EncounterRules.EMPLOYER_TEAM_ID); string factionId = employerFaction.FactionDefID; string employerFactionName = "Military Support"; if (employerFaction.Name != "INVALID_UNSET" && employerFaction.Name != "NoFaction") { FactionDef employerFactionDef = UnityGameInstance.Instance.Game.DataManager.Factions.Get(factionId); if (employerFactionDef == null) { Main.Logger.LogError($"[RuntimeCastFactory] Error finding FactionDef for faction with id '{factionId}'"); } employerFactionName = employerFactionDef.Name.ToUpper(); } string employerFactionKey = (employerFaction.Name != "INVALID_UNSET" && employerFaction.Name != "NoFaction") ? "All" : employerFaction.ToString(); string gender = DataManager.Instance.GetRandomGender(); string firstName = DataManager.Instance.GetRandomFirstName(gender, employerFactionKey); string lastName = DataManager.Instance.GetRandomLastName(employerFactionKey); string rank = DataManager.Instance.GetRandomRank(employerFactionKey); string portraitPath = DataManager.Instance.GetRandomPortraitPath(gender); Gender btGender = Gender.Male; if (gender == "Female") { btGender = Gender.Female; } if (gender == "Unspecified") { btGender = Gender.NonBinary; } CastDef runtimeCastDef = new CastDef(); // Temp test data runtimeCastDef.id = $"castDef_{rank}{firstName}{lastName}"; runtimeCastDef.internalName = $"{rank}{firstName}{lastName}"; runtimeCastDef.firstName = $"{rank} {firstName}"; runtimeCastDef.lastName = lastName; runtimeCastDef.callsign = rank; runtimeCastDef.rank = employerFactionName; runtimeCastDef.gender = btGender; runtimeCastDef.FactionValue = employerFaction; runtimeCastDef.showRank = true; runtimeCastDef.showFirstName = true; runtimeCastDef.showCallsign = false; runtimeCastDef.showLastName = true; runtimeCastDef.defaultEmotePortrait.portraitAssetPath = portraitPath; ((DictionaryStore <CastDef>)UnityGameInstance.BattleTechGame.DataManager.CastDefs).Add(runtimeCastDef.id, runtimeCastDef); return(runtimeCastDef); }
// Generates a random quip and publishes it public static void PublishQuip(AbstractActor source, List <string> quips) { string quip = quips[Mod.Random.Next(0, quips.Count)]; string localizedQuip = new Localize.Text(quip).ToString(); CastDef castDef = Coordinator.CreateCast(source); DialogueContent content = Coordinator.BuildDialogueContent(castDef, localizedQuip, Color.white); Mod.Log.Info?.Write($"Publishing quip: {localizedQuip} with portrait: {castDef.defaultEmotePortrait.portraitAssetPath}"); source.Combat.MessageCenter.PublishMessage(new CustomDialogMessage(source, content, 3)); }
public AddDialogueChunk(string dialogueGuid, string dialogChunkName, string debugDescription, string cameraTargetGuid, bool usePresetDialog = true, string presetDialog = null, CastDef castDef = null) { this.dialogueGuid = dialogueGuid; this.dialogChunkName = dialogChunkName; this.debugDescription = debugDescription; this.cameraTargetGuid = cameraTargetGuid; if (usePresetDialog) { this.presetDialog = presetDialog; } this.castDef = castDef; }
// Generates a random quip and publishes it public static void PublishQuip(AbstractActor source, List <string> quips) { string quip = quips[Mod.Random.Next(0, quips.Count)]; string localizedQuip = new Localize.Text(quip).ToString(); CastDef castDef = Coordinator.CreateCast(source); DialogueContent content = new DialogueContent( localizedQuip, Color.white, castDef.id, null, null, DialogCameraDistance.Medium, DialogCameraHeight.Default, 0 ); content.ContractInitialize(source.Combat); source.Combat.MessageCenter.PublishMessage(new CustomDialogMessage(source, content, 3)); }
public static ConversationContent CreateConversationContent(string presetDialogue, string cameraTargetGuid, CastDef cast = null) { CastDef castDef = (cast == null) ? RuntimeCastFactory.CreateCast() : cast; if (MissionControl.Instance.IsSkirmish()) { presetDialogue = Regex.Replace(presetDialogue, "{COMMANDER\\..+}", "Commander"); } DialogueContent dialogueContent1 = new DialogueContent( presetDialogue, Color.white, castDef.id, "", cameraTargetGuid, BattleTech.DialogCameraDistance.Medium, BattleTech.DialogCameraHeight.Default, -1 ); ConversationContent conversation = new ConversationContent("Conversation MC Test 1", new DialogueContent[] { dialogueContent1 }); return(conversation); }
public static bool Prefix(TeamOverride __instance, Contract contract, DataManager dataManager, ref Contract ___contract, ref DataManager ___dataManager, ref string ___teamLeaderCastDefId, ref List <LanceOverride> ___lanceOverrideList, ref Faction ___faction) { ___contract = contract; ___dataManager = dataManager; if (___teamLeaderCastDefId == CastDef.castDef_TeamLeader_Current) { ___teamLeaderCastDefId = CastDef.GetCombatCastDefIdFromFaction(___faction, contract.BattleTechGame.DataManager); } for (int i = 0; i < ___lanceOverrideList.Count; ++i) { LanceOverride lanceOverride = ___lanceOverrideList[i]; lanceOverrides[lanceOverride.GetHashCode()] = __instance; IRBT14MadlibsFix.Logger.Log($"TO:RML setting teamOverride:[{__instance.GetHashCode()}] for lanceOverride:[{lanceOverride.GetHashCode()}]"); lanceOverride.RunMadLibs(contract); } return(false); }
public static DialogueGameLogic CreateDialogLogic(GameObject parent, string name, string cameraTargetGuid, string presetDialogue = null, CastDef castDef = null) { GameObject dialogueGameLogicGo = CreateDialogLogicGameObject(parent, name); DialogueGameLogic dialogueGameLogic = dialogueGameLogicGo.AddComponent <DialogueGameLogic>(); if (presetDialogue == null) { presetDialogue = DataManager.Instance.GetRandomDialogue("AllyDrop", MissionControl.Instance.CurrentContractType, MissionControl.Instance.EncounterRulesName); } dialogueGameLogic.conversationContent = CreateConversationContent(presetDialogue, cameraTargetGuid, castDef); return(dialogueGameLogic); }
public static void Prefix(AttackStackSequence __instance, MessageCenterMessage message) { stopwatch.Restart(); if (ShouldSkipProcessing(__instance, message)) { return; } if (!(message is AttackCompleteMessage attackCompleteMessage)) { return; } var director = __instance.directorSequences; if (director == null) { return; } LogReport(new string('═', 46)); LogReport($"{director[0].attacker.DisplayName} attacks {director[0].chosenTarget.DisplayName}"); // get the attacker in case they have mech quirks AbstractActor defender = null; switch (director[0]?.chosenTarget) { case Vehicle _: defender = (Vehicle)director[0]?.chosenTarget; break; case Mech _: defender = (Mech)director[0]?.chosenTarget; break; } // a building or turret? if (defender == null) { LogDebug("Not a mech or vehicle"); return; } if (defender.IsDead || defender.IsFlaggedForDeath) { return; } var attacker = director[0].attacker; var index = GetActorIndex(defender); if (modSettings.OneChangePerTurn && TrackedActors[index].PanicWorsenedRecently) { LogDebug($"OneChangePerTurn {defender.Nickname} - abort"); return; } if (!modSettings.AlwaysPanic && !ShouldPanic(defender, attackCompleteMessage.attackSequence)) { return; } // automatically eject a klutzy pilot on knockdown with an additional roll failing on 13 if (defender.IsFlaggedForKnockdown) { var defendingMech = (Mech)defender; if (defendingMech.pilot.pilotDef.PilotTags.Contains("pilot_klutz")) { if (Random.Range(1, 100) == 13) { defender.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage (new ShowActorInfoSequence(defender, "WOOPS!", FloatieMessage.MessageNature.Debuff, false))); LogReport("Very klutzy!"); return; } } } // store saving throw // check it against panic // check it again ejection var savingThrow = SavingThrows.GetSavingThrow(defender, attacker); Mech_AddExternalHeat_Patch.heatDamage = 0; // panic saving throw if (SavingThrows.SavedVsPanic(defender, savingThrow)) { return; } // stop if pilot isn't Panicked if (TrackedActors[index].PanicStatus != PanicStatus.Panicked) { return; } // eject saving throw if (!modSettings.AlwaysPanic && SavingThrows.SavedVsEject(defender, savingThrow)) { return; } // ejecting // random phrase if (modSettings.EnableEjectPhrases && defender is Mech && Random.Range(1, 100) <= modSettings.EjectPhraseChance) { var ejectMessage = ejectPhraseList[Random.Range(0, ejectPhraseList.Count)]; // thank you IRBTModUtils //LogDebug($"defender {defender}"); var castDef = Coordinator.CreateCast(defender); var content = new DialogueContent( ejectMessage, Color.white, castDef.id, null, null, DialogCameraDistance.Medium, DialogCameraHeight.Default, 0 ); content.ContractInitialize(defender.Combat); defender.Combat.MessageCenter.PublishMessage(new PanicSystemDialogMessage(defender, content, 6)); } // remove effects, to prevent exceptions that occur for unknown reasons var combat = UnityGameInstance.BattleTechGame.Combat; var effectsTargeting = combat.EffectManager.GetAllEffectsTargeting(defender); foreach (var effect in effectsTargeting) { // some effects removal throw, so silently drop them try { defender.CancelEffect(effect); } catch { // ignored } } if (modSettings.VehiclesCanPanic && defender is Vehicle) { // make the regular Pilot Ejected floatie not appear, for this ejection var original = AccessTools.Method(typeof(BattleTech.VehicleRepresentation), "PlayDeathFloatie"); var prefix = AccessTools.Method(typeof(VehicleRepresentation), nameof(VehicleRepresentation.PrefixDeathFloatie)); harmony.Patch(original, new HarmonyMethod(prefix)); defender.EjectPilot(defender.GUID, attackCompleteMessage.stackItemUID, DeathMethod.PilotEjection, true); harmony.Unpatch(original, HarmonyPatchType.Prefix); CastDef castDef = Coordinator.CreateCast(defender); DialogueContent content = new DialogueContent( "Destroy the tech, let's get outta here!", Color.white, castDef.id, null, null, DialogCameraDistance.Medium, DialogCameraHeight.Default, 0 ); content.ContractInitialize(defender.Combat); defender.Combat.MessageCenter.PublishMessage(new PanicSystemDialogMessage(defender, content, 5)); } else { defender.EjectPilot(defender.GUID, attackCompleteMessage.stackItemUID, DeathMethod.PilotEjection, false); } LogReport("Ejected"); //LogDebug($"Runtime {stopwatch.Elapsed}"); if (!modSettings.CountAsKills) { return; } try { // this seems pretty convoluted var attackerPilot = combat.AllMechs.Where(mech => mech.pilot.Team.IsLocalPlayer) .Where(x => x.PilotableActorDef == attacker.PilotableActorDef).Select(y => y.pilot).FirstOrDefault(); var statCollection = attackerPilot?.StatCollection; if (statCollection == null) { return; } if (defender is Mech) { // add UI icons.. and pilot history? ... MechsKilled already incremented?? // TODO count kills recorded on pilot history so it's not applied twice statCollection.Set("MechsKilled", attackerPilot.MechsKilled + 1); var stat = statCollection.GetStatistic("MechsEjected"); if (stat == null) { statCollection.AddStatistic("MechsEjected", 1); return; } var value = stat.Value <int>(); statCollection.Set("MechsEjected", value + 1); } // add achievement kill (more complicated) var combatProcessors = Traverse.Create(UnityGameInstance.BattleTechGame.Achievements).Field("combatProcessors").GetValue <AchievementProcessor[]>(); var combatProcessor = combatProcessors.FirstOrDefault(x => x.GetType() == AccessTools.TypeByName("BattleTech.Achievements.CombatProcessor")); // field is of type Dictionary<string, CombatProcessor.MechCombatStats> var playerMechStats = Traverse.Create(combatProcessor).Field("playerMechStats").GetValue <IDictionary>(); if (playerMechStats != null) { foreach (DictionaryEntry kvp in playerMechStats) { if ((string)kvp.Key == attackerPilot.GUID) { Traverse.Create(kvp.Value).Method("IncrementKillCount").GetValue(); } } } else if (modSettings.VehiclesCanPanic && defender is Vehicle) { var stat = statCollection.GetStatistic("VehiclesEjected"); if (stat == null) { statCollection.AddStatistic("VehiclesEjected", 1); return; } var value = stat.Value <int>(); statCollection.Set("VehiclesEjected", value + 1); } } catch (Exception ex) { LogDebug(ex); } }
public static void ProcessBatchedTurnDamage(AbstractActor actor) { int heatdamage = 0; if (ShouldSkipProcessing(actor)) { return; } AbstractActor attacker = TurnDamageTracker.attackActor(); LogReport($"\n{new string('═', 46)}"); LogReport($"Damage to {actor.DisplayName}/{actor.Nickname}/{actor.GUID}"); LogReport($"Damage by {attacker.DisplayName}/{attacker.Nickname}/{attacker.GUID}"); // get the attacker in case they have mech quirks AbstractActor defender = null; switch (actor) { case Vehicle _: defender = (Vehicle)actor; break; case Mech _: defender = (Mech)actor; break; } // a building or turret? if (defender == null) { LogDebug("Not a mech or vehicle"); return; } if (defender.IsDead || defender.IsFlaggedForDeath) { LogDebug("He's dead Jim....."); return; } var index = GetActorIndex(defender); if (modSettings.OneChangePerTurn && TrackedActors[index].PanicWorsenedRecently) { LogDebug($"OneChangePerTurn {defender.Nickname} - abort"); return; } float damageIncludingHeatDamage = 0; if (!modSettings.AlwaysPanic && !ShouldPanic(defender, attacker, out heatdamage, out damageIncludingHeatDamage)) { return; } // automatically eject a klutzy pilot on knockdown with an additional roll failing on 13 if (defender.IsFlaggedForKnockdown) { var defendingMech = (Mech)defender; if (defendingMech.pilot.pilotDef.PilotTags.Contains("pilot_klutz")) { if (Random.Range(1, 100) == 13) { defender.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage (new ShowActorInfoSequence(defender, "WOOPS!", FloatieMessage.MessageNature.Debuff, false))); LogReport("Very klutzy!"); return; } } } // store saving throw // check it against panic // check it again ejection var savingThrow = SavingThrows.GetSavingThrow(defender, attacker, heatdamage, damageIncludingHeatDamage); // panic saving throw if (SavingThrows.SavedVsPanic(defender, savingThrow)) { return; } if (!modSettings.OneChangePerTurn) { TurnDamageTracker.resetDamageTrackerFor(defender); } // stop if pilot isn't Panicked if (TrackedActors[index].PanicStatus != PanicStatus.Panicked) { return; } // eject saving throw if (!modSettings.AlwaysPanic && SavingThrows.SavedVsEject(defender, savingThrow)) { return; } // ejecting // random phrase if (modSettings.EnableEjectPhrases && defender is Mech && Random.Range(1, 100) <= modSettings.EjectPhraseChance) { var ejectMessage = ejectPhraseList[Random.Range(0, ejectPhraseList.Count)]; var castDef = Coordinator.CreateCast(defender); var content = Coordinator.BuildDialogueContent(castDef, ejectMessage, Color.white); defender.Combat.MessageCenter.PublishMessage(new PanicSystemDialogMessage(defender, content, 6)); } // remove effects, to prevent exceptions that occur for unknown reasons var combat = UnityGameInstance.BattleTechGame.Combat; var effectsTargeting = combat.EffectManager.GetAllEffectsTargeting(defender); foreach (var effect in effectsTargeting) { // some effects removal throw, so silently drop them try { defender.CancelEffect(effect); } catch { // ignored } } if (modSettings.VehiclesCanPanic && defender is Vehicle v) { // make the regular Pilot Ejected floatie not appear, for this ejection Patches.VehicleRepresentation.supressDeathFloatieOnce(); defender.EjectPilot(defender.GUID, -1, DeathMethod.PilotEjection, true); CastDef castDef = Coordinator.CreateCast(defender); var content = Coordinator.BuildDialogueContent(castDef, "Destroy the tech, let's get outta here!", Color.white); defender.Combat.MessageCenter.PublishMessage(new PanicSystemDialogMessage(defender, content, 5)); } else { defender.EjectPilot(defender.GUID, -1, DeathMethod.PilotEjection, false); } LogReport("Ejected"); //LogDebug($"Runtime {stopwatch.Elapsed}"); if (!modSettings.CountAsKills) { return; } //handle weird cases due to damage from all sources if (attacker.GUID == defender.GUID) { //killed himself - possibly mines or made a building land on his own head ;) LogReport("Self Kill not counting"); return; } if (attacker.team.GUID == defender.team.GUID) { //killed a friendly LogReport("Friendly Fire, Same Team Kill, not counting"); return; } if (TurnDamageTracker.EjectionAlreadyCounted(defender)) { return; } try { // this seems pretty convoluted var attackerPilot = combat.AllMechs.Where(mech => mech.pilot.Team.IsLocalPlayer) .Where(x => x.PilotableActorDef == attacker.PilotableActorDef).Select(y => y.pilot).FirstOrDefault(); var statCollection = attackerPilot?.StatCollection; if (statCollection == null) { return; } if (defender is Mech) { // add UI icons.. and pilot history? ... MechsKilled already incremented?? // TODO count kills recorded on pilot history so it's not applied twice -added a check above should work unless other mods are directly modifying stats statCollection.Set("MechsKilled", attackerPilot.MechsKilled + 1); var stat = statCollection.GetStatistic("MechsEjected"); if (stat == null) { statCollection.AddStatistic("MechsEjected", 1); } else { var value = stat.Value <int>(); statCollection.Set("MechsEjected", value + 1); } } else if (modSettings.VehiclesCanPanic && defender is Vehicle) { statCollection.Set("OthersKilled", attackerPilot.OthersKilled + 1); var stat = statCollection.GetStatistic("VehiclesEjected"); if (stat == null) { statCollection.AddStatistic("VehiclesEjected", 1); //return; } else { var value = stat.Value <int>(); statCollection.Set("VehiclesEjected", value + 1); } } try { object PlayerMechStats = playerMechStatsField.GetValue(CombatProcessor); bool result = (bool)tryGetValue.Invoke(PlayerMechStats, new[] { attackerPilot.GUID, mechCombatStats }); if (result) { incrementKillCount.Invoke(mechCombatStats, null); } } catch (Exception e) { LogError(e); // add achievement kill (more complicated) var combatProcessors = Traverse.Create(UnityGameInstance.BattleTechGame.Achievements).Field("combatProcessors").GetValue <AchievementProcessor[]>(); var combatProcessor = combatProcessors.FirstOrDefault(x => x.GetType() == AccessTools.TypeByName("BattleTech.Achievements.CombatProcessor")); // field is of type Dictionary<string, CombatProcessor.MechCombatStats> var playerMechStats = Traverse.Create(combatProcessor).Field("playerMechStats").GetValue <IDictionary>(); if (playerMechStats != null) { foreach (DictionaryEntry kvp in playerMechStats) { if ((string)kvp.Key == attackerPilot.GUID) { Traverse.Create(kvp.Value).Method("IncrementKillCount").GetValue(); } } } } var r = attackerPilot.StatCollection.GetStatistic("MechsEjected") == null ? 0 : attackerPilot.StatCollection.GetStatistic("MechsEjected").Value <int>(); LogDebug($"{attackerPilot.Callsign} SetMechEjectionCount {r}"); r = attackerPilot.StatCollection.GetStatistic("VehiclesEjected") == null ? 0 : attackerPilot.StatCollection.GetStatistic("VehiclesEjected").Value <int>(); LogDebug($"{attackerPilot.Callsign} SetVehicleEjectionCount {r}"); } catch (Exception ex) { LogDebug(ex); } }
public static CastDef CreateCast(AbstractActor actor) { string castDefId = $"castDef_{actor.GUID}"; if (actor.Combat.DataManager.CastDefs.Exists(castDefId)) { return(actor.Combat.DataManager.CastDefs.Get(castDefId)); } FactionValue actorFaction = actor?.team?.FactionValue; bool factionExists = actorFaction.Name != "INVALID_UNSET" && actorFaction.Name != "NoFaction" && actorFaction.FactionDefID != null && actorFaction.FactionDefID.Length != 0 ? true : false; string employerFactionName = "Military Support"; if (factionExists) { Mod.Log.Debug($"Found factionDef for id:{actorFaction}"); string factionId = actorFaction?.FactionDefID; FactionDef employerFactionDef = UnityGameInstance.Instance.Game.DataManager.Factions.Get(factionId); if (employerFactionDef == null) { Mod.Log.Error($"Error finding FactionDef for faction with id '{factionId}'"); } else { employerFactionName = employerFactionDef.Name.ToUpper(); } } else { Mod.Log.Debug($"FactionDefID does not exist for faction: {actorFaction}"); } CastDef newCastDef = new CastDef { // Temp test data FactionValue = actorFaction, firstName = $"{employerFactionName} -", showRank = false, showCallsign = true, showFirstName = true, showLastName = false }; // DisplayName order is first, callsign, lastname newCastDef.id = castDefId; string portraitPath = GetRandomPortraitPath(); newCastDef.defaultEmotePortrait.portraitAssetPath = portraitPath; if (actor.GetPilot() != null) { Mod.Log.Debug("Actor has a pilot, using pilot values."); Pilot pilot = actor.GetPilot(); newCastDef.callsign = pilot.Callsign; // Hide the faction name if it's the player's mech if (actor.team.IsLocalPlayer) { newCastDef.showFirstName = false; } } else { Mod.Log.Debug("Actor is not piloted, generating castDef."); newCastDef.callsign = GetRandomCallsign(); } Mod.Log.Debug($" Generated cast with callsign: {newCastDef.callsign} and DisplayName: {newCastDef.DisplayName()} using portrait: '{portraitPath}'"); ((DictionaryStore <CastDef>)UnityGameInstance.BattleTechGame.DataManager.CastDefs).Add(newCastDef.id, newCastDef); return(newCastDef); }