Esempio n. 1
0
    private bool Admire(Character player, Character npc, int bribeMod = 0)
    {
        // This essentially makes the calculations more likely to move towards 50
        var disposition = npc.GetDisposition(player);
        var d           = 1 - Abs(disposition - 50) * 0.02f;
        var target      = d * (GetAdmireRating(player) - GetAdmireRating(npc) + 50);

        target  = Max(PerMinChance, target);
        target -= Random.Range(0, 100);

        DialogRecord dialog;
        var          change = (int)(DieRollMult * target);

        if (change >= 0)
        {
            change = Max(PerMinChange, change);
            dialog = DialogRecord.GetPersuasionDialog(player, npc, PersuasionResult.AdmireSuccess);
        }
        else
        {
            dialog = DialogRecord.GetPersuasionDialog(player, npc, PersuasionResult.AdmireFail);
        }

        // Update the disposition in the UI
        npc.DispositionMod += Clamp(change, -disposition, 100 - disposition);
        controller.SetDisposition(npc.GetDisposition(player));

        // Display the response
        controller.DisplayTopic(dialog);

        return(change >= 0);
    }
Esempio n. 2
0
    // Displays a dialog choice, and assigns it a callback
    void IDialogView.DisplayChoice(string text, DialogRecord dialog, int choice)
    {
        var textClone = Instantiate(choicePrefab, infoParent);

        textClone.Initialize(text, () => ChoiceSelected(dialog, choice));
        currentChoices.Add(textClone);

        ScrollToBottom();
    }
    private void DisplayInfo(DialogRecord dialog, InfoRecord info)
    {
        // Replace any text defines with actual text
        var dialogText = TextDefineProcessor.ProcessText(info.Response, player, Npc);

        dialogText = CheckForTopicsInText(dialogText);
        dialogView.DisplayInfo(dialogText, dialog?.name);

        if (info.Result != null)
        {
            DialogResultProcessor.ProcessResult(this, info.Result, dialog, player, Npc);
        }
    }
Esempio n. 4
0
    // Don't need to do this every frame. Should make it a coroutine like above
    private void Update()
    {
        var random = Random.Range(0, 10000);
        var chance = voiceIdleOdds * Time.deltaTime;

        if (random < chance)
        {
            var audioClip = DialogRecord.GetDialogInfo(DialogType.Voice, GetComponent <Character>(), null, VoiceType.Idle.ToString());
            if (audioClip != null && audio != null)
            {
                audio.PlayOneShot(audioClip.AudioClip);
            }
        }
    }
Esempio n. 5
0
    private bool Bribe(Character player, Character npc, int amount)
    {
        var disposition = npc.GetDisposition(player);
        var d           = 1 - 0.02f * Abs(disposition - 50);

        var playerRating = (player.GetSkill(CharacterSkill.sSkillMercantile) + player.LuckTerm + player.PersonalityTerm) * player.FatigueTerm;
        var npcRating    = (npc.GetSkill(CharacterSkill.sSkillMercantile) + npc.ReputationTerm + npc.LuckTerm + npc.PersonalityTerm) * npc.FatigueTerm;

        float bribeMod;

        if (amount == 10)
        {
            bribeMod = GameSetting.Get("fBribe10Mod").FloatValue;
        }
        else if (amount == 100)
        {
            bribeMod = GameSetting.Get("fBribe100Mod").FloatValue;
        }
        else
        {
            bribeMod = GameSetting.Get("fBribe1000Mod").FloatValue;
        }

        var target3 = Max(PerMinChance, d * (playerRating - npcRating + 50) + bribeMod);
        var roll    = Random.Range(0, 100);

        var          change = (int)((target3 - roll) * DieRollMult);
        DialogRecord dialog;

        if (roll <= target3)
        {
            change = Max(PerMinChange, change);
            dialog = DialogRecord.GetPersuasionDialog(player, npc, PersuasionResult.BribeSuccess);
        }
        else
        {
            dialog = DialogRecord.GetPersuasionDialog(player, npc, PersuasionResult.BribeFail);
        }

        // Update the disposition in the UI
        npc.DispositionMod += Clamp(change, -disposition, 100 - disposition);
        controller.SetDisposition(npc.GetDisposition(player));

        // Display the response
        controller.DisplayTopic(dialog);

        return(roll <= target3);
    }
    void IDialogController.DisplayService(CharacterService service)
    {
        // Check if the service can be refused
        if (service.IsRefusable)
        {
            var dialog = DialogRecord.GetPersuasionDialog(player, Npc, PersuasionResult.ServiceRefusal);
            var info   = dialog.GetInfo(player, Npc, isServiceRefusal: true);

            // If a response was found, the service has been refused by the npc
            if (info != null)
            {
                DisplayInfo(dialog, info);
                return;
            }
        }

        service.DisplayService(this, player, Npc);
    }
