private void AbsorbedDamage(DamageInfo dinfo)
        {
            SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(base.Wearer.Position, base.Wearer.Map, false));
            this.impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
            Vector3 loc = base.Wearer.TrueCenter() + this.impactAngleVect.RotatedBy(180f) * 0.5f;
            float   num = Mathf.Min(10f, 2f + dinfo.Amount / 10f);

            FleckMaker.Static(loc, base.Wearer.Map, FleckDefOf.ExplosionFlash, num);
            int num2 = (int)num;

            for (int i = 0; i < num2; i++)
            {
                FleckMaker.ThrowDustPuff(loc, base.Wearer.Map, Rand.Range(0.8f, 1.2f));
            }
            this.lastAbsorbDamageTick = Find.TickManager.TicksGame;
            this.KeepDisplaying();
        }
예제 #2
0
        private void AbsorbedDamage(DamageInfo dinfo)
        {
            SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
            impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
            Vector3 loc = parent.TrueCenter() + (impactAngleVect.RotatedBy(180f) * 0.5f);
            float   num = Mathf.Min(10f, 2f + (dinfo.Amount / 10f));

            MoteMaker.MakeStaticMote(loc, parent.Map, ThingDefOf.Mote_ExplosionFlash, num);
            int num2 = (int)num;

            for (int i = 0; i < num2; i++)
            {
                MoteMaker.ThrowDustPuff(loc, parent.Map, Rand.Range(0.8f, 1.2f));
            }
            lastAbsorbDamageTick = Find.TickManager.TicksGame;
            KeepDisplaying();
        }
예제 #3
0
        // Token: 0x06000030 RID: 48 RVA: 0x00003B44 File Offset: 0x00001D44
        public void Break()
        {
            Pawn wearer = base.Wearer;

            if (wearer != null && (wearer?.Map) != null)
            {
                SoundStarter.PlayOneShot(SoundDefOf.EnergyShield_Broken, new TargetInfo(wearer.Position, wearer.Map, false));
                MoteMaker.MakeStaticMote(GenThing.TrueCenter(wearer), wearer.Map, ThingDefOf.Mote_ExplosionFlash, 12f);
                for (int i = 0; i < 6; i++)
                {
                    MoteMaker.ThrowDustPuff(GenThing.TrueCenter(wearer) + Vector3Utility.HorizontalVectorFromAngle((float)Rand.Range(0, 360)) * Rand.Range(0.3f, 0.6f), wearer.Map, Rand.Range(0.8f, 1.2f));
                }
            }
            this.energy       = 0f;
            this.ticksToReset = this.StartingTicksToReset;
            this.ActiveCamo   = false;
            this.CamoState    = 2;
        }
예제 #4
0
        private List <NeededRoad> CalculateNeededRoads(Map map)
        {
            List <int> list = new List <int>();

            Find.WorldGrid.GetTileNeighbors(map.Tile, list);
            List <NeededRoad> list2 = new List <NeededRoad>();

            foreach (int item in list)
            {
                RoadDef roadDef = Find.WorldGrid.GetRoadDef(map.Tile, item);
                if (roadDef != null)
                {
                    list2.Add(new NeededRoad
                    {
                        angle = Find.WorldGrid.GetHeadingFromTo(map.Tile, item),
                        road  = roadDef
                    });
                }
            }
            if (list2.Count > 1)
            {
                Vector3 vector = Vector3.zero;
                foreach (NeededRoad item2 in list2)
                {
                    NeededRoad current2 = item2;
                    vector += Vector3Utility.HorizontalVectorFromAngle(current2.angle);
                }
                vector  /= (float)(-list2.Count);
                vector  += Rand.UnitVector3 * 1f / 6f;
                vector.y = 0f;
                for (int i = 0; i < list2.Count; i++)
                {
                    List <NeededRoad> list3 = list2;
                    int        index        = i;
                    NeededRoad value        = default(NeededRoad);
                    NeededRoad neededRoad   = list2[i];
                    value.angle = (Vector3Utility.HorizontalVectorFromAngle(neededRoad.angle) + vector).AngleFlat();
                    NeededRoad neededRoad2 = list2[i];
                    value.road   = neededRoad2.road;
                    list3[index] = value;
                }
            }
            return(list2);
        }
