예제 #1
0
 public static void Postfix()
 {
     // Temporary "Room Size" mod functionality restored for DLC
     // Must be removed once "Room Size" is updated for DLC
     // Original mod by trevis can be found here: https://steamcommunity.com/sharedfiles/filedetails/?id=1715802131
     TuningData <RoomProber.Tuning> .Get().maxRoomSize = Settings.Instance.ResizeMaxRoomSize;
 }
    private bool MinionCloseEnoughToConvo(MinionIdentity minion, Conversation setup)
    {
        Vector3 centroid  = GetCentroid(setup);
        float   magnitude = (centroid - minion.transform.GetPosition()).magnitude;

        return(magnitude < TuningData <Tuning> .Get().maxDistance * 0.5f);
    }
예제 #3
0
 private static void Postfix(RoomProber __instance)
 {
     //Debug.Log(" === RoomSizeMod_RoomProber Postfix === ");
     //RoomProber.MaxRoomSize = 1024;
     //RoomProber.MaxRoomSize = RoomSizeState.StateManager.State.OverallMaximumRoomSize;
     TuningData <RoomProber.Tuning> .Get().maxRoomSize = RoomSizeState.StateManager.State.OverallMaximumRoomSize;
 }
 public void Sim200ms(float dt)
 {
     if (!(GameClock.Instance.GetTime() / 600f < TuningData <Tuning> .Get().cyclesBeforeFirstGreeting))
     {
         for (int num = activeSetups.Count - 1; num >= 0; num--)
         {
             GreetingSetup greetingSetup = activeSetups[num];
             if (!ValidNavigatingMinion(greetingSetup.A.minion) || !ValidOppositionalMinion(greetingSetup.A.minion, greetingSetup.B.minion))
             {
                 greetingSetup.A.reactable.Cleanup();
                 greetingSetup.B.reactable.Cleanup();
                 activeSetups.RemoveAt(num);
             }
         }
         candidateCells.Clear();
         foreach (MinionIdentity item in Components.LiveMinionIdentities.Items)
         {
             if ((!cooldowns.ContainsKey(item) || !(GameClock.Instance.GetTime() - cooldowns[item] < 720f * TuningData <Tuning> .Get().greetingDelayMultiplier)) && ValidNavigatingMinion(item))
             {
                 for (int i = 0; i <= 2; i++)
                 {
                     int offsetCell = GetOffsetCell(item, i);
                     if (candidateCells.ContainsKey(offsetCell) && ValidOppositionalMinion(item, candidateCells[offsetCell]))
                     {
                         BeginNewGreeting(item, candidateCells[offsetCell], offsetCell);
                         break;
                     }
                     candidateCells[offsetCell] = item;
                 }
             }
         }
     }
 }
예제 #5
0
        public void RenderEveryTick(float dt)
        {
            SoundCuller soundCuller = CameraController.Instance.soundCuller;

            if (shouldPauseOnGamePause && Time.timeScale == 0f)
            {
                sound.setPaused(true);
                return;
            }

            bool audible = !enableCulling || (enableCameraScaling && soundCuller.IsAudible(transform.position, falloffDistanceSq)) || soundCuller.IsAudibleNoCameraScaling(transform.position, falloffDistanceSq);

            if (!audible)
            {
                sound.setPaused(true);
                return;
            }

            sound.setPaused(false);

            Vector3 soundPos = transform.position;

            soundPos.z = 0;

            float velocityScale = TuningData <LoopingSoundManager.Tuning> .Get().velocityScale;

            VECTOR scaledSoundPos = SoundEvent.GetCameraScaledPosition(soundPos, false).ToFMODVector();
            VECTOR scaledSoundVel = (velocity * velocityScale).ToFMODVector();

            sound.set3DAttributes(ref scaledSoundPos, ref scaledSoundVel);
        }
    private void RefreshRooms()
    {
        int maxRoomSize = TuningData <Tuning> .Get().maxRoomSize;

        foreach (CavityInfo data in cavityInfos.GetDataList())
        {
            if (data.dirty)
            {
                Debug.Assert(data.room == null, "I expected info.room to always be null by this point");
                if (data.numCells > 0)
                {
                    if (data.numCells <= maxRoomSize)
                    {
                        CreateRoom(data);
                    }
                    foreach (KPrefabID building in data.buildings)
                    {
                        building.Trigger(144050788, data.room);
                    }
                    foreach (KPrefabID plant in data.plants)
                    {
                        plant.Trigger(144050788, data.room);
                    }
                }
                data.dirty = false;
            }
        }
        dirty = false;
    }
        public static void Postfix(ref Database.RoomTypes __instance)
        {
            //Debug.Log(" === PoperPowerPlant_RoomTypes Postfix === ");

            // Get Power Plant
            RoomType roomType = __instance.TryGet(__instance.PowerPlant.Id);

            // Custom max size constraint for room
            int        customMaxSize     = 240;
            Constraint MaxSizeConstraint = new Constraint(null, (Room room) => room.cavity.numCells <= customMaxSize,
                                                          1,
                                                          string.Format(ROOMS.CRITERIA.MAXIMUM_SIZE.NAME, "" + customMaxSize),
                                                          string.Format(ROOMS.CRITERIA.MAXIMUM_SIZE.DESCRIPTION, "" + customMaxSize),
                                                          null);

            // Custom max size for all rooms
            TuningData <RoomProber.Tuning> .Get().maxRoomSize = customMaxSize;

            // Iterate constraints
            RoomConstraints.Constraint[] additional_constraints = roomType.additional_constraints;
            for (int i = 0; i < additional_constraints.Length; i++)
            {
                // Change max size constraint
                if (additional_constraints[i].name.Contains("Maximum size:"))
                {
                    additional_constraints[i] = MaxSizeConstraint;
                    break;
                }
            }
        }