Esempio n. 7
0
    // Adds a new topic to the topic list
    void IDialogView.AddTopic(DialogRecord topic)
    {
        // Convert tile to title case
        var title = char.ToUpper(topic.name[0]) + topic.name.Substring(1);

        // Create the UI game object
        var clone = Instantiate(topicPrefab, topicsParent);

        clone.Initialize(title, () => controller.DisplayTopic(topic));

        // Add it to the current list of topics, and sort
        currentTopics.Add(topic);
        currentTopics.Sort((x, y) => x.name.CompareTo(y.name));

        // Get the index and use it to position the transform in the list correctly
        var index = currentTopics.IndexOf(topic);

        clone.transform.SetSiblingIndex(index);
    }
    void IActivatable.Activate(GameObject target)
    {
        // Get the dialog component of the listener, so we can use it's NpcRecord
        player = target.GetComponent <Character>();

        // Get the npc greeting, as if there is no greeting, the Npc can't be talked to.
        var greeting = DialogRecord.GetDialogInfo(DialogType.Greeting, Npc, player);

        if (greeting == null)
        {
            return;
        }

        // Check if the listener knows the current topic, otherwise it will not be available
        // This could be done within the same loop as getting the dialog topic
        topics = DialogRecord.GetDialog(Npc, player);

        var knownTopics = new List <DialogRecord>();

        foreach (var topic in topics)
        {
            // Only show topics that the player knows
            if (player.Journal.Topics.ContainsKey(topic.name))
            {
                knownTopics.Add(topic);
            }
        }

        // Display services
        var services = GetComponents <CharacterService>();

        // Load the dialog and instantiate
        dialogView = DialogView.Create(this, record.FullName, knownTopics, services, Npc.GetDisposition(player));

        // Process the greeting after getting topics, or there will be no topics to check against
        DisplayInfo(null, greeting);

        // Set this last, so it isn't true the first time the player talks to an Npc.
        GetComponent <Character>().HasTalkedToPlayer = true;
    }
Esempio n. 9
0
    private bool Taunt(Character player, Character npc)
    {
        var disposition = npc.GetDisposition(player);
        var d           = 1 - 0.02f * Abs(disposition - 50);
        var target      = d * (GetAdmireRating(player) - GetAdmireRating(npc) + 50);

        target = Max(PerMinChance, target);

        var roll = Random.Range(0, 100);
        var win  = roll <= target;

        var change = Abs((int)(target - roll));
        var x      = (int)(-change * DieRollMult);

        if (win)
        {
            var s     = change * DieRollMult * PerTempMult;
            var flee  = Min(-PerMinChange, (int)(-s));
            var fight = Max(PerMinChange, (int)(s));

            if (Abs(x) < PerMinChange)
            {
                x = -PerMinChange;
            }
        }

        // Update the disposition in the UI
        npc.DispositionMod += Clamp(x, -disposition, 100 - disposition);
        controller.SetDisposition(npc.GetDisposition(player));

        // Display the response
        var dialog = DialogRecord.GetPersuasionDialog(player, npc, win ? PersuasionResult.TauntSuccess : PersuasionResult.TauntFail);

        controller.DisplayTopic(dialog);

        return(win);
    }