예제 #5
0
        public virtual void AbsorbedDamage(DamageInfo dinfo)
        {
            SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(Pawn.Position, Pawn.Map, false));
            this.impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
            Vector3 loc = Pawn.TrueCenter() + this.impactAngleVect.RotatedBy(180f) * 0.5f;
            float   num = Mathf.Min(10f, 2f + dinfo.Amount / 10f);

            MoteMaker.MakeStaticMote(loc, Pawn.Map, ThingDefOf.Mote_ExplosionFlash, num);
            int num2 = (int)num;

            for (int i = 0; i < num2; i++)
            {
                Rand.PushState();
                AdeptusMoteMaker.ThrowDustPuff(loc, Pawn.Map, Rand.Range(0.8f, 1.2f));
                Rand.PopState();
            }
            this.lastAbsorbDamageTick = Find.TickManager.TicksGame;
            this.KeepDisplaying();
        }
예제 #6
0
        private List <NeededRoad> CalculateNeededRoads(Map map)
        {
            List <int> list = new List <int>();

            Find.WorldGrid.GetTileNeighbors(map.Tile, list);
            List <NeededRoad> list2 = new List <NeededRoad>();
            NeededRoad        item;

            foreach (int item2 in list)
            {
                RoadDef roadDef = Find.WorldGrid.GetRoadDef(map.Tile, item2);
                if (roadDef != null)
                {
                    item = new NeededRoad
                    {
                        angle = Find.WorldGrid.GetHeadingFromTo(map.Tile, item2),
                        road  = roadDef
                    };
                    list2.Add(item);
                }
            }
            if (list2.Count > 1)
            {
                Vector3 zero = Vector3.zero;
                foreach (NeededRoad item3 in list2)
                {
                    zero += Vector3Utility.HorizontalVectorFromAngle(item3.angle);
                }
                zero  /= (float)(-list2.Count);
                zero  += Rand.UnitVector3 * 1f / 6f;
                zero.y = 0f;
                for (int i = 0; i < list2.Count; i++)
                {
                    item = (list2[i] = new NeededRoad
                    {
                        angle = (Vector3Utility.HorizontalVectorFromAngle(list2[i].angle) + zero).AngleFlat(),
                        road = list2[i].road
                    });
                }
            }
            return(list2);
        }
예제 #7
0
        private static void SpawnAqueousCaveWellAt(Map map, IntVec3 position)
        {
            // Spawn main hole.
            SetCellsInRadiusNoRoofNoRock(map, position, 10f);
            SpawnCaveWellOpening(map, position);
            SetCellsInRadiusTerrain(map, position, 10f, TerrainDefOf.Gravel);
            SetCellsInRadiusTerrain(map, position, 8f, TerrainDefOf.WaterShallow);

            // Spawn small additional holes.
            var smallHolesNumber = Rand.RangeInclusive(2, 5);

            for (var holeIndex = 0; holeIndex < smallHolesNumber; holeIndex++)
            {
                IntVec3 smallHolePosition = position + (7f * Vector3Utility.HorizontalVectorFromAngle(Rand.Range(0, 360))).ToIntVec3();
                SetCellsInRadiusNoRoofNoRock(map, smallHolePosition, 5f);
                SetCellsInRadiusTerrain(map, smallHolePosition, 3.2f, TerrainDefOf.WaterShallow);
                SetCellsInRadiusTerrain(map, smallHolePosition, 2.1f, TerrainDefOf.WaterDeep);
            }
            SetCellsInRadiusTerrain(map, position, 5.2f, TerrainDefOf.WaterDeep);
        }