예제 #8
0
        private static void Postfix(RoomProber __instance)
        {
            Debug.Log(" === RoomSizeMod_RoomProber Postfix === Original Max. Room Size: " + TuningData <RoomProber.Tuning> .Get().maxRoomSize);
            //RoomProber.MaxRoomSize = 1024;
            //RoomProber.MaxRoomSize = RoomSizeState.StateManager.State.OverallMaximumRoomSize;
            TuningData <RoomProber.Tuning> .Get().maxRoomSize = RoomSizeConfig.Instance.OverallMaximumRoomSize;

            Debug.Log(" === RoomSizeMod_RoomProber Postfix === New Max. Room Size: " + TuningData <RoomProber.Tuning> .Get().maxRoomSize);
        }
 public static void AddRoot(ICPULoad root)
 {
     nodes.Add(root, new Node
     {
         load                 = root,
         children             = new List <Node>(),
         frameTime            = root.GetEstimatedFrameTime(),
         loadBalanceThreshold = TuningData <Tuning> .Get().defaultLoadBalanceThreshold
     });
 }
예제 #10
0
        public static void Prefix(CameraController __instance)
        {
            Debug.Log(" === CameraControllerMod INI === ");

            AccessTools.Field(typeof(CameraController), "maxOrthographicSize").SetValue(__instance, 100f);
            //AccessTools.Field(typeof(CameraController), "maxOrthographicSizeDebug").SetValue(__instance, 300f);
            TuningData <CameraController.Tuning> .Get().maxOrthographicSizeDebug = 300f;

            // Traverse.Create<CameraController>().Property("maxOrthographicSize").SetValue(100.0);
            // Traverse.Create<CameraController>().Property("maxOrthographicSizeDebug").SetValue(200.0);
            Debug.Log(" === CameraControllerMod END === ");
        }
