Adding custom quest action

Discuss modding questions and implementation details.
Post Reply
imsobadatnicknames
Posts: 371
Joined: Sun Jun 02, 2019 4:28 pm
Location: Colombia

Adding custom quest action

Post by imsobadatnicknames »

So. I recently released a mod called Pilgrimages (http://forums.dfworkshop.net/viewtopic. ... 783b88080b)

The gist of it is that it lets you go to wilderness shrines to pray to the divines. Most of the time, prayer will only get you some vague advice messages, but there's a chance that you will get a negative or positive effect, like being given an item, getting teleported to a random dungeon, being assigned a quest by one of the divines, getting your legal reputation modified, etc. All off this is handled through the quest system.

I intend to keep updating the mod with some more effects, and an effect i have had in mind since the start is being blessed/cursed with a week of good/bad luck. It'd essentially lower or raise your Luck attribute temporarily and then set it back to normal.

I think making this work with the rest of the mod would require to implement a custom quest action to modify player attributes. There is already some level of interaction between the quest system and player attributes, as actions like "when attribute Luck is at least 50" can clearly check the value of these player attribute variables, so the idea would be to introduce an action capable of modifying them, along the lines of "change attribute Luck +10"

I'm mostly a noob when it comes to Unity and C#. I did learn some basic stuff about using transforms and vector3 movement to make a mouselook fps character and using a raycast to create crosshair interaction a few months ago for a college project, but that's as much as I know.

I AM pretty good at figuring out how stuff works once I start fiddling around with it, but the scripts of a project as vast as DFU are so intimidating to even look at that I don't even know where to grab onto to start fiddling around with it.

So... I was hoping someone here in the forums could give at least some idea of where to start looking to eventually figure this out.
Last edited by imsobadatnicknames on Sun Oct 11, 2020 5:28 am, edited 3 times in total.
Released mods: https://www.nexusmods.com/users/5141135 ... files&BH=0
Daggerfall isn't the only ridiculously intrincate fantasy world simulator with the initials DF that I make mods for: http://www.bay12forums.com/smf/index.php?topic=177071.0

User avatar
Jay_H
Posts: 4061
Joined: Tue Aug 25, 2015 1:54 am
Contact:

Re: Adding custom quest action

Post by Jay_H »

You can see this article which outlines how to create a new quest action: https://www.dfworkshop.net/questing-par ... of-a-task/

I have some memory of Interkarma not allowing the quest system to influence character skills and stats, so I don't know how feasible that'd be. I will allow the Chief to correct me if in error :)

imsobadatnicknames
Posts: 371
Joined: Sun Jun 02, 2019 4:28 pm
Location: Colombia

Re: Adding custom quest action

Post by imsobadatnicknames »

Oh... alright. Even if it's 100% impossible I'll check that link out, since it's something I wanna learn to do regardless.

Thank you!
Released mods: https://www.nexusmods.com/users/5141135 ... files&BH=0
Daggerfall isn't the only ridiculously intrincate fantasy world simulator with the initials DF that I make mods for: http://www.bay12forums.com/smf/index.php?topic=177071.0

User avatar
Hazelnut
Posts: 3015
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Adding custom quest action

Post by Hazelnut »

If it's intended to be a temporary buff then it should probably add an incumbent effect. I know quest system can do spell effects but not sure it's possible.

If it's meant to be a permanent stat increase then a new action that increases the max stat should be easy to write.
See my mod code for examples of how to change various aspects of DFU: https://github.com/ajrb/dfunity-mods

imsobadatnicknames
Posts: 371
Joined: Sun Jun 02, 2019 4:28 pm
Location: Colombia

Re: Adding custom quest action

Post by imsobadatnicknames »

Hazelnut wrote: Sun Oct 11, 2020 11:01 am If it's intended to be a temporary buff then it should probably add an incumbent effect. I know quest system can do spell effects but not sure it's possible.

If it's meant to be a permanent stat increase then a new action that increases the max stat should be easy to write.
It's intended to be a temporary buff/debuff, but I also have plans for permanent stat increases. I mentioned that praying at a shrine might result in one of the divines assigning you a quest. Currently these quests have no reward and no consequence for failure, but I eventually intend to make it so that completing a quest for one of the divines gives you a permanent 1-point boost to a random attribute.

