﻿===== RanchStationConfig =====
using Klei.AI;
using STRINGS;
using TUNING;
using UnityEngine;

public class RanchStationConfig : IBuildingConfig
{
	public const string ID = "RanchStation";

	public override BuildingDef CreateBuildingDef()
	{
		BuildingDef obj = BuildingTemplates.CreateBuildingDef("RanchStation", 2, 3, "rancherstation_kanim", 30, 30f, TUNING.BUILDINGS.CONSTRUCTION_MASS_KG.TIER4, MATERIALS.ALL_METALS, 1600f, BuildLocationRule.OnFloor, noise: NOISE_POLLUTION.NOISY.TIER1, decor: TUNING.BUILDINGS.DECOR.NONE);
		obj.ViewMode = OverlayModes.Rooms.ID;
		obj.Overheatable = false;
		obj.AudioCategory = "Metal";
		obj.AudioSize = "large";
		obj.LogicInputPorts = LogicOperationalController.CreateSingleInputPortList(new CellOffset(0, 0));
		obj.RequiredSkillPerkID = Db.Get().SkillPerks.CanUseRanchStation.Id;
		obj.AddSearchTerms(SEARCH_TERMS.RANCHING);
		obj.AddSearchTerms(SEARCH_TERMS.CRITTER);
		return obj;
	}

	public override void ConfigureBuildingTemplate(GameObject go, Tag prefab_tag)
	{
		go.AddOrGet<LoopingSounds>();
		go.GetComponent<KPrefabID>().AddTag(RoomConstraints.ConstraintTags.RanchStationType);
	}

	public override void DoPostConfigureComplete(GameObject go)
	{
		go.AddOrGet<LogicOperationalController>();
		RanchStation.Def def = go.AddOrGetDef<RanchStation.Def>();
		def.IsCritterEligibleToBeRanchedCb = (GameObject creature_go, RanchStation.Instance ranch_station_smi) => !creature_go.GetComponent<Effects>().HasEffect("Ranched");
		def.RancherWipesBrowAnim = true;
		def.OnRanchCompleteCb = delegate(GameObject creature_go, WorkerBase rancher_wb)
		{
			creature_go.GetSMI<RanchableMonitor.Instance>().TargetRanchStation.GetSMI<RancherChore.RancherChoreStates.Instance>();
			float num = rancher_wb.GetAttributes()?.Get(Db.Get().Attributes.Ranching.Id).GetTotalValue() ?? 0f;
			float num2 = 1f + num * 0.1f;
			creature_go.GetComponent<Effects>().Add("Ranched", should_save: true).timeRemaining *= num2;
			AmountInstance amountInstance = Db.Get().Amounts.HitPoints.Lookup(creature_go);
			amountInstance?.ApplyDelta(amountInstance.GetMax() - amountInstance.value + 1f);
		};
		def.RanchedPreAnim = "grooming_pre";
		def.RanchedLoopAnim = "grooming_loop";
		def.RanchedPstAnim = "grooming_pst";
		def.WorkTime = 12f;
		def.GetTargetRanchCell = delegate(RanchStation.Instance smi)
		{
			int result = Grid.InvalidCell;
			if (!smi.IsNullOrStopped())
			{
				result = Grid.CellRight(Grid.PosToCell(smi.transform.GetPosition()));
			}
			return result;
		};
		RoomTracker roomTracker = go.AddOrGet<RoomTracker>();
		roomTracker.requiredRoomType = Db.Get().RoomTypes.CreaturePen.Id;
		roomTracker.requirement = RoomTracker.Requirement.Required;
		go.AddOrGet<SkillPerkMissingComplainer>().requiredSkillPerk = Db.Get().SkillPerks.CanUseRanchStation.Id;
		Prioritizable.AddRef(go);
	}
}

===== ShearingStationConfig =====
using TUNING;
using UnityEngine;

