Beispiel #1
0
        // 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));
        }
 // The message type to send dialog through
 public CustomDialogMessage(AbstractActor dialogueSource, DialogueContent dialogueContent, float showDuration = 0f) : base()
 {
     this.dialogueSource     = dialogueSource;
     this.dialogueSourceGUID = dialogueSource.GUID;
     this.dialogueContent    = dialogueContent;
     this.showDuration       = showDuration != 0f ? showDuration : dialogueContent.GetDialogueTime();
 }
    private void ParseNewDialogue(int id)
    {
        _DBC_Dialogue dialogue = dialogues.Search_Index_EQU(id);

        if (dialogue == null)
        {
            return;
        }

        currIndex   = 0;
        currContent = new List <DialogueContent>();
        string[] temps = dialogue.diglogueGroup.Split(']');
        foreach (string item in temps)
        {
            if (item.Length <= 0)
            {
                continue;
            }

            string temp = item;
            temp = temp.Replace(",[", "");
            temp = temp.Replace("[", "");
            DialogueContent content = new DialogueContent();
            int             first   = temp.IndexOf('/');
            content.iconName = temp.Substring(0, first);
            int second = temp.IndexOf('/', first + 1);
            content.speakerName  = temp.Substring(first + 1, second - first - 1);
            content.speakContent = temp.Substring(second + 1, temp.Length - second - 1);

            currContent.Add(content);
        }
        return;
    }
Beispiel #4
0
    private void HandleDialogueInput()
    {
        if (currentDialogue == null || currentDialogue.selectionEvent == null)
        {
            return;
        }

        int index = currentDialogue.index;

        if (Input.GetKeyDown(KeyCode.S))
        {
            currentDialogue.index = Math.Min(index + 1, currentDialogue.values.Count - 1);
            RenderDialogue(currentDialogue);
        }
        else if (Input.GetKeyDown(KeyCode.W))
        {
            currentDialogue.index = Math.Max(0, index - 1);
            RenderDialogue(currentDialogue);
        }
        else if (Input.GetKeyDown(KeyCode.E))
        {
            SelectionEvent ev = currentDialogue.selectionEvent;
            currentDialogue = null;
            ev.Invoke(index);
        }
    }
        // Clone of DialogueContent::ApplyCastDef
        private static void ApplyCastDef(DialogueContent dialogueContent)
        {
            Contract contract = SharedState.Combat.ActiveContract;

            if (dialogueContent.selectedCastDefId == CastDef.castDef_TeamLeader_Employer)
            {
                TeamOverride teamOverride = contract.GameContext.GetObject(GameContextObjectTagEnum.TeamEmployer) as TeamOverride;
                dialogueContent.selectedCastDefId = teamOverride.teamLeaderCastDefId;
            }
            else if (dialogueContent.selectedCastDefId == CastDef.castDef_TeamLeader_EmployersAlly)
            {
                TeamOverride teamOverride2 = contract.GameContext.GetObject(GameContextObjectTagEnum.TeamEmployersAlly) as TeamOverride;
                dialogueContent.selectedCastDefId = teamOverride2.teamLeaderCastDefId;
            }
            else if (dialogueContent.selectedCastDefId == CastDef.castDef_TeamLeader_Target)
            {
                TeamOverride teamOverride3 = contract.GameContext.GetObject(GameContextObjectTagEnum.TeamTarget) as TeamOverride;
                dialogueContent.selectedCastDefId = teamOverride3.teamLeaderCastDefId;
            }
            else if (dialogueContent.selectedCastDefId == CastDef.castDef_TeamLeader_TargetsAlly)
            {
                TeamOverride teamOverride4 = contract.GameContext.GetObject(GameContextObjectTagEnum.TeamTargetsAlly) as TeamOverride;
                dialogueContent.selectedCastDefId = teamOverride4.teamLeaderCastDefId;
            }
            else if (dialogueContent.selectedCastDefId == CastDef.castDef_TeamLeader_Neutral)
            {
                TeamOverride teamOverride5 = contract.GameContext.GetObject(GameContextObjectTagEnum.TeamNeutralToAll) as TeamOverride;
                dialogueContent.selectedCastDefId = teamOverride5.teamLeaderCastDefId;
            }
            else if (dialogueContent.selectedCastDefId == CastDef.castDef_TeamLeader_Hostile)
            {
                TeamOverride teamOverride6 = contract.GameContext.GetObject(GameContextObjectTagEnum.TeamHostileToAll) as TeamOverride;
                dialogueContent.selectedCastDefId = teamOverride6.teamLeaderCastDefId;
            }
        }
        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);
        }
Beispiel #7
0
        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));
        }
        /// <summary>
        /// Given a dialogue object, switch to the dialogue menu and start the dialogue sequence.
        /// </summary>
        /// <param name="dialogue">The dialogue object containing the speaker name and sentences.</param>
        public static void ShowDialogue(DialogueContent dialogue, Action onDialogueComplete = null)
        {
            GoInto("MenuDialogue");

            MenuDialogueBehaviour menuDialogueBehaviour = GameObject.Find("Canvas").transform.Find("MenuDialogue")
                                                          .GetComponent <MenuDialogueBehaviour>();

            menuDialogueBehaviour.StartDialogue(dialogue, onDialogueComplete);
        }
