Failed To Create Tale Object

Started by Worthy0ne, January 05, 2022, 02:23:05 PM

Previous topic - Next topic

Worthy0ne

Hi,

I am new to modding and I am trying to create a new recreation building. So far, I have made the building def, job def, and joyGiverDriver Def in my .xml file.
Right now, I am making the C# code for my "driverClass" for the job. So far its working as intended. my toils, inside my driverClass, walk the pawn to the building cell then the pawn throws horseshoes at it for X number of ticks then leaves but,
I am getting this error in-game when I test my building;

Failed to create tale object PlayedGame with parameters Bryn: System.MissingMethodException: Constructor on type 'RimWorld.Tale_SinglePawnAndDef' not found.
  at System.RuntimeType.CreateInstanceImpl (System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes, System.Threading.StackCrawlMark& stackMark) [0x00213] in <eae584ce26bc40229c1b1aa476bfa589>:0
  at System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x00095] in <eae584ce26bc40229c1b1aa476bfa589>:0
  at (wrapper dynamic-method) System.Activator.System.Activator.CreateInstance_Patch1(System.Type,object[])
  at RimWorld.TaleFactory.MakeRawTale (RimWorld.TaleDef def, System.Object[] args) [0x00000] in <cdbd0ed5089a418da09b9a259f9dbd8f>:0
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Verse.Log:Error (string)
RimWorld.TaleFactory:MakeRawTale (RimWorld.TaleDef,object[])
RimWorld.TaleRecorder:RecordTale (RimWorld.TaleDef,object[])
Verse.AI.Pawn_JobTracker:EndCurrentJob (Verse.AI.JobCondition,bool,bool)
Verse.AI.JobDriver:EndJobWith (Verse.AI.JobCondition)
Verse.AI.JobDriver:TryActuallyStartNextToil ()
Verse.AI.JobDriver:ReadyForNextToil ()
MyFirstMod.BoxDriver:<MakeNewToils>b__6_2 ()
Verse.AI.JobDriver:DriverTick ()
Verse.AI.Pawn_JobTracker:JobTrackerTick ()
Verse.Pawn:Tick ()
Verse.TickList:Tick ()
Verse.TickManager:DoSingleTick ()
Verse.TickManager:TickManagerUpdate ()
Verse.Game:UpdatePlay ()
Verse.Root_Play:Update ()


It happens after the driver executes all of the toils. I am guessing that (during a game) the "tale" is used when a pawn creates an art and writes something that has happened to a random pawn? I am not sure how I add a tale or where to put it in the code. Does this go in the xml or the C# code? Can I disable the need for a tale?

my C# code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Runtime.CompilerServices;
using RimWorld;
using Verse;
using Verse.AI;

namespace MyFirstMod
{
    public class BoxDriver : JobDriver
{
public float joyGainRate = 1f;
private int tickTime;
private int EndingTick = 1000;

public BoxDriver() : base()
{
tickTime = 0;
}

public override bool TryMakePreToilReservations(bool errorOnFailed)
{
return this.pawn.Reserve(this.job.targetA, this.job, this.job.def.joyMaxParticipants, 0, null, errorOnFailed) && this.pawn.ReserveSittableOrSpot(this.job.targetB.Cell, this.job, errorOnFailed) && (!base.TargetC.HasThing || !(base.TargetC.Thing is Building_Bed) || this.pawn.Reserve(this.job.targetC, this.job, ((Building_Bed)base.TargetC.Thing).SleepingSlotsCount, 0, null, errorOnFailed));
}

public override bool CanBeginNowWhileLyingDown()
{
return base.TargetC.HasThing && base.TargetC.Thing is Building_Bed && JobInBedUtility.InBedOrRestSpotNow(this.pawn, base.TargetC);
}

protected override IEnumerable<Toil> MakeNewToils()
{

Log.Message("Hello World!"); //Outputs "Hello World!" to the dev console.

        Toil toil1 = new Toil();
toil1.initAction = () =>
{
Find.Selector.Select(pawn);

};
toil1.defaultCompleteMode = ToilCompleteMode.Instant;
yield return toil1;

IntVec3 V1 = this.job.targetB.Cell;
V1 = V1 + new IntVec3(0,0,0);

Toil toil2 = Toils_Goto.GotoCell(V1, PathEndMode.OnCell); //Toils_Goto.GotoCell(TargetIndex.A, PathEndMode.OnCell);
yield return toil2;

Log.Message("waiting for timer");
Toil toil3 = new Toil();
toil3.initAction = () =>
{
Find.Selector.Select(pawn);

};
toil3.AddPreTickAction(() =>
{
if (tickTime > EndingTick)
ReadyForNextToil();
var rand = new Random();
int num = rand.Next(20);
if (num == 1)
FleckMaker.ThrowHorseshoe(this.pawn, base.TargetA.Cell);
});
toil3.tickAction = () =>
{
tickTime++;
};
toil3.AddFinishAction(() =>
{
Log.Message("finished timer");
});
toil3.defaultCompleteMode = ToilCompleteMode.Never;
yield return toil3;

}

public override string GetReport()
{
string repString = "playin with the box";

return repString;
}

protected virtual void WatchTickAction()
{
Log.Message("a");
if (this.pawn.IsHashIntervalTick(400))
{
Log.Message("bb");
FleckMaker.ThrowHorseshoe(this.pawn, base.TargetA.Cell);
}
this.pawn.rotationTracker.FaceCell(base.TargetA.Cell);
this.pawn.GainComfortFromCellIfPossible(false);
JoyUtility.JoyTickCheckEnd(this.pawn, JoyTickFullJoyAction.EndJob, 1f, (Building)base.TargetThingA);
}
}
}




Tell me if more information is needed, thanks.

Worthy0ne

It turns out I just needed to add this function,

public override object[] TaleParameters()
{
return new object[]
{
this.pawn,
base.TargetA.Thing.def
};
}


If anyone has insight on how this function works exactly, I'd love to know.