public class ShearingStationConfig : IBuildingConfig
{
	public const string ID = "ShearingStation";

	public override BuildingDef CreateBuildingDef()
	{
		BuildingDef obj = BuildingTemplates.CreateBuildingDef("ShearingStation", 3, 3, "shearing_station_kanim", 100, 10f, BUILDINGS.CONSTRUCTION_MASS_KG.TIER4, MATERIALS.RAW_METALS, 1600f, BuildLocationRule.OnFloor, noise: NOISE_POLLUTION.NONE, decor: BUILDINGS.DECOR.NONE);
		obj.RequiresPowerInput = true;
		obj.EnergyConsumptionWhenActive = 60f;
		obj.ExhaustKilowattsWhenActive = 0.125f;
		obj.SelfHeatKilowattsWhenActive = 0.5f;
		obj.Floodable = true;
		obj.Entombable = true;
		obj.AudioCategory = "Metal";
		obj.AudioSize = "large";
		obj.UtilityInputOffset = new CellOffset(0, 0);
		obj.UtilityOutputOffset = new CellOffset(0, 0);
		obj.DefaultAnimState = "on";
		obj.ShowInBuildMenu = true;
		return obj;
	}

	public override void ConfigureBuildingTemplate(GameObject go, Tag prefab_tag)
	{
		go.AddOrGet<LoopingSounds>();
		go.AddOrGet<BuildingComplete>().isManuallyOperated = true;
		go.GetComponent<KPrefabID>().AddTag(RoomConstraints.ConstraintTags.RanchStationType);
		RoomTracker roomTracker = go.AddOrGet<RoomTracker>();
		roomTracker.requiredRoomType = Db.Get().RoomTypes.CreaturePen.Id;
		roomTracker.requirement = RoomTracker.Requirement.Required;
	}

	public override void DoPostConfigureComplete(GameObject go)
	{
		RanchStation.Def def = go.AddOrGetDef<RanchStation.Def>();
		def.IsCritterEligibleToBeRanchedCb = (GameObject creature_go, RanchStation.Instance ranch_station_smi) => creature_go.GetSMI<IShearable>()?.IsFullyGrown() ?? false;
		def.OnRanchCompleteCb = delegate(GameObject creature_go, WorkerBase rancher_wb)
		{
			IShearable sMI = creature_go.GetSMI<IShearable>();
			Tuple<Tag, float> itemDroppedOnShear = sMI.GetItemDroppedOnShear();
			DropShearable(rancher_wb.gameObject, creature_go, itemDroppedOnShear.first, itemDroppedOnShear.second);
			sMI.Shear();
		};
		def.RancherInteractAnim = "anim_interacts_shearingstation_kanim";
		def.WorkTime = 12f;
		def.RanchedPreAnim = "shearing_pre";
		def.RanchedLoopAnim = "shearing_loop";
		def.RanchedPstAnim = "shearing_pst";
		def.RancherWipesBrowAnim = false;
		go.AddOrGet<SkillPerkMissingComplainer>().requiredSkillPerk = Db.Get().SkillPerks.CanUseRanchStation.Id;
		Prioritizable.AddRef(go);
	}

	private void DropShearable(GameObject go, GameObject critter, Tag item_dropped, float mass)
	{
		PrimaryElement component = critter.GetComponent<PrimaryElement>();
		GameObject gameObject = Util.KInstantiate(Assets.GetPrefab(item_dropped));
		int cell = Grid.CellLeft(Grid.PosToCell(go));
		gameObject.transform.SetPosition(Grid.CellToPosCCC(cell, Grid.SceneLayer.Ore));
		PrimaryElement component2 = gameObject.GetComponent<PrimaryElement>();
		component2.Temperature = component.Temperature;
		component2.Mass = mass;
		component2.AddDisease(component.DiseaseIdx, component.DiseaseCount, "Shearing");
		gameObject.SetActive(value: true);
		Vector2 initial_velocity = new Vector2(Random.Range(-1f, 1f) * 1f, Random.value * 2f + 2f);
		if (GameComps.Fallers.Has(gameObject))
		{
			GameComps.Fallers.Remove(gameObject);
		}
		GameComps.Fallers.Add(gameObject, initial_velocity);
	}
}

