Ok. So far making the body part specific mutations / weapons is going well (60+ mutations & bioweapons!), largely ripping off Minus, CrazehMeow & GottJammern's work: I've also created a new social dynamic via traits / thoughts, but I've hit a couple of walls...
1) The mechanic is supposed to work as follows:
Choose body part. e.g. leg
Select leg to be mutated.
Roll on table to determine which mutation is applied (3 positive, 2 negative, needs weighted chances)
Permanently set that mutation to the part.
I'm used to weighted tables in XML (using subtables to roll off), but Rimworld doesn't seem to use this process. I'm attempting to fudge the ability to remove the body parts, but if anyone knows if there's a <LABEL> that does it already, that'd be grand.
Basically, I need the ability to RNG a loot table where the result is perma-bound to that bodypart.
2) Traits: I've generated them, made all the thoughts / conditionals, but need several things clearing up:
a) how / where are the "observedX" located?
<ThoughtDef>
<defName>ObservedMinorMutation</defName>
<label>observed minor mutation</label>
<description>Some of us are changing in small ways, it makes me uncomforable. I am ok so far though.</description>
<baseMoodEffect>-1</baseMoodEffect>
<duration>10000</duration>
<stackedEffectMultiplier>1</stackedEffectMultiplier>
<stackLimit>3</stackLimit>
<nullifyingTraits>
<li>Psychopath</li>
<li>Mutation</li>
<li>Empathetic</li>
</nullifyingTraits>
</ThoughtDef>
b) Where do I define thought predicates? e.g.
<ThoughtDef>
<defName>GeneticFundamentalistUnhappy</defName>
<label>has a mutation</label>
<description>I am warped into an unnatural horror, I am unclean, I deserve to burn!</description>
<baseMoodEffect>-50</baseMoodEffect>
<activePredicate>ThoughtPredicates.HasMutation</activePredicate>
<requiredTraits>
<li>GeneticFundamentalist</li>
</requiredTraits>
</ThoughtDef>
c) How do I tie a body part to a trait? The mechanics are supposed to work so that any mutation gives the <MUTATION> trait, some have specific traits that they should give and so on. Is it currently possible to activate / give pawns traits outside of birth generation? Also, is it possible to tie not just Skills, but specific stats to a trait? e.g. in the following I'd like to give specific +stat to <defName>RecruitPrisonerChance</defName>. Would the following work?
<TraitDef>
<defName>HypnoticEyes</defName>
<commonality>0</commonality>
<degreeDatas>
<li>
<label>Hypnotic Eyes</label>
<description>NAME's eyes have become alluring and seem to draw a person's gaze to them. HECAP can use this to the colony's benefit in trading matters.</description>
</li>
</degreeDatas>
<requiredWorkTags>
<li>Social</li>
</requiredWorkTags>
<skillGains>
<li>
<key>Social</key>
<value>2</value>
</li>
</skillGains>
<statGains>
<li>
<Key>RecruitPrisonerChance</key>
<value>3</value>
</TraitDef>
Note: I just added <statGain>, I know it doesn't exist at the moment : or can I add the following to the actual <BODYPART> addition? This seems another good way to do it.
<equippedStatOffsets>
<SocialImpact>1.50</SocialImpact>
</equippedStatOffsets>
d) Where are the ranges for trait spectrums, and is it possible to force the client to replace a previous trait on the spectrum with the next one?
<TraitDef>
<defName>Mutation</defName>
<commonality>0.1</commonality>
<degreeDatas>
<li>
<label>minor mutation</label>
<description>NAME's body has changed from the human normal in a small but noticable way. HECAP feels ostracized and unnatural.</description>
<degree>-0.5</degree>
<statModifiers>
<MentalBreakThreshold>6</MentalBreakThreshold>
<permaThought>MoodOffsetMinorMutation</permaThought>
</statModifiers>
</li>
<li>
<label>medium mutation</label>
<description>NAME's body has changed internally to a large extent. HECAP can feel the internal changes and wonders if they will spread.</description>
<degree>-0.75</degree>
<statModifiers>
<MentalBreakThreshold>18</MentalBreakThreshold>
<permaThought>MoodOffsetMediumMutation</permaThought>
</statModifiers>
</li>
<li>
<label>major mutation</label>
<description>NAME's body has changed externally away from the human norm. HECAP has at least one body part that is obviously no longer baseline human, and their mind stirs with alien thoughts.</description>
<degree>-1</degree>
<statModifiers>
<MentalBreakThreshold>24</MentalBreakThreshold>
<permaThought>MoodOffsetMajorMutation</permaThought>
</statModifiers>
</li>
<li>
<label>monstrous mutation</label>
<description>NAME's body is now longer recognizable. HECAP has undergone so many changes that there is danger of loosing their humanity and descending into insanity.</description>
<degree>-2</degree>
<statModifiers>
<MentalBreakThreshold>36</MentalBreakThreshold>
<permaThought>MoodOffsetMonstrousMutation</permaThought>
</statModifiers>
</li>
</degreeDatas>
</TraitDef>
e) Hmm, issues, issues. Looking at:
<HealthDiffDef Name="AddedBodyPartBase" Abstract="True">
<naturallyHealed>false</naturallyHealed>
</HealthDiffDef>
It might be a solution to make mutations a separate class & take it from there (this also makes preventing mutations from being removed or bionics being replaced by mutations a lot easier):
<HealthDiffDef Name="MutatedBodyPartBase" Abstract="True">
<naturallyHealed>true</naturallyHealed>
</HealthDiffDef>
Anyone got any good ideas on where to define / add this please?
Lots of questions, hopefully there are code ninjas around.
Note: the mentaleffects are currently balanced to the TTM package (where it's incredibly easy to get large positive +morale bonuses constantly) - I might have to balance downwards for the vanilla client.
Traits are personality traits. They have nothing to do with the health system; if you want to create a linkage there you'll have to code it yourself.
Define thought predicates by creating a static class with a method in it and referencing that. Use a decompiler to look at the existing code.
I had a lot of trouble understanding your post; it would be good if you could write your questions clearly and in an encapsulated way so they can be answered one by one.
Quote from: Tynan on November 17, 2014, 03:59:06 PM
Traits are personality traits. They have nothing to do with the health system; if you want to create a linkage there you'll have to code it yourself.
I'll take that as:
Question:
Is it currently possible to activate / give pawns traits outside of birth generation? Also, is it possible to tie not just Skills, but specific stats to a trait?Answer: No, not without coding it yourself: hierarchy is set as Trait highest and set on birth (?).
<TraitDef>
<defName>Masochist</defName>
<commonality>0.2</commonality>
<degreeDatas>
<li>
<label>masochist</label>
<description>For NAME, there's something exciting about getting hurt. HECAP doesn't know why, HE's just wired differently.</description>
</li>
</degreeDatas>
</TraitDef>This is a personality trait that is conditional on external factors.
If you look at point 2)d), I'm attempting to do the same thing, but slightly dynamically. i.e. A pawn with <nudist> gets a conditional +mood mod if they're not wearing clothes (binary conditional on external event). 2)d) = a pawn with a <mutation> enters the Mutation spectrum and is designed to work so that as conditionals are met (progressively more mutations) traits are unlocked, making the pawn more and more likely to suffer a breakdown / have unhappiness mood effects.
The two are conceptually very similar, my example is merely treating # of installed bodyparts = the same as clothes, but in a dynamic fashion. Has no real ties to the health system ~ I should probably move the spectrum to a thought.conditional, which is why I asked about them.
So, the question was if it actually needed more code: I guess I look for the <activePredicate>ThoughtPredicates.MasochistLittlePain</activePredicate> code then and set a global so that all pawns have a neutral <mutation> trait on birth ("humanity") that is then triggered. e.g.
<TraitDef>
<defName>Humanity</defName>
<commonality>10</commonality>
<degreeDatas>
<li>
<label>baseline human</label>
<description>NAME's body is unchanged since birth. HECAP is happy in their own skin</description>
<degree>0</degree>
</li>Then add the -negatives as mutations in thoughts_conditionsspecial.xml
I'm guessing that would work without massive recoding? i.e. if traits are static and cannot change, then that's what I have to code.
Quote from: Tynan on November 17, 2014, 03:59:06 PMDefine thought predicates by creating a static class with a method in it and referencing that. Use a decompiler to look at the existing code.
Ok, so there's no XML expressions for any of this, got you. I presume that the "observedX" conditionals (for dead bodies etc) are also purely in the code base? i.e. do you have a flag system which can be attached to pawns? if so, is it just in the code base? [set mutation flag = 1, 2, 3, 4 means "observedX"
and thoughts_conditionsspecial.xml can effect both the pawn with the condition and those viewing it].
Sounds good, but irksome that we can't modify traits on the fly.
Quote from: Tynan on November 17, 2014, 03:59:06 PMI had a lot of trouble understanding your post; it would be good if you could write your questions clearly and in an encapsulated way so they can be answered one by one.
This thread: https://ludeon.com/forums/index.php?topic=7390.0 preceeded this one. There are specific questions about if certain XML tags work in different classes in there. e.g.
Can you add <statBases> to bodyparts?
<subOptionsChooseOne> < is there a subtag for weighting on this, and does it work outside the pawndefs?
Can you add <permaThought>XXX</permaThought> to conditional thoughtdefs in thoughts_conditionsSpecial.xml and still have it work?
Does the tag <MentalBreakThreshold>work in thoughts_conditionsSpecial.xml?
e.g. We change 2)d) trait into a singular trait, and then throw the dynamic stuff into thoughts_conditionsSpecial.xml:
<TraitDef>
<defName>HomoSapiensSapiens</defName>
<commonality>10</commonality>
<degreeDatas>
<li>
<label>baseline human</label>
<description>NAME's body is unchanged since birth. HECAP is happy in their own skin</description>
</li>
</degreeDatas>
</TraitDef>
and
<ThoughtDef>
<defName>HasMinorMutation</defName>
<label>minor mutation</label>
<description>NAME's body has changed from the human normal in a small but noticable way. HECAP feels ostracized and unnatural.</description>
<statModifiers>
<MentalBreakThreshold>6</MentalBreakThreshold>
<permaThought>MoodOffsetMinorMutation</permaThought>
</statModifiers>
<activePredicate>ThoughtPredicates.HasMinorMutation</activePredicate>
<requiredTraits>
<li>HomoSapiensSapiens</li>
</requiredTraits>
</li>
</ThoughtDef>As you can spot, some of those tags are currently only defined for other files: do they still work? (as you can see - I can easily change the way a mechanic works, but I then run into questions about if tags work... sigh)
At the moment I'm looking to use whatever XML stuff is available from the alpha7 build
without coding additional gubbins. The point is to see what the engine can do, not whether or not I can code a similar game experience (I can't, and it's not worthwhile to do it).
Anyhow, thanks for the response.
Can you add <permaThought>XXX</permaThought> to conditional thoughtdefs in thoughts_conditionsSpecial.xml and still have it work?
Does the tag <MentalBreakThreshold>work in thoughts_conditionsSpecial.xml?
No, neither work.
Means you can't currently alter pawn MentalBreakThresholds over time. Bleh.
You can do it using a kind of apparel (a fake armor for example).
I use it for the alert speaker in M&Co. Security enforcement mod.
This may change in alpha 8 with all the changelog "stats cleanup".
Quote from: Rikiki on November 18, 2014, 12:08:19 PM
You can do it using a kind of apparel (a fake armor for example).
I use it for the alert speaker in M&Co. Security enforcement mod.
This may change in alpha 8 with all the changelog "stats cleanup".
I'll take a look.
On thoughts: currently this is the brute force way to give universally:
foreach (Pawn current in GenLinq.InRandomOrder<Pawn>(list))
{
current.psychology.thoughts.TryGainThought(new Thought(ThoughtDef.Named("SolarFlareSubEventACosmicRadiation")));
}
result = true;
}
else
{
result = false;
}Found them:
Alter to mutations:
// RimWorld.ThoughtPredicates
public static bool HasBionicBodyPart(Pawn p)
{
foreach (HealthDiff current in p.healthTracker.bodyModel.healthDiffs)
{
AddedBodyPartProps addedBodyPart = current.def.addedBodyPart;
if (addedBodyPart != null && addedBodyPart.isBionic)
{
return true;
}
}
return false;
}Colonist left unburied:
public static bool ColonistLeftUnburied(Pawn p)
{
if (p.Faction != Faction.OfColony)
{
return false;
}
List<Thing> list = Find.ListerThings.ThingsListMatching(ThingRequest.ForGroup(ThingRequestGroup.Corpse));
if (list != null)
{
for (int i = 0; i < list.Count; i++)
{
Corpse corpse = (Corpse)list[i];
if (corpse.Age > 80000 && corpse.sourcePawn.Faction == Faction.OfColony && !corpse.IsInAnyStorage())
{
return true;
}
}
}
return false;
}
Observedthoughts are given by the parent object, thus:
public Thought GiveObservedThought()
{
if (!this.sourcePawn.RaceProps.humanoid)
{
return null;
}
Thing thing = this.StoringBuilding();
if (thing == null)
{
bool flag = false;
CompRottable comp = base.GetComp<CompRottable>();
if (comp != null && comp.Stage != RotStage.Fresh)
{
flag = true;
}
if (flag)
{
return new Thought_Observation(ThoughtDef.Named("ObservedLayingRottingCorpse"), this);
}
return new Thought_Observation(ThoughtDef.Named("ObservedLayingCorpse"), this);
}
else
{
if (!(thing.def.defName == "GibbetCage"))
{
return null;
}
if (this.sourcePawn.Faction == Faction.OfColony)
{
return new Thought_Observation(ThoughtDef.Named("ObservedGibbetCageFullColonist"), this);
}
return new Thought_Observation(ThoughtDef.Named("ObservedGibbetCageFullStranger"), this);
}
}Hmm.