Esempio n. 10
0
    private IEnumerator Start()
    {
        // Do an intial overlap sphere so that any Npc's already in range of others don't greet eachother
        var colliders = Physics.OverlapSphere(transform.position, GreetDistance * greetDistanceMultiplier, LayerMask.GetMask("Npc"));

        foreach (var collider in colliders)
        {
            // Do a raycast to make sure the NPC is actually visible
            var        direction = collider.bounds.center - headTransform.position;
            RaycastHit hit;
            if (!Physics.Raycast(headTransform.position, direction, out hit, GreetDistance * greetDistanceMultiplier, LayerMask.GetMask("Default", "Npc", "Raycast Only")) ||
                hit.collider != collider)
            {
                continue;
            }

            greetedNpcs.Add(collider);
        }

        while (isActiveAndEnabled)
        {
            yield return(new WaitForSeconds(GreetUpdateInterval));

            // First, check if any of the previously-greeted Npc's have moved far enough away that they should be re-greeted if they get close. Add the greet distance to the rest ddistance, so that npcs with a long greet range don't re-greet players early
            greetedNpcs.RemoveWhere(col => Vector3.Distance(transform.position, col.transform.position) >= greetDistanceReset + GreetDistance * greetDistanceMultiplier);

            // Now periodically check for new Npcs, and if so, greet them
            colliders = Physics.OverlapSphere(headTransform.position, GreetDistance * greetDistanceMultiplier, LayerMask.GetMask("Npc"));
            foreach (var collider in colliders)
            {
                if (greetedNpcs.Contains(collider))
                {
                    continue;
                }

                // Raycast to the NPC first, to make sure there's nothing in the way. (This may not work, as it will probably raycast from the foot position
                var        direction = collider.bounds.center - headTransform.position;
                RaycastHit hit;
                if (!Physics.Raycast(headTransform.position, direction, out hit, GreetDistance * greetDistanceMultiplier, LayerMask.GetMask("Default", "Npc", "Raycast Only")) ||
                    hit.collider != collider)
                {
                    continue;
                }

                // Record this npc so we don't forget them
                greetedNpcs.Add(collider);

                // Get the Npc's NpcRecord
                var listener = collider.GetComponentInParent <DialogController>();
                if (listener == null)
                {
                    continue;
                }

                // Play greeting for any new Npc's detected
                var audioClip = DialogRecord.GetDialogInfo(DialogType.Voice, GetComponent <Character>(), listener.GetComponent <Character>(), VoiceType.Hello.ToString());
                if (audio != null)
                {
                    audio.PlayOneShot(audioClip.AudioClip);
                }
            }
        }
    }
Esempio n. 11
0
    private bool Intimidate(Character player, Character npc)
    {
        // Common
        var disposition   = npc.GetDisposition(player);
        var playerRating2 = GetAdmireRating(player) + player.LevelTerm;
        var npcRating2    = (npc.LevelTerm + npc.ReputationTerm + npc.LuckTerm + npc.PersonalityTerm + npc.GetSkill(CharacterSkill.sSkillSpeechcraft)) * npc.FatigueTerm;

        var d       = 1 - 0.02f * Abs(disposition - 50);
        var target2 = d * (playerRating2 - npcRating2 + 50);

        // Specific
        target2 = Max(PerMinChance, target2);
        var roll = Random.Range(0, 100);
        var win  = roll <= target2;

        var r = roll != target2?RoundToInt(target2 - roll) : 1;

        if (roll <= target2)
        {
            var s     = (int)(r * DieRollMult * PerTempMult);
            var flee  = Max(PerMinChange, s);
            var fight = Min(-PerMinChange, -s);
        }

        var c = -Abs((int)(r * DieRollMult));

        int x, y;

        if (win)
        {
            if (Abs(c) < PerMinChange)
            {
                x = 0;
                y = -PerMinChange;                 // bug, see comments?
            }
            else
            {
                x = -(int)(c * PerTempMult);
                y = c;
            }
        }
        else
        {
            x = (int)(c * PerTempMult);
            y = c;
        }

        var tempChange = x;

        // Clamp to 100
        var cappedDispositionChange = Clamp(disposition + tempChange, 0, 100) - disposition;

        // ANother clamp method?
        if (disposition + tempChange > 100)
        {
            cappedDispositionChange = 100 - disposition;
        }
        else if (disposition + tempChange < 0)
        {
            cappedDispositionChange = disposition;
        }

        if (win)
        {
            npc.DispositionMod += (int)(cappedDispositionChange / PerTempMult);
        }
        else
        {
            npc.DispositionMod += y;
        }

        // Update the disposition in the UI
        controller.SetDisposition(npc.GetDisposition(player));

        var dialog = DialogRecord.GetPersuasionDialog(player, npc, win ? PersuasionResult.IntimidateSuccess : PersuasionResult.IntimidateFail);

        // Display the response
        controller.DisplayTopic(dialog);

        return(win);
    }
Esempio n. 12
0
    private static void ShowChoices(IDialogController controller, IEnumerable <MethodArgument> parameters, DialogRecord dialog)
    {
        // Every second parameter should be a number?
        var previousChoice = string.Empty;

        foreach (var parameter in parameters)
        {
            if (parameter.Type == ArgumentType.String)
            {
                previousChoice = parameter.StringValue;
            }
            else if (parameter.Type == ArgumentType.Int)
            {
                var choice = parameter.IntValue;
                controller.DisplayChoice(previousChoice, dialog, choice);
            }
            else
            {
                throw new ArgumentException("Incorrect argument passed to Choices. Must be a String or Int");
            }
        }
    }
