Ludeon Forums

RimWorld => Mods => Help => Topic started by: Robostove on November 29, 2016, 11:30:19 PM

Title: Showing a ThingComp gizmo when it's equipped by a drafted pawn
Post by: Robostove on November 29, 2016, 11:30:19 PM
I've created a ThingComp that overrides CompGetGizmosExtra() to add a "charges remaining" gizmo to a weapon. The gizmo is displayed when I select the item on the ground, but it doesn't display when the item is equipped by a drafted pawn.

How do I get it to show up?
Title: Re: Showing a ThingComp gizmo when it's equipped by a drafted pawn
Post by: RawCode on November 30, 2016, 02:39:04 AM
your code?
it won't display on it's own, you must define when, how and where to render new button and what information to use.
Title: Re: Showing a ThingComp gizmo when it's equipped by a drafted pawn
Post by: skullywag on November 30, 2016, 03:19:47 AM
Look at the vanilla personal shields code. All you need is in there.
Title: Re: Showing a ThingComp gizmo when it's equipped by a drafted pawn
Post by: Robostove on November 30, 2016, 07:13:01 PM
I implemented this by looking at Combat Realism's source for their ammo gizmo and making some modifications.

My override of GizmoOnGui:
[StaticConstructorOnStartup]
    public class GizmoChargeStatus : Command
    {
        //...
        public override GizmoResult GizmoOnGUI(Vector2 topLeft)
        {
            if (!initialized)
                InitializeTextures();

            Rect overRect = new Rect(topLeft.x, topLeft.y, Width, Height);
            Widgets.DrawBox(overRect);
            GUI.DrawTexture(overRect, BGTex);

            Rect inRect = overRect.ContractedBy(6);

            Rect textRect = inRect;
            textRect.height = overRect.height / 2;
            Text.Font = GameFont.Tiny;
            Widgets.Label(textRect, "Charges Remaining");

            // Bar
            Rect barRect = inRect;
            barRect.yMin = overRect.y + overRect.height / 2f;
            float ePct = (float)compCharge.curCharge / compCharge.Props.chargeCount;
            Widgets.FillableBar(barRect, ePct);
            Text.Font = GameFont.Small;
            Text.Anchor = TextAnchor.MiddleCenter;
            Widgets.Label(barRect, compCharge.curCharge + " / " + compCharge.Props.chargeCount);
            Text.Anchor = TextAnchor.UpperLeft;

            return new GizmoResult(GizmoState.Clear);
        }
        //...


My override of CompGetGizmosExtra:

    public class CompChargeUser : ThingComp
    {
        //...
        public override IEnumerable<Command> CompGetGizmosExtra()
        {
            GizmoChargeStatus chargeStatusGizmo = new GizmoChargeStatus { compCharge = this };
            yield return chargeStatusGizmo;
        }
        //...
    }


That handles the 'how' and 'where' of rendering the button, but I haven't figured out the 'when'. I noticed PersonalShield has an override called GetWornGizmos, but that's apparel specific.

Do I have to override Tick for this and manually call GizmoOnGui?
Title: Re: Showing a ThingComp gizmo when it's equipped by a pawn [SOLVED]
Post by: Robostove on December 03, 2016, 08:26:12 PM
Alright, figured it out. The base game doesn't expect primary equipment (i.e. weapons) to have attached gizmos, so it doesn't check for them.

I detoured Pawn_EquipmentTracker.GetGizmos() to get all the gizmos attached to ThingComps on equipped items.


        internal static IEnumerable<Gizmo> Detour_GetGizmos(this Pawn_EquipmentTracker _this)
        {
            //reflect required methods
            MethodInfo ShouldUseSquadAttackGizmo = typeof(Pawn_EquipmentTracker).GetMethod("ShouldUseSquadAttackGizmo", BindingFlags.Instance | BindingFlags.NonPublic);
            MethodInfo GetSquadAttackGizmo = typeof(Pawn_EquipmentTracker).GetMethod("GetSquadAttackGizmo", BindingFlags.Instance | BindingFlags.NonPublic);

            //From here until the next comment is just the original GetGizmos updated to use reflected methods
            bool flag = false;

            if ((bool)ShouldUseSquadAttackGizmo.Invoke(_this, null))
            {
                yield return (Gizmo)GetSquadAttackGizmo.Invoke(_this, null);
            }
            int num = 0;
            IEnumerator<ThingWithComps> enumerator = _this.AllEquipment.GetEnumerator();
            while (enumerator.MoveNext())
            {
                ThingWithComps current = enumerator.Current;

                //Here's the meat of it. This returns ThingComp gizmos for all equipment
                IEnumerator<Gizmo> compGizmosEnumerator = current.GetGizmos().GetEnumerator();
                while (compGizmosEnumerator.MoveNext())
                {
                    yield return compGizmosEnumerator.Current;
                }

                //... (original method code)
            }
        }


Edit: Also has the side effect of having the forbid item gizmo show up when equipped, since CompForbiddable is one of the comps it is grabbing gizmos from.