Beispiel #9
0
    public DialogueSystem(TextAsset text, Text textUI, Image faceImage, Image bgImage, Image toNextImage = null)
    {
        dialogue       = new DialogueContent(text);
        dialogueText   = textUI;
        this.faceImage = faceImage;
        this.bgImage   = bgImage;
        toNextIcon     = toNextImage;

        InitProperties();
    }
        // 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));
        }
Beispiel #11
0
    /// <summary>
    /// Play dialogue.
    /// </summary>
    /// <param name="newContent">DialogueContent - new content scritable object.Null by default.</param>
    public void PlayDialogue(DialogueContent newContent = null)
    {
        if (!playing && dialogueRoutine == null)
        {
            if (newContent != null)
            {
                SetUpContent(newContent);
            }

            dialogueRoutine = StartCoroutine(PlayDialogueRoutine());
        }
    }
Beispiel #12
0
    protected override void OnAppear(int sequence, int openOrder, WindowContext context)
    {
        base.OnAppear(sequence, openOrder, context);
        Content = context as DialogueContent;
//        LeftIcon.sprite = Content.LeftIcon;
//        RightIcon.sprite = Content.RightIcon;
//        Content.LeftModel.transform.SetParent(LeftModel);
//        Content.RightModel.transform.SetParent(RightModel);
        LoadDialogueData(Content.FileName);
        this.NodeData = GetDialogue(Content.StartNode);
        Coroutine     = SingletonMono <GameFrameWork> .GetInstance().StartCoroutine(ShowContentText());
    }
        // 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));
        }
        /// <summary>
        /// Given a dialogue object, load the sentences and display the first sentence.
        /// </summary>
        /// <param name="dialogue">The dialogue object containing the speaker name and the sentences.</param>
        public void StartDialogue(DialogueContent dialogue, Action onDialogueComplete = null)
        {
            _speakerText.text = dialogue.Speaker;
            _sentences.Clear();
            _onDialogueComplete = onDialogueComplete;

            foreach (string sentence in dialogue.Sentences)
            {
                _sentences.Enqueue(sentence);
            }

            DisplayNextSentence();
        }
Beispiel #15
0
    public DialogueSystem(TextAsset text, GameObject Dialogue)
    {
        dialogue = new DialogueContent(text);

        GameObject dialogueObject = Dialogue;

        dialogueText = dialogueObject.transform.Find("Text").gameObject.GetComponentInChildren <Text>();
        faceImage    = dialogueObject.transform.Find("Face").gameObject.GetComponentInChildren <Image>();
        toNextIcon   = dialogueObject.transform.Find("ToNextIcon").gameObject.GetComponentInChildren <Image>();
        bgImage      = dialogueObject.transform.GetComponent <Image>();

        InitProperties();
    }
Beispiel #16
0
        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);
        }
Beispiel #17
0
 /// <summary>
 /// Set up new dialogue content.
 /// </summary>
 /// <param name="newContent">DialogueContent - New dialogue content</param>
 public void SetUpContent(DialogueContent newContent)
 {
     this.content = newContent;
 }
Beispiel #18
0
 private SelectionEvent SetDialogueContent(string text, List <string> selectionValues)
 {
     currentDialogue = new DialogueContent(text, selectionValues);
     RenderDialogue(currentDialogue);
     return(currentDialogue.selectionEvent);
 }
 public void AddDialogue(DialogueContent dialogueContent)
 {
     AddDialogue(dialogueContent.title, dialogueContent.content);
 }