===== RanchableMonitor =====
public class RanchableMonitor : GameStateMachine<RanchableMonitor, RanchableMonitor.Instance, IStateMachineTarget, RanchableMonitor.Def>
{
	public class Def : BaseDef
	{
	}

	public new class Instance : GameInstance
	{
		public RanchStation.Instance TargetRanchStation;

		private Navigator navComponent;

		private RanchedStates.Instance states;

		public ChoreConsumer ChoreConsumer { get; private set; }

		public Navigator NavComponent => navComponent;

		public RanchedStates.Instance States
		{
			get
			{
				if (states == null)
				{
					states = controller.GetSMI<RanchedStates.Instance>();
				}
				return states;
			}
		}

		public Instance(IStateMachineTarget master, Def def)
			: base(master, def)
		{
			ChoreConsumer = GetComponent<ChoreConsumer>();
			navComponent = GetComponent<Navigator>();
		}

		public bool ShouldGoGetRanched()
		{
			if (TargetRanchStation != null && TargetRanchStation.IsRunning())
			{
				return TargetRanchStation.IsRancherReady;
			}
			return false;
		}
	}

	public override void InitializeStates(out BaseState default_state)
	{
		default_state = root;
		root.ToggleBehaviour(GameTags.Creatures.WantsToGetRanched, (Instance smi) => smi.ShouldGoGetRanched());
	}
}

===== RanchedStates =====
using STRINGS;

public class RanchedStates : GameStateMachine<RanchedStates, RanchedStates.Instance, IStateMachineTarget, RanchedStates.Def>
{
	public class Def : BaseDef
	{
		public string StartWaitingAnim = "queue_pre";

		public string WaitingAnim = "queue_loop";

		public string EndWaitingAnim = "queue_pst";

		public int WaitCellOffset = 1;
	}