Esempio n. 13
0
    // Journal IC14_Ponius 45
    // player->additem gold_001 1000
    // Choice "Offer to track down the clerk and recover the gold." 1 "Thank him for his frankness and leave." 2
    // Journal "VA_VampChild" 100
    // Journal "VA_VampChild" 30
    // Player->additem "extravagant_ring_aund_uni" 1

    // Identifier space string space int
    // identifier arrow identifier space string space int
    // Identifier space string space int space string space int
    // identifier string int

    // "Minabibi Assardarainat"->PositionCell 217 846 74 190 "Sadrith Mora, Wolverine Hall: Mage's Guild"
    // String arrow Identifier int int int int

    public static void ProcessResult(IDialogController dialogView, string result, DialogRecord dialog, Character player, Character Npc)
    {
        var lexer  = new DialogResultLexer(result);
        var tokens = lexer.ProcessResult().ToList();

        var parser      = new DialogResultParser();
        var methodCalls = parser.ParseFile(tokens);

        foreach (var methodCall in methodCalls)
        {
            switch (methodCall.Method)
            {
            // Choice "Offer to track down the clerk and recover the gold." 1 "Thank him for his frankness and leave." 2
            case "choice":
            case "Choice":
            case "Choice,":
                ShowChoices(dialogView, methodCall.Args, dialog);
                break;

            default:
                Debug.Log(methodCall);
                break;
            }
        }

        return;

        // split the result into lines
        var stringReader = new StringReader(result);
        var parameters   = new List <string>();

        // Iterate through each line
        string line;

        while ((line = stringReader.ReadLine()) != null)
        {
            // Ignore any lines starting with a semi colon as they are comments
            if (line.StartsWith(";"))
            {
                continue;
            }

            // Get the function name by splitting the first two words. If no spaces are found, then no extra parameters exist
            // Split by spaces, and quotes?
            var phrase   = new StringBuilder();
            var inQuotes = false;
            for (var i = 0; i < line.Length; i++)
            {
                switch (line[i])
                {
                case ' ':
                    // If in quotes, append spaces to the parameter
                    if (inQuotes)
                    {
                        phrase.Append(line[i]);
                    }
                    else
                    {
                        // If not in quotes, add the current phrase to the list of parameters, and clear the string builder
                        // Ensure we're not adding empty spaces to the parameter list
                        if (phrase.ToString() != string.Empty)
                        {
                            parameters.Add(phrase.ToString());
                        }

                        phrase.Clear();
                    }
                    break;

                case '"':
                    inQuotes = !inQuotes;
                    break;

                default:
                    phrase.Append(line[i]);
                    break;
                }
            }

            // Append the last phrase from the string builder
            parameters.Add(phrase.ToString());

            // Process the function
            // This will probably eventually be replaced by a script interpreter/tokenizer thing, but for now see if this works.
            switch (parameters[0])
            {
            //case "additem":
            //	break;
            //case "addtopic":
            //case "Addtopic":
            //	break;
            // Choice is a word, followed by an option in Quotes, then a number specifying the index. This may occur multipel times
            //case "choice":
            //case "Choice": // Choice "Offer to track down the clerk and recover the gold." 1 "Thank him for his frankness and leave." 2
            //case "Choice,":
            //	ShowChoices(dialogView, parameters, dialog);
            //	break;
            //case "ClearInfoActor":
            // should not add this entry to journal
            //break;
            //case "Goodbye": // Show Goodbye choice, close dialog
            //break;
            case "Journal":                     //Jouranl ID Index, ID may be in quotes (But not always?)
            case "Journal,":
            case "Journal.":
                var exists = player.Journal.AddOrUpdateEntry(parameters[1], int.Parse(parameters[2]));
                if (!exists)
                {
                    dialogView.DisplayResult(GameSetting.Get("sJournalEntry").StringValue);
                }
                break;

            case "moddisposition":
            case "ModDisposition":                     // Followed by a space? and then a number (can be positive or negative)
                Npc.DispositionMod += int.Parse(parameters[1]);
                dialogView.SetDisposition(Npc.GetDisposition(player));
                break;

            //case "ModPCFacRep": //ModPCFacRep 10 "Fighters Guild"
            //	break;
            case "player->AddItem,":
            case "player->Additem,":
            case "Player->AddItem":
            {
                var item = Record.GetRecord <ItemRecord>(parameters[1].TrimEnd(','));
                // If a second parameter exists, it may be the count
                int quantity = parameters.Count > 2 ? int.Parse(parameters[2]) : 1;
                player.Inventory.AddItem(item, quantity);
                var message = GameSetting.Get(quantity == 1 ? "sNotifyMessage60" : "sNotifyMessage61").StringValue;
                message = message.Replace("%s", item.FullName);
                message = message.Replace("%d", quantity.ToString());
                dialogView.DisplayResult(message);
            }
            break;

            //case "PCClearExpelled": // Makes the PC no longer expelled from the speakers faction (Unsure if sometimes followed by a parameter)
            //break;
            case "PCJoinFaction":                     // Should be followed by the faction name eg PCJoinFaction "Mages Guild"
                player.JoinFaction(Record.GetRecord <Faction>(parameters[1]));
                break;

            // This can also appear instead of joining the faction, so must join the faction first if not a member
            //PCRaiseRank "Hlaalu" (This may not have the faction name written after, in which case the speaker's faction should be used)
            case "PCRaiseRank":
                if (!Npc.IsInSameFaction(player))
                {
                    player.JoinFaction(Npc.Factions.First().Key);
                }
                else
                {
                    player.Factions[Npc.Factions.First().Key].Rank++;
                }
                break;

            case "player->removeitem":
            {
                var item = Record.GetRecord <ItemRecord>(parameters[1].TrimEnd(','));
                player.Inventory.RemoveItem(item, 1);
                var message = GameSetting.Get("sNotifyMessage62").StringValue;
                message = message.Replace("%s", item.FullName);
                dialogView.DisplayResult(message);
            }
            break;

            //case "set":
            //	if (parameters.Count > 1) Debug.Log(parameters[1]);
            //	break;
            //case "ShowMap":
            //	break;
            default:
                // Should check string for a "->" character, if found, the first part is object id, i.e.:
                //  arrille->moddisposition
                // Should search for an object ID here, and if found, look for the -> symbol, then switch on what follows eg(Player->AddItem Gold_001 500)
                parameters.ForEach((param) => Debug.Log(param));
                break;
            }

            // Clear the list of parameters for the next iteration
            parameters.Clear();
        }
    }