예제 #8
0
        private static void SpawnDryCaveWellAt(Map map, IntVec3 position)
        {
            // Spawn main hole.
            SetCellsInRadiusNoRoofNoRock(map, position, 10f);
            SpawnCaveWellOpening(map, position);
            SetCellsInRadiusTerrain(map, position, 10f, TerrainDefOf.Gravel);
            SetCellsInRadiusTerrain(map, position, 8f, TerrainDefOf.Soil);

            // Spawn small additional holes.
            int smallHolesNumber = Rand.RangeInclusive(2, 5);

            for (int holeIndex = 0; holeIndex < smallHolesNumber; holeIndex++)
            {
                IntVec3 smallHolePosition = position + (7f * Vector3Utility.HorizontalVectorFromAngle(Rand.Range(0, 360))).ToIntVec3();
                SetCellsInRadiusNoRoofNoRock(map, smallHolePosition, 5f);
                SetCellsInRadiusTerrain(map, smallHolePosition, 3.2f, TerrainDefOf.Soil);
                SetCellsInRadiusTerrain(map, smallHolePosition, 2.1f, TerrainDef.Named("SoilRich"));
            }
            SetCellsInRadiusTerrain(map, position, 6.5f, TerrainDef.Named("SoilRich"));
        }
예제 #9
0
        // Token: 0x06000041 RID: 65 RVA: 0x0000385C File Offset: 0x00001A5C
        public void AbsorbedDamage(DamageInfo dinfo)
        {
            var wearer = Wearer;

            SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(wearer.Position, wearer.Map));
            impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
            var loc = wearer.TrueCenter() + (impactAngleVect.RotatedBy(180f) * 0.5f);
            var num = Mathf.Min(10f, 2f + (dinfo.Amount / 10f));

            FleckMaker.Static(loc, wearer.Map, FleckDefOf.ExplosionFlash, num);
            var num2 = (int)num;

            for (var i = 0; i < num2; i++)
            {
                FleckMaker.ThrowDustPuff(loc, wearer.Map, Rand.Range(0.8f, 1.2f));
            }

            lastAbsorbDamageTick = Find.TickManager.TicksGame;
            KeepDisplaying();
        }
        // Token: 0x06000030 RID: 48 RVA: 0x00003B44 File Offset: 0x00001D44
        public void Break()
        {
            var wearer = Wearer;

            if (wearer?.Map != null)
            {
                SoundDefOf.EnergyShield_Broken.PlayOneShot(new TargetInfo(wearer.Position, wearer.Map));
                FleckMaker.Static(wearer.TrueCenter(), wearer.Map, FleckDefOf.ExplosionFlash, 12f);
                for (var i = 0; i < 6; i++)
                {
                    FleckMaker.ThrowDustPuff(
                        wearer.TrueCenter() + (Vector3Utility.HorizontalVectorFromAngle(Rand.Range(0, 360)) *
                                               Rand.Range(0.3f, 0.6f)), wearer.Map, Rand.Range(0.8f, 1.2f));
                }
            }

            energy       = 0f;
            ticksToReset = StartingTicksToReset;
            ActiveCamo   = false;
            CamoState    = 2;
        }