	public new class Instance : GameInstance
	{
		public float OriginalSpeed;

		private int waitCell;

		private KBatchedAnimController animController;

		private RanchableMonitor.Instance ranchMonitor;

		public float cheerAnimLength;

		public RanchableMonitor.Instance Monitor
		{
			get
			{
				if (ranchMonitor == null)
				{
					ranchMonitor = this.GetSMI<RanchableMonitor.Instance>();
				}
				return ranchMonitor;
			}
		}

		public KBatchedAnimController AnimController => animController;

		public Instance(Chore<Instance> chore, Def def)
			: base((IStateMachineTarget)chore, def)
		{
			animController = GetComponent<KBatchedAnimController>();
			OriginalSpeed = Monitor.NavComponent.defaultSpeed;
			chore.AddPrecondition(ChorePreconditions.instance.CheckBehaviourPrecondition, GameTags.Creatures.WantsToGetRanched);
			KAnim.Anim anim = animController.GetAnim(new HashedString("excited_loop"));
			cheerAnimLength = ((anim != null) ? (anim.totalTime + 0.2f) : 1.2f);
		}

		public RanchStation.Instance GetRanchStation()
		{
			if (Monitor != null)
			{
				return Monitor.TargetRanchStation;
			}
			return null;
		}

		public void EnterQueue()
		{
			if (GetRanchStation() != null)
			{
				InitializeWaitCell();
				Monitor.NavComponent.GoTo(waitCell);
			}
		}

		public void AbandonRanchStation()
		{
			if (Monitor.TargetRanchStation != null && status != Status.Failed)
			{
				StopSM("Abandoned Ranch");
			}
		}

		public void SetRanchStation(RanchStation.Instance ranch_station)
		{
			if (Monitor.TargetRanchStation != null && Monitor.TargetRanchStation != ranch_station)
			{
				Monitor.TargetRanchStation.Abandon(base.smi.Monitor);
			}
			base.smi.sm.ranchTarget.Set(ranch_station.gameObject, base.smi);
			Monitor.TargetRanchStation = ranch_station;
		}

		public int ModifyNavTargetForCritter(int navCell)
		{
			if (base.smi.HasTag(GameTags.Creatures.Flyer))
			{
				return Grid.CellAbove(navCell);
			}
			return navCell;
		}

		private void InitializeWaitCell()
		{
			if (GetRanchStation() != null)
			{
				int cell = 0;
				Extents stationExtents = Monitor.TargetRanchStation.StationExtents;
				int cell2 = ModifyNavTargetForCritter(Grid.XYToCell(stationExtents.x, stationExtents.y));
				int num = 0;
				if (Grid.Raycast(cell2, new Vector2I(-1, 0), out var hitDistance, base.def.WaitCellOffset, ~(Grid.BuildFlags.DupePassable | Grid.BuildFlags.DupeImpassable)))
				{
					num = 1 + base.def.WaitCellOffset - hitDistance;
					cell = ModifyNavTargetForCritter(Grid.XYToCell(stationExtents.x + 1, stationExtents.y));
				}
				int num2 = 0;
				if (num != 0 && Grid.Raycast(cell, new Vector2I(1, 0), out var hitDistance2, base.def.WaitCellOffset, ~(Grid.BuildFlags.DupePassable | Grid.BuildFlags.DupeImpassable)))
				{
					num2 = base.def.WaitCellOffset - hitDistance2;
				}
				int x = (base.def.WaitCellOffset - num) * -1;
				if (num == base.def.WaitCellOffset)
				{
					x = 1 + base.def.WaitCellOffset - num2;
				}
				CellOffset offset = new CellOffset(x, 0);
				waitCell = Grid.OffsetCell(cell2, offset);
			}
		}

		public void UpdateWaitingState()
		{
			if (IsCrittersTurn(base.smi))
			{
				if (base.smi.IsInsideState(base.sm.ranch.Wait.Waiting))
				{
					base.smi.GoTo(base.smi.sm.ranch.Wait.DoneWaiting);
				}
				else
				{
					base.smi.GoTo(base.smi.sm.ranch.Cheer);
				}
			}
			else
			{
				base.smi.GoTo(base.smi.sm.ranch.Wait.WaitInLine);
			}
		}
	}

	public class RanchStates : State
	{
		public CheerStates Cheer;

		public MoveStates Move;

		public WaitStates Wait;

		public State Ranching;

		public State Wavegoodbye;

		public State Runaway;
	}

	public class CheerStates : State
	{
		public State Cheer;

		public State Pst;
	}

	public class MoveStates : State
	{
		public State MoveToRanch;
	}

	public class WaitStates : State
	{
		public State WaitInLine;

		public State Waiting;

		public State DoneWaiting;
	}

	private RanchStates ranch;

	private TargetParameter ranchTarget;

