Change the number of materials deconstruct gives back

Started by Neceros, January 07, 2018, 07:39:42 PM

Previous topic - Next topic

Neceros

Can anyone point me in the right direction to changing the topic at hand:
"Change the number of materials deconstruct gives back"


Thanks

Neceros


BrokenValkyrie

Yes, you can use float value. Not sure why you have false in there.

This will drop full resource minus 1 of each.

<resourcesFractionWhenDeconstructed>1</resourcesFractionWhenDeconstructed>


Keep in mind that it has been hard coded to always deduct one resource. Only way around that is using Harmony.


    public static Func<int, int> GetBuildingResourcesLeaveCalculator(Thing diedThing, DestroyMode mode)
    {
      if (!GenLeaving.CanBuildingLeaveResources(diedThing, mode))
        return (Func<int, int>) (count => 0);
      switch (mode)
      {
        case DestroyMode.Vanish:
          return (Func<int, int>) (count => 0);
        case DestroyMode.KillFinalize:
          return (Func<int, int>) (count => GenMath.RoundRandom((float) count * 0.5f));
        case DestroyMode.Deconstruct:
          return (Func<int, int>) (count => GenMath.RoundRandom(Mathf.Min((float) count * diedThing.def.resourcesFractionWhenDeconstructed, (float) (count - 1))));
        case DestroyMode.FailConstruction:
          return (Func<int, int>) (count => GenMath.RoundRandom((float) count * 0.5f));
        case DestroyMode.Cancel:
          return (Func<int, int>) (count => GenMath.RoundRandom((float) count * 1f));
        case DestroyMode.Refund:
          return (Func<int, int>) (count => count);
        default:
          throw new ArgumentException("Unknown destroy mode " + (object) mode);
      }
    }

Neceros

#3
Thank you very much!

Edit:

Hmm, I figured ThingDef attributes propagated down the class when instanced. When adding that resourcesFractionWhenDeconstructed tag to the base buildings it didn't spread to the other buildings like I thought it would.

I'm simply trying to make a mod that removes as much as I can the resource penalty of deconstructing a construct/building. Is that possible and easy?

jamaicancastle

Inheritance works a little oddly when you change the parent class in XML. Basically, the game loads in all the defs from one mod, then sorts out inheritance (and cross-references and a few other things) for those defs, then moves on to the defs from another mod.

The upshot is that a change to a base class will only propagate to its children if those children are defined (or overwritten) in the same mod or a later-loading mod. In this case, the defs are defined in Core, so they use the version of the base class that exists when Core is being loaded.

Your three options are basically to add it to BuildingBase and then include copies of all the building defs (ugly, but it would work; I recommend putting your mod in the list immediately after core to avoid conflicts with other mods), or to write an xpath patch for each building to update its resourcesFraction (works, but takes forever), or write a Harmony patch to the deconstruction method (simple and quick if you know C#, not so much if you don't).

BrokenValkyrie

Here is an xpath patch for building base.

<?xml version="1.0" encoding="UTF-8"?>
<Patch>
  <Operation Class="PatchOperationAdd">
    <xpath>Defs/ThingDef[@Name = "BuildingBase"]</xpath>
    <value>
<resourcesFractionWhenDeconstructed>1</resourcesFractionWhenDeconstructed>
    </value>
  </Operation>
</Patch>


Which building aren't affected? Have you used god mode to construct and deconstruct building to see if the value matched?

Its hard coded to subtract one. So a Beacon with a cost of 50 steel and 1 component will be deconstructed for 49 steel and 0 component. Assuming you want going for max refund of material.

I could probably write the harmony code to get rid of the -1 of resource, by using post fix operation and replacing the value. It would be a bad idea to change resourceFractionWhenDeconstructed programmatically because some building purposely made it 0.

Neceros

I did not know about xpath patching. A quick read makes it sound really awesome. Thank you for writing that patch code, I will try it out. As you have it here, it sounds amazing. I don't mind a little loss of resources.

BrokenValkyrie

I written the code, because the minus 1 can remove important resource like computer AI. I've attached the compiled code.


using System;
using RimWorld;
using Verse;
using Harmony;
using System.Reflection;
using UnityEngine;

namespace FullResourceRefund
{

[StaticConstructorOnStartup]
[HarmonyPatch(typeof(GenLeaving))]
[HarmonyPatch("GetBuildingResourcesLeaveCalculator")]
static class HarmonyPatches
{
static HarmonyPatches()
{
var harmony = HarmonyInstance.Create("com.github.rimworld.mod.FullResourceRefund");

MethodInfo targetMethod = AccessTools.Method(typeof(GenLeaving), "GetBuildingResourcesLeaveCalculator");
HarmonyMethod postfixMethod = new HarmonyMethod(typeof(FullResourceRefund.HarmonyPatches).GetMethod("LeaveNoResourceBehind"));

harmony.Patch(targetMethod, null, postfixMethod);


}

[HarmonyPostfix]
public static void LeaveNoResourceBehind(Thing diedThing, DestroyMode mode, ref Func<int,int> __result)
{
if (mode == DestroyMode.Deconstruct)
{
__result = (Func<int, int>)(count => GenMath.RoundRandom(Mathf.Min((float)count * diedThing.def.resourcesFractionWhenDeconstructed)));
}
         
}
}

}


[attachment deleted by admin: too old]

ethouiche

A bit of topic, but is it possible to have the same behaviour for <killedLeavings> ?
It seems deconstructing can take in account the stuff(stony/leathery/woody) used to build the item, when killedLeavings cant.


BrokenValkyrie

Not possible to code the same behavior, looking at the code it drops all content so no need to code it. KilledLeaving is a list of item(including content number). Its used for special building like crashed psychic ship.


      ThingOwner<Thing> thingOwner = new ThingOwner<Thing>();
      if (mode == DestroyMode.KillFinalize && diedThing.def.killedLeavings != null)
      {
        for (int index = 0; index < diedThing.def.killedLeavings.Count; ++index)
        {
          Thing thing = ThingMaker.MakeThing(diedThing.def.killedLeavings[index].thingDef, (ThingDef) null);
          thing.stackCount = diedThing.def.killedLeavings[index].count;
          thingOwner.TryAdd(thing, true);
        }
      }