예제 #11
0
        public override void PostPreApplyDamage(DamageInfo dinfo, out bool absorbed)
        {
            //Log.Message(string.Format("Bypassing: {0}", !Props.BypassingDamageDefs.Any(def => dinfo.Def == def)));

            Rand.PushState();
            bool invSave = Rand.Chance(Props.InvunerableSaveChance);

            Rand.PopState();
            if (dinfo.Def != null && base.parent is Pawn pawn && pawn != null && invSave && !Props.BypassingDamageDefs.Any(def => dinfo.Def == def))
            {
                absorbed = true;
                SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(base.parent.Position, base.parent.Map, false));
                Vector3 impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
                Vector3 loc             = base.parent.TrueCenter() + impactAngleVect.RotatedBy(180f) * 0.5f;
                float   num             = Mathf.Min(10f, 2f + (float)dinfo.Amount / 10f);
                AdeptusMoteMaker.MakeStaticMote(loc, base.parent.Map, ThingDefOf.Mote_ExplosionFlash, num);
                int num2 = (int)num;
                for (int i = 0; i < num2; i++)
                {
                    Rand.PushState();
                    AdeptusMoteMaker.ThrowDustPuff(loc, base.parent.Map, Rand.Range(0.8f, 1.2f));
                    float angle = (float)Rand.Range(0, 360);
                    Rand.PopState();
                    float   num3   = Mathf.Lerp(1.2f, 1.55f, 2f);
                    Vector3 vector = pawn.Drawer.DrawPos;
                    vector.y = Altitudes.AltitudeFor(AltitudeLayer.MoteOverhead);
                    int num4 = Find.TickManager.TicksGame - this.lastAbsorbDamageTick;
                    if (num4 < 8)
                    {
                        float num5 = (float)(8 - num4) / 8f * 0.05f;
                        vector += impactAngleVect * num5;
                        num3   -= num5;
                    }
                    Vector3   s      = new Vector3(num3, 1f, num3);
                    Matrix4x4 matrix = default;
                    matrix.SetTRS(vector, Quaternion.AngleAxis(angle, Vector3.up), s);
                    Graphics.DrawMesh(MeshPool.plane10, matrix, CompInvunerableSaveOGStatic.BubbleMat, 0);
                }
                this.lastAbsorbDamageTick = Find.TickManager.TicksGame;
            }
예제 #12
0
        private List <GenStep_Roads.NeededRoad> CalculateNeededRoads(Map map)
        {
            List <int> list = new List <int>();

            Find.WorldGrid.GetTileNeighbors(map.Tile, list);
            List <GenStep_Roads.NeededRoad> list2 = new List <GenStep_Roads.NeededRoad>();

            foreach (int current in list)
            {
                RoadDef roadDef = Find.WorldGrid.GetRoadDef(map.Tile, current, true);
                if (roadDef != null)
                {
                    list2.Add(new GenStep_Roads.NeededRoad
                    {
                        angle = Find.WorldGrid.GetHeadingFromTo(map.Tile, current),
                        road  = roadDef
                    });
                }
            }
            if (list2.Count > 1)
            {
                Vector3 vector = Vector3.zero;
                foreach (GenStep_Roads.NeededRoad current2 in list2)
                {
                    vector += Vector3Utility.HorizontalVectorFromAngle(current2.angle);
                }
                vector  /= (float)(-(float)list2.Count);
                vector  += Rand.UnitVector3 * 1f / 6f;
                vector.y = 0f;
                for (int i = 0; i < list2.Count; i++)
                {
                    list2[i] = new GenStep_Roads.NeededRoad
                    {
                        angle = (Vector3Utility.HorizontalVectorFromAngle(list2[i].angle) + vector).AngleFlat(),
                        road  = list2[i].road
                    };
                }
            }
            return(list2);
        }