	public override void InitializeStates(out BaseState default_state)
	{
		default_state = ranch;
		root.Exit("AbandonedRanchStation", delegate(Instance smi)
		{
			if (smi.Monitor.TargetRanchStation != null)
			{
				if (smi.Monitor.TargetRanchStation.IsCritterInQueue(smi.Monitor))
				{
					Debug.LogWarning("Why are we exiting RanchedStates while in the queue?");
					smi.Monitor.TargetRanchStation.Abandon(smi.Monitor);
				}
				smi.Monitor.TargetRanchStation = null;
			}
			smi.sm.ranchTarget.Set(null, smi);
		});
		ranch.EnterTransition(ranch.Cheer, (Instance smi) => IsCrittersTurn(smi)).EventHandler(GameHashes.RanchStationNoLongerAvailable, delegate(Instance smi)
		{
			smi.GoTo((BaseState)null);
		}).BehaviourComplete(GameTags.Creatures.WantsToGetRanched, on_exit: true)
			.Update(delegate(Instance smi, float deltaSeconds)
			{
				RanchStation.Instance ranchStation2 = smi.GetRanchStation();
				if (ranchStation2.IsNullOrDestroyed())
				{
					smi.StopSM("No more target ranch station.");
				}
				else
				{
					Option<CavityInfo> option = Option.Maybe(Game.Instance.roomProber.GetCavityForCell(Grid.PosToCell(smi)));
					Option<CavityInfo> cavityInfo = ranchStation2.GetCavityInfo();
					if (option.IsNone() || cavityInfo.IsNone())
					{
						smi.StopSM("No longer in any cavity.");
					}
					else if (option.Unwrap() != cavityInfo.Unwrap())
					{
						smi.StopSM("Critter is in a different cavity");
					}
				}
			})
			.EventHandler(GameHashes.RancherReadyAtRanchStation, delegate(Instance smi)
			{
				smi.UpdateWaitingState();
			})
			.Exit(ClearLayerOverride);
		CheerStates cheer = ranch.Cheer;
		string text = CREATURES.STATUSITEMS.EXCITED_TO_GET_RANCHED.NAME;
		string tooltip = CREATURES.STATUSITEMS.EXCITED_TO_GET_RANCHED.TOOLTIP;
		StatusItemCategory main = Db.Get().StatusItemCategories.Main;
		cheer.ToggleStatusItem(text, tooltip, "", StatusItem.IconType.Info, NotificationType.Neutral, allow_multiples: false, default(HashedString), 129022, null, null, main).Enter("FaceRancher", delegate(Instance smi)
		{
			smi.GetComponent<Facing>().Face(smi.GetRanchStation().transform.GetPosition());
		}).PlayAnim("excited_loop")
			.OnAnimQueueComplete(ranch.Cheer.Pst)
			.ScheduleGoTo((Instance smi) => smi.cheerAnimLength, ranch.Move);
		ranch.Cheer.Pst.ScheduleGoTo(0.2f, ranch.Move);
		State state = ranch.Move.DefaultState(ranch.Move.MoveToRanch).Enter("Speedup", delegate(Instance smi)
		{
			smi.GetComponent<Navigator>().defaultSpeed = smi.OriginalSpeed * 1.25f;
		});
		string text2 = CREATURES.STATUSITEMS.EXCITED_TO_GET_RANCHED.NAME;
		string tooltip2 = CREATURES.STATUSITEMS.EXCITED_TO_GET_RANCHED.TOOLTIP;
		main = Db.Get().StatusItemCategories.Main;
		state.ToggleStatusItem(text2, tooltip2, "", StatusItem.IconType.Info, NotificationType.Neutral, allow_multiples: false, default(HashedString), 129022, null, null, main).Exit("RestoreSpeed", delegate(Instance smi)
		{
			smi.GetComponent<Navigator>().defaultSpeed = smi.OriginalSpeed;
		});
		ranch.Move.MoveToRanch.EnterTransition(ranch.Wait.WaitInLine, GameStateMachine<RanchedStates, Instance, IStateMachineTarget, Def>.Not(IsCrittersTurn)).MoveTo(GetRanchNavTarget, ranch.Wait.WaitInLine).Target(ranchTarget)
			.EventTransition(GameHashes.CreatureArrivedAtRanchStation, ranch.Wait.WaitInLine, (Instance smi) => !IsCrittersTurn(smi));
		ranch.Wait.WaitInLine.EnterTransition(ranch.Ranching, IsCrittersTurn).Enter(delegate(Instance smi)
		{
			smi.EnterQueue();
		}).EventTransition(GameHashes.DestinationReached, ranch.Wait.Waiting);
		ranch.Wait.Waiting.Face(ranchTarget).PlayAnim((Instance smi) => smi.def.StartWaitingAnim).QueueAnim((Instance smi) => smi.def.WaitingAnim, loop: true);
		ranch.Wait.DoneWaiting.PlayAnim((Instance smi) => smi.def.EndWaitingAnim).OnAnimQueueComplete(ranch.Move.MoveToRanch);
		ranch.Ranching.Enter(GetOnTable).Enter("SetCreatureAtRanchingStation", delegate(Instance smi)
		{
			smi.GetRanchStation().MessageCreatureArrived(smi);
			smi.AnimController.SetSceneLayer(Grid.SceneLayer.BuildingUse);
		}).EventTransition(GameHashes.RanchingComplete, ranch.Wavegoodbye)
			.ToggleMainStatusItem(delegate(Instance smi)
			{
				RanchStation.Instance ranchStation = GetRanchStation(smi);
				return (ranchStation != null) ? ranchStation.def.CreatureRanchingStatusItem : Db.Get().CreatureStatusItems.GettingRanched;
			});
		State state2 = ranch.Wavegoodbye.Enter(ClearLayerOverride).OnAnimQueueComplete(ranch.Runaway);
		string text3 = CREATURES.STATUSITEMS.EXCITED_TO_BE_RANCHED.NAME;
		string tooltip3 = CREATURES.STATUSITEMS.EXCITED_TO_BE_RANCHED.TOOLTIP;
		main = Db.Get().StatusItemCategories.Main;
		state2.ToggleStatusItem(text3, tooltip3, "", StatusItem.IconType.Info, NotificationType.Neutral, allow_multiples: false, default(HashedString), 129022, null, null, main);
		State state3 = ranch.Runaway.MoveTo(GetRunawayCell);
		string text4 = CREATURES.STATUSITEMS.IDLE.NAME;
		string tooltip4 = CREATURES.STATUSITEMS.IDLE.TOOLTIP;
		main = Db.Get().StatusItemCategories.Main;
		state3.ToggleStatusItem(text4, tooltip4, "", StatusItem.IconType.Info, NotificationType.Neutral, allow_multiples: false, default(HashedString), 129022, null, null, main);
	}

