public static void CreateBaseOreTemplates() { baseOreTemplate = new GameObject("OreTemplate"); Object.DontDestroyOnLoad(baseOreTemplate); baseOreTemplate.SetActive(false); baseOreTemplate.AddComponent <KPrefabID>(); baseOreTemplate.AddComponent <PrimaryElement>(); baseOreTemplate.AddComponent <Pickupable>(); baseOreTemplate.AddComponent <KSelectable>(); baseOreTemplate.AddComponent <SaveLoadRoot>(); baseOreTemplate.AddComponent <StateMachineController>(); baseOreTemplate.AddComponent <Clearable>(); baseOreTemplate.AddComponent <Prioritizable>(); baseOreTemplate.AddComponent <KBatchedAnimController>(); baseOreTemplate.AddComponent <SimTemperatureTransfer>(); baseOreTemplate.AddComponent <Modifiers>(); OccupyArea occupyArea = baseOreTemplate.AddOrGet <OccupyArea>(); occupyArea.OccupiedCellsOffsets = new CellOffset[1] { default(CellOffset) }; DecorProvider decorProvider = baseOreTemplate.AddOrGet <DecorProvider>(); decorProvider.baseDecor = -10f; decorProvider.baseRadius = 1f; baseOreTemplate.AddOrGet <ElementChunk>(); }
public GameObject CreatePrefab() { GameObject gameObject = CreateOilFloater(ID, PHO_STRINGS.VARIANT_OWO.NAME, PHO_STRINGS.VARIANT_OWO.DESC, base_kanim_id, false); DecorProvider decorProvider = gameObject.AddOrGet <DecorProvider>(); decorProvider.SetValues(TUNING.DECOR.BONUS.TIER5); EffectArea owoEffect = gameObject.AddComponent <EffectArea>(); owoEffect.EffectName = "OwO_effect"; owoEffect.Area = 5; EntityTemplates.ExtendEntityToFertileCreature(gameObject, EGG_ID, PHO_STRINGS.VARIANT_OWO.EGG_NAME, PHO_STRINGS.VARIANT_OWO.DESC, egg_kanim_id, OilFloaterTuning.EGG_MASS, ID + "Baby", 60.0000038f, 20f, EGG_CHANCES_OWO, EGG_SORT_ORDER, true, false, true, 1f); return(gameObject); }
public GameObject CreatePrefab() { GameObject gameObject = EntityTemplates.CreateLooseEntity( id: ID, name: STRINGS.ITEMS.INDUSTRIAL_PRODUCTS.SKELETON.NAME, desc: STRINGS.ITEMS.INDUSTRIAL_PRODUCTS.SKELETON.DESC, mass: MASS, unitMass: true, anim: Assets.GetAnim("bones_kanim"), initialAnim: "object", sceneLayer: Grid.SceneLayer.Ore, collisionShape: EntityTemplates.CollisionShape.RECTANGLE, width: 0.9f, height: 0.8f, isPickupable: true, sortOrder: 0, element: SimHashes.Creature, additionalTags: new List <Tag> { GameTags.IndustrialIngredient, GameTags.Organics }); gameObject.AddOrGet <SimpleMassStatusItem>(); gameObject.AddOrGet <OccupyArea>().OccupiedCellsOffsets = EntityTemplates.GenerateOffsets(1, 1); DecorProvider decorProvider = gameObject.AddOrGet <DecorProvider>(); decorProvider.baseDecor = TUNING.DUPLICANTSTATS.CLOTHING.DECOR_MODIFICATION.BASIC; decorProvider.baseRadius = 3f; gameObject.AddOrGetDef <EffectLineOfSight.Def>().effectName = DeathPatches.OBSERVED_ROTTEN_CORPSE; gameObject.AddOrGet <Skeleton>(); ConfigureRecipes(); return(gameObject); }
/// <summary> /// Adds a decor provider to the list. /// </summary> /// <param name="prefabID">The prefab ID of the provider.</param> /// <param name="provider">The provider to add.</param> /// <param name="decor">The provider's current decor score.</param> /// <returns>true if the decor score was changed, or false otherwise.</returns> public bool AddDecorProvider(Tag prefabID, DecorProvider provider, float decor) { BestDecorList values = null; bool add = false; if (provider == null) { throw new ArgumentNullException("provider"); } lock (decorProviders) { if (decor < 0.0f && negativeDecor != null) { // Hard mode mwahaha if (!negativeDecor.ContainsKey(provider)) { negativeDecor.Add(provider, decor); Grid.Decor[cell] += decor; add = true; } } else if (!decorProviders.TryGetValue(prefabID, out values)) { decorProviders.Add(prefabID, values = new BestDecorList(cell)); UpdateNumPositive(); } } if (values != null) { lock (values) { add = values.AddDecorItem(decor, provider); } } return(add); }
public static GameObject CreateArtifact(string id, string name, string desc, string initial_anim, string ui_anim, ArtifactTier artifact_tier, PostInitFn postInitFn = null, SimHashes element = SimHashes.Creature) { GameObject gameObject = EntityTemplates.CreateLooseEntity("artifact_" + id.ToLower(), name, desc, 25f, true, Assets.GetAnim("artifacts_kanim"), initial_anim, Grid.SceneLayer.Ore, EntityTemplates.CollisionShape.RECTANGLE, 1f, 1f, true, SORTORDER.BUILDINGELEMENTS, element, new List <Tag> { GameTags.MiscPickupable }); OccupyArea occupyArea = gameObject.AddOrGet <OccupyArea>(); occupyArea.OccupiedCellsOffsets = EntityTemplates.GenerateOffsets(1, 1); DecorProvider decorProvider = gameObject.AddOrGet <DecorProvider>(); decorProvider.SetValues(artifact_tier.decorValues); decorProvider.overrideName = gameObject.name; SpaceArtifact spaceArtifact = gameObject.AddOrGet <SpaceArtifact>(); spaceArtifact.SetUIAnim(ui_anim); spaceArtifact.SetArtifactTier(artifact_tier); gameObject.AddOrGet <KSelectable>(); gameObject.GetComponent <KBatchedAnimController>().initialMode = KAnim.PlayMode.Loop; postInitFn?.Invoke(gameObject); KPrefabID component = gameObject.GetComponent <KPrefabID>(); component.AddTag(GameTags.PedestalDisplayable, false); component.AddTag(GameTags.Artifact, false); return(gameObject); }
/// <summary> /// Removes a decor provider from the list. /// </summary> /// <param name="prefabID">The prefab ID of the provider.</param> /// <param name="provider">The provider to remove.</param> /// <param name="decor">The provider's current decor score.</param> /// <returns>true if the decor score was changed, or false otherwise.</returns> public bool RemoveDecorProvider(Tag prefabID, DecorProvider provider, float decor) { BestDecorList values; bool removed = false; lock (decorProviders) { decorProviders.TryGetValue(prefabID, out values); } if (values != null) { int count; // Lock the right things at the right times lock (values) { removed = values.RemoveDecorItem(decor, provider); count = values.Count; } if (count < 1) { lock (decorProviders) { decorProviders.Remove(prefabID); } } } return(removed); }
private void OnOccupantChanged(object data) { Attributes attributes = this.GetAttributes(); if (decorModifier != null) { attributes.Remove(decorModifier); attributes.Remove(decorRadiusModifier); decorModifier = null; decorRadiusModifier = null; } if (data != null) { GameObject gameObject = (GameObject)data; DecorProvider component = gameObject.GetComponent <DecorProvider>(); float value = 5f; float value2 = 3f; if ((Object)component != (Object)null) { value = Mathf.Max(Db.Get().BuildingAttributes.Decor.Lookup(gameObject).GetTotalValue() * 2f, 5f); value2 = Db.Get().BuildingAttributes.DecorRadius.Lookup(gameObject).GetTotalValue() + 2f; } string description = string.Format(BUILDINGS.PREFABS.ITEMPEDESTAL.DISPLAYED_ITEM_FMT, gameObject.GetComponent <KPrefabID>().PrefabTag.ProperName()); decorModifier = new AttributeModifier(Db.Get().BuildingAttributes.Decor.Id, value, description, false, false, true); decorRadiusModifier = new AttributeModifier(Db.Get().BuildingAttributes.DecorRadius.Id, value2, description, false, false, true); attributes.Add(decorModifier); attributes.Add(decorRadiusModifier); } }
private static GameObject ConfigPlacedEntity(GameObject template, string id, string name, string desc, float mass, KAnimFile anim, string initialAnim, Grid.SceneLayer sceneLayer, int width, int height, EffectorValues decor, EffectorValues noise = default(EffectorValues), SimHashes element = SimHashes.Creature, List <Tag> additionalTags = null, float defaultTemperature = 293f) { if ((Object)anim == (Object)null) { Debug.LogErrorFormat("Cant create [{0}] entity without an anim", name); } ConfigBasicEntity(template, id, name, desc, mass, true, anim, initialAnim, sceneLayer, element, additionalTags, defaultTemperature); KBoxCollider2D kBoxCollider2D = template.AddOrGet <KBoxCollider2D>(); kBoxCollider2D.size = new Vector2f(width, height); float num = 0.5f * (float)((width + 1) % 2); kBoxCollider2D.offset = new Vector2f(num, (float)height / 2f); KBatchedAnimController component = template.GetComponent <KBatchedAnimController>(); component.Offset = new Vector3(num, 0f, 0f); OccupyArea occupyArea = template.AddOrGet <OccupyArea>(); occupyArea.OccupiedCellsOffsets = GenerateOffsets(width, height); DecorProvider decorProvider = template.AddOrGet <DecorProvider>(); decorProvider.SetValues(decor); decorProvider.overrideName = name; return(template); }
private void InitalizeEffectors() { if (provider == null) { provider = this.gameObject.GetComponent <DecorProvider>(); if (provider == null) { return; } } if (initialEffector.amount == 0) { initialEffector = new EffectorValues() { amount = (int)provider.baseDecor, radius = (int)provider.baseRadius } } ; if (bonusEffector.amount == 0) { bonusEffector = new EffectorValues() { amount = (int)((1 + BonusScale) * initialEffector.amount), radius = (int)((1 + BonusScale) * initialEffector.radius) } } ; }
/// <summary> /// Applied after OnPrefabInit runs. /// </summary> internal static void Postfix(DecorProvider __instance, ref int[] ___cells, ref int ___cellCount) { __instance.gameObject.AddOrGet<DecorSplatNew>(); // Save a lot of memory ___cells = new int[16]; ___cellCount = 0; }
protected override void OnSpawn() { base.OnSpawn(); int cell = Grid.PosToCell(this); if (!Grid.IsValidCell(cell)) { base.gameObject.DeleteObject(); } else { UpdateCachedCell(cell); ReachabilityMonitor.Instance instance = new ReachabilityMonitor.Instance(this); instance.StartSM(); FetchableMonitor.Instance instance2 = new FetchableMonitor.Instance(this); instance2.StartSM(); SetWorkTime(1.5f); faceTargetWhenWorking = true; KSelectable component = GetComponent<KSelectable>(); if ((UnityEngine.Object)component != (UnityEngine.Object)null) { component.SetStatusIndicatorOffset(new Vector3(0f, -0.65f, 0f)); } OnTagsChanged(null); TryToOffsetIfBuried(); DecorProvider component2 = GetComponent<DecorProvider>(); if ((UnityEngine.Object)component2 != (UnityEngine.Object)null && string.IsNullOrEmpty(component2.overrideName)) { component2.overrideName = UI.OVERLAYS.DECOR.CLUTTER; } UpdateEntombedVisualizer(); Subscribe(-1582839653, OnTagsChangedDelegate); } }
/// <summary> /// Registers a decor provider with the system. /// </summary> /// <param name="instance">The decor provider to register.</param> internal void RegisterDecor(DecorProvider instance) { lock (provInfo) { if (!provInfo.ContainsKey(instance)) { provInfo.Add(instance, new DecorSplatNew(instance)); } } }
public static GameObject CreatePacu(string id, string name, string desc, string anim_file, bool is_baby) { GameObject prefab = BasePacuConfig.CreatePrefab(id, "PacuTropicalBaseTrait", name, desc, anim_file, is_baby, "trp_", 303.15f, 353.15f); prefab = EntityTemplates.ExtendEntityToWildCreature(prefab, PacuTuning.PEN_SIZE_PER_CREATURE, 25f); DecorProvider decorProvider = prefab.AddOrGet <DecorProvider>(); decorProvider.SetValues(DECOR); return(prefab); }
internal DecorSplatNew(DecorProvider provider) { this.provider = provider ?? throw new ArgumentNullException("provider"); cacheDecor = 0.0f; cells = new List <int>(256); partitioner = IntHandle.InvalidHandle; solidChangedPartitioner = IntHandle.InvalidHandle; provider.Subscribe((int)GameHashes.OperationalFlagChanged, OnOperationalFlagChanged); }
/// <summary> /// Applied before Refresh runs. /// </summary> internal static bool Prefix(DecorProvider __instance) { var obj = __instance.gameObject; DecorSplatNew splat; bool cont = true; if (obj != null && (splat = obj.GetComponent<DecorSplatNew>()) != null) { // Replace it cont = false; splat.RefreshDecor(); } return cont; }
/// <summary> /// Applied before GetDecorForCell runs. /// </summary> internal static bool Prefix(DecorProvider __instance, int cell, out float __result) { bool cont = true; var inst = DecorCellManager.Instance; if (inst != null) { __result = inst.GetDecorProvided(cell, __instance); cont = false; } else __result = 0.0f; return cont; }
/// <summary> /// Applied before Refresh runs. /// </summary> internal static bool Prefix(DecorProvider __instance) { var obj = __instance.gameObject; var inst = DecorCellManager.Instance; bool cont = true; if (obj != null && inst != null) { cont = false; inst.RefreshDecor(__instance); } return(cont); }
public Splat(DecorProvider provider) { this = default(Splat); AttributeInstance decor = provider.decor; this.decor = 0f; if (decor != null) { this.decor = decor.GetTotalValue(); } if (provider.HasTag(GameTags.Stored)) { this.decor = 0f; } int num = Grid.PosToCell(provider.gameObject); if (Grid.IsValidCell(num)) { if (!Grid.Transparent[num] && Grid.Solid[num] && (UnityEngine.Object)provider.simCellOccupier == (UnityEngine.Object)null) { this.decor = 0f; } if (this.decor != 0f) { provider.cellCount = 0; this.provider = provider; int num2 = 5; AttributeInstance decorRadius = provider.decorRadius; if (decorRadius != null) { num2 = (int)decorRadius.GetTotalValue(); } Orientation orientation = Orientation.Neutral; if ((bool)provider.rotatable) { orientation = provider.rotatable.GetOrientation(); } OccupyArea occupyArea = provider.occupyArea; extents = occupyArea.GetExtents(orientation); extents.x = Mathf.Max(extents.x - num2, 0); extents.y = Mathf.Max(extents.y - num2, 0); extents.width = Mathf.Min(extents.width + num2 * 2, Grid.WidthInCells - 1); extents.height = Mathf.Min(extents.height + num2 * 2, Grid.HeightInCells - 1); partitionerEntry = GameScenePartitioner.Instance.Add("DecorProvider.SplatCollectDecorProviders", provider.gameObject, extents, GameScenePartitioner.Instance.decorProviderLayer, provider.onCollectDecorProvidersCallback); solidChangedPartitionerEntry = GameScenePartitioner.Instance.Add("DecorProvider.SplatSolidCheck", provider.gameObject, extents, GameScenePartitioner.Instance.solidChangedLayer, provider.refreshPartionerCallback); AddDecor(); } } }
/// <summary> /// Destroys all references to the specified decor provider in the decor system. /// </summary> /// <param name="instance">The DecorProvider that is being destroyed.</param> internal void DestroyDecor(DecorProvider instance) { DecorSplatNew splat; lock (provInfo) { if (provInfo.TryGetValue(instance, out splat)) { provInfo.Remove(instance); } } if (splat != null) { splat.Dispose(); } }
public static GameObject CreateOilFloater(string id, string name, string desc, string anim_file, bool is_baby) { GameObject gameObject = BaseOilFloaterConfig.BaseOilFloater(id, name, desc, anim_file, "OilfloaterDecorBaseTrait", 283.15f, 343.15f, is_baby, "oxy_"); DecorProvider decorProvider = gameObject.AddOrGet <DecorProvider>(); decorProvider.SetValues(DECOR.BONUS.TIER6); EntityTemplates.ExtendEntityToWildCreature(gameObject, OilFloaterTuning.PEN_SIZE_PER_CREATURE, 150f); Trait trait = Db.Get().CreateTrait("OilfloaterDecorBaseTrait", name, name, null, false, null, true, true); trait.Add(new AttributeModifier(Db.Get().Amounts.Calories.maxAttribute.Id, OilFloaterTuning.STANDARD_STOMACH_SIZE, name, false, false, true)); trait.Add(new AttributeModifier(Db.Get().Amounts.Calories.deltaAttribute.Id, (0f - OilFloaterTuning.STANDARD_CALORIES_PER_CYCLE) / 600f, name, false, false, true)); trait.Add(new AttributeModifier(Db.Get().Amounts.HitPoints.maxAttribute.Id, 25f, name, false, false, true)); trait.Add(new AttributeModifier(Db.Get().Amounts.Age.maxAttribute.Id, 150f, name, false, false, true)); return(BaseOilFloaterConfig.SetupDiet(gameObject, SimHashes.Oxygen.CreateTag(), Tag.Invalid, CALORIES_PER_KG_OF_ORE, 0f, null, 0f, 0f)); }
protected override void OnPrefabInit() { base.OnPrefabInit(); decorProvider = GetComponent <DecorProvider>(); if (decorModifier == null) { decorModifier = new AttributeModifier("Decor", 0f, DUPLICANTS.MODIFIERS.CLOTHING.NAME, false, false, false); } if (conductivityModifier == null) { AttributeInstance attributeInstance = base.gameObject.GetAttributes().Get("ThermalConductivityBarrier"); conductivityModifier = new AttributeModifier("ThermalConductivityBarrier", ClothingInfo.BASIC_CLOTHING.conductivityMod, DUPLICANTS.MODIFIERS.CLOTHING.NAME, false, false, false); attributeInstance.Add(conductivityModifier); } }
public void RemoveMonumentPiece() { if (IsMonumentCompleted()) { List <GameObject> attachedNetwork = AttachableBuilding.GetAttachedNetwork(GetComponent <AttachableBuilding>()); foreach (GameObject item in attachedNetwork) { if ((Object)item.GetComponent <MonumentPart>() != (Object)this) { DecorProvider component = item.GetComponent <DecorProvider>(); component.SetValues(BUILDINGS.DECOR.BONUS.MONUMENT.INCOMPLETE); } } } }
/// <summary> /// Adds a decor provider to a given cell. /// </summary> /// <param name="cell">The cell.</param> /// <param name="provider">The object providing decor.</param> /// <param name="decor">The quantity of decor to add or subtract.</param> public void AddDecorProvider(int cell, DecorProvider provider, float decor) { var parent = provider.gameObject; bool allowForCritter = (parent == null) ? false : (!noCritterDecor || parent.GetComponent <CreatureBrain>() == null); // Must be a valid cell, and the object must be either not a critter or critter // decor enabled if (Grid.IsValidCell(cell) && cell < size && cell >= 0 && allowForCritter) { lock (decorGrid) { AddOrGet(cell).AddDecorProvider(provider.PrefabID(), provider, decor); } } }
public GameObject CreatePrefab() { GameObject gameObject = EntityTemplates.CreateLooseEntity(ID, ITEMS.FOOD.ROTPILE.NAME, ITEMS.FOOD.ROTPILE.DESC, 1f, false, Assets.GetAnim("rotfood_kanim"), "object", Grid.SceneLayer.Front, EntityTemplates.CollisionShape.RECTANGLE, 0.8f, 0.4f, true, 0, SimHashes.Creature, null); KPrefabID component = gameObject.GetComponent <KPrefabID>(); component.AddTag(GameTags.Organics, false); component.AddTag(GameTags.Compostable, false); gameObject.AddOrGet <EntitySplitter>(); gameObject.AddOrGet <OccupyArea>(); gameObject.AddOrGet <Modifiers>(); gameObject.AddOrGet <RotPile>(); DecorProvider decorProvider = gameObject.AddComponent <DecorProvider>(); decorProvider.SetValues(DECOR.PENALTY.TIER2); return(gameObject); }
/// <summary> /// Retrieves the decor provided by the specified provider. /// </summary> /// <param name="cell">The cell to check.</param> /// <param name="provider">The provider which could be providing decor.</param> /// <returns>The decor provided by that provider.</returns> internal float GetDecorProvided(int cell, DecorProvider provider) { float decor = 0.0f; if (Grid.IsValidCell(cell) && cell < size && cell >= 0) { lock (decorGrid) { var dc = decorGrid[cell]; if (dc != null) { decor = dc.GetDecorProvidedBy(provider); } } } return(decor); }
/// <summary> /// Adds a decor provider to the list. /// </summary> /// <param name="prefabID">The prefab ID of the provider.</param> /// <param name="provider">The provider to add.</param> /// <param name="decor">The provider's current decor score.</param> /// <returns>true if the decor score was changed, or false otherwise.</returns> public bool AddDecorProvider(Tag prefabID, DecorProvider provider, float decor) { BestDecorList values; bool add = false; lock (decorProviders) { if (!decorProviders.TryGetValue(prefabID, out values)) { decorProviders.Add(prefabID, values = new BestDecorList(cell)); } } lock (values) { add = values.AddDecorItem(decor, provider); } return(add); }
/// <summary> /// Removes a decor item. /// </summary> /// <param name="decor">The current decor of the item.</param> /// <param name="provider">The decor item to remove.</param> public bool RemoveDecorItem(float decor, DecorProvider provider) { bool found = false; // Find and remove /*foreach (var pair in decorByValue) { * var pairKey = pair.Key; * if (pairKey.Provider == provider) { * decorByValue.Remove(pairKey); * found = true; * break; * } * }*/ found = decorByValue.Remove(new DecorWrapper(decor, provider)); return(found && UpdateBestDecor()); }
/// <summary> /// Removes a decor provider from a given cell. /// </summary> /// <param name="cell">The cell.</param> /// <param name="provider">The object providing decor.</param> /// <param name="decor">The quantity of decor to add or subtract.</param> public void RemoveDecorProvider(int cell, DecorProvider provider, float decor) { if (Grid.IsValidCell(cell) && cell < size && cell >= 0) { lock (decorGrid) { var dc = decorGrid[cell]; if (dc != null) { dc.RemoveDecorProvider(provider.PrefabID(), provider, decor); if (dc.Count == 0) { decorGrid[cell] = null; } } } } }
/// <summary> /// Retrieves the decor score provided by the provider. /// </summary> /// <param name="provider">The decor provider to check.</param> /// <returns>The score provided by that provider, or 0 if it does not provide decor there.</returns> public float GetDecorProvidedBy(DecorProvider provider) { BestDecorList values; float decor = 0.0f; if (provider == null) { throw new ArgumentNullException("provider"); } lock (decorProviders) { decorProviders.TryGetValue(provider.PrefabID(), out values); } if (values != null && provider == values.BestProvider) { decor = values.BestDecor; } return(decor); }
/// <summary> /// Replaces the Refresh method of DecorProvider to handle the decor ourselves. /// </summary> /// <param name="provider">The DecorProvider that is being refreshed.</param> internal void RefreshDecor(DecorProvider provider) { if (provider == null) { throw new ArgumentNullException("provider"); } var obj = provider.gameObject; // Get status of the object var prefabID = obj.GetComponent <KPrefabID>(); var entombStatus = obj.GetComponent <Structure>(); var disableStatus = obj.GetComponent <BuildingEnabledButton>(); var breakStatus = obj.GetComponent <BuildingHP>(); var glumStatus = obj.GetComponent <Klei.AI.Modifiers>()?.attributes?.Get( happinessAttribute); // Entombed/disabled = 0 decor, broken = use value in DecorTuning for broken bool broken = brokenFlag != null && breakStatus != null && breakStatus.IsBroken; bool disabled = (entombStatus != null && entombStatus.IsEntombed()) || (disableStatus != null && !disableStatus.IsEnabled) || (glumStatus != null && glumStatus.GetTotalValue() < 0.0f); if (provInfo.TryGetValue(provider, out DecorSplatNew splat)) { splat?.Refresh(broken, disabled); } // Handle rooms which require an item with 20 decor: has to actually be functional bool hasTag = prefabID.HasTag(RoomConstraints.ConstraintTags.Decor20); bool needsTag = provider.decor.GetTotalValue() >= 20f && !broken && !disabled; if (hasTag != needsTag) { // Tag needs to be added/removed if (needsTag) { prefabID.AddTag(RoomConstraints.ConstraintTags.Decor20, false); } else { prefabID.RemoveTag(RoomConstraints.ConstraintTags.Decor20); } // Force room recalculation Game.Instance.roomProber.SolidChangedEvent(Grid.PosToCell(obj), true); } }