destroyOnNoFuel and fire overlays

Started by larSyn, March 14, 2018, 01:26:44 PM

Previous topic - Next topic

larSyn

I'm trying to add a torch-like object and the flame appears both when it is first built and there is no fuel in it and when it runs out of fuel.  It also doesn't light up when first built.   I basically copied the Core Torch file directly over and changed some stuff around for my object, so I'm at a loss for why it's not working.

Is it possible to have the fire overlay disappear when the "destroyOnNoFuel" tag is set to false?  And have the fire only appear once it is fueled or have it fueled upon construction? 

jamaicancastle

The two behaviors here are both governed by comps, which have an associated class in C#. In this case you want to make CompFireOverlay obey the associated object's CompRefuelable. There are two basic ways to do that: you can use Harmony to patch the existing comp, or you can just write a new one in C# that does the same thing but with your additions.

A lot of comps already refer to one another, so you can use them as examples. For instance, the standing lamp's CompGlower refers to its CompFlickable so that it doesn't produce light when turned off.

The glowing and heating up that torches do, which you'll presumably want to also make dependent on having fuel, are controlled by CompGlower and CompHeatPusher, respectively. You can modify them in exactly the same way.

larSyn

Thanks!  I'll try and figure out the C# method.  New to coding, so, I'm gonna stay away from Harmony until I have more experience.

larSyn

Ok, so I was able to figure out that the fireOverlay needs to respond to receiveCompSignal, but I still can't figure out how to get the fire graphic to disappear when the "RanOutOfFuel" signal triggers.  If anyone could help, I would greatly appreciate it.

jamaicancastle

The way CompFireOverlay works is that it draws in the fire each tick, after the object itself is drawn. Therefore, you don't have to worry overmuch with comp signals - you just need to check in PostDraw() whether the fire should be drawn that frame or not, by locating the object's CompRefuelable and using its HasFuel property. If it doesn't have fuel, simply skip the rest of the method, where the fire is actually drawn.

Each comp stores the object it's attached to as "parent", and you can ask a thing for a specific comp using the following method:
parent.GetComp<CompRefuelable>();
(Note that the other comp's class goes in the angle brackets <>, not the parentheses.)

Because PostDraw() is called a lot, it's inefficient to look the comp up every time. However, we can store it as a variable in our own comp, like so:
private CompRefuelable refuelableComp

Then you'll want to add the following:
public override void Initialize(CompProperties props)
{
base.Initialize(props);
refuelableComp = parent.GetComp<CompRefuelable>();
}

If you're using VisualStudio, start with the keyword "override" and it will display a list of base functions you can override; for comps, this is very useful, since virtually anything you override from the base comp will be called at appropriate times without any further prodding from you. Initialize() is how the comp is set up when the object is first created, so it's good for one-time setup details like this. The last line before the bracket asks the parent for its refuelable comp and saves it to a field so we don't have to keep looking it up all the time. (As a general rule, a thing's comps won't change much, if at all, after it's created.)

Once it's saved, it's trivial to look it up during PostDraw():
public override void PostDraw()
{
if(refuelableComp == null || refuelableComp.HasFuel)
{
//code that draws the fire overlay in here
}
}

The null check prevents the game from throwing errors if refuelableComp doesn't exist. It also makes the comp more modular: if the ThingDef doesn't have a CompRefuelable in the first place, its fire overlay will still work, without getting stuck on the question of whether a nonexistent comp has fuel in it or not.

larSyn

Thanks for helping a noob out, jamaicancastle, I really do appreciate it.  I tried what you suggested and was able to get the fire to not appear without fuel, but now it doesn't appear once fueled.  Here's the code that i have now:

[StaticConstructorOnStartup]
    public class AS_CompFireOverlay : ThingComp
    {
        private static readonly Graphic FireGraphic = GraphicDatabase.Get<Graphic_Flicker>("Things/Special/Fire", ShaderDatabase.TransparentPostLight, Vector2.one, Color.white);

        public AS_CompProperties_FireOverlay Props
        {
            get
            {
                return (AS_CompProperties_FireOverlay)this.props;
            }
        }

        private CompRefuelable refuelableComp;

        public override void Initialize(CompProperties props)
        {
            base.Initialize(props);
            refuelableComp = parent.GetComp<CompRefuelable>();
        }

        public override void PostDraw()
        {
            if (refuelableComp == null || refuelableComp.HasFuel)
            {
                base.PostDraw();
                Vector3 drawPos = this.parent.DrawPos;
                drawPos.y += 0.046875f;
                AS_CompFireOverlay.FireGraphic.Draw(drawPos, Rot4.North, this.parent, 0f);
            }
        }
    }


I'm probably missing something simple here.  Again thanks for any help. 

jamaicancastle

I'm not sure that it's simple. Looking through the fire graphic, I came across some references to CompFireOverlay, so it looks like it wants that class in particular. However, it should still pick up a subclass. You'll want to change your class to inherit from CompFireOverlay instead of directly from ThingComp, like so:
public class AS_CompFireOverlay : CompFireOverlay

It may complain about the FireGraphic field, since it's private, but you can just use the one from the base class in either case, so just remove that line. The only other change is in PostDraw(): the call to base.PostDraw() will go to CompFireOverlay's PostDraw which already contains the three lines below it, so you don't need them.

You'll probably also need to set your CompProperties class to inherit from CompProperties_FireOverlay in the same manner. In that case, it should be fine without any other adjustments.

If you make those changes, the graphics code should be able to read your comp as though it were also a vanilla CompFireOverlay when it expects one, which should make it work. Otherwise it's probably going to need to be a Harmony patch.

larSyn

Ha!  That worked!  I also had to delete a couple lines in CompProperties_FireOverlay (the fire size and offset settings) but that did it.  Thanks so much for your help!  :)  I'll be sure to include you in my credits/thanks section once the mod is up!