예제 #13
0
        public override bool CheckPreAbsorbDamage(DamageInfo dinfo)
        {
            if (ShieldMax <= 0 || shieldInit > 0)
            {
                //受到伤害时重置启动倒计时
                shieldInit = shieldInitSec.SecondsToTicks();
                return(false);
            }
            dinfo.SetAmount(dinfo.Amount / shieldDamagedRate);
            float impact = dinfo.Amount;

            if (impact > shieldCur)
            {
                dinfo.SetAmount(-shieldCur);
                shieldCur  = 0;
                shieldInit = shieldInitSec.SecondsToTicks();
                //剩余护盾相对冲击量越高,抵挡最后一次伤害的概率就越高
                return(Rand.Chance(shieldCur / impact));
            }
            else
            {
                shieldCur -= impact;
                SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(Wearer.Position, Wearer.Map, false));
                impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
                Vector3 loc = Wearer.TrueCenter() + impactAngleVect.RotatedBy(180f) * 0.5f;
                float   num = Mathf.Min(10f, 2f + dinfo.Amount / 10f);
                MoteMaker.MakeStaticMote(loc, Wearer.Map, ThingDefOf.Mote_ExplosionFlash, num);
                int num2 = (int)num;
                for (int i = 0; i < num2; i++)
                {
                    MoteMaker.ThrowDustPuff(loc, Wearer.Map, Rand.Range(0.8f, 1.2f));
                }
                int gt = Find.TickManager.TicksGame;
                lastAbsorbDamageTick = gt;
                lastKeepDisplayTick  = gt;
            }
            return(true);
        }
예제 #14
0
        protected virtual void Break()
        {
            if (this.Pawn?.Map != null && this.Pawn.Position.InBounds(this.Pawn.Map))
            {
                if (Props.brokenSound != null)
                {
                    Props.brokenSound.PlayOneShot(new TargetInfo(this.Pawn.Position, this.Pawn.Map));
                }
                else
                {
                    SoundDefOf.EnergyShield_Broken.PlayOneShot(new TargetInfo(this.Pawn.Position, this.Pawn.Map));
                }

                FleckMaker.Static(this.Pawn.TrueCenter(), this.Pawn.Map, FleckDefOf.ExplosionFlash, 12f);
                for (int i = 0; i < 6; i++)
                {
                    FleckMaker.ThrowDustPuff(this.Pawn.TrueCenter() + Vector3Utility.HorizontalVectorFromAngle(Rand.Range(0, 360)) * Rand.Range(0.3f, 0.6f), this.Pawn.Map, Rand.Range(0.8f, 1.2f));
                }
            }

            energy       = 0f;
            ticksToReset = StartingTicksToReset;
        }
예제 #15
0
 public override void PostPreApplyDamage(DamageInfo dinfo, out bool absorbed)
 {
     if (dinfo.Def == AdeptusDamageDefOf.OG_WarpStormStrike)
     {
         absorbed = true;
         SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(base.parent.Position, base.parent.Map, false));
         Vector3 impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
         Vector3 loc             = base.parent.TrueCenter() + impactAngleVect.RotatedBy(180f) * 0.5f;
         float   num             = Mathf.Min(10f, 2f + (float)dinfo.Amount / 10f);
         FleckMaker.Static(loc, base.parent.Map, FleckDefOf.ExplosionFlash, num);
         int num2 = (int)num;
         for (int i = 0; i < num2; i++)
         {
             Rand.PushState();
             FleckMaker.ThrowDustPuff(loc, base.parent.Map, Rand.Range(0.8f, 1.2f));
             Rand.PopState();
         }
     }
     else
     {
         base.PostPreApplyDamage(dinfo, out absorbed);
     }
 }
예제 #16
0
        public override void PostPreApplyDamage(DamageInfo dinfo, out bool absorbed)
        {
            base.PostPreApplyDamage(dinfo, out absorbed);
            if (absorbed)
            {
                return;
            }

            float impact = dinfo.Amount * shieldDamagedRate;

            if (impact > shieldCur)
            {
                dinfo.SetAmount(-shieldCur);
                shieldCur  = 0;
                shieldInit = shieldInitTick;
                //剩余护盾相对冲击量越高,抵挡最后一次伤害的概率就越高
                absorbed = Rand.Chance(shieldCur / impact);
            }
            else
            {
                shieldCur -= impact;
                SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(parent.Position, parent.Map, false));
                impactAngleVect = Vector3Utility.HorizontalVectorFromAngle(dinfo.Angle);
                Vector3 loc = parent.TrueCenter() + impactAngleVect.RotatedBy(180f) * 0.5f;
                float   num = Mathf.Min(10f, 2f + dinfo.Amount / 10f);
                MoteMaker.MakeStaticMote(loc, parent.Map, ThingDefOf.Mote_ExplosionFlash, num);
                int num2 = (int)num;
                for (int i = 0; i < num2; i++)
                {
                    MoteMaker.ThrowDustPuff(loc, parent.Map, Rand.Range(0.8f, 1.2f));
                }
                int gt = Find.TickManager.TicksGame;
                lastAbsorbDamageTick = gt;
                lastKeepDisplayTick  = gt;
                absorbed             = true;
            }
        }
