Problems with placeworkers

Started by alleZSoyez, May 18, 2019, 05:31:19 PM

Previous topic - Next topic

alleZSoyez

Hello all! It's been a while, but I'm hoping to pick up working on this mod again after ragequitting over this very issue!

I've created a mirror object. When a pawn walks past it, it'll give a minor mood effect based on whatever beauty/ugly trait the pawn has, or whether the pawn is disfigured. The mirror works great, except for one thing. I've made a placeworker to only let the mirror hang on walls, since this game has a serious lack of wall objects. Once it's on the wall, however, it's as if it doesn't exist anymore. The pawns can't see it. I've even tried to target the space in front of the mirror, which cannot be obstructed, but still the pawns don't see it even if they're standing in the same space and facing the mirror head-on! If I don't use the placeworker, and let the mirror be placed as freely as a table, floating in midair it works again. Could someone give me some insight on this, please?

XML
  <!--======================WALL MIRROR=======================-->
  <ThingDef ParentName="FurnitureWithQualityBase">
    <defName>TatesTFM_WallMirror</defName>
    <thingClass>TatesTinyFurnitureMod.Building_Mirror_TTFM</thingClass>
    <label>wall mirror</label>
    <description>Mirrors are known to make a room feel a little bigger, but not everyone likes them.</description>
    <minifiedDef>MinifiedMirror</minifiedDef>
    <designationCategory>Furniture</designationCategory>
    <graphicData>
      <texPath>alleZSoyez_TatesTinyFurniture/WallMirror/WallMirror</texPath>
      <shaderType>CutoutComplex</shaderType>
      <graphicClass>Graphic_Multi</graphicClass>
      <drawSize>(1,1)</drawSize>
    </graphicData>
    <altitudeLayer>BuildingOnTop</altitudeLayer>
    <defaultPlacingRot>South</defaultPlacingRot>
    <uiIconPath>alleZSoyez_TatesTinyFurniture/WallMirror/WallMirror_UI</uiIconPath>
    <statBases>
      <MaxHitPoints>20</MaxHitPoints>
      <WorkToBuild>400</WorkToBuild>
      <Mass>3</Mass>
      <Flammability>1.0</Flammability>
      <Comfort>0.5</Comfort>
      <Beauty>1</Beauty>
    </statBases>
    <passability>Standable</passability>
    <stuffCategories>
      <li>Metallic</li>
      <li>Woody</li>
      <li>Stony</li>
    </stuffCategories>
    <costList>
      <Steel>5</Steel>
    </costList>
    <costStuffCount>10</costStuffCount>
    <techLevel>Medieval</techLevel>
    <pathCost>1</pathCost>
    <staticSunShadowHeight>0.1</staticSunShadowHeight>
    <castEdgeShadows>true</castEdgeShadows>
    <fillPercent>0.35</fillPercent>
    <researchPrerequisites>
      <li>ComplexFurniture</li>
    </researchPrerequisites>
    <building>
      <isEdifice>false</isEdifice>
      <canPlaceOverImpassablePlant>false</canPlaceOverImpassablePlant>
    </building>
    <placeWorkers>
      <li>TatesTinyFurnitureMod.PlaceWorker_OnlyOnWalls</li>
    </placeWorkers>
    <size>(1,1)</size>
    <clearBuildingArea>false</clearBuildingArea>
  </ThingDef>


