示例#1
0
		/// <summary>
		/// Moves the Duplicant from the cell to a destination cell, using a smooth transition
		/// if possible.
		/// </summary>
		/// <param name="instance">The fall monitor to update if successful.</param>
		/// <param name="destination">The destination cell.</param>
		/// <param name="navigator">The navigator to move.</param>
		private static void ForceMoveTo(FallMonitor.Instance instance, int destination,
				Navigator navigator, ref bool flipEmote) {
			var navType = navigator.CurrentNavType;
			var navGrid = navigator.NavGrid;
			int cell = Grid.PosToCell(navigator);
			bool moved = false;
			foreach (var transition in navGrid.transitions)
				if (transition.isEscape && navType == transition.start) {
					int possibleDest = transition.IsValid(cell, navGrid.NavTable);
					if (destination == possibleDest) {
						// The "nice" method, use their animation
						Grid.CellToXY(cell, out int startX, out _);
						Grid.CellToXY(destination, out int endX, out _);
						flipEmote = endX < startX;
						navigator.BeginTransition(transition);
						moved = true;
						break;
					}
				}
			if (!moved) {
				var transform = instance.transform;
				// Teleport to the new location
				transform.SetPosition(Grid.CellToPosCBC(destination, Grid.SceneLayer.Move));
				navigator.Stop(false, true);
				if (instance.gameObject.HasTag(GameTags.Incapacitated))
					navigator.SetCurrentNavType(NavType.Floor);
				instance.UpdateFalling();
				instance.GoTo(instance.sm.standing);
			}
		}
示例#2
0
            /// <summary>
            /// Applied after MountPole runs. We do not apply damage there and reinitialise the variables for next time.
            /// </summary>
            /// <param name="__instance">The current FallMonitor.Instance.</param>
            /// <param name="__navigator">The current FallMonitor.Instance.navigator.</param>
            internal static void Postfix(FallMonitor.Instance __instance, Navigator ___navigator)
            {
                //First disable completly if FallDamageDifficulty == None
                if (DangerousWorldOptions.Instance.FallDamageDifficultyOption == FallDamageDifficulty.None)
                {
                    return;
                }

#if DEBUG
                PUtil.LogDebug(("MountPole: {0}").F(__instance.gameObject.name));
#endif
                if (__instance.gameObject.HasTag(GameTags.Minion))
                {
                    if (!dupesDict.ContainsKey(__instance.gameObject))
                    {
#if DEBUG
                        PUtil.LogError("Unknown dupe mountPole");
#endif
                        dupesDict.Add(__instance.gameObject, -1);
                    }

                    dupesDict[__instance.gameObject] = -1;

#if DEBUG
                    PUtil.LogDebug(("Dupe: {0}, recoverd to Pole").F(__instance.gameObject.name));
#endif
                }
            }
示例#3
0
			/// <summary>
			/// Applied before TryEntombedEscape runs.
			/// </summary>
			internal static bool Prefix(FallMonitor.Instance __instance,
					Navigator ___navigator, ref bool ___flipRecoverEmote) {
				// This is not run too often so searching is fine
				bool moved = false;
				var layers = ___navigator?.transitionDriver?.overrideLayers;
				if (layers != null)
					foreach (var layer in layers)
						if (layer is LocationHistoryTransitionLayer lhs) {
							moved = TryClearEntombment(lhs, ___navigator, __instance,
								ref ___flipRecoverEmote);
							if (moved) break;
						}
				return !moved;
			}
示例#4
0
		/// <summary>
		/// Tries to move a Duplicant to a more sensible location when they are about to fall.
		/// </summary>
		/// <param name="instance">The fall monitor to update if successful.</param>
		/// <param name="navigator">The Duplicant to check.</param>
		/// <param name="layer">The location history of the Duplicant.</param>
		/// <returns>true if the Duplicant was successfully moved away from entombment, or
		/// false otherwise.</returns>
		private static bool TryEscapeFalling(LocationHistoryTransitionLayer layer,
				Navigator navigator, FallMonitor.Instance instance, ref bool flipEmote) {
			bool moved = false;
			for (int i = 0; i < LocationHistoryTransitionLayer.TRACK_CELLS; i++) {
				int last = layer.VisitedCells[i], above = Grid.CellAbove(last);
#if DEBUG
				PUtil.LogDebug("{0} is falling, trying to move to {1:D}".F(navigator.
					gameObject?.name, last));
#endif
				if (Grid.IsValidCell(last) && IsValidNavCell(navigator, last)) {
					ForceMoveTo(instance, last, navigator, ref flipEmote);
					break;
				}
			}
			return moved;
		}
示例#5
0
        /// <summary>
        /// Tries to move a Duplicant to a more sensible location when entombed or falling.
        /// </summary>
        /// <param name="layer">The location history of the Duplicant.</param>
        /// <param name="navigator">The Duplicant to check.</param>
        /// <param name="instance">The fall monitor to update if successful.</param>
        /// <returns>true if the Duplicant was successfully moved away, or false otherwise.</returns>
        private static bool TryEscape(LocationHistoryTransitionLayer layer,
                                      Navigator navigator, FallMonitor.Instance instance, ref bool flipEmote)
        {
            bool moved = false;

            for (int i = 0; i < LocationHistoryTransitionLayer.TRACK_CELLS; i++)
            {
                int last = layer.VisitedCells[i];
                if (Grid.IsValidCell(last) && IsValidNavCell(navigator, last))
                {
                    PUtil.LogDebug("{0} is in trouble, trying to escape to {1:D}".F(navigator.
                                                                                    gameObject?.name, last));
                    ForceMoveTo(instance, last, navigator, ref flipEmote);
                    // Prevents a loop back and forth between two cells in the history
                    layer.Reset();
                    break;
                }
            }
            return(moved);
        }