예제 #17
0
        private void Break()
        {
            if (Wearer.Position == null || Wearer.Map == null)
            {
                return;
            }

            SoundDefOf.EnergyShield_Broken.PlayOneShot(new TargetInfo(Wearer.Position, Wearer.Map));
            //MoteMaker.MakeStaticMote(Wearer.TrueCenter(), Wearer.Map, ThingDefOf.Mote_ExplosionFlash, 12f);
            FleckMaker.Static(base.Wearer.TrueCenter(), base.Wearer.Map, FleckDefOf.ExplosionFlash, 12f);
            for (int i = 0; i < 6; i++)
            {
                /*
                 *              MoteMaker.ThrowDustPuff(
                 *  Wearer.TrueCenter() + Vector3Utility.HorizontalVectorFromAngle(Rand.Range(0, 360)) * Rand.Range(0.3f, 0.6f),
                 *  Wearer.Map,
                 *  Rand.Range(0.8f, 1.2f)
                 *  );
                 */
                FleckMaker.ThrowDustPuff(base.Wearer.TrueCenter() + Vector3Utility.HorizontalVectorFromAngle((float)Rand.Range(0, 360)) * Rand.Range(0.3f, 0.6f), base.Wearer.Map, Rand.Range(0.8f, 1.2f));
            }
            energy       = 0f;
            ticksToReset = StartingTicksToReset;
        }
예제 #18
0
        private void Break()
        {
            //float overkill = Math.Min(EnergyMax * 10 / 3, -energy);
            float overkill = Math.Min(OverKillUpLimit, -energy);

            if (overkill >= FragemntPerCharge)
            {
                SoundDefOf.EnergyShield_Broken.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
                MoteMaker.MakeStaticMote(parent.TrueCenter(), parent.Map, ThingDefOf.Mote_ExplosionFlash, 12f);
                overkilled = true;
            }
            else
            {
                SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
            }
            for (int i = 0; i < 6; i++)
            {
                MoteMaker.ThrowDustPuff(parent.TrueCenter() + (Vector3Utility.HorizontalVectorFromAngle(Rand.Range(0, 360)) * Rand.Range(0.3f, 0.6f)), parent.Map, Rand.Range(0.8f, 1.2f));
            }
            //energy = 0f;
            energy        = -Math.Min(EnergyMax * 10 / 3, overkill * 3);
            pendingCharge = 0f;
            ticksToReset  = StartingTicksToReset;
        }
