Checking for specific date

For all talk about quest development - creation, testing, and quest system bug diagnosis.
haloterm
Posts: 220
Joined: Sat Feb 16, 2019 5:21 am

Re: Checking for specific date

Post by haloterm »

Hazelnut wrote: Mon Feb 15, 2021 6:32 pm yes that's correct
Can I simply have the .cs file in my mod's "script" folder ("blackhorsecourier/scripts") or do I need to adher to the folder structure of DFU (like "blackhorsecourier/scripts/game/questing/actions")?

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

Re: Checking for specific date

Post by Hazelnut »

You can have it wherever you like since you register it with DFU it doesn't need to go looking.
See my mod code for examples of how to change various aspects of DFU: https://github.com/ajrb/dfunity-mods

haloterm
Posts: 220
Joined: Sat Feb 16, 2019 5:21 am

Re: Checking for specific date

Post by haloterm »

Hazelnut wrote: Tue Feb 16, 2021 7:31 pm You can have it wherever you like since you register it with DFU it doesn't need to go looking.
Hm... I am not sure how to do that correctly.

I have the following content of my action (posting it here, so maybe someone who knows what he's doing can tell me if that's basically correct; it should simply allow "yearly from day.month. to day.month." such as "yearly from 28.8. to 31.8."):

Code: Select all

// custom quest action for Black Horse Courier
//
// this creates a new quest action which checks if we are in a given range of days
//
// _Example_ task:
//     when yearly from 15.1. to 4.5.

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using DaggerfallWorkshop.Utility;
using FullSerializer;

namespace DaggerfallWorkshop.Game.Questing
{
    /// <summary>
    /// Raise or lower task state based on month
    /// Date must be in day1.month1. to day2.month2. (like "1.8. to 15.8." for August 8th to 15th)
    /// </summary>
    public class YearlyFrom : ActionTemplate
    {
        int day1;
        int day2;
        int month1;
        int month2;

        public override string Pattern
        {
            get { return @"yearly from (?<day1>\d+).(?<month1>\d+). to (?<day2>\d+).(?<month2>\d+)."; }
        }

        public YearlyFrom(Quest parentQuest)
            : base(parentQuest)
        {
            IsTriggerCondition = true;
            IsAlwaysOnTriggerCondition = true;
        }

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

            // Factory new action
            YearlyFrom action = new YearlyFrom(parentQuest);
            action.day1 = Parser.ParseInt(match.Groups["day1"].Value);
            action.day2 = Parser.ParseInt(match.Groups["day2"].Value);
            action.month1 = Parser.ParseInt(match.Groups["month1"].Value);
            action.month2 = Parser.ParseInt(match.Groups["month2"].Value);

            return action;
        }

        public override bool CheckTrigger(Task caller)
        {
            // Get live world time (day 1 to 30, month 1 to 12)
            DaggerfallDateTime worldTime = DaggerfallUnity.Instance.WorldTime.Now;
            int currentDay = worldTime.day;
            int currentMonth = worldTime.month;


            // Check if inside range
            if ((currentDay >= day1 && currentDay <= day2)  &&  (currentMonth >= month1 && currentMonth <= month2))
                return true;
            else
                return false;
        }


        #region Serialization

        [fsObject("v1")]
        public struct SaveData_v1
        {
            public int day1;
            public int day2;
            public int month1;
            public int month2;

        }

        public override object GetSaveData()
        {
            SaveData_v1 data = new SaveData_v1();
            data.day1 = day1;
            data.day2 = day2;
            data.month1 = month1;
            data.month2 = month2;

            return data;
        }

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

            SaveData_v1 data = (SaveData_v1)dataIn;
            day1 = data.day1;
            day2 = data.day2;
            month1 = data.month1;
            month2 = data.month2;
        }

        #endregion
    }
}
And then I have to put it somewhere with RegisterAction in my BlackHorseCourier.cs file:

Code: Select all

// Black Horse Courier

using System;
using System.Collections.Generic;
using UnityEngine;
using DaggerfallConnect;
using DaggerfallConnect.Arena2;
using DaggerfallConnect.FallExe;
using DaggerfallWorkshop;
using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Banking;
using DaggerfallWorkshop.Game.Guilds;
using DaggerfallWorkshop.Game.Questing;
using DaggerfallWorkshop.Game.Entity;
using DaggerfallWorkshop.Game.Formulas;
using DaggerfallWorkshop.Game.Items;
using DaggerfallWorkshop.Game.MagicAndEffects;
using DaggerfallWorkshop.Game.UserInterface;
using DaggerfallWorkshop.Game.UserInterfaceWindows;
using DaggerfallWorkshop.Game.Utility.ModSupport;
using DaggerfallWorkshop.Game.Utility.ModSupport.ModSettings;
using DaggerfallWorkshop.Utility;

namespace BlackHorseCourier
{
    public class BlackHorseCourier : MonoBehaviour
    {