示例#6
0
            /// <summary>
            /// Applied after AttemptInitialRecovery runs. Sets the variables depending on whether or not the dupe is falling.
            /// </summary>
            /// <param name="__instance">The current FallMonitor.Instance.</param>
            /// <param name="__navigator">The current FallMonitor.Instance.navigator.</param>
            internal static void Postfix(FallMonitor.Instance __instance, Navigator ___navigator)
            {
                //First disable completly if FallDamageDifficulty == None
                if (DangerousWorldOptions.Instance.FallDamageDifficultyOption == FallDamageDifficulty.None)
                {
                    return;
                }

                if (__instance.gameObject.HasTag(GameTags.Minion))
                {
#if DEBUG
                    PUtil.LogDebug(("AttemptRecovery: {0} state: {1}").F(__instance.gameObject.name, __instance.GetCurrentState().name));
#endif
                    if (!dupesDict.ContainsKey(__instance.gameObject))
                    {
                        dupesDict.Add(__instance.gameObject, -1);
                    }
                    if (__instance.GetCurrentState() == __instance.sm.falling_pre)
                    {
#if DEBUG
                        PUtil.LogDebug(("AttemptRecovery: {0} is falling").F(__instance.gameObject.name));
#endif
                        dupesDict[__instance.gameObject] = Grid.PosToCell((KMonoBehaviour)___navigator);
#if DEBUG
                        PUtil.LogDebug(("falling from: {0}").F(dupesDict[__instance.gameObject]));
#endif
                    }
                    else
                    {
#if DEBUG
                        PUtil.LogDebug(("AttemptRecovery: {0} recovered").F(__instance.gameObject.name));
#endif
                        dupesDict[__instance.gameObject] = -1;
                    }
                }
            }
示例#7
0
            /// <summary>
            /// Applied after TryEntombedEscape. Whether or not the dupe manages to escape, if he was falling we apply the same damage.
            /// </summary>
            /// <param name="__instance">The current FallMonitor.Instance.</param>
            /// <param name="__navigator">The current FallMonitor.Instance.navigator.</param>

            internal static void Postfix(FallMonitor.Instance __instance, Navigator ___navigator)
            {
                //First disable completly if FallDamageDifficulty == None
                if (DangerousWorldOptions.Instance.FallDamageDifficultyOption == FallDamageDifficulty.None)
                {
                    return;
                }

                if (__instance.gameObject.HasTag(GameTags.Minion))
                {
                    if (!dupesDict.ContainsKey(__instance.gameObject))
                    {
#if DEBUG
                        PUtil.LogError("Unknown dupe tryEntombedEscape");
#endif
                        dupesDict.Add(__instance.gameObject, -1);
                    }

#if DEBUG
                    PUtil.LogDebug(("TryEntombedEscape. Dupe: {0}, falled to {1}").F(__instance.gameObject.name, Grid.PosToCell((KMonoBehaviour)___navigator)));
#endif

                    if (dupesDict[__instance.gameObject] >= 0)
                    {
                        Grid.CellToXY(dupesDict[__instance.gameObject], out int xFrom, out int yFrom);
                        Grid.CellToXY(Grid.PosToCell((KMonoBehaviour)___navigator), out int xTo, out int yTo);
                        int dist = yFrom - yTo;

                        Health dupeHealth = __instance.gameObject.GetComponent <Health>();
                        if (dupeHealth != null)
                        {
                            if (dist > DangerousWorldOptions.Instance.fallOptions.damageHeightLimit)
                            {
#if DEBUG
                                PUtil.LogDebug(("Fall damage. Difficulty: {0}, deathEnable: {1}, deathHeight: {2}").F(DangerousWorldOptions.Instance.FallDamageDifficultyOption.ToString(), DangerousWorldOptions.Instance.fallOptions.deathEnabled, DangerousWorldOptions.Instance.fallOptions.deathHeightLimit));
#endif
                                if (DangerousWorldOptions.Instance.fallOptions.deathEnabled && dist > DangerousWorldOptions.Instance.fallOptions.deathHeightLimit)
                                {
                                    __instance.gameObject.GetSMI <DeathMonitor.Instance>().Kill(Db.Get().Deaths.Slain); //TODO: use own death type
                                }
                                else
                                {
                                    dupeHealth.Damage((dist - DangerousWorldOptions.Instance.fallOptions.damageHeightLimit) * 10f / DangerousWorldOptions.Instance.fallOptions.damageDivider); //TODO: make it use own death type
                                    if (DangerousWorldOptions.Instance.fallOptions.crippleEnabled && (dist > DangerousWorldOptions.Instance.fallOptions.crippleHeightLimit) && (UnityEngine.Random.Range((int)0, (int)100) <= dist * 10))
                                    {
#if DEBUG
                                        PUtil.LogDebug(("Dupe: {0}, hasEffect Crippled: {1}").F(__instance.gameObject.name, __instance.gameObject.AddOrGet <Effects>().HasEffect("DangerousWorlCrippled")));
#endif
                                        if (!__instance.gameObject.AddOrGet <Effects>().HasEffect("DangerousWorldCrippled"))
                                        {
                                            __instance.gameObject.AddOrGet <Effects>().Add("DangerousWorldCrippled", true);
                                        }
#if DEBUG
                                        PUtil.LogDebug(("Dupe: {0}, hasEffect Crippled: {1}").F(__instance.gameObject.name, __instance.gameObject.AddOrGet <Effects>().HasEffect("DangerousWorlCrippled")));
#endif
                                    }
                                }
                            }
                        }
                        dupesDict[__instance.gameObject] = -1;
                    }
                }
            }