// Empty, for now #endregion #region Overrides of CustomForcedBehavior public override void OnStart() { // Hunting ground processing... // NB: We had to defer this processing from the constructor, because XElement isn't available // to parse child XML nodes until OnStart() is called. HuntingGrounds = HuntingGroundsType.GetOrCreate(Element, "HuntingGrounds", HuntingGroundCenter); IsAttributeProblem |= HuntingGrounds.IsAttributeProblem; // Let QuestBehaviorBase do basic initializaion of the behavior, deal with bad or deprecated attributes, // capture configuration state, install BT hooks, etc. This will also update the goal text. OnStart_QuestBehaviorCore( string.Format("Using {0} on {1}", GetItemNameFromId(ItemId), string.Join(", ", MobIds.Select(m => GetMobNameFromId(m)).Distinct()))); // If the quest is complete, this behavior is already done... // So we don't want to falsely inform the user of things that will be skipped. if (!IsDone) { ItemToUse = Me.CarriedItems.FirstOrDefault(i => (i.Entry == ItemId)); if (ItemToUse == null) { LogError("[PROFILE ERROR] Unable to locate in our bags", GetItemNameFromId(ItemId)); TreeRoot.Stop(); BehaviorDone(); } CurrentHuntingGroundWaypoint = HuntingGrounds.FindFirstWaypoint(Me.Location); } }
private WoWUnit GetNpc() { return(ObjectManager.GetObjectsOfType <WoWUnit>() .Where( u => u.IsAlive && MobIds.Contains(((int)u.Entry)) && (u.ThreatInfo.ThreatStatus > ThreatStatus.UnitNotInThreatTable || !Query.IsInCompetition(u, NonCompeteDistance))) .OrderBy(u => u.DistanceSqr) .FirstOrDefault()); }
public InteractWith(Dictionary <string, string> args) : base(args) { try { // QuestRequirement* attributes are explained here... // http://www.thebuddyforum.com/mediawiki/index.php?title=Honorbuddy_Programming_Cookbook:_QuestId_for_Custom_Behaviors // ...and also used for IsDone processing. WaitForNpcs = GetAttributeAsBoolean("WaitForNpcs", false, null) ?? true; BuyItemCount = GetAttributeAsInteger("BuyItemCount", false, 1, 1000, null) ?? 1; BuyItemId = GetAttributeAsItemId("BuyItemId", false, null) ?? 0; BuySlot = GetAttributeAsInteger("BuySlot", false, -1, 100, null) ?? -1; CollectionDistance = GetAttributeAsInteger("CollectionDistance", false, 1, 10000, null) ?? 100; GossipOptions = GetAttributeAsIntegerArray("GossipOptions", false, -1, 10, new [] { "GossipOption" }) ?? new int[0]; Loot = GetAttributeAsBoolean("Loot", false, null) ?? false; MobIds = GetNumberedAttributesAsIntegerArray("MobId", 1, 1, int.MaxValue, new [] { "MobID", "NpcId" }) ?? new int[0]; ObjType = GetAttributeAsEnum <ObjectType>("ObjectType", false, new [] { "MobType" }) ?? ObjectType.Npc; NotMoving = GetAttributeAsBoolean("NotMoving", false, null) ?? false; NumOfTimes = GetAttributeAsNumOfTimes("NumOfTimes", false, null) ?? 1; QuestId = GetAttributeAsQuestId("QuestId", false, null) ?? 0; QuestRequirementComplete = GetAttributeAsEnum <QuestCompleteRequirement>("QuestCompleteRequirement", false, null) ?? QuestCompleteRequirement.NotComplete; QuestRequirementInLog = GetAttributeAsEnum <QuestInLogRequirement>("QuestInLogRequirement", false, null) ?? QuestInLogRequirement.InLog; Range = GetAttributeAsRange("Range", false, null) ?? 4; WaitTime = GetAttributeAsWaitTime("WaitTime", false, null) ?? 3000; Existing = GetAttributeAsBoolean("Existing", false, null) ?? false; Alive = GetAttributeAsBoolean("Alive", false, null) ?? false; for (int i = 0; i < GossipOptions.Length; ++i) { GossipOptions[i] -= 1; } WoWUnit mob = ObjectManager.GetObjectsOfType <WoWUnit>() .Where(unit => MobIds.Contains((int)unit.Entry)) .FirstOrDefault(); MobName = ((mob != null) && !string.IsNullOrEmpty(mob.Name)) ? mob.Name : ("Mob(" + MobIds[0] + ")"); } catch (Exception except) { // Maintenance problems occur for a number of reasons. The primary two are... // * Changes were made to the behavior, and boundary conditions weren't properly tested. // * The Honorbuddy core was changed, and the behavior wasn't adjusted for the new changes. // In any case, we pinpoint the source of the problem area here, and hopefully it // can be quickly resolved. UtilLogMessage("error", "BEHAVIOR MAINTENANCE PROBLEM: " + except.Message + "\nFROM HERE:\n" + except.StackTrace + "\n"); IsAttributeProblem = true; } }
// Private LINQ queries... private IEnumerable <WoWObject> ViableTargets() { return(ObjectManager.GetObjectsOfType <WoWObject>(true, false) .Where(target => (target.IsValid && MobIds.Contains((int)target.Entry) && TargetAurasShowing(target, _targetAuraToButtonMap).Any() && (target.Distance < HuntingGroundRadius) && !target.IsLocallyBlacklisted() && !BlacklistIfPlayerNearby(target) && Query.IsStateMatch_IgnoreMobsInBlackspots(target, IgnoreMobsInBlackspots))) .OrderBy(target => Me.Location.SurfacePathDistance(target.Location))); }
// 24Feb2013-08:11UTC chinajade private bool IsViableForItemUse(WoWUnit wowUnit) { return (Query.IsViable(wowUnit) && wowUnit.IsAlive && wowUnit.Attackable && MobIds.Contains((int)wowUnit.Entry) && Query.IsViableForInteracting(wowUnit, IgnoreMobsInBlackspots, NonCompeteDistance) && Query.IsViableForPulling(wowUnit, IgnoreMobsInBlackspots, NonCompeteDistance) && (ItemUseAlwaysSucceeds || !wowUnit.HasAura(ItemAppliesAuraId)) && wowUnit.CollectionDistance() <= CollectionDistance); }
public BreakImmunityByKillingMobsInCloseProximity(Dictionary <string, string> args) : base(args) { QBCLog.BehaviorLoggingContext = this; try { // QuestRequirement* attributes are explained here... // http://www.thebuddyforum.com/mediawiki/index.php?title=Honorbuddy_Programming_Cookbook:_QuestId_for_Custom_Behaviors // ...and also used for IsDone processing. // Primary attributes... MobIds = GetNumberedAttributesAsArray <int>("MobId", 0, ConstrainAs.MobId, new[] { "NpcId" }); if (MobIds != null && !MobIds.Any()) { MobIds = GetAttributeAsArray <int>("MobIds", true, ConstrainAs.MobId, new[] { "NpcIds" }, null); } ImmunityBreakingMobIds = GetNumberedAttributesAsArray <int>( "ImmunityBreakingMobId", 0, ConstrainAs.MobId, new[] { "ImmunityBreakingNpcId" }); if (ImmunityBreakingMobIds != null && !ImmunityBreakingMobIds.Any()) { ImmunityBreakingMobIds = GetAttributeAsArray <int>( "ImmunityBreakingMobIds", true, ConstrainAs.MobId, new[] { "ImmunityBreakingNpcIds" }, null); } SearchLocation = GetAttributeAsNullable <Vector3>("", false, ConstrainAs.Vector3NonEmpty, null) ?? Me.Location; ImmunityAuraId = GetAttributeAsNullable <int>("ImmunityAuraId", true, ConstrainAs.AuraId, null) ?? 0; MaxRange = GetAttributeAsNullable <double>("MaxRange", false, new ConstrainTo.Domain <double>(0, 40), null) ?? 8; } catch (Exception except) { // Maintenance problems occur for a number of reasons. The primary two are... // * Changes were made to the behavior, and boundary conditions weren't properly tested. // * The Honorbuddy core was changed, and the behavior wasn't adjusted for the new changes. // In any case, we pinpoint the source of the problem area here, and hopefully it // can be quickly resolved. QBCLog.Exception(except); IsAttributeProblem = true; } }
public override void OnStart() { // Let QuestBehaviorBase do basic initializaion of the behavior, deal with bad or deprecated attributes, // capture configuration state, install BT hooks, etc. This will also update the goal text. var isBehaviorShouldRun = OnStart_QuestBehaviorCore( string.Format("Using {0} on {1}", Utility.GetItemNameFromId(ItemId), string.Join(", ", MobIds.Select(m => Utility.GetObjectNameFromId(m)).Distinct()))); // If the quest is complete, this behavior is already done... // So we don't want to falsely inform the user of things that will be skipped. if (isBehaviorShouldRun) { _waitTimerAfterUsingItem.WaitTime = TimeSpan.FromMilliseconds(WaitTimeAfterItemUse); } }
public CannonControl(Dictionary <string, string> args) : base(args) { QBCLog.BehaviorLoggingContext = this; try { // QuestRequirement* attributes are explained here... // http://www.thebuddyforum.com/mediawiki/index.php?title=Honorbuddy_Programming_Cookbook:_QuestId_for_Custom_Behaviors // ...and also used for IsDone processing. // Primary attributes... MobIds = GetNumberedAttributesAsArray <int>("MobId", 0, ConstrainAs.MobId, new[] { "NpcId" }); if (MobIds != null && !MobIds.Any()) { MobIds = GetAttributeAsArray <int>("MobIds", false, ConstrainAs.MobId, new[] { "NpcIds" }, null); } Buttons = GetAttributeAsArray <int>("Buttons", true, new ConstrainTo.Domain <int>(1, 12), null, null); ExitButton = GetAttributeAsNullable <int>("ExitButton", false, ConstrainAs.HotbarButton, null) ?? 0; MaxAngle = GetAttributeAsNullable <double>("MaxAngle", false, new ConstrainTo.Domain <double>(-1.5, 1.5), null) ?? 1.5; MinAngle = GetAttributeAsNullable <double>("MinAngle", false, new ConstrainTo.Domain <double>(-1.5, 1.5), null) ?? -1.5; Velocity = GetAttributeAsNullable <double>("Velocity", false, new ConstrainTo.Domain <double>(2.0, 1000), null) ?? 70; Gravity = GetAttributeAsNullable <double>("Gravity", false, new ConstrainTo.Domain <double>(0.01, 80), null) ?? 30; VehicleId = GetAttributeAsNullable <int>("VehicleId", false, ConstrainAs.VehicleId, null) ?? 0; VehicleSearchLocation = GetAttributeAsNullable <Vector3>("", false, ConstrainAs.Vector3NonEmpty, null) ?? Me.Location; WeaponArticulation = new WeaponArticulation(MinAngle, MaxAngle); Weapons = Buttons.Select(b => new VehicleWeapon(b, WeaponArticulation, Velocity, Gravity)).ToArray(); } catch (Exception except) { // Maintenance problems occur for a number of reasons. The primary two are... // * Changes were made to the behavior, and boundary conditions weren't properly tested. // * The Honorbuddy core was changed, and the behavior wasn't adjusted for the new changes. // In any case, we pinpoint the source of the problem area here, and hopefully it // can be quickly resolved. QBCLog.Exception(except); IsAttributeProblem = true; } }
protected override Composite CreateBehavior_CombatMain() { return(new Decorator(context => !IsDone, new PrioritySelector( // Update values for this BT node visit... new Action(context => { VehicleUnoccupied = FindUnoccupiedVehicle(); // Figure out our final destination (i.e., a location or a mob)... // NB: this can change as we travel. If our destination is a mob, // We can't "see" distant mobs until we get within 100 yards or so of them. // Until we close that distance, we'll head towards the provided location. // As soon as we "see" the mob, we'll switch to the mob as the destination. FinalDestination = Destination; FinalDestinationName = "destination"; if (MobIds.Count() > 0) { // If we can see our destination mob, calculate a path to it... var nearestMob = Query.FindMobsAndFactions(MobIds).OrderBy(u => u.Distance).FirstOrDefault() as WoWUnit; if (nearestMob != null) { // Target destination mob as feedback to the user... Utility.Target(nearestMob); FinalDestination = nearestMob.Location; FinalDestinationName = nearestMob.SafeName; } } return RunStatus.Failure; // fall thru }), // Proceed if we're not in combat, or are ignoring it... new Decorator(context => !Me.Combat || IgnoreCombat, new PrioritySelector( // If we were successfully mounted... // and within a few yards of our destination when we were dismounted, we must // assume we were auto-dismounted, and the behavior is complete... new Decorator(context => DidSuccessfullyMount && !IsInVehicle() && (WoWMovement.ActiveMover.Location.Distance(FinalDestination) < 15.0), new Action(context => { BehaviorDone(); })), // Enable combat while not in a vehicle new Decorator(ctx => (LevelBot.BehaviorFlags & BehaviorFlags.Combat) == 0 && !Query.IsInVehicle(), new Action(ctx => LevelBot.BehaviorFlags |= BehaviorFlags.Combat)), // Disable combat while in a vehicle new Decorator(ctx => (LevelBot.BehaviorFlags & BehaviorFlags.Combat) != 0 && Query.IsInVehicle(), new Action(ctx => LevelBot.BehaviorFlags &= ~BehaviorFlags.Combat)), // If we're not in a vehicle, go fetch one... new Decorator(context => !IsInVehicle() && Query.IsViable(VehicleUnoccupied), new Sequence( new CompositeThrottleContinue( Throttle.UserUpdate, new Action(context => { TreeRoot.StatusText = string.Format("Moving to {0} {1}", VehicleUnoccupied.SafeName, Me.Combat ? "(ignoring combat)" : ""); })), new DecoratorContinue(context => VehicleUnoccupied.WithinInteractRange, new Action(context => { VehicleUnoccupied.Interact(); })), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( VehicleUnoccupied.Location, VehicleUnoccupied.SafeName, MovementBy)) )), // If we can't find a vehicle, terminate if requested... new CompositeThrottle( context => !IsInVehicle() && !Query.IsViable(VehicleUnoccupied), Throttle.UserUpdate, new Action(context => { if (!WaitForVehicle) { BehaviorDone(string.Format("No Vehicle, and WaitForVehicle=\"{0}\"", WaitForVehicle)); } else { TreeRoot.StatusText = "No vehicles in area--waiting for vehicle to become available."; } })), // Move vehicle to destination... new Decorator(context => IsInVehicle(), new PrioritySelector( // If we successfully mounted the vehicle, record the fact... new Decorator(context => !DidSuccessfullyMount, new Action(context => { DidSuccessfullyMount = true; })), new Decorator(context => !Navigator.AtLocation(FinalDestination), new ActionRunCoroutine( interactUnitContext => UtilityCoroutine.MoveTo( FinalDestination, FinalDestinationName, MovementBy))), new Decorator(context => WoWMovement.ActiveMover.IsMoving, new Action(context => { WoWMovement.MoveStop(); })), // Arrived at destination, use spell if necessary... // NB: We want to make certain movement is settled before we attempt // to cast spell, so we won't be interrupted. new SleepForLagDuration(), CreateSpellBehavior() )) )), // Squelch combat, if requested... new Decorator(context => IgnoreCombat, new ActionAlwaysSucceed()) ))); }
protected override Composite CreateBehavior() { return(_root ?? (_root = new PrioritySelector( new Decorator(c => Npc != null, new Action(c => { if (!Npc.Attackable) { Blacklist.Add(Npc.Guid, new TimeSpan(0, 5, 0)); } if ((Me.Combat && (Me.GotTarget && Me.CurrentTarget != Npc && !MobIds.Contains((int)Me.CurrentTarget.Entry)) || Me.HealthPercent < HealthPercent) || IsDone) { return RunStatus.Success; } WoWUnit lootable = ObjectManager.GetObjectsOfType <WoWUnit>().OrderBy(u => u.Distance). FirstOrDefault(u => u.Lootable); if (lootable != null) { if (!lootable.WithinInteractRange) { if (Npc.Distance < 30 && SpellManager.CanCast("Death Grip")) { SpellManager.Cast("Death Grip"); WoWMovement.MoveStop(); } else { Navigator.MoveTo(lootable.Location); } } else { lootable.Interact(); } if (Logic.Inventory.Frames.LootFrame.LootFrame.Instance != null && Logic.Inventory.Frames.LootFrame.LootFrame.Instance.IsVisible) { Logic.Inventory.Frames.LootFrame.LootFrame.Instance.LootAll(); if (Me.GotTarget) { Blacklist.Add(Me.CurrentTarget, new TimeSpan(1, 0, 0)); } Me.ClearTarget(); } return RunStatus.Running; } if (!Me.GotTarget || Me.CurrentTarget != Npc) { Npc.Target(); } if (!Npc.WithinInteractRange) { TreeRoot.GoalText = string.Format("Moving to {0}", Npc.Name); Navigator.MoveTo(WoWMathHelper.CalculatePointFrom(Me.Location, Npc.Location, 3)); } else { if (Me.IsMoving) { WoWMovement.MoveStop(); } if (!Me.IsAutoAttacking || !Me.IsSafelyFacing(ObjectManager.Me.CurrentTarget)) { TreeRoot.GoalText = string.Format("Bullying {0}", Npc.Name); Npc.Interact(); } } return RunStatus.Running; })), new Action(c => Navigator.MoveTo(Location)) ))); }
protected override Composite CreateBehavior_CombatMain() { return(new Decorator(context => !IsDone, new PrioritySelector( // Update values for this BT node visit... new Action(context => { VehicleUnoccupied = FindUnoccupiedVehicle(); // Figure out our final destination (i.e., a location or a mob)... // NB: this can change as we travel. If our destination is a mob, // We can't "see" distant mobs until we get within 100 yards or so of them. // Until we close that distance, we'll head towards the provided location. // As soon as we "see" the mob, we'll switch to the mob as the destination. FinalDestination = Destination; FinalDestinationName = "destination"; if (MobIds.Count() > 0) { // If we can see our destination mob, calculate a path to it... WoWUnit nearestMob = FindUnitsFromIds(MobIds).OrderBy(u => u.Distance).FirstOrDefault(); if (nearestMob != null) { // Target destination mob as feedback to the user... if (!Me.GotTarget || (Me.CurrentTarget != nearestMob)) { nearestMob.Target(); } FinalDestination = nearestMob.Location; FinalDestinationName = nearestMob.Name; } } return RunStatus.Failure; // fall thru }), // Proceed if we're not in combat, or are ignoring it... new Decorator(context => !Me.Combat || IgnoreCombat, new PrioritySelector( // If we were successfully mounted... // and within a few yards of our destination when we were dismounted, we must // assume we were auto-dismounted, and the behavior is complete... new Decorator(context => DidSuccessfullyMount && !IsInVehicle() && (Me.Location.Distance(FinalDestination) < 15.0), new Action(context => { BehaviorDone(); })), // If we're not in a vehicle, go fetch one... new Decorator(context => !IsInVehicle() && IsViable(VehicleUnoccupied), new Sequence( new Action(context => { TreeRoot.StatusText = string.Format("Moving to {0} {1}", VehicleUnoccupied.Name, Me.Combat ? "(ignoring combat)" : ""); }), new DecoratorContinue(context => VehicleUnoccupied.WithinInteractRange, new Action(context => { VehicleUnoccupied.Interact(); })), UtilityBehaviorPS_MoveTo(context => VehicleUnoccupied.Location, context => VehicleUnoccupied.Name) )), // If we successfully mounted the vehicle, record the fact... new Decorator(context => IsInVehicle() && !DidSuccessfullyMount, new Action(context => { DidSuccessfullyMount = true; })), // Move vehicle to destination... UtilityBehaviorPS_MoveTo(context => FinalDestination, context => FinalDestinationName, context => Precision, context => IsInVehicle(), context => LocationObserver()), new Decorator(context => Me.IsMoving, new Sequence( new Action(context => { WoWMovement.MoveStop(); }), new WaitContinue(TimeSpan.FromMilliseconds(CastTime), context => false, new ActionAlwaysSucceed()) )), // Arrived at destination, use spell if necessary... CreateSpellBehavior() )), // Squelch combat, if requested... new Decorator(context => IgnoreCombat, new ActionAlwaysSucceed()) ))); }
public InteractWith(Dictionary <string, string> args) : base(args) { try { // Warn of deprecated attributes... if (args.ContainsKey("BuySlot")) { LogMessage("warning", "*****\n" + "* THE BUYSLOT ATTRIBUTE IS DEPRECATED, and may be retired in a near, future release.\n" + "*\n" + "* BuySlot presents a number of problems. If a vendor presents 'seasonal' or\n" + "* limited-quantity wares, the slot number for the desired item can change.\n" + "\n" + "* Please update the profile to use *BuyItemId* attribute in preference to BuySlot.\n" + "*****"); } // QuestRequirement* attributes are explained here... // http://www.thebuddyforum.com/mediawiki/index.php?title=Honorbuddy_Programming_Cookbook:_QuestId_for_Custom_Behaviors // ...and also used for IsDone processing. BuyItemCount = GetAttributeAsNullable <int>("BuyItemCount", false, ConstrainAs.CollectionCount, null) ?? 1; BuyItemId = GetAttributeAsNullable <int>("BuyItemId", false, ConstrainAs.ItemId, null) ?? 0; BuySlot = GetAttributeAsNullable <int>("BuySlot", false, new ConstrainTo.Domain <int>(-1, 100), null) ?? -1; CollectionDistance = GetAttributeAsNullable <double>("CollectionDistance", false, ConstrainAs.Range, null) ?? 100; GossipOptions = GetAttributeAsArray <int>("GossipOptions", false, new ConstrainTo.Domain <int>(-1, 10), new[] { "GossipOption" }, null); Location = GetAttributeAsNullable <WoWPoint>("", false, ConstrainAs.WoWPointNonEmpty, null) ?? Me.Location; Loot = GetAttributeAsNullable <bool>("Loot", false, null, null) ?? false; MobIds = GetNumberedAttributesAsArray <int>("MobId", 1, ConstrainAs.MobId, new[] { "NpcId" }); ObjType = GetAttributeAsNullable <ObjectType>("ObjectType", false, null, new[] { "MobType" }) ?? ObjectType.Npc; NpcState = GetAttributeAsNullable <NpcStateType>("MobState", false, null, new[] { "NpcState" }) ?? NpcStateType.DontCare; NavigationState = GetAttributeAsNullable <NavigationType>("Nav", false, null, new[] { "Navigation" }) ?? NavigationType.Mesh; MobHpPercentLeft = GetAttributeAsNullable <double>("MobHpPercentLeft", false, ConstrainAs.Percent, new[] { "HpLeftAmount" }) ?? 100.0; NotMoving = GetAttributeAsNullable <bool>("NotMoving", false, null, null) ?? false; NumOfTimes = GetAttributeAsNullable <int>("NumOfTimes", false, ConstrainAs.RepeatCount, null) ?? 1; QuestId = GetAttributeAsNullable("QuestId", false, ConstrainAs.QuestId(this), null) ?? 0; QuestRequirementComplete = GetAttributeAsNullable <QuestCompleteRequirement>("QuestCompleteRequirement", false, null, null) ?? QuestCompleteRequirement.NotComplete; QuestRequirementInLog = GetAttributeAsNullable <QuestInLogRequirement>("QuestInLogRequirement", false, null, null) ?? QuestInLogRequirement.InLog; Range = GetAttributeAsNullable <double>("Range", false, ConstrainAs.Range, null) ?? 4.0; WaitForNpcs = GetAttributeAsNullable <bool>("WaitForNpcs", false, null, null) ?? true; WaitTime = GetAttributeAsNullable <int>("WaitTime", false, ConstrainAs.Milliseconds, null) ?? 3000; IgnoreCombat = GetAttributeAsNullable <bool>("IgnoreCombat", false, null, null) ?? false; for (int i = 0; i < GossipOptions.Length; ++i) { GossipOptions[i] -= 1; } IEnumerable <WoWUnit> mobs = ObjectManager.GetObjectsOfType <WoWUnit>(true, false) .Where(unit => MobIds.Contains((int)unit.Entry)); MobNames = string.Join(", ", mobs.Select(mob => (!string.IsNullOrEmpty(mob.Name) ? mob.Name : ("Mob(" + mob.Entry.ToString() + ")"))) .ToArray()); } catch (Exception except) { // Maintenance problems occur for a number of reasons. The primary two are... // * Changes were made to the behavior, and boundary conditions weren't properly tested. // * The Honorbuddy core was changed, and the behavior wasn't adjusted for the new changes. // In any case, we pinpoint the source of the problem area here, and hopefully it // can be quickly resolved. LogMessage("error", "BEHAVIOR MAINTENANCE PROBLEM: " + except.Message + "\nFROM HERE:\n" + except.StackTrace + "\n"); IsAttributeProblem = true; } }