예제 #19
0
        public virtual IntVec3 FindFapLocation(Pawn pawn)
        {
            IntVec3 position     = pawn.Position;
            int     bestPosition = -100;
            IntVec3 cell         = pawn.Position;
            int     maxDistance  = 40;

            FloatRange  temperature      = pawn.ComfortableTemperatureRange();
            bool        is_somnophile    = xxx.has_quirk(pawn, "Somnophile");
            bool        is_exhibitionist = xxx.has_quirk(pawn, "Exhibitionist");
            List <Pawn> all_pawns        = pawn.Map.mapPawns.AllPawnsSpawned.Where(x
                                                                                   => x.Position.DistanceTo(pawn.Position) < 100 &&
                                                                                   xxx.is_human(x) &&
                                                                                   x != pawn
                                                                                   ).ToList();

            //Log.Message("[RJW] Pawn is " + xxx.get_pawnname(pawn) + ", current cell is " + cell);

            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
            List <IntVec3> random_cells = new List <IntVec3>();

            for (int loop = 0; loop < 50; ++loop)
            {
                random_cells.Add(position + IntVec3.FromVector3(Vector3Utility.HorizontalVectorFromAngle(Rand.Range(0, 360)) * Rand.RangeInclusive(1, maxDistance)));
            }

            random_cells = random_cells.Where(x
                                              => x.Standable(pawn.Map) &&
                                              x.InAllowedArea(pawn) &&
                                              x.GetDangerFor(pawn, pawn.Map) != Danger.Deadly &&
                                              !x.ContainsTrap(pawn.Map) &&
                                              !x.ContainsStaticFire(pawn.Map)
                                              ).Distinct().ToList();

            //Log.Message("[RJW] Found " + random_cells.Count + " valid cells.");

            foreach (IntVec3 random_cell in random_cells)
            {
                if (!xxx.can_path_to_target(pawn, random_cell))
                {
                    continue;                    // too far
                }
                int  score = 0;
                Room room  = random_cell.GetRoom(pawn.Map);

                bool might_be_seen = all_pawns.Any(x
                                                   => GenSight.LineOfSight(x.Position, random_cell, pawn.Map) &&
                                                   x.Position.DistanceTo(random_cell) < 50 &&
                                                   x.Awake()
                                                   );

                if (is_exhibitionist)
                {
                    if (might_be_seen)
                    {
                        score += 5;
                    }
                    else
                    {
                        score -= 10;
                    }
                }
                else
                {
                    if (might_be_seen)
                    {
                        score -= 30;
                    }
                }
                if (is_somnophile)                 // Fap while Watching someone sleep. Not creepy at all!
                {
                    if (all_pawns.Any(x
                                      => GenSight.LineOfSight(random_cell, x.Position, pawn.Map) &&
                                      x.Position.DistanceTo(random_cell) < 6 &&
                                      !x.Awake()
                                      ))
                    {
                        score += 50;
                    }
                }

                if (random_cell.GetTemperature(pawn.Map) > temperature.min && random_cell.GetTemperature(pawn.Map) < temperature.max)
                {
                    score += 20;
                }
                else
                {
                    score -= 20;
                }
                if (random_cell.Roofed(pawn.Map))
                {
                    score += 5;
                }
                if (random_cell.HasEatSurface(pawn.Map))
                {
                    score += 5;                     // Hide in vegetation.
                }
                if (random_cell.GetDangerFor(pawn, pawn.Map) == Danger.Some)
                {
                    score -= 25;
                }
                else if (random_cell.GetDangerFor(pawn, pawn.Map) == Danger.None)
                {
                    score += 5;
                }
                if (random_cell.GetTerrain(pawn.Map) == TerrainDefOf.WaterShallow ||
                    random_cell.GetTerrain(pawn.Map) == TerrainDefOf.WaterMovingShallow ||
                    random_cell.GetTerrain(pawn.Map) == TerrainDefOf.WaterOceanShallow)
                {
                    score -= 20;
                }

                if (random_cell.GetThingList(pawn.Map).Any(x => x.def.IsWithinCategory(ThingCategoryDefOf.Corpses)) && !xxx.is_necrophiliac(pawn))
                {
                    score -= 20;
                }
                if (random_cell.GetThingList(pawn.Map).Any(x => x.def.IsWithinCategory(ThingCategoryDefOf.Foods)))
                {
                    score -= 10;
                }

                if (room == pawn.Position.GetRoom(pawn.MapHeld))
                {
                    score -= 10;
                }
                if (room.PsychologicallyOutdoors)
                {
                    score += 5;
                }
                if (room.isPrisonCell)
                {
                    score += 5;
                }
                if (room.IsHuge)
                {
                    score -= 5;
                }
                if (room.ContainedBeds.Any())
                {
                    score += 5;
                }
                if (room.IsDoorway)
                {
                    score -= 10;
                }
                if (!room.Owners.Any())
                {
                    score += 10;
                }
                else if (room.Owners.Contains(pawn))
                {
                    score += 20;
                }
                if (room.Role == RoomRoleDefOf.Bedroom || room.Role == RoomRoleDefOf.PrisonCell)
                {
                    score += 10;
                }
                else if (room.Role == RoomRoleDefOf.Barracks || room.Role == RoomRoleDefOf.Laboratory || room.Role == RoomRoleDefOf.RecRoom)
                {
                    score += 2;
                }
                else if (room.Role == RoomRoleDefOf.DiningRoom || room.Role == RoomRoleDefOf.Hospital || room.Role == RoomRoleDefOf.PrisonBarracks)
                {
                    score -= 5;
                }
                if (room.GetStat(RoomStatDefOf.Cleanliness) < 0.01f)
                {
                    score -= 5;
                }
                if (room.GetStat(RoomStatDefOf.GraveVisitingJoyGainFactor) > 0.1f)
                {
                    score -= 5;
                }

                if (score <= bestPosition)
                {
                    continue;
                }

                bestPosition = score;
                cell         = random_cell;
            }

            return(cell);

            //Log.Message("[RJW] Best cell is " + cell);
        }
        /// <summary>
        /// Throw a fish mote. So cute! :-)
        /// </summary>
        public Mote ThrowFishMote()
        {
            if (!this.Position.ShouldSpawnMotesAt(this.Map) || this.Map.moteCounter.Saturated)
            {
                return(null);
            }

            bool     startFromLeft = Rand.Chance(0.5f);
            ThingDef moteDef       = null;

            if (this.speciesDef == Util_FishIndustry.MashgonPawnKindDef)
            {
                if (startFromLeft)
                {
                    moteDef = Util_FishIndustry.MoteFishMashgonEastDef;
                }
                else
                {
                    moteDef = Util_FishIndustry.MoteFishMashgonWestDef;
                }
            }
            else if (this.speciesDef == Util_FishIndustry.BluebladePawnKindDef)
            {
                if (startFromLeft)
                {
                    moteDef = Util_FishIndustry.MoteFishBluebladeEastDef;
                }
                else
                {
                    moteDef = Util_FishIndustry.MoteFishBluebladeWestDef;
                }
            }
            else if (this.speciesDef == Util_FishIndustry.TailteethPawnKindDef)
            {
                if (startFromLeft)
                {
                    moteDef = Util_FishIndustry.MoteFishTailteethEastDef;
                }
                else
                {
                    moteDef = Util_FishIndustry.MoteFishTailteethWestDef;
                }
            }
            MoteThrown moteThrown = (MoteThrown)ThingMaker.MakeThing(moteDef, null);

            moteThrown.Scale = Mathf.Lerp(0.2f, 0.6f, (float)this.breedingProgressInTicks / (float)this.breedingDurationInTicks);
            Vector3 moteStartPosition = this.Position.ToVector3Shifted();

            moteThrown.exactRotation = Rand.Range(0f, 45f); // Texture rotation.
            if (startFromLeft)
            {
                // From left to right.
                moteStartPosition += 0.8f * Vector3Utility.HorizontalVectorFromAngle(270f + moteThrown.exactRotation);
                moteThrown.SetVelocity(90f + moteThrown.exactRotation, 0.25f);
            }
            else
            {
                // From east to west.
                moteStartPosition += 0.8f * Vector3Utility.HorizontalVectorFromAngle(90f + moteThrown.exactRotation);
                moteThrown.SetVelocity(270f + moteThrown.exactRotation, 0.25f);
            }
            moteThrown.exactPosition = moteStartPosition;
            GenSpawn.Spawn(moteThrown, this.Position, this.Map);
            return(moteThrown);
        }