I read the article Jay linked and since last night I've been looking at the scripts in Assets/Scripts/Game/Questing/Actions and I'm beginning to understand how they work, except for the SaveData, GetSaveData and RestoreSaveData parts that every single one of them has towards the end. They look important but I have no idea what they do.

Also, looking at the DaggerfallStats script and came accross this:

Code: Select all

        // Mods are temporary changes to stat values from effects
        // Default is 0 - effects can raise/lower mod values during their lifecycle
        // This is designed so that effects are never operating on permanent stat values
        int[] mods = new int[Count];
        int[] maxMods = new int[Count];

Idk if it'll be useful for this but there's that :p
Released mods: https://www.nexusmods.com/users/5141135 ... files&BH=0
Daggerfall isn't the only ridiculously intrincate fantasy world simulator with the initials DF that I make mods for: http://www.bay12forums.com/smf/index.php?topic=177071.0

imsobadatnicknames
Posts: 371
Joined: Sun Jun 02, 2019 4:28 pm
Location: Colombia

Re: Adding custom quest action

Post by imsobadatnicknames »

Hazelnut wrote: Sun Oct 11, 2020 11:01 am .
I spent a while reading through the quest action scripts, and this ended up being my first attept at making one that modifies a character attribute.

Code: Select all

using System.Text.RegularExpressions;
using FullSerializer;
using DaggerfallConnect;
using System;

namespace DaggerfallWorkshop.Game.Questing
{
    /// <summary>
    /// Changes attribute by an ammount
    /// </summary>
    public class ChangeAttribute : ActionTemplate
    {

        int amount;

        DFCareer.Stats attribute;
        int minAttributeValue;

        public override string Pattern
        {
            get { return @"change attribute (?<attributeName>\w+) by (?<sign>[+-])(?<amount>\d+)"; }
        }

        public ChangeAttribute(Quest parentQuest)
            : base(parentQuest)
        {

        }

        public override IQuestAction CreateNew(string source, Quest parentQuest)
        {
            // Source must match pattern
            Match match = Test(source);
            if (!match.Success)
                return null;

            // Get signed value
            int value;
            string sign = match.Groups["sign"].Value;
            if (sign == "+")
                value = Parser.ParseInt(match.Groups["amount"].Value);
            else if (sign == "-")
                value = -Parser.ParseInt(match.Groups["amount"].Value);
            else
                throw new System.Exception("Invalid sign encountered by ChangeAttribute action");

            // Factory new action
            ChangeAttribute action = new ChangeAttribute(parentQuest);
            string attributeName = match.Groups["attributeName"].Value;
            if (!Enum.IsDefined(typeof(DFCareer.Stats), attributeName))
            {
                SetComplete();   
                throw new Exception(string.Format("ChangeAttribute: Attribute name {0} is not a known Daggerfall attribute", attributeName));
            }
            action.attribute = (DFCareer.Stats)Enum.Parse(typeof(DFCareer.Stats), attributeName);
            action.amount = value;

            return action;
        }

        public override void Update(Task caller)
        {
            GameManager.Instance.PlayerEntity.Stats.GetLiveStatValue(attribute) = GameManager.Instance.PlayerEntity.Stats.GetLiveStatValue(attribute) + amount;
        }

        #region Serialization

        [fsObject("v1")]
        public struct SaveData_v1
        {
            public DFCareer.Stats attribute;
            public int amount;
        }

        public override object GetSaveData()
        {
            SaveData_v1 data = new SaveData_v1();
            data.attribute = attribute;
            data.amount = amount;

            return data;
        }

        public override void RestoreSaveData(object dataIn)
        {
            if (dataIn == null)
                return;

            SaveData_v1 data = (SaveData_v1)dataIn;
            attribute = data.attribute;
            amount = data.amount;
        }
        
        #endregion
    }
}

So, i define a quest action with the syntax "change attribute (attributeName) by (sign)(amount)", then use "sign" and "amount" to create a "value" variable, and then paste that value back into the "amount" variable, like the ChangeReputeWith script does.

