Replies: 16 (Who?), Viewed: 1497 times.
Lab Assistant
Original Poster
#1 Old 14th Jul 2015 at 9:44 PM
Default Understanding Dreamtrees
So, after getting my first Hello World mod to work and confirming that yes, I can compile a coding mod, I have bitten off more than I can chew, as per usual for me learning stuff. Namely, I'm trying to understand dreamtrees in hopes of creating my own to allow teens to have the relevant wants for use with the NRaas Woohooer. I know something similar has been done elsewhere, but this is not about that, this is about me making my own to see if I can and to understand the game a bit better.

And it's not going all that bad in trying to wrap my head around it, mainly thanks to this tutorial by Velocitygrass, but I am still a little confused, and my search-fu is failing me on finding more details, so... I have to ask.

If I understand a Dreamtree right, it's a hierarchy. You have wishes that get fulfilled which in turn allows new wishes to show and so on. Hence "tree". And most of the properties of an <InstanceNode> do seem rather straightforward. But not all of them, so, I would like to doublecheck the important ones, before I start building a tree.

I'm fairly sure I got these right:
<id> is the ID of the NODE. It has to be unique, but apparently there is no discernible pattern for it. Just that is has to be unique. FV32 hashes of unique names seem good enough.
<parentid> is the ID of the node one higher in the tree.
<protypeid> is the ID of the want itself, pulled from S3_0333406C_00000000_9A976C90ECC75C81_DreamsAndPromisesNodes%%+_XML.xml
<DreamVisible>, <AgeGroups>, and <Traits> seem self-explanatory, but some have internal names different from the ones displayed in-game.

I have no idea about these:
<Center> has an <X> and a <Y> value and I have no idea whatsoever why on earth this exists. Why does it have coordinates? Do they matter, or can I input random numbers?
<IsRoot> I mean, I get it in so far as this is where the tree starts, but can I choose to anchor it to another dreamtree by using a <parentid> from one of the default trees? And if the tree has its own root, how do I get it to show up?

There are some minor details I want to look for, but I figure if I find similar nodes in the official trees, I can copy off those. Wouldn't want all the fun of discovery removed. I could use a delay timer node that just holds, but I'll see if I can find one of those myself before asking.

As an aside, I have been unable to find the function to create one of those little yellow messages in the top-right. Would be nice for debugging purposes, since dreamtrees are silent until something happens. I know "SimpleMessageDialog.Show()" from Sims3.UI to make a dialog box, but I can't find the other one. I'm probably overlooking something obvious there.

Also, just in case anyone has traveled this path before me... are those specific wants locked down in some way? Can I use the existing primitives or will I have to make new ones?
Advertisement
Inventor
#2 Old 16th Jul 2015 at 9:35 PM Last edited by Arsil : 17th Jul 2015 at 8:03 AM.
Oh my, I miss helping people here, but I don't have that combination of time+energy+enthusiasm
any more and I have to admit that, even if I loved it (maybe even more than making mods), it was
very stressful, because I would have felt bad leaving messages unanswered so I tried to reply to
every single one, even when I didn't have much to say, especially about meshing :P
EDIT: also, even if it takes me a lot of time and effort to write in a almost decent English,
I sure don't mind to expatiate...
--------

--------
Quote:
Also, just in case anyone has traveled this path before me... are those specific wants locked down in some way? Can I use the existing primitives or will I have to make new ones?

Not many traveled this path.

I'm not sure if "wants" is the right term for them (or at least I always mix them up!), so I'll call them with
their technical name: [Dream]NodePrimitives. Yes, you can refer to the existing ones and I'll tell you
more, make your own isn't that trivial (you have to "inject" a custom entry to the DreamNames'
enum and the CheckFunction and FeedbackFunction can only refer to a specific EA's namespace+dll,
so to use custom methods you have to use a scripting workaround or rewrite the parsing method).

If you need another reference, other than the amazing velocitygrass's work, you can take
a look at another groundbreaking modder, SimsMX, and his Hypochondriasis mod
(you can find it on SimLogical).
There's also been a thread in this very section some time ago, asking about the correlation
between lifetime wishes (those you choose on CAS while creating a Sim) and traits, you can
check that too but I doubt there's much information there. As far as I know (or I should say
remember, since I've a crappy memory), there's nothing about wishes/dreams/promises on NRaas Mods.
--------
I can't find the point where the <Center> tag is parsed . Being defined inside an InstanceNode,
it should be parsed by ParseNodeInstance, called inside ParseDreamTreeByKey, but I can't
find it anywhere. Maybe I'm simply missing it or maybe it's an obsolete tag ignored by the
latest versions of the game.

