Remove body part conditions

Started by smoq2, January 22, 2015, 09:32:25 AM

Previous topic - Next topic

smoq2

I noticed that you are unable to harverst specific body parts if they or their children parts are damaged. E.g. You cannot harvest a left arm if the pawn has an old scratch on their left hand.

I'm trying to find where the conditions whether a part is "harvestable" are stated, so I checked around the xml files and couldn't find anything there, then I turned to the source code files but to no avail.

If someone can shine some light on the matter I'd be grateful.

want_some

What are you wanting to do? Harvest the body part with the scratch or remove the scratch from the said body part?


Learning to mod while also updating TTM Mod!
Full credit goes to Minami26

smoq2

#2
I want damaged limbs/organs to be harvestable/removable as well.

The end-result of the project should allow the player to use the following scenarios:

Pawn has damaged part - Replace with natural part / Replace with bionic part / Remove part altogether ; Damaged part gets destroyed in the process

I found the source code that is responsible for installing parts on pawns and I'll reconstruct (had to decompile it, so it's a big mess, since I don't have one from the author) it to not spawn the joint as an item if it was damaged later, but for now, I just need to find where the conditions whether a given operation can/cannot be performed are listed.

[EDIT]

I suspect the answers I seek can be found in MedicalRecipesUtility.cs, Recipe_InstallArtificialBodyPart.cs and Recipe_InstallNaturalBodyPart.cs. However, the quality of decompilation with dotPeek is not enough for me to make much sense of the code included in those files. Does anyone have the "real" source for those 3?

want_some

Quote from: smoq2 on January 23, 2015, 05:13:28 AM
-snip-
I suspect the answers I seek can be found in MedicalRecipesUtility.cs, Recipe_InstallArtificialBodyPart.cs and Recipe_InstallNaturalBodyPart.cs. However, the quality of decompilation with dotPeek is not enough for me to make much sense of the code included in those files. Does anyone have the "real" source for those 3?

I use .NET Reflector 8.4 to recompile. just make sure you link the dll files of UnityEngine.dll and the Assembly-CSharp.dll in the A8 "RimWorld657Win_Data/Managed" folder of the game directory.

To link the two dlls with your mod, or someone else's dll. Right click the file and open with the program. Once loaded, File the file on the left side of the screen and click the + symbol.

Click the + for the dll and then the 3rd option. Usually when you open files like that you might get a popup window. MAKE SURE you read the name that its requesting. Click "Browse" and go to "RimWorld657Win_Data/Managed" folder and select the requested dll file. You may have to click other files to get both requests (sometimes more) and once you have all requested files, you can then right click the MAIN folder (the one you first clicked on after you opened the dll with the program) and select the option "Extract Source Code" and place it in a seperate folder (i make a new folder on Desktop for easy access) and click start. Then open the .sln file with VS and there, you have the source code.

*Disclaimer*
This program does not guarantee 100% accurate source code!


Learning to mod while also updating TTM Mod!
Full credit goes to Minami26

smoq2

Well, it is somewhat better, but too much of the code is still obscured. Check the IsClean method - that's probably the one I need.

namespace RimWorld
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using Verse;

    internal class MedicalRecipesUtility
    {
        public static bool IsClean(Pawn pawn, BodyPartRecord part)
        {
            <IsClean>c__AnonStorey170 storey = new <IsClean>c__AnonStorey170 {
                part = part
            };
            if (pawn.Dead)
            {
                return false;
            }
            return !pawn.healthTracker.bodyModel.healthDiffs.Where<HealthDiff>(new Func<HealthDiff, bool>(storey.<>m__DC)).Any<HealthDiff>();
        }

        public static bool IsCleanAndDroppable(Pawn pawn, BodyPartRecord part)
        {
            if (pawn.Dead)
            {
                return false;
            }
            return ((part.def.spawnThingOnRemoved != null) && IsClean(pawn, part));
        }

        public static void RestorePartAndSpawnAllPreviousParts(Pawn pawn, BodyPartRecord part, IntVec3 pos)
        {
            SpawnNaturalPartIfClean(pawn, part, pos);
            SpawnAddedParts(pawn, part, pos);
            BodyPartDamageInfo info = new BodyPartDamageInfo(part, false, null);
            DamageInfo dinfo = new DamageInfo(DamageTypeDefOf.RestoringBodyPart, 0, null, new BodyPartDamageInfo?(info), null);
            pawn.TakeDamage(dinfo);
        }

        public static void SpawnAddedParts(Pawn pawn, BodyPartRecord part, IntVec3 pos)
        {
            <SpawnAddedParts>c__AnonStorey171 storey = new <SpawnAddedParts>c__AnonStorey171 {
                part = part
            };
            if (pawn.healthTracker.bodyModel.GetNotMissingParts(null, null).Contains<BodyPartRecord>(storey.part))
            {
                IEnumerator<AddedBodyPart> enumerator = pawn.healthTracker.bodyModel.healthDiffs.Where<HealthDiff>(new Func<HealthDiff, bool>(storey.<>m__DD)).Cast<AddedBodyPart>().GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        AddedBodyPart current = enumerator.Current;
                        if (current.def.addedBodyPart.spawnThingOnRemoved != null)
                        {
                            GenSpawn.Spawn(current.def.addedBodyPart.spawnThingOnRemoved, pos);
                        }
                    }
                }
                finally
                {
                    if (enumerator == null)
                    {
                    }
                    enumerator.Dispose();
                }
                for (int i = 0; i < storey.part.parts.Count; i++)
                {
                    SpawnAddedParts(pawn, storey.part.parts[i], pos);
                }
            }
        }

        public static Thing SpawnNaturalPartIfClean(Pawn pawn, BodyPartRecord part, IntVec3 pos)
        {
            if (IsCleanAndDroppable(pawn, part))
            {
                return GenSpawn.Spawn(part.def.spawnThingOnRemoved, pos);
            }
            return null;
        }

        [CompilerGenerated]
        private sealed class <IsClean>c__AnonStorey170
        {
            internal BodyPartRecord part;

            internal bool <>m__DC(HealthDiff x)
            {
                return (x.Part == this.part);
            }
        }

        [CompilerGenerated]
        private sealed class <SpawnAddedParts>c__AnonStorey171
        {
            internal BodyPartRecord part;

            internal bool <>m__DD(HealthDiff x)
            {
                return ((x.Part == this.part) && (x is AddedBodyPart));
            }
        }
    }
}