Esempio n. 14
0
 public void AddTopic(string topic, DialogRecord dialog)
 {
     topics[topic] = dialog;
 }
    void IDialogController.DisplayTopic(DialogRecord dialog, int choice)
    {
        var info = dialog.GetInfo(player, Npc, choice);

        DisplayInfo(dialog, info);
    }
Esempio n. 16
0
 private void ChoiceSelected(DialogRecord dialog, int choice)
 {
     controller.DisplayTopic(dialog, choice);
     currentChoices.ForEach(component => Destroy(component.gameObject));
     currentChoices.Clear();
 }
Esempio n. 17
0
    public static void Create(BinaryReader reader)
    {
        var header = new RecordHeader(reader);

        switch (header.Type)
        {
        case RecordType.BirthSign:
            BirthSignRecord.Create(reader, header);
            break;

        case RecordType.BodyPart:
            BodyPartRecord.Create(reader, header);
            break;

        case RecordType.Cell:
            CellRecord.Create(reader, header);
            break;

        case RecordType.Dialogue:
            DialogRecord.Create(reader, header);
            break;

        case RecordType.GameSetting:
            GameSetting.Create(reader, header);
            break;

        case RecordType.Info:
            InfoRecord.Create(reader, header);
            break;

        case RecordType.Land:
            LandRecord.Create(reader, header);
            break;

        case RecordType.LandTexture:
            LandTextureRecord.Create(reader, header);
            break;

        case RecordType.MagicEffect:
            MagicEffectRecord.Create(reader, header);
            break;

        case RecordType.PathGrid:
            Pathgrid.Create(reader, header);
            break;

        case RecordType.Script:
            Script.Create(reader, header);
            break;

        case RecordType.Skill:
            SkillRecord.Create(reader, header);
            break;

        case RecordType.SoundGenerator:
            SoundGenerator.Create(reader, header);
            break;

        case RecordType.Tes3:
            Tes3Record.Create(reader, header);
            break;

        default:
        {
            var size = GotoSubrecord(SubRecordType.Id, header);
            var id   = reader.ReadString(size);
            reader.BaseStream.Position = header.DataOffset + header.DataSize;
            var recordData = CreateRecordData(header.Type);
            recordData.Header = header;
            Records.Add(id, recordData);
            break;
        }
        }
    }
 void IDialogController.DisplayChoice(string description, DialogRecord dialog, int choice) => dialogView.DisplayChoice(description, dialog, choice);