C# (thoughtworker)
   //************* mirror thought
    [DefOf]
    public static class ThoughtDefOf
    {
        public static ThoughtDef SawSelfInMirror;
    }

    public class MirrorThought : Thought_Situational { }

    //************* the thought maker
    public class ThoughtWorker_Mirror : ThoughtWorker
    {
        public bool MirrorExistsNearby(Pawn p)
        {
            Building_Mirror_TTFM thisMirror;

            try
            {
                thisMirror = (Building_Mirror_TTFM)GenClosest.ClosestThingReachable(p.Position, p.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.None, TraverseParms.For(p), 3f);
            }
            catch
            {
                return false;
            }

            if (thisMirror != null)
            {
                // make sure the pawn is not facing away from the mirror and that the pawn is before the mirror part
                // for some reason the game uses z value as "y" but it's really z
                // however, we want the square "in front" of the mirror, which is dependent on rotation, otherwise the wall will block it
                Vector2 mirrorRotReadable = thisMirror.Rotation.AsVector2;
                Rot4 mirrorRot = thisMirror.Rotation;
                IntVec3 mirrorPos = thisMirror.Position;
                IntVec3 inFrontOfMirror = new IntVec3();

                // down
                if (mirrorRotReadable == Vector2.down)
                {
                    inFrontOfMirror = mirrorPos - new IntVec3(0, 0, 1);
                }
                // up
                else if (mirrorRotReadable == Vector2.up)
                {
                    inFrontOfMirror = mirrorPos;
                }
                // left/right
                else if (mirrorRotReadable == Vector2.right)
                {
                    inFrontOfMirror = mirrorPos + new IntVec3(1, 0, 0);
                }
                else if (mirrorRotReadable == Vector2.left)
                {
                    inFrontOfMirror = mirrorPos - new IntVec3(1, 0, 0);
                }

                int px = p.Position.x;
                int pz = p.Position.z;
                               
                Vector2 pr = p.Rotation.AsVector2;
               
                // which way is the mirror facing, is the pawn facing the mirror (pawn can't be facing same direction as mirror), and is the pawn in front of the mirror?
                if (mirrorRotReadable == Vector2.up && pr != Vector2.up && pz >= inFrontOfMirror.z || // mirror up
                    mirrorRotReadable == Vector2.down && pr != Vector2.down && pz <= inFrontOfMirror.z || // mirror down
                    mirrorRotReadable == Vector2.left && pr != Vector2.left && px <= inFrontOfMirror.x || // mirror left
                    mirrorRotReadable == Vector2.right && pr != Vector2.right && px >= inFrontOfMirror.x  // mirror right
                    )
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        protected override ThoughtState CurrentStateInternal(Pawn p)
        { // is there a mirror nearby?
            if (MirrorExistsNearby(p) == true)
            { // can see?
                if (p.health.capacities.CapableOf(PawnCapacityDefOf.Sight))
                {   // is disfigured?
                    if (RelationsUtility.IsDisfigured(p))
                    {
                        return ThoughtState.ActiveAtStage(5);
                    }
                    else // not disfigured
                    { // has beauty?
                        bool b = p.story.traits.HasTrait(TraitDefOf.Beauty);
                        if (b == true)
                        {   // how much?
                            int d = p.story.traits.DegreeOfTrait(TraitDefOf.Beauty);

                            // get values for final output
                            switch (d)
                            {
                                case -2:
                                    return ThoughtState.ActiveAtStage(1);
                                case -1:
                                    return ThoughtState.ActiveAtStage(2);
                                case 1:
                                    return ThoughtState.ActiveAtStage(3);
                                case 2:
                                    return ThoughtState.ActiveAtStage(4);
                                default:
                                    return ThoughtState.ActiveAtStage(0);
                            }
                        }
                        else { return ThoughtState.ActiveAtStage(0); } // doesn't have beauty trait
                    }
                }
                else { return ThoughtState.Inactive; } // can't see
            }
            else { return ThoughtState.Inactive; } // no mirror
        }
    }


C# (placeworker)
//************ mirrors should only attach to walls
    public class PlaceWorker_OnlyOnWalls : PlaceWorker
    {
        public override AcceptanceReport AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Map map, Thing thingToIgnore = null)
        {
            Vector2 mr = rot.AsVector2;
            IntVec3 downOneTile = new IntVec3(0, 0, -1);
            IntVec3 upOneTile = new IntVec3(0, 0, 1);
            IntVec3 rightOneTile = new IntVec3(1, 0, 0);
            IntVec3 leftOneTile = new IntVec3(-1, 0, 0);

            IntVec3 inFrontOfMirror = new IntVec3();
            // this finds the tile in front of the mirror
            if (mr == Vector2.down)
            {
                inFrontOfMirror = loc + IntVec3.North.RotatedBy(rot);
            }
            else if (mr == Vector2.up)
            {
                inFrontOfMirror = loc + IntVec3.North.RotatedBy(rot)-new IntVec3(0,0,1);
            }
            else
            {
                inFrontOfMirror = loc + IntVec3.South.RotatedBy(rot);
            }

            Thing onWall = map.thingGrid.ThingAt(loc, ThingDefOf.Wall);
            Thing wallRightBelowMirror = map.thingGrid.ThingAt(loc + downOneTile, ThingDefOf.Wall);

            // front of mirror cannot be blocked by another impassible thing
            if (inFrontOfMirror.Impassable(map))
            {
                return "Front of mirror cannot be obstructed.";
            }
            else
            {
                // facing north
                if (mr == Vector2.up)
                {
                    // wall exists below where we want mirror
                    if (wallRightBelowMirror == null || wallRightBelowMirror.Position != loc + downOneTile)
                    {
                        return "When facing north, mirror must be placed directly above a wall.";
                    }
                }
                // facing other direction
                else
                {
                    // wall exists right where we're placing it
                    if (onWall == null || onWall.Position != loc)
                    {
                        return "Mirror must be placed directly onto wall.";
                    }
                }
                return true;
            }
        }

        // draw the part that we need unobstructed
        public override void DrawGhost(ThingDef def, IntVec3 center, Rot4 rot, Color ghostCol)
        {
            Map currentMap = Find.CurrentMap;
            IntVec3 inFrontOfMirror = new IntVec3();
            // this finds the tile "in front" of the mirror
            if (rot.AsVector2 == Vector2.down)
            {
                inFrontOfMirror = center + IntVec3.North.RotatedBy(rot);
            }
            else if (rot.AsVector2 == Vector2.up)
            {
                inFrontOfMirror = center + IntVec3.North.RotatedBy(rot)-new IntVec3(0,0,1);
            }
            else
            {
                inFrontOfMirror = center + IntVec3.South.RotatedBy(rot);
            }
           
            GenDraw.DrawFieldEdges(new List<IntVec3>{ inFrontOfMirror }, Color.white);
           
        }

        public override bool ForceAllowPlaceOver(BuildableDef otherDef)
        {
            return otherDef == ThingDefOf.Wall;
        }
    }

Mehni

Quote            try
            {
                thisMirror = (Building_Mirror_TTFM)GenClosest.ClosestThingReachable(p.Position, p.Map, ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial), PathEndMode.None, TraverseParms.For(p), 3f);
            }
            catch
            {
                return false;
            }

You have a try/catch block which looks like it'll trigger the catch a lot of the time. This is effectively an unhandled error, and you're going in blind.