want_some

#5
yea, sometimes the code isnt really clear but it works for most things. As for this, i'm not sure what other program that does a better job. I will look around to see if i can find any other program that does a little better at gettig the code

EDIT
Found diff decompiler and it seems that it does way better job. Heres the code for the Requested class


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Verse;

namespace RimWorld
{
    internal class MedicalRecipesUtility
    {
        public MedicalRecipesUtility()
        {
        }

        public static bool IsClean(Pawn pawn, BodyPartRecord part)
        {
            if (pawn.Dead)
            {
                return false;
            }
            return !(
                from x in pawn.healthTracker.bodyModel.healthDiffs
                where x.Part == part
                select x).Any<HealthDiff>();
        }

        public static bool IsCleanAndDroppable(Pawn pawn, BodyPartRecord part)
        {
            if (pawn.Dead)
            {
                return false;
            }
            return (part.def.spawnThingOnRemoved == null ? false : MedicalRecipesUtility.IsClean(pawn, part));
        }

        public static void RestorePartAndSpawnAllPreviousParts(Pawn pawn, BodyPartRecord part, IntVec3 pos)
        {
            MedicalRecipesUtility.SpawnNaturalPartIfClean(pawn, part, pos);
            MedicalRecipesUtility.SpawnAddedParts(pawn, part, pos);
            BodyPartDamageInfo bodyPartDamageInfo = new BodyPartDamageInfo(part, false, (List<HealthDiffDef>)null);
            DamageInfo damageInfo = new DamageInfo(DamageTypeDefOf.RestoringBodyPart, 0, null, new BodyPartDamageInfo?(bodyPartDamageInfo), null);
            pawn.TakeDamage(damageInfo);
        }

        public static void SpawnAddedParts(Pawn pawn, BodyPartRecord part, IntVec3 pos)
        {
            BodyPartHeight? nullable = null;
            BodyPartDepth? nullable1 = null;
            if (!pawn.healthTracker.bodyModel.GetNotMissingParts(nullable, nullable1).Contains<BodyPartRecord>(part))
            {
                return;
            }
            IEnumerable<AddedBodyPart> addedBodyParts = (
                from x in pawn.healthTracker.bodyModel.healthDiffs
                where (x.Part != part ? false : x is AddedBodyPart)
                select x).Cast<AddedBodyPart>();
            IEnumerator<AddedBodyPart> enumerator = addedBodyParts.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    AddedBodyPart current = enumerator.Current;
                    if (current.def.addedBodyPart.spawnThingOnRemoved == null)
                    {
                        continue;
                    }
                    GenSpawn.Spawn(current.def.addedBodyPart.spawnThingOnRemoved, pos);
                }
            }
            finally
            {
                if (enumerator == null)
                {
                }
                enumerator.Dispose();
            }
            for (int i = 0; i < part.parts.Count; i++)
            {
                MedicalRecipesUtility.SpawnAddedParts(pawn, part.parts[i], pos);
            }
        }

        public static Thing SpawnNaturalPartIfClean(Pawn pawn, BodyPartRecord part, IntVec3 pos)
        {
            if (!MedicalRecipesUtility.IsCleanAndDroppable(pawn, part))
            {
                return null;
            }
            return GenSpawn.Spawn(part.def.spawnThingOnRemoved, pos);
        }
    }
}


to me it seems like it was able to clear up the code for the isClean method


Learning to mod while also updating TTM Mod!
Full credit goes to Minami26