	private static void ClearLayerOverride(Instance smi)
	{
		smi.AnimController.SetSceneLayer(Grid.SceneLayer.Creatures);
	}

	private static RanchStation.Instance GetRanchStation(Instance smi)
	{
		return smi.GetRanchStation();
	}

	private static void GetOnTable(Instance smi)
	{
		Navigator navigator = smi.Get<Navigator>();
		if (navigator.IsValidNavType(NavType.Floor))
		{
			navigator.SetCurrentNavType(NavType.Floor);
		}
		smi.Get<Facing>().SetFacing(mirror_x: false);
	}

	private static bool IsCrittersTurn(Instance smi)
	{
		RanchStation.Instance ranchStation = GetRanchStation(smi);
		if (ranchStation == null)
		{
			return false;
		}
		if (ranchStation.IsRancherReady)
		{
			return ranchStation.TryGetRanched(smi);
		}
		return false;
	}

	private static int GetRanchNavTarget(Instance smi)
	{
		RanchStation.Instance ranchStation = GetRanchStation(smi);
		int num = smi.ModifyNavTargetForCritter(ranchStation.GetRanchNavTarget());
		if (smi.HasTag(GameTags.LargeCreature))
		{
			Vector2I vector2I = Grid.PosToXY(smi.gameObject.transform.position);
			Vector2I vector2I2 = Grid.CellToXY(num);
			if (vector2I.x > vector2I2.x)
			{
				num = Grid.CellLeft(num);
			}
		}
		return num;
	}

	private static int GetRunawayCell(Instance smi)
	{
		int cell = Grid.PosToCell(smi.transform.GetPosition());
		int num = Grid.OffsetCell(cell, 2, 0);
		if (Grid.Solid[num])
		{
			num = Grid.OffsetCell(cell, -2, 0);
		}
		return num;
	}
}