        protected static string[] placesTable =
        {
            "TuluneCity,            0x435d, 1, -1",
            "CredenceHall,          0xc544, 1, -1",
            "Camelford,             0xc545, 1, -1",
            "Elizay,                0xc546, 1, -1",
            "OldLysoldasFarm,       0x3FA7, 1, -1",
            "PilgrimKynareth,       0x2E9E, 1, -1",
            "PilgrimMara,           0x38F2, 1, -1",
            "PilgrimDibella,        0x4FF4, 1, -1",
            "PilgrimAkatosh,        0x57B7, 1, -1",
            "PilgrimZenithar,       0x6582, 1, -1",
            "PilgrimArkay,          0x6681, 1, -1",
            "PilgrimStendarr,       0x67AF, 1, -1",
            "PilgrimJulianos,       0x72DC, 1, -1",
        };


        static Mod mod;

        [Invoke(StateManager.StateTypes.Start, 0)]
        public static void Init(InitParams initParams)
        {
            mod = initParams.Mod;
            var go = new GameObject(mod.Title);
            go.AddComponent<BlackHorseCourier>();
        }


        public static void InitMod()
        {
            Debug.Log("Begin mod init: BlackHorseCourier");

            Debug.Log("Registering quest list BlackHorseCourier");
            if (!QuestListsManager.RegisterQuestList("BlackHorseCourier"))
                throw new Exception("Quest list name is already in use, unable to register BlackHorseCourier quest list.");

            // Add additional data into the quest machine for the quests
            Debug.Log("Adding new BlackHorseCourier locations into quest places table");
            QuestMachine questMachine = GameManager.Instance.QuestMachine;
            questMachine.PlacesTable.AddIntoTable(placesTable);

            Debug.Log("Finished mod init: BlackHorseCourier");
        }


        void Awake()
        {
            //var settings = mod.GetSettings();
            // ---

            InitMod();

            mod.IsReady = true;
        }

    }
}
Intuitively, I would do that simply after I added my quests to the questmachine, but how do I tell RegisterAction to use my custom action?

I would write

// Register new quest action DaysInYear
questMachine.RegisterAction( SOMETHING )

but what should that "SOMETHING" be?

It seems RegisterAction requires a parameter of the type "IQuestAction", but I have no idea how to relate that to my custom action.

Sorry for these dumb questions, but I am no programmer, I can just programming in non-object oriented FreePascal, and I just want to write a simple quest that checks for a given month period -.- So I really have no idea what I am doing here. More help (or simply the required code lines) would be appreciated.

User avatar
TheLacus
Posts: 1322
Joined: Wed Sep 14, 2016 6:22 pm
Contact:

Re: Checking for specific date

Post by TheLacus »

Hi, this is how to register a new action:

Code: Select all

questMachine.RegisterAction(new YearlyFrom(null));
While not strictly required, I'd also suggest to put all your mod code inside namespace BlackHorseCourier, inlcuding custom action.
Mod System documentation - Learn how to create mods for Daggerfall Unity.
Modder Discussion - General help and discussion for the mod system.
Github Issues - Submit a bug report for the game, including the mod system.

haloterm
Posts: 220
Joined: Sat Feb 16, 2019 5:21 am

Re: Checking for specific date

Post by haloterm »

TheLacus wrote: Wed Feb 17, 2021 3:21 pm Hi, this is how to register a new action:

Code: Select all

questMachine.RegisterAction(new YearlyFrom(null));
While not strictly required, I'd also suggest to put all your mod code inside namespace BlackHorseCourier, inlcuding custom action.
Oh. That is easy :) Thank you.

I will also follow your namespace suggestion.

haloterm
Posts: 220
Joined: Sat Feb 16, 2019 5:21 am

Re: Checking for specific date

Post by haloterm »

Hmm.... after correcting a few typos (day instead of Day, month instead of Month) the scripts compile fine (checked in Unity editor with "precompile" option in mod builder).

However, it does not seem to have an effect while ingame. In the player.log I get

Unknown line signature encounted 'yearly from 1.1. to 30.12.'.

so it apparently does not recognize my action as valid.

(I use it in a test quest at the same place where usually one could use the "daily" action instead).

So either my action did not register successfully, or my pattern matching is wrong:

Code: Select all

public override string Pattern
        {
            get { return @"yearly from (?<day1>\d+).(?<month1>\d+). to (?<day2>\d+).(?<month2>\d+)."; }
        }

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

Re: Checking for specific date

Post by Hazelnut »

Dots are a special regex char that mean match any character, so they will need backspaces I think. It might be easier to use dashes as date component separators.

for example:

Code: Select all

        public override string Pattern
        {
            get { return @"yearly from (?<day1>\d+)-(?<month1>\d+) to (?<day2>\d+)-(?<month2>\d+)"; }
        }
should match "yearly from 1-1 to 30-12"
See my mod code for examples of how to change various aspects of DFU: https://github.com/ajrb/dfunity-mods

Post Reply