예제 #11
0
            public static void Prefix(ICollection <int> visited_cells, KCompactedVector <CavityInfo> ___cavityInfos, HandleVector <int> .Handle[] ___CellCavityID)
            {
                int maxRoomSize = TuningData <RoomProber.Tuning> .Get().maxRoomSize;

                foreach (int current in visited_cells)
                {
                    HandleVector <int> .Handle handle = ___CellCavityID [current];
                    if (handle.IsValid())
                    {
                        CavityInfo data = ___cavityInfos.GetData(handle);
                        if (0 < data.numCells && data.numCells <= maxRoomSize)
                        {
                            GameObject gameObject = Grid.Objects [current, (int)ObjectLayer.Plants];
                            if (gameObject != null)
                            {
                                KPrefabID component = gameObject.GetComponent <KPrefabID> ();
                                bool      flag2     = false;
                                foreach (KPrefabID current2 in data.buildings)
                                {
                                    if (component.InstanceID == current2.InstanceID)
                                    {
                                        flag2 = true;
                                        break;
                                    }
                                }
                                foreach (KPrefabID current3 in data.plants)
                                {
                                    if (component.InstanceID == current3.InstanceID)
                                    {
                                        flag2 = true;
                                        break;
                                    }
                                }
                                if (!flag2)
                                {
                                    if (component.GetComponent <Deconstructable> ())
                                    {
                                        data.AddBuilding(component);
                                    }
                                    else
                                    {
                                        if (component.HasTag(GameTags.Plant) && !component.HasTag("ForestTreeBranch".ToTag()))
                                        {
                                            data.AddPlants(component);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
    private void RebuildDirtyCavities(ICollection <int> visited_cells)
    {
        int maxRoomSize = TuningData <Tuning> .Get().maxRoomSize;

        foreach (int visited_cell in visited_cells)
        {
            HandleVector <int> .Handle handle = CellCavityID[visited_cell];
            if (handle.IsValid())
            {
                CavityInfo data = cavityInfos.GetData(handle);
                if (0 < data.numCells && data.numCells <= maxRoomSize)
                {
                    GameObject gameObject = Grid.Objects[visited_cell, 1];
                    if ((UnityEngine.Object)gameObject != (UnityEngine.Object)null)
                    {
                        KPrefabID component = gameObject.GetComponent <KPrefabID>();
                        bool      flag      = false;
                        foreach (KPrefabID building in data.buildings)
                        {
                            if (component.InstanceID == building.InstanceID)
                            {
                                flag = true;
                                break;
                            }
                        }
                        foreach (KPrefabID plant in data.plants)
                        {
                            if (component.InstanceID == plant.InstanceID)
                            {
                                flag = true;
                                break;
                            }
                        }
                        if (!flag)
                        {
                            if ((bool)component.GetComponent <Deconstructable>())
                            {
                                data.AddBuilding(component);
                            }
                            else if (component.HasTag(GameTags.Plant) && !component.HasTag("ForestTreeBranch".ToTag()))
                            {
                                data.AddPlants(component);
                            }
                        }
                    }
                }
            }
        }
        visited_cells.Clear();
    }
예제 #13
0
    private IEnumerator PlayScheduleTone(Schedule schedule, bool forwards)
    {
        int[] tones = schedule.GetTones();
        int   i     = 0;

        if (i < tones.Length)
        {
            int t = (!forwards) ? (tones.Length - 1 - i) : i;
            PlayTone(tones[t], forwards);
            yield return((object)new WaitForSeconds(TuningData <Tuning> .Get().toneSpacingSeconds));

            /*Error: Unable to find new state assignment for yield return*/;
        }
    }
예제 #14
0
        private static void InitDb()
        {
            var db = Db.Get();

            // тюнингуем и актифируем комнату
            // подхватывать максимальный размер комнаты из тюнинга
            int maxRoomSize = TuningData <RoomProber.Tuning> .Get().maxRoomSize;

            RoomConstraints.Constraint MAXIMUM_SIZE_MAX = new RoomConstraints.Constraint(
                building_criteria: null,
                room_criteria: (Room room) => room.cavity.numCells <= maxRoomSize,
                times_required: 1,
                name: string.Format(ROOMS.CRITERIA.MAXIMUM_SIZE.NAME, maxRoomSize),
                description: string.Format(ROOMS.CRITERIA.MAXIMUM_SIZE.DESCRIPTION, maxRoomSize),
                stomp_in_conflict: null);

            var additional_constraints = db.RoomTypes.MachineShop.additional_constraints;

            for (int i = 0; i < additional_constraints.Length; i++)
            {
                if (additional_constraints[i] == RoomConstraints.MAXIMUM_SIZE_96)
                {
                    additional_constraints[i] = MAXIMUM_SIZE_MAX;
                    break;
                }
            }

            db.RoomTypes.Add(db.RoomTypes.MachineShop);

            // добавляем перк для работы на станции
            CanMachineTinker = db.SkillPerks.Add(new SimpleSkillPerk(REQUIRED_ROLE_PERK, STRINGS.PERK_CAN_MACHINE_TINKER.DESCRIPTION));
            db.Skills.Technicals1.perks.Add(CanMachineTinker);

            // добавляем модификаторы и эффекты
            string text        = DUPLICANTS.MODIFIERS.MACHINETINKER.NAME;
            string description = STRINGS.DUPLICANTS.MODIFIERS.MACHINETINKER.TOOLTIP;

            CraftingSpeed = db.Attributes.Add(new Attribute(CRAFTING_SPEED_MODIFIER_NAME, false, Attribute.Display.General, false, BASE_SPEED_VALUE));
            CraftingSpeed.SetFormatter(new PercentAttributeFormatter());

            MachinerySpeedModifier = new AttributeModifier(MACHINERY_SPEED_MODIFIER_NAME, MACHINERY_SPEED_MODIFIER, text);
            CraftingSpeedModifier  = new AttributeModifier(CRAFTING_SPEED_MODIFIER_NAME, CRAFTING_SPEED_MODIFIER, text);

            MachineTinkerEffect = db.effects.Add(new Effect(MACHINE_TINKER_EFFECT_NAME, text, description, MACHINE_TINKER_EFFECT_DURATION * Constants.SECONDS_PER_CYCLE, true, true, false));
            MachineTinkerEffect.Add(MachinerySpeedModifier);
            MachineTinkerEffect.Add(CraftingSpeedModifier);
        }
예제 #15
0
    public int[] GenerateTones()
    {
        int minToneIndex = TuningData <ScheduleManager.Tuning> .Get().minToneIndex;

        int maxToneIndex = TuningData <ScheduleManager.Tuning> .Get().maxToneIndex;

        int firstLastToneSpacing = TuningData <ScheduleManager.Tuning> .Get().firstLastToneSpacing;

        int[] array = new int[4]
        {
            UnityEngine.Random.Range(minToneIndex, maxToneIndex - firstLastToneSpacing + 1),
            UnityEngine.Random.Range(minToneIndex, maxToneIndex + 1),
            UnityEngine.Random.Range(minToneIndex, maxToneIndex + 1),
            0
        };
        array[3] = UnityEngine.Random.Range(array[0] + firstLastToneSpacing, maxToneIndex + 1);
        return(array);
    }
예제 #16
0
        /**
         * Reverse gravity application (floatation)
         */
        private static void ApplyYVelocityChanges(ref GravityComponent grav, float dt)
        {
            GravityComponents.Tuning tuning = TuningData <GravityComponents.Tuning> .Get();

            float   yExtent  = Helpers.GetYExtent(grav);
            Vector2 position = (Vector2)grav.transform.GetPosition() + Vector2.up * (yExtent + 0.01f);

            float distanceToSurface = Helpers.GetLiquidSurfaceDistanceAbove(position);

            if (distanceToSurface != float.PositiveInfinity && distanceToSurface > 2 * yExtent)
            {
                Vector2 target = position + Vector2.up * distanceToSurface;
                Mathf.SmoothDamp(position.y, target.y, ref grav.velocity.y, 1f, tuning.maxVelocityInLiquid, dt);
            }
            else if (grav.velocity.y > 0)
            {
                Mathf.SmoothDamp(position.y, position.y, ref grav.velocity.y, 5f, tuning.maxVelocityInLiquid, dt);
            }
        }
        public static void Prefix(CameraController __instance)
        {
            if (!CameraControllerState.StateManager.State.Enabled ||
                !CameraControllerState.StateManager.State.maxOrthographicSizeEnabled)
            {
                return;
            }

            Debug.Log(" === CameraControllerMod INI === ");


            AccessTools.Field(typeof(CameraController), "maxOrthographicSize").SetValue(__instance, CameraControllerState.StateManager.State.maxOrthographicSize);
            //AccessTools.Field(typeof(CameraController), "maxOrthographicSizeDebug").SetValue(__instance, 300f);
            TuningData <CameraController.Tuning> .Get().maxOrthographicSizeDebug = CameraControllerState.StateManager.State.maxOrthographicSizeDebug;

            // Traverse.Create<CameraController>().Property("maxOrthographicSize").SetValue(100.0);
            // Traverse.Create<CameraController>().Property("maxOrthographicSizeDebug").SetValue(200.0);
            Debug.Log(" === CameraControllerMod END === ");
        }
예제 #18
0
    protected override void Start()
    {
        tuning = TuningData <Tuning> .Get();

        SetupCameras();
        base.Start();
        for (int i = 0; i < anims.Length; i++)
        {
            int minionIndex = i;
            KBatchedAnimController kBatchedAnimController = anims[i].minions[0];
            kBatchedAnimController.onAnimComplete += delegate(HashedString name)
            {
                WaitForABit(minionIndex, name);
            };
            WaitForABit(i, HashedString.Invalid);
        }
        dreckoController         = base.transform.GetChild(0).Find("startmenu_drecko").GetComponent <KBatchedAnimController>();
        dreckoController.enabled = false;
        nextDreckoTime           = UnityEngine.Random.Range(tuning.minFirstDreckoInterval, tuning.maxFirstDreckoInterval) + Time.unscaledTime;
    }
예제 #19
0
        /// <summary>
        /// Triggers a refresh of rooms. Only to be called on the foreground thread!
        /// </summary>
        public void Refresh()
        {
            int maxRoomSize = TuningData <RoomProber.Tuning> .Get().maxRoomSize;

            lock (cavityInfos) {
                while (buildingChanges.TryDequeue(out int cell))
                {
                    ref var cavityID = ref cavityForCell[cell];
                    bool    wall     = RoomProber.CavityFloodFiller.IsWall(cell);
                    bool    valid    = cavityID.IsValid();
                    if (valid == wall)
                    {
                        // If a wall building like a mesh door was built but did not trigger a
                        // solid change update, then the tile will have a valid room on a wall
                        // building, set up a solid change
                        solidChanges.Enqueue(cell);
                    }
                    else if (valid)
                    {
                        var cavity = cavityInfos.GetData(cavityID);
                        int cells  = cavity.numCells;
                        if (cells > 0 && cells <= maxRoomSize)
                        {
                            AddBuildingToRoom(cell, cavity);
                        }
                    }
                }
                while (destroyed.TryDequeue(out var destroyedID))
                {
                    if (destroyedID.IsValid())
                    {
                        var cavity = cavityInfos.GetData(destroyedID);
                        if (cavity != null)
                        {
                            DestroyRoom(cavity.room);
                        }
                        cavityInfos.Free(destroyedID);
                    }
                }
                RefreshRooms();
            }
 public float GetEstimatedFrameTime()
 {
     return(TuningData <Tuning> .Get().frameTime);
 }
 public override float LoadBalanceThreshold()
 {
     return(TuningData <Tuning> .Get().loadBalanceThreshold);
 }
 public override float GetEstimatedFrameTime()
 {
     return(TuningData <Tuning> .Get().estimatedFrameTime);
 }
 protected override int MinProbeSize()
 {
     return(TuningData <Tuning> .Get().minProbeSize);
 }
 protected override int InitialProbeCount()
 {
     return(TuningData <Tuning> .Get().initialProbeCount);
 }
 public void Sim200ms(float dt)
 {
     for (int num = activeSetups.Count - 1; num >= 0; num--)
     {
         Conversation conversation = activeSetups[num];
         for (int num2 = conversation.minions.Count - 1; num2 >= 0; num2--)
         {
             if (!ValidMinionTags(conversation.minions[num2]) || !MinionCloseEnoughToConvo(conversation.minions[num2], conversation))
             {
                 conversation.minions.RemoveAt(num2);
             }
             else
             {
                 setupsByMinion[conversation.minions[num2]] = conversation;
             }
         }
         if (conversation.minions.Count <= 1)
         {
             activeSetups.RemoveAt(num);
         }
         else
         {
             bool flag = true;
             if (conversation.numUtterances == 0 && GameClock.Instance.GetTime() > conversation.lastTalkedTime + TuningData <Tuning> .Get().delayBeforeStart)
             {
                 MinionIdentity minionIdentity = conversation.minions[UnityEngine.Random.Range(0, conversation.minions.Count)];
                 conversation.conversationType.NewTarget(minionIdentity);
                 flag = DoTalking(conversation, minionIdentity);
             }
             else if (conversation.numUtterances > 0 && conversation.numUtterances < TuningData <Tuning> .Get().maxUtterances&& GameClock.Instance.GetTime() > conversation.lastTalkedTime + TuningData <Tuning> .Get().speakTime + TuningData <Tuning> .Get().delayBetweenUtterances)
             {
                 int            num3        = conversation.minions.IndexOf(conversation.lastTalked);
                 int            index       = (num3 + UnityEngine.Random.Range(1, conversation.minions.Count)) % conversation.minions.Count;
                 MinionIdentity new_speaker = conversation.minions[index];
                 flag = DoTalking(conversation, new_speaker);
             }
             else if (conversation.numUtterances >= TuningData <Tuning> .Get().maxUtterances)
             {
                 flag = false;
             }
             if (!flag)
             {
                 activeSetups.RemoveAt(num);
             }
         }
     }
     foreach (MinionIdentity item in Components.LiveMinionIdentities.Items)
     {
         if (ValidMinionTags(item) && !setupsByMinion.ContainsKey(item) && !MinionOnCooldown(item))
         {
             foreach (MinionIdentity item2 in Components.LiveMinionIdentities.Items)
             {
                 if (!((UnityEngine.Object)item2 == (UnityEngine.Object)item) && ValidMinionTags(item2))
                 {
                     if (setupsByMinion.ContainsKey(item2))
                     {
                         Conversation conversation2 = setupsByMinion[item2];
                         if (conversation2.minions.Count < TuningData <Tuning> .Get().maxDupesPerConvo)
                         {
                             Vector3 centroid  = GetCentroid(conversation2);
                             float   magnitude = (centroid - item.transform.GetPosition()).magnitude;
                             if (magnitude < TuningData <Tuning> .Get().maxDistance * 0.5f)
                             {
                                 conversation2.minions.Add(item);
                                 setupsByMinion[item] = conversation2;
                                 break;
                             }
                         }
                     }
                     else if (!MinionOnCooldown(item2))
                     {
                         float magnitude2 = (item2.transform.GetPosition() - item.transform.GetPosition()).magnitude;
                         if (magnitude2 < TuningData <Tuning> .Get().maxDistance)
                         {
                             Conversation conversation3 = new Conversation();
                             conversation3.minions.Add(item);
                             conversation3.minions.Add(item2);
                             Type type = convoTypes[UnityEngine.Random.Range(0, convoTypes.Count)];
                             conversation3.conversationType = (ConversationType)Activator.CreateInstance(type);
                             conversation3.lastTalkedTime   = GameClock.Instance.GetTime();
                             activeSetups.Add(conversation3);
                             setupsByMinion[item]  = conversation3;
                             setupsByMinion[item2] = conversation3;
                             break;
                         }
                     }
                 }
             }
         }
     }
     setupsByMinion.Clear();
 }
    private Thought GetThoughtForTopic(Conversation setup, Conversation.Topic topic)
    {
        if (string.IsNullOrEmpty(topic.topic))
        {
            DebugUtil.DevAssert(false, "topic.topic was null");
            return(null);
        }
        Sprite sprite = setup.conversationType.GetSprite(topic.topic);

        if ((UnityEngine.Object)sprite != (UnityEngine.Object)null)
        {
            Conversation.Mode mode = Conversation.Topic.Modes[(int)topic.mode];
            return(new Thought("Topic_" + topic.topic, null, sprite, mode.icon, mode.voice, "bubble_chatter", mode.mouth, DUPLICANTS.THOUGHTS.CONVERSATION.TOOLTIP, true, TuningData <Tuning> .Get().speakTime));
        }
        return(null);
    }
예제 #27
0
        internal static void Init()
        {
            var db = Db.Get();

            // тюнингуем и актифируем комнату
            // подхватывать максимальный размер комнаты из тюнинга
            int maxRoomSize = TuningData <RoomProber.Tuning> .Get().maxRoomSize;

            var MAXIMUM_SIZE_MAX = new RoomConstraints.Constraint(
                building_criteria: null,
                room_criteria: (Room room) => room.cavity.numCells <= maxRoomSize,
                times_required: 1,
                name: string.Format(ROOMS.CRITERIA.MAXIMUM_SIZE.NAME, maxRoomSize),
                description: string.Format(ROOMS.CRITERIA.MAXIMUM_SIZE.DESCRIPTION, maxRoomSize),
                stomp_in_conflict: null);

            var additional_constraints = db.RoomTypes.MachineShop.additional_constraints;

            for (int i = 0; i < additional_constraints.Length; i++)
            {
                if (additional_constraints[i] == RoomConstraints.MAXIMUM_SIZE_96)
                {
                    additional_constraints[i] = MAXIMUM_SIZE_MAX;
                    break;
                }
            }

            db.RoomTypes.Add(db.RoomTypes.MachineShop);

            // детектим "Rooms Expanded". модифицируем "мастерскую" чтобы она могла быть обгрейднутна до "кухни"
            var RoomsExpanded = PPatchTools.GetTypeSafe("RoomsExpanded.RoomTypes_AllModded", "RoomsExpandedMerged");

            if (RoomsExpanded != null)
            {
                PUtil.LogDebug("RoomsExpanded found. Attempt to add compatibility.");
                try
                {
                    KitchenRoom = (RoomType)RoomsExpanded.GetPropertySafe <RoomType>("KitchenRoom", true)?.GetValue(null, null);
                    if (KitchenRoom != null)
                    {
                        var upgrade_paths = db.RoomTypes.MachineShop.upgrade_paths.AddToArray(KitchenRoom);
                        Traverse.Create(db.RoomTypes.MachineShop).Property(nameof(RoomType.upgrade_paths)).SetValue(upgrade_paths);
                        Traverse.Create(db.RoomTypes.MachineShop).Property(nameof(RoomType.priority)).SetValue(KitchenRoom.priority);
                        KitchenBuildingTag = "KitchenBuildingTag".ToTag();
                        RoomsExpandedFound = true;
                    }
                }
                catch (System.Exception e)
                {
                    PUtil.LogExcWarn(e);
                }
            }

            // добавляем перк для работы на станции
            CanMachineTinker = db.SkillPerks.Add(new SimpleSkillPerk(
                                                     id: REQUIRED_ROLE_PERK,
                                                     description: STRINGS.PERK_CAN_MACHINE_TINKER.DESCRIPTION));
            db.Skills.Technicals1.perks.Add(CanMachineTinker);

            // добавляем модификаторы и эффекты
            string text        = DUPLICANTS.MODIFIERS.MACHINETINKER.NAME;
            string description = STRINGS.DUPLICANTS.MODIFIERS.MACHINETINKER.TOOLTIP;

            CraftingSpeed = db.Attributes.Add(new Attribute(
                                                  id: CRAFTING_SPEED_MODIFIER_NAME,
                                                  is_trainable: false,
                                                  show_in_ui: Attribute.Display.General,
                                                  is_profession: false,
                                                  base_value: BASE_SPEED_VALUE));
            CraftingSpeed.SetFormatter(new PercentAttributeFormatter());

            MachinerySpeedModifier = new AttributeModifier(
                attribute_id: MACHINERY_SPEED_MODIFIER_NAME,
                value: MACHINERY_SPEED_MODIFIER,
                description: text,
                is_readonly: false);
            CraftingSpeedModifier = new AttributeModifier(
                attribute_id: CRAFTING_SPEED_MODIFIER_NAME,
                value: CRAFTING_SPEED_MODIFIER,
                description: text,
                is_readonly: false);

            MachineTinkerEffect = db.effects.Add(new Effect(
                                                     id: MACHINE_TINKER_EFFECT_NAME,
                                                     name: text,
                                                     description: description,
                                                     duration: MACHINE_TINKER_EFFECT_DURATION * Constants.SECONDS_PER_CYCLE,
                                                     show_in_ui: true,
                                                     trigger_floating_text: true,
                                                     is_bad: false));
            MachineTinkerEffect.Add(MachinerySpeedModifier);
            MachineTinkerEffect.Add(CraftingSpeedModifier);

            MachineTinkerEffectDuration = db.AttributeConverters.Create(
                id: "MachineTinkerEffectDuration",
                name: "Engie's Jerry Rig Effect Duration",
                description: STRINGS.DUPLICANTS.ATTRIBUTES.MACHINERY.MACHINE_TINKER_EFFECT_MODIFIER,
                attribute: db.Attributes.Machinery,
                multiplier: MACHINE_TINKER_EFFECT_DURATION_PER_SKILL,
                base_value: 0,
                formatter: new ToPercentAttributeFormatter(1f, GameUtil.TimeSlice.None),
                available_dlcs: DlcManager.AVAILABLE_ALL_VERSIONS);
        }
 protected override int IdealProbeSize()
 {
     return(TuningData <Tuning> .Get().idealProbeSize);
 }
    private bool MinionOnCooldown(MinionIdentity minion)
    {
        KPrefabID component = minion.GetComponent <KPrefabID>();

        return(!component.HasTag(GameTags.AlwaysConverse) && ((lastConvoTimeByMinion.ContainsKey(minion) && GameClock.Instance.GetTime() < lastConvoTimeByMinion[minion] + TuningData <Tuning> .Get().minionCooldownTime) || GameClock.Instance.GetTime() / 600f < TuningData <Tuning> .Get().cyclesBeforeFirstConversation));
    }
 protected override int ProbeSizeStep()
 {
     return(TuningData <Tuning> .Get().probeSizeStep);
 }