Now, since the WhenAttributeLevel script compares the current value of the attribute to the variable minAttributeValue by using "return GameManager.Instance.PlayerEntity.Stats.GetLiveStatValue(attribute) >= minAttributeValue;", my first wad that maybe assigning it a new value would be something like "GameManager.Instance.PlayerEntity.Stats.GetLiveStatValue(attribute) = GameManager.Instance.PlayerEntity.Stats.GetLiveStatValue(attribute) + amount;", but I was prepared to be completely wrong about it, and I was.

So, it'd be nice if someone could point me towards a script that modifies a player attribute by a value defined earlier in the script to check what would be the proper way to do it. I tried to find one before doing this but there are so many folders full of so many scripts that I kinda got lost.
Released mods: https://www.nexusmods.com/users/5141135 ... files&BH=0
Daggerfall isn't the only ridiculously intrincate fantasy world simulator with the initials DF that I make mods for: http://www.bay12forums.com/smf/index.php?topic=177071.0

imsobadatnicknames
Posts: 371
Joined: Sun Jun 02, 2019 4:28 pm
Location: Colombia

Re: Adding custom quest action

Post by imsobadatnicknames »

I tried to do it by adding a stat modifier with SetStatMod but I get a "The name 'SetStatMod' doesn't exist in the current context" compiler error.

Code: Select all


using System.Text.RegularExpressions;
using FullSerializer;
using DaggerfallConnect;
using DaggerfallConnect.Utility;
using DaggerfallConnect.FallExe;
using DaggerfallWorkshop.Utility;
using DaggerfallWorkshop.Game.Entity;
using DaggerfallWorkshop.Game.Items;
using DaggerfallWorkshop.Game.Utility;
using DaggerfallWorkshop.Game.Questing;
using System;

namespace DaggerfallWorkshop.Game.Questing
{
    /// <summary>
    /// Changes attribute by an ammount
    /// </summary>
    public class ChangeAttribute : ActionTemplate
    {

        int amount;

        DFCareer.Stats attribute;
        int minAttributeValue;

        public override string Pattern
        {
            get { return @"change attribute (?<attributeName>\w+) by (?<sign>[+-])(?<amount>\d+)"; }
        }

        public ChangeAttribute(Quest parentQuest)
            : base(parentQuest)
        {

        }

        public override IQuestAction CreateNew(string source, Quest parentQuest)
        {
            // Source must match pattern
            Match match = Test(source);
            if (!match.Success)
                return null;

            // Get signed value
            int value;
            string sign = match.Groups["sign"].Value;
            if (sign == "+")
                value = Parser.ParseInt(match.Groups["amount"].Value);
            else if (sign == "-")
                value = -Parser.ParseInt(match.Groups["amount"].Value);
            else
                throw new System.Exception("Invalid sign encountered by ChangeAttribute action");

            // Factory new action
            ChangeAttribute action = new ChangeAttribute(parentQuest);
            string attributeName = match.Groups["attributeName"].Value;
            if (!Enum.IsDefined(typeof(DFCareer.Stats), attributeName))
            {
                SetComplete();   
                throw new Exception(string.Format("ChangeAttribute: Attribute name {0} is not a known Daggerfall attribute", attributeName));
            }
            action.attribute = (DFCareer.Stats)Enum.Parse(typeof(DFCareer.Stats), attributeName);
            action.amount = value;

            return action;
        }

        public override void Update(Task caller)
        {
            SetStatMod(attribute, amount);
            SetComplete();
        }

        #region Serialization

        [fsObject("v1")]
        public struct SaveData_v1
        {
            public DFCareer.Stats attribute;
            public int amount;
        }

        public override object GetSaveData()
        {
            SaveData_v1 data = new SaveData_v1();
            data.attribute = attribute;
            data.amount = amount;

            return data;
        }

        public override void RestoreSaveData(object dataIn)
        {
            if (dataIn == null)
                return;

            SaveData_v1 data = (SaveData_v1)dataIn;
            attribute = data.attribute;
            amount = data.amount;
        }
        
        #endregion
    }
}
Idk if I should just accept that I just don't have enough C# knowledge to do something like this and shelf it for the time being
Released mods: https://www.nexusmods.com/users/5141135 ... files&BH=0
Daggerfall isn't the only ridiculously intrincate fantasy world simulator with the initials DF that I make mods for: http://www.bay12forums.com/smf/index.php?topic=177071.0

Post Reply