About your other question, logically I'd say that if an InstanceNode is defined as "root" then
it can't/shouldn't reference another node using the <ParentId> tag, but you can try to search
for counterexamples.
--------
If you make any progress, please share, I might or might not be interested in this subject myself.
Inventor
#3 Old 17th Jul 2015 at 10:08 AM Last edited by Arsil : 17th Jul 2015 at 3:12 PM.
I got news, it's about the localization of the NodePrimitive (be it a wish or a dream).
This is already hinted in the tutorial maybe, but it's not stated clearly (since it says
to use NRaas ErrorTrap - that may be an outdated info, now that function is done
by NRaas UntranslatedKey AFAIK - to get the hashing key).

Code:
	Gameplay/Dreams/ID_IN_HEX_FORMAT_WITHOUT_0x:GenericName
	Gameplay/Dreams/ID_IN_HEX_FORMAT_WITHOUT_0x:FemaleName
	Gameplay/Dreams/ID_IN_HEX_FORMAT_WITHOUT_0x:MaleName
	Gameplay/Dreams/ID_IN_HEX_FORMAT_WITHOUT_0x:Description

Stupid smiley... that is - without blanks - "0 x : Description" (EDIT: oh, maybe I removed the smiley)

So, if the Id of the NodePrimitive (which must be the same as the guid of the custom entry of the DreamNames' enum)
is for example 3339161187 (hex 0xC7078E63), value taken from Sims_MX's mod - don't use it, then the STBL keys are:
Code:
	Gameplay/Dreams/C7078E63:GenericName ---> (FNV64 = 0xDA81D...)
	Gameplay/Dreams/C7078E63:FemaleName
	Gameplay/Dreams/C7078E63:MaleName
	Gameplay/Dreams/C7078E63:Description


Note that there may be a difference in the meaning of the 2nd and 3rd string that depends
if we're talking about a lifetime wish or a dream/promise. velocitygrass hints at the bullet
points in the description of the lifetimewish, while in case of a dream/promise they may
actually be used for a male/female target.

Another thing I noticed is that the parser doesn't like IDs in hex format in the dreamTree's xml
(I haven't verified if this is true for all of them - treehash/Id/ParentId/PrototypeId - or just some)
because it throws an exception, while the hex format seem accepted in the nodePrimitives's xml.
I like to specify the IDs with the hex format, that helped me to make the connection with the STBL key.
Lab Assistant
Original Poster
#4 Old 17th Jul 2015 at 4:03 PM
Wow that's a lot of info. So <Center> is a localization tag? Hm, I'd imagine it has something to do with the position of the text, then. Well, I'll give it a pass over when everything else is running. I'll file it mentally as "not important yet." It might be eventually, but I'll worry about it then. So far this mod is for personal use. But I do have that Perfectionist trait myself, so... Once it works I will need it to look like it was always there.

So far, so good, though. It compiles and runs in game. Had to make all of Sims3.Gameplay.Systems public, which turned ugly as ILASM didn't want to run, so yeah. But it's done now. I put in a SimpleMessageDialog.Show on the main menu, which is where I think it needs to hit, and sure enough, a popup appears there. But I cannot tell if the tree is being loaded or not, and I have no clue how to see the loaded DreamTrees ingame, if that's even possible. Sure would be handy, even if it just dumps it as text. I can just search for one of my <id> numbers then. Which are all decimal.

So, I'm kind of in debugging mode now. Either I'm loading it wrong (which is definitely an option since I am no C# wizard) or there's an issue with the tree itself. Maybe I should make a "Sleep for 5 hours -> Meet Someone New" tree or similar just to have an easy trigger for a non-specific wish. I'm still not entirely sure what wish is a good root wish anyway. Something that happens easily, or something wholly automatic. And I'm pretty sure a few of the standard ones don't have a Root wish. Sure would be nice to be able to tag along one of the built in trees. I know those run, after all.

I will say this, though. I have a lot more respect for people who can do this now. XML mods are easy. Pure scripting and DreamTrees? Not so much. I may have found out why I rarely see any mods that have to do with wishes... and I'm fumbling nearly blind at them. That's the strength of a newbie modder, though. No sense of danger.
Inventor
#5 Old 17th Jul 2015 at 6:42 PM
Quote:
Originally Posted by McNum
So <Center> is a localization tag?


I didn't say that and I don't think so. Those were two separate topics.

Quote:
I put in a SimpleMessageDialog.Show on the main menu, which is where I think it needs to hit, and sure enough, a popup appears there. But I cannot tell if the tree is being loaded or not, and I have no clue how to see the loaded DreamTrees ingame, if that's even possible. Sure would be handy, even if it just dumps it as text. I can just search for one of my <id> numbers then. Which are all decimal.


That should be easy. For a NodePrimitive, you can use this:
Code:
// after the parsing of your xml file has been done
DreamNodePrimitive dnp = DreamsAndPromisesManager.GetPrimitive(DREAM_NODE_PRIMITIVE_ID);
if (dnp == null) DebugMsg("DNP #<number> NOT added");
else DebugMsg("DNP #<number> added succesfully");

The ID is the one you used in the xml for the DreamNodePrimitives (and, I'll say it one more time to
be clear, it's also the guid/value of the injected DreamNames' enum). By the way, this is the system I'm
planning to use to set a custom CheckFunction and FeedbackFunction: instead of partially rewriting
the parser, I'll put a placeholder value in the xml and then I'll retrieve the node and replace the functions
from the code in this way:
Code:
dnp.mCheckFunction = CUSTOM_METHOD1;
dnp.mFeedbackFunction = CUSTOM_METHOD2;

This is also how I fixed the "Throw a great party" dream/wish, replacing its feedback function
with one that takes into account the party outcomes introduced by UL.

But you asked about the dreamTree, not the NodePrimitives, right? I guess you can do something like that
also for the dreamTree and its single nodeInstances. Something like (it's only pseudo-code)
Code:
DreamTree dt =  DreamsAndPromisesManager.sDreamTrees.Get(treeHash or name);
...
dt.mNodePrimitives.Get(ID);


Even if you are trying to do a mod for personal use, I hope you are willing to share your experience/results.
If no one shares, it's hard to make progresses. GL.
Lab Assistant
Original Poster
#6 Old 17th Jul 2015 at 8:55 PM
Quote:
Originally Posted by Arsil
I didn't say that and I don't think so. Those were two separate topics.

Ah. My mistake. Well, my approach will remain "Unless it breaks something I'm working on right now, I'll fix it later." I can grab sane X and Y values off the default DreamTrees. Just gotta search for the same ProtypeId and and grab a set from there.

Quote:
Originally Posted by Arsil
That should be easy. For a NodePrimitive, you can use this:
Code:
// after the parsing of your xml file has been done
DreamNodePrimitive dnp = DreamsAndPromisesManager.GetPrimitive(DREAM_NODE_PRIMITIVE_ID);
if (dnp == null) DebugMsg("DNP #<number> NOT added");
else DebugMsg("DNP #<number> added succesfully");

The ID is the one you used in the xml for the DreamNodePrimitives (and, I'll say it one more time to
be clear, it's also the guid/value of the injected DreamNames' enum). By the way, this is the system I'm
planning to use to set a custom CheckFunction and FeedbackFunction: instead of partially rewriting
the parser, I'll put a placeholder value in the xml and then I'll retrieve the node and replace the functions
from the code in this way:
Code:
dnp.mCheckFunction = CUSTOM_METHOD1;
dnp.mFeedbackFunction = CUSTOM_METHOD2;

This is also how I fixed the "Throw a great party" dream/wish, replacing its feedback function
with one that takes into account the party outcomes introduced by UL.

I'll keep this in mind in case the mod grows in the making. If I need something and it just doesn't exists, I'll have to make my own NodePrimitives, but for now, I'm sticking with the default Dreams and Promises XML file. Depending on how the game reacts to rolling a Woohoo wish on a teen Sim, I am prepared to create duplicate Nodes just to avoid the default ones. But I'll fight that fight when it becomes clear that it has to be fought.

That said, the DebugMsg thing is interesting. Does that make a text dump in my The Sims 3 folder? I'll assume for a DreamTree, I can either check for the tree's hash or check if one of the InstanceNodes exists in the DreamsAndPromisesManager.

Also, as an aside, you fixed the Threw a Great Party want? I had noticed that it was inconsistent in getting fulfilled.
Quote:
Originally Posted by Arsil
But you asked about the dreamTree, not the NodePrimitives, right? I guess you can do something like that
also for the dreamTree and its single nodeInstances. Something like (it's only pseudo-code)
Code:
DreamTree dt =  DreamsAndPromisesManager.sDreamTrees.Get(treeHash or name);
...
dt.mNodePrimitives.Get(ID);


Even if you are trying to do a mod for personal use, I hope you are willing to share your experience/results.
If no one shares, it's hard to make progresses. GL.

Yeah, been trying to think what my mod really needs to do and it's on paper quite simple. I need to add my own DreamTree to the DreamsAndPromisesManager, which I'm assuming has already parsed all the default ones by the time my mod fires up. (But may need to check on the load order, or make it so it works no matter if it's first, middle, or last in a DreamTree load order.) Bluntly speaking, though, I'm trying to do "DreamTrees += MyDreamTree" I just have to figure out how and where to do that.

And of course I'll share whatever works or fails. I'm quite well aware that I'm leaning heavily on the work of others who have graciously decided to share their methods with me. It's only fair that I repay in kind. I just don't have anything really share-worthy yet. Hopefully I will over the weekend. I am a relentless commenter when I code, though, for my own sake, so if I get code to share, it'll hopefully be easy to follow. As long as I know what's going on myself.

If i get it to work, I'll post my source code here for the community's sake and to ask for improvements, maybe. If I cannot get it to work, I'll likely do that same and ask "What can I do about this?" Either way, I'll post it. I just want first go at getting it to work. I still have some ideas on what to try. The battle has only just begun.

I have a feeling I chose poorly for a first proper scriptmod, though. Could have gone with something easy, but nope. DreamsAndPromisesManager. Ah well, I am learning and progressing, albeit slowly. So, onwards!
Inventor
#7 Old 17th Jul 2015 at 9:38 PM
DebugMsg is just a wrapper, you can put whatever you want inside it, I usually simply call SimpleMessageDialog.Show()

Quote:
I need to add my own DreamTree to the DreamsAndPromisesManager, which I'm assuming has already parsed all the default ones by the time my mod fires up. (But may need to check on the load order, or make it so it works no matter if it's first, middle, or last in a DreamTree load order.) Bluntly speaking, though, I'm trying to do "DreamTrees += MyDreamTree" I just have to figure out how and where to do that.


If that's the case, if I remember correctly if you use directly a DMTR type resource instead of
an _XML one for the dreamTree, then that resource is parsed automatically by the game
(probably even if it's in a package in the Mods/Packages folder), so you don't have to explicitly
invoke the parser specifying the resource to read.

If you don't want to create custom NodePrimitives, know that you can't create a dream/wish
with a custom name, but I guess that's ok for what you want to do, and anyway many names
and description are translated using generic and parametric (???) strings such as
"Improve skill <SkillName>" where SkillName is a kind of argument that is specified in the
InstanceNode's fields of a dreamTree and "passed" to the NodePrimitive (not only for
translate its name but also as argument for the Check/Feedback functions).
I guess it works exactly as a parameter for a localized string: "Improve skill {0.string}", where "0."
is used to reference the first parameter (a string) passed to the function
"Localization.LocalizeString(key, new object() { s })"
(I'm not sure if I've used the exact syntax).
Lab Assistant
Original Poster
#8 Old 17th Jul 2015 at 10:07 PM Last edited by McNum : 18th Jul 2015 at 12:29 AM.
Well, if it parses DMTRs without needing more than the file itself, I'm going to feel a little silly. Because, yes, I'm using a DMTR resource. Because, well, I was making a DreamTree. Not that converting it to an XML would be difficult, I mean, it's just an XML with a different filetype anyway.

I guess that'll be the thing to test. Make a DreamTree as a DMTR, with a very easy to satisfy start, and an MaxAdvertisment of very much to get it to appear. If that's what that does, but... what else would it do? Like a "Satisfy on Next Heartbeat -> Throw a party". That should, if the tree is running, make all Sims want to throw a party immediately, if I understand it right. Then I can try with the other wants, and see if it blocks them. It just seems to me that if it's this simple, then Woohooer would have come with it as an option... and yet it does not.

EDIT: Well, I have something to share now, which is not so much a result, but a method. How I reverse engineered what to use as a Root.

When you start a brand new game, what's the first want, ever, to roll? "Join Career". So, I extracted Career Opener from the game and started sleuthing. How? Only one way to find out. Backtrace to root!

"Join Career" comes from a "Satisfy on Next Heartbeat" comes from "Has no job" comes from "Is teen or older" comes from "Is born", which is Root.

In other words, if I want a want tree to silently linger in the background until ready to go, it must start with "Is Born" which is <PrototypeId>2534868489</PrototypeId> Then when a sim ages to teen, it will satisfy a hidden "Is Teen or Older" and the rest will activate. Other trees, like Hot Tub socials start with this as well.

And that is how I puzzled my way down to the root of a DreamTree. This should prove most useful later.

EDIT again: It would appear that the game does not actually parse loose DMTR files in Packages. I made a simple Is Born -> Is Teen or older -> Satisfy on next Heart Beat -> Throw a Party DreamTree and Throw a Party does not appear on a freshly made Sim, nor does it appear when I force a ResetDnP cheat on it.

For reference, this is the DreamTree I was attempting to parse automatically:

The IDs have been changed, but this is a very similar chain of events to the Join Career wish that always appears. Yet Throw a Party does not. Hmm... I may have to parse it separately, then. Unless I missed something obvious that would cause that tree to be unreadable by the game.
Inventor
#9 Old 18th Jul 2015 at 8:10 AM
Oh, sorry if I've mislead you. I think I read that in the tutorial itself, but maybe it doesn't work that way, at least for mods.

Keep up your researches! Unfortunately my experiments so far were no joy either and it seems you are
ahead of me in understanding how dreamTrees work and are intertwined. One thing I tried was sorting
the DMTR resources based on the file size, so I could try to examine the shortest (and hopefully simplest)
ones, but even this way I still don't get them ^^
Lab Assistant
Original Poster
#10 Old 18th Jul 2015 at 8:21 PM
Oh, you've been quite helpful. You challenged my assumption and made me need to try and explain myself. Both are quite handy when trying to figure out someone else's code logic.

I did some more experimenting, and I think I can conclude that, no, I cannot get Sims 3 to automatically parse a DMTR from a Package. It doesn't load when it has an Is Born as Root, and it doesn't load when using an Is Born from a default tree as a parent to one of its InstanceNodes. In other words, I have doubts that The Sims 3 even recognizes the DMTR resource in the Mod folder. As if the DMTRs are pre-approved, or something.

Now, there are two paths ahead from here. One is to grab GameplaySystems.package, go in and modify an existing DMTR, and put the whole Package in the Mods folder. Basically making it a blunt version of a Core Mod. ...but then it would have to be a Core Mod, and those are a pain to share. So, while I imagine this would work, I think I'll try another route.

The other route is setting up a custom parser using an XML file rather than a DMTR. I think I can get one of those done from the LTW tutorial, but this will require me to go quite a bit above my current C# skills. But it will make the final Package clean.

Now in an effort to figure out why this happens, I started to read the Sims3.Gameplay.DreamsAndPromises.DreamsAndPromisesManager.ParseDreamTrees code, since that seems incredibly relevant to my interests here, and I have to admit, I don't get all of it. However... I think I know why it ignores my DMTRs. Looks to me like it is set up to only load the default DreamTrees, and while it does search for them, the search has been limited in some fashion, but I am not entirely sure what this line does:
Code:
	KeySearch keySearch = new KeySearch(100969434u);

But that has to be where it finds all the DMTRs it wants to load. And I have no idea what the 100969434u part means. Why does it end with a u?

But the gist of it is that if I want more trees parsed, I think attempting to hook it onto the default ParseDreamTrees function is no longer an avenue worth exploring. I have to force the game to parse them, and not as a DMTR, but as an XML file that the game itself will have to convert.

Still, today has been some productive failures. And this shuts down the simplest plan. Guess I have to make my own parser next. Well this should be interesting. And difficult. Gotta re-read everything and than plan this out.
Inventor
#11 Old 18th Jul 2015 at 9:04 PM
Quote:
Originally Posted by McNum
Now, there are two paths ahead from here. One is to grab GameplaySystems.package, go in and modify an existing DMTR, and put the whole Package in the Mods folder. Basically making it a blunt version of a Core Mod. ...but then it would have to be a Core Mod, and those are a pain to share. So, while I imagine this would work, I think I'll try another route.


Nah, core mods override the game dlls, what you want to do is an override mod and there's nothing bad in that(*).
On the contrary, to see if you can modify succesfully an existing dreamTree - or completely replace it - is probably
the best solution.

(*)The only drawback is that this way you are modifying an existing dreamTree and that, yes, could be a problem per se.

Quote:
The other route is setting up a custom parser using an XML file rather than a DMTR. I think I can get one of those done from the LTW tutorial, but this will require me to go quite a bit above my current C# skills. But it will make the final Package clean.


I would gladly share the parser I made with you, but I'm not sure if it works.
You can use as reference the one made by SimsMX in his Hypochondriasis mod.
That works for sure (if I recall correctly). I think the one made by velocitygrass
lacks the parser of dreamTrees. I may be wrong but lifetime wishes only use
NodePrimitives and linked wishes (but I may remember wrongly her code).

Quote:
ParseDreamTrees. Looks to me like it is set up to only load the default DreamTrees, and while it does search for them,
the search has been limited in some fashion, but I am not entirely sure what this line does:
Code:
	KeySearch keySearch = new KeySearch(100969434u);

But that has to be where it finds all the DMTRs it wants to load.
And I have no idea what the 100969434u part means. Why does it end with a u?


That number, if you convert it to hexadecimal, will give you the TypeId of DMTR resources.

The "u" at the end of a number means "unsigned" (the first bit is not used for the sign,
so the number can only be positive, not negative, doubling the range of positive values
a variable can assume, but losing all the negative range).

It seems it's actually supposed to parse any DMTR resource, even if in a mod
(on the other hand, all xml resources too are read automatically by the game,
otherwise xml instantiators wouldn't work). Uhm...
Are you sure you have set your DMTR resource IDs correctly?
Lab Assistant
Original Poster
#12 Old 18th Jul 2015 at 9:25 PM Last edited by McNum : 18th Jul 2015 at 9:49 PM.
I am not entirely sure of where to find the ResourceID to be honest. I just had S3PE import it as a DMTR file, and it has the extension .dreamtree like the originals, so I assume it is right. But am I missing something basic here?

Though I cannot say that I am 100% sure that the DreamTree I made works perfectly. I wish there was a way to check what DreamTrees were running when the game was going. I don't suppose I could make some code that does a text dump of that DreamTree cache the default parser does? I mean if it exists as an array and Sims 3 can do XML dumps on errors, then surely that has to be possible. I feel like I'm flying a bit more blind than I want to in debugging this. All I can do is start a new game and see if a Sim rolls the "Throw a Party" want alongside the career one. I'd like to be a bit more detailed than that. A list of loaded DMTR resources would be fantastic to have.

EDIT: I downloaded the Hypochondriac mod you suggested, and as soon as I opened the Package, one thing was plain as day: No DMTR resources, despite it explicitly having a DreamTree. The DreamTree is XML. (And is has no <Center> tag. If that's not required, it is SO getting tossed...)

So, that will be Sunday's plan. Figure out what happens there. But I think the DMTR method is on its last legs.
Lab Assistant
Original Poster
#13 Old 20th Jul 2015 at 12:47 PM
Sorry for going dark for a few days, but I have a good reason to. Because as of half an hour ago, the custom DreamTree parses!

I am pretty surprised I made it that far, so as promised, I will share as much as I can.

First of all, that thing I complained about not being able to see if a DreamTree was loaded? Yeah, you can. With the NRaas Debug Enabler, click on a Sim, pick NRaas -> Debug Enabler -> Options: Smart Phone and choose Export Dreams from the menu. All dreams currently affecting the selected Sim will be dumped as an XML file. So, if you're messing with DreamTrees, get the NRaas Debug Enabler.

Secondly, debug messages! I can has. Made a string variable, named it "dMsg". Then for every thing that happens, I made a dMsg += "Stuff"; line and capped it off with a SimpleMessageDialog.Show("Want Tree Mod", dMsg); line. Done. I now know what parts of the code triggers. Also \n is a new line within a string.

So with those things out of the way, I went to war. I cannot say I used a simple solution, in fact, it's rather convoluted. I took VelocityGrass' tutorial mod for the LTW, where the Package file was graciously offered alongside, and examined exactly how its ParseDreamTrees class worked. After giving up on that, I rewrote my mod four times, with no success, and then I went back to that one and tried to understand it again. Because I will not copy any code I don't already understand. That's just a recipe for disaster.

That code parses the XML file, element by element, and inserts it manually into the DreamTreeManager, making space for debug messages all the way. It may not be short, but it's pretty handy when you finally get it. And most importantly, it worked, after updating some of it to use the current version of the game. DreamTrees can now be age and species specific, and will ask for that variable.

So, great success, all is well, right? ...no. As i suspected, getting Teens to roll those wants is blocked. I know that because i linked First Kiss to both Woohoo and Throw a Party, and they DO get the party wish. (As an aside that's kind of cute, so this debug feature might just survive for fun.) In other words, I need to make a sister primitive or two that also trigger on kWoohooed, but aren't the default ones. So the next battle is McNum vs. enums. But I think I earned a break now. Went all out in trying to get this. And now I do.

As promised, I will share the source when it's done. But I suppose there's no harm in sharing a WIP, so the .cs and the XMLs are attached here for the curious. IT IS NOT FINAL, but it is a very respectable DreamTree parser now. Still, got more work to do before it's done. This mod just keeps growing all the time... Can't say I'm not having fun learning how to do this, though.
Download - please read all instructions before downloading any files!
File Type: zip WantTreeWIP1.zip (5.0 KB, 8 downloads) - View custom content
Description: WIP Source code
Inventor
#14 Old 20th Jul 2015 at 3:06 PM Last edited by Arsil : 20th Jul 2015 at 3:17 PM.
Hey, congrats and keep up the good work ^^

Please tell me that for a single simple custom dream it's not needed to use so many InstanceNodes...

Can you help me with a quick recap?
- what your dreamTree is supposed to do? I understand is about teens but I guess I got lost
- why is not working? It is because the existing primitives you are referring to don't take into account teens?
Maybe instead of creating custom primitives you can replace the Check/Feedback function of the existing
ones (if that's the place where teens are excluded).

You'll find about enums in the tutorial itself, it's explained very well and there's a working example on how to add
"custom entries" (a generic method that you can call to add an entry to any kind of enum, since you pass the enum
type and the key/id pair as arguments).

I know this sounds very selfish (and - quite frankly - it is) but if I'd ask you to write a dreamTree
for a custom dream about improving a skill, you think you could try it?
As far as I know, something like this uses the existing nodePrimitive "Improve at $skill" and then
there are as many dreamTrees as skills (not sure about this, it's a speculation on my part) to
make it work for each one since the skill name is specified by a tag of the nodeInstance,
but all dreamTrees I've examined are so intricate that I can't extract just the InstanceNodes I need.
Of course the aforementioned dreamTrees aren't just used for the "Improve at $skill" dream,
I think each contain a series of other dreams that share some pattern (the conditions to
activate the dreams for example). Am I right or I'm making wrong assumptions?
Lab Assistant
Original Poster
#15 Old 20th Jul 2015 at 4:03 PM
Quote:
Originally Posted by Arsil
Hey, congrats and keep up the good work ^^

Please tell me that for a single simple custom dream it's not needed to use so many InstanceNodes...

Thanks.

InstanceNodes accumulate. That debug function I mention where you can get all currently active dreams, visible and hidden on a Sim? Fresh out of CAS, it's a 450KB file. That's the Dreams a Sim that has done nothing but stand around for one Sim Minute. And that explains a lot about why a lot of Sims can slow down the game, actually... You have many, many intermediate nodes to delay wishes, to activate wishes intermittently, and all matter of weird requirements. So yes, this is a relatively simple tree. You just need many nodes to say something simple.

Quote:
Originally Posted by Arsil
Can you help me with a quick recap?
- what your dreamTree is supposed to do? I understand is about teens but I guess I got lost
- why is not working? It is because the existing primitives you are referring to don't take into account teens?
Maybe instead of creating custom primitives you can replace the Check/Feedback function of the existing
ones (if that's the place where teens are excluded).

From my planning TXT file:

That last one at 1.1.2 is just for easy testing. Got a Sim with those traits as part of my testing crew of Sims. And I may have typecast Family-Oriented Sims as slightly manic here. Sims are more fun when they're manic.

As for why it's not working, well, let's ask WooHooWithSimCheckFunction about that...

Could be a clue.

Just found that one, actually. I need to figure out if I can replace this, or if I need to make my own. It's in Sims3GameplayObjects.dll, so... It would be nice to be able to replace just bits of a DLL, but I'm not sure if I can. I would prefer a Package that can stand on its own. Despite not actually making the wishes possible to attain on its own. A standalone mod that requires a companion to actually do things. That's a little weird, come to think of it.

Quote:
Originally Posted by Arsil
You'll find about enums in the tutorial itself, it's explained very well and there's a working example on how to add
"custom entries" (a generic method that you can call to add an entry to any kind of enum, since you pass the enum
type and the key/id pair as arguments).

Yeah, I think I can handle it. It looks simpler than it might be. I'm leaning towards just making two new primitives and using those, unless I can be sneaky with the DLL. If not, I might go the whole shebang and make them truly custom wishes instead of the generic ones. New flavor text or similar.

Quote:
Originally Posted by Arsil
I know this sounds very selfish (and - quite frankly - it is) but if I'd ask you to write a dreamTree
for a custom dream about improving a skill, you think you could try it?
As far as I know, something like this uses the existing nodePrimitive "Improve at $skill" and then
there are as many dreamTrees as skills (not sure about this, it's a speculation on my part) to
make it work for each one since the skill name is specified by a tag of the nodeInstance,
but all dreamTrees I've examined are so intricate that I can't extract just the InstanceNodes I need.
Of course the aforementioned dreamTrees aren't just used for the "Improve at $skill" dream,
I think each contain a series of other dreams that share some pattern (the conditions to
activate the dreams for example). Am I right or I'm making wrong assumptions?

I haven't looked that much into the skill trees, but there's a whole lot of [skillname] Advancment trees in GameplayData.package, so that's probably a good idea to look at. The way I read these ugly things is that I use Notepad++ and have both the Dreamtree and DreamsandPromisesNodes.XML open at the same time. The Node <Id> in the XML file corresponds to the <prototypeid> in the tree. The generic "Improve at skill" want, for instance has <Id>754851437</Id> in DnPNodes.XML, so if you want to use it, you'd write <prototypeId>754851437</prototypeId>.

If you want me to help with this, there's one thing you need to know first. What should the tree do, exactly? It's a simple nagging thing were every three Sim days it will reroll a want to increase the skill? Does it have some activities that would influence it? (Like Go Jogging and Athletics.) I mean it's no coincidence that hitting level 1 Athletic immediately throws out Go jogging at you or level 6 gives Train Sim. That's a Dreamtree in action. Presumably the Athletic Advancement one.
Inventor
#16 Old 20th Jul 2015 at 5:27 PM
I've explained how to replace a check function (be sneaky with the dll, as you said), a few posts back.
And for the custom function, that you have to precede with the attribute (I guess that's how is called)
[DreamsAndPromisesCheckFunction], you simply have to copy/paste the existing function and
use "TeenOrAbove" instead of "YoungAdultOrAbove". This way you don''t (well, let's say shouldn't)
worry about modifying the existing primitive because it will keep working as before but it will also work
for teens (of course you have to evaluate if that has bad consequences or side-effects).

About the dreamTrees that include improving a skill, I've already done the work you suggested, it's just
that I get confused by all the branches of the tree and the cross-references to the primitives.
What should the tree do? I just want it to work like the existing ones (do all have that 3 days delay
or were you just making an example?) and yes, it should have a condition and an activity that triggers it:
- (CONDITION) the Sim should already know the skill (at least level 1)
- (ACTIVITY) a specific game event should "stimulate the dream" (something like kEventTakeBath or
kReadBook for example)

Look, I already feel bad about asking you to do it for me, if you are so kind to help me,
I'm mostly interested in knowing how you'd approach it and know if my assumptions
so far were right or wrong, so I can try again to do it myself. But, hey, if you feel like
doing it for me, I won't stop you.
Lab Assistant
Original Poster
#17 Old 20th Jul 2015 at 6:26 PM Last edited by McNum : 20th Jul 2015 at 8:59 PM.
Quote:
Originally Posted by Arsil
I've explained how to replace a check function (be sneaky with the dll, as you said), a few posts back.
And for the custom function, that you have to precede with the attribute (I guess that's how is called)
[DreamsAndPromisesCheckFunction], you simply have to copy/paste the existing function and
use "TeenOrAbove" instead of "YoungAdultOrAbove". This way you don''t (well, let's say shouldn't)
worry about modifying the existing primitive because it will keep working as before but it will also work
for teens (of course you have to evaluate if that has bad consequences or side-effects).

About the dreamTrees that include improving a skill, I've already done the work you suggested, it's just
that I get confused by all the branches of the tree and the cross-references to the primitives.
What should the tree do? I just want it to work like the existing ones (do all have that 3 days delay
or were you just making an example?) and yes, it should have a condition and an activity that triggers it:
- (CONDITION) the Sim should already know the skill (at least level 1)
- (ACTIVITY) a specific game event should "stimulate the dream" (something like kEventTakeBath or
kReadBook for example)

Look, I already feel bad about asking you to do it for me, if you are so kind to help me,
I'm mostly interested in knowing how you'd approach it and know if my assumptions
so far were right or wrong, so I can try again to do it myself. But, hey, if you feel like
doing it for me, I won't stop you.

If you want to try it yourself, you totally should. It looks scarier than it is. It's a flowchart, nothing more, nothing less. Start by doing a text search in DreamsandPromisesNodes.XML. See if what you want is already there.

It is quite helpful to draw it on paper or similar. I wrote mine in that TXT file since for all intents and purposes, it's a simple tree, but I'll break out pencil and paper if it goes bigger. I'll likely have to tweak my own for a while. I think it may be a tad too frisky once it gets working. But that's a playtest thing.

As for what's possible, let me come with a few suggestions for a skills tree. I have not analyzed one of the built in ones, this is merely what I would do. Start with "Is Born" then "Is Teen or Older" unless the skill can be done by children as well. Then have a "Learn Skill" (which will require a check and a feedback function tailored towards that skill) want, but set it to <DreamVisible>false</DreamVisible>. You can grab these from the built in skill DreamTrees. From there, you can add conditionals. Like let's use your Take a Bath example.

The Primitive for "Bathe" is this:

So from that, we grab the Primitive's ID and use that as the <PrototypeId> of a new InstanceNode. For the Node's own <Id>, you get to choose whatever you want. I use FNV32 hashes of shorthand names. The third part is that you need the <ParentId> which is the Id of the Node that triggers this one. Which in this case could be "Learn Skill" or a delay of sorts put in after it. In turn, you can use the <Id> of THIS Node as <ParentId> for one or more nodes so it will activate those. From there, the rest is settings, I'd recommend you find something similar and tweak to taste.

Dreams can repeat, you can have dreams trigger if a Sim has slept for 5 hours or more in a row. For a skill, I'd likely use that as the generic Improve Skill want feeder. But give it a <NextDreamSelectionProbability> of 35-40-ish so it's not every day a Sim will wake up and want to do that skill. That's just the nagging function. Remember to set it as <Repeatable>true</Repeatable>.

But really, if you want the dirty trick of DreamTrees, it's <DreamVisible>false</DreamVisible>. They will stay active in the background until fulfilled and then push the next Dream. For mine, "Is Born", "Is Teen or Older", "Have First Kiss", "Meet Sim", and "Be in alluring context" are all invisible. If I hadn't put in the "Throw Party" one, I'd have no visual indication that it's running.

Also fun: TimerNodes. Feel free to just copy one of mine, they're pretty much universal. The time is in Sim Hours. And you can set it to trigger multiple times. Mine don't use <SatisfyOnStart>true</SatisfyOnStart>, but that's also a thing. It triggers immediately, and then counts down to triggering again.

Really, it seems to me after learning some of this that a large part of The Sims 3 runs on DreamTrees. I wouldn't be terribly surprised if nearly anything you can do has a corresponding feedback function. And if it doesn't you can make one. Keep your Ids, ParentIds and PrototypeIds straight and you have most of it down already.

EDIT: Okay, I have no idea what I'm doing with the CheckFunctions here. I extracted them fine from the DLL, edited them so they would include Teens, and now... I have no idea on how to actually get them to run. How do I activate them so they'll override the defaults?

I don't need some big universal solution, just a simple one I can run twice. I feel kind of stumped on how to actually get the game to see them.

How do I get this to move?

Can I invoke the class directly? Visual Studio is not letting me, or maybe I just don't know the secret handshake. Where in the file should they be, anyway? I could throw them up top if that does anything.
Back to top