Beispiel #20
0
    // Render the given DialogueContent instance onto the canvas.
    // Beware: This method does not care about the currently active
    //		   dialogue _at all_. It could lead to some weird bugs
    //		   if you call it outside of SetDialogueContent.
    private void RenderDialogue(DialogueContent content)
    {
        dialogueText.text = content.text;

        // If the caller did not specify any selection options we don't need
        // to do anything. In fact, we probably even want to hide the
        // scroll view.
        bool hasSelection = content.values != null && content.values.Count > 0;

        Text[] textChildArray = scrollContent.GetComponentsInChildren <Text>();

        if (hasSelection)
        {
            List <Text> children = new List <Text>(textChildArray);

            // These two if branches make sure that we have the exact amount
            // of text entries needed to accomodate all selection options
            if (children.Count < content.values.Count)
            {
                int missing = content.values.Count - children.Count;

                for (int i = 0; i < missing; i++)
                {
                    GameObject inst = Instantiate(selectionItemPrefab);
                    inst.transform.SetParent(scrollContent.transform, false);
                    children.Add(inst.GetComponent <Text>());
                }
            }
            else if (children.Count > content.values.Count)
            {
                int tooMany = children.Count - content.values.Count;

                for (int i = 0; i < tooMany; i++)
                {
                    // We need to remove from top to bottom, otherwise
                    // the entries shift and we remove the wrong ones
                    int index = children.Count - 1 - i;
                    Destroy(children[index].gameObject);
                    children.Remove(children[index]);
                }
            }

            int itemsPerPage = 2;
            int activePage   = content.index / itemsPerPage;

            // Set text and color for all text entries
            for (int i = 0; i < children.Count; i++)
            {
                Text child = children[i];
                int  page  = i / itemsPerPage;

                if (page == activePage)
                {
                    child.enabled = true;
                    child.text    = content.values[i];
                    child.color   = content.index == i ? highlightedColor : Color.black;
                }
                else
                {
                    child.enabled = false;
                }

                if (content.index == i)
                {
                    RectTransform scrollTransform = (RectTransform)scrollContent.transform;
                    Vector2       scrollPosition  = scrollTransform.anchoredPosition;

                    // We make the assumption that all menu items have the same height
                    RectTransform childTransform = (RectTransform)child.transform;
                    scrollPosition.y = childTransform.rect.height * activePage * itemsPerPage;

                    scrollTransform.anchoredPosition = scrollPosition;
                }
            }
        }
        else
        {
            foreach (Text child in textChildArray)
            {
                Destroy(child.gameObject);
            }
        }
    }
 public CustomDialogMessage(string dialogueSourceGUID, DialogueContent dialogueContent, float showDuration = 0f) : base()
 {
     this.dialogueSourceGUID = dialogueSourceGUID;
     this.dialogueContent    = dialogueContent;
     this.showDuration       = showDuration != 0f ? showDuration : dialogueContent.GetDialogueTime();
 }
Beispiel #22
0
        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)];
                // 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 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);
                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, -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);
                    }
                }

                // 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);
            }
        }
Beispiel #23
0
        void OnGUI()
        {
            if (dialogue == null)
            {
                return;
            }
            if (!isActive)
            {
                if (GUI.Button(new Rect(Screen.width * .5f, Screen.height * .5f, 200, 22), "Start Dialogue"))
                {
                    isActive = true;
                    dialogueController.startDialogue(this, this);
                }

                return;
            }

            const float uiRespHeight          = 22;
            const float uiRespBlockHeight     = uiRespHeight + 3;
            const float uiContentHeaderHeight = 20;
            const float uiContentOffset       = uiContentHeaderHeight + 3;
            const float uiContentHeight       = 105;
            const float uiResponseHeight      = 6 * uiRespHeight + 8;
            const float uiFullHeight          = uiContentHeight + uiResponseHeight;
            const float m = 4;

            float sw = Screen.width - 2 * m;
            float sh = Screen.height - m;

            Rect fullRect = new Rect(m, sh - uiFullHeight, sw, uiFullHeight);

            DialogueContent content = dialogueController.getCurrentContent();

            DialogueResponse[] responses   = dialogueController.getCurrentResponses();
            string             contentTxt  = content.text;
            string             charNameTxt = dialogue.characters[content.speakerId].name;

            GUI.BeginGroup(fullRect);
            GUI.Box(new Rect(0, 0, fullRect.width, fullRect.height), "");

            // Content block:
            Rect contRect   = new Rect(m, m + uiContentOffset, fullRect.width - 2 * m, uiContentHeight);
            Rect headerRect = new Rect(contRect.x, 0, contRect.width, uiContentHeaderHeight);

            GUI.Label(headerRect, string.Format("<b>{0}:</b>", charNameTxt));
            GUI.Label(contRect, contentTxt);

            // Response block:
            Rect respRect = new Rect(contRect.x, fullRect.height - uiResponseHeight - m, contRect.width, uiResponseHeight);

            GUI.BeginGroup(respRect);

            // Show all available response options:
            for (int i = 0; i < responses.Length; ++i)
            {
                Rect             iRespRect = new Rect(0, i * uiRespBlockHeight, respRect.width, uiRespHeight);
                DialogueResponse response  = responses[i];
                string           iRespTxt  = response.responseText;

                // Display each response as a simple button:
                if (GUI.Button(iRespRect, iRespTxt))
                {
                    // Call onto dialogue controller to select this response:
                    dialogueController.selectResponse(i);
                }
            }

            GUI.EndGroup();
            GUI.EndGroup();

            // Quest popup:
            float       questPopupDelta   = Time.time - uiQuestPopupTime;
            const float questPopupMaxTime = 3.0f;

            if (questPopupDelta < questPopupMaxTime)
            {
                Color prevCol = GUI.color;

                float alpha = 1 - Mathf.Clamp01((questPopupDelta - 1.0f) / (questPopupMaxTime - 1.0f));
                GUI.color = new Color(1, 0.75f, 0, alpha);
                GUI.Box(new Rect(Screen.width * .5f - 180, 128, 360, 60), "New Quest:\n<b>Saving the princess.</b>");

                GUI.color = prevCol;
            }
        }
Beispiel #24
0
        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);
            }
        }