public void AttackAI(Unit Target)
        {
            if (Target == null)
            {
                if (State == AiState.FIGHTING)
                {
                    CombatStop();
                }

                return;
            }

            long Tick = TCPManager.GetTimeStampMS();

            SetTarget(Target);
            LookAt(Target);

            if (NextAttackTime < Tick)
            {
                if (Obj.IsWithinRadius(Target, 10))
                {
                    Obj.GetUnit().Strike(Target);
                    NextAttackTime = Tick + 2000;
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Attempts to change the state of a weapon from mobile to deployed.
        /// </summary>
        /// <param name="player"></param>
        private void TryDeploy(Player player)
        {
            if (PlayerCount > 0)
            {
                player.SendClientMessage("You cannot deploy a siege weapon while it is being towed.");
                return;
            }

            IsDeployed = true;

            _weapon.MvtInterface.StopMove();

            if (Type == SiegeType.RAM)
            {
                _Owner.Region.Bttlfront.GetClosestKeep(_Owner.WorldPosition)?.TryAlignRam(_Owner, player);
            }

            foreach (Player p in _Owner.PlayersInRange)
            {
                _Owner.SendRemove(p);
                _Owner.SendMeTo(p);
            }

            _nextUseTime = TCPManager.GetTimeStampMS() + 1000;
            _deathTime   = TCPManager.GetTimeStampMS() + 300 * 1000;

            player.SendClientMessage($"Deployed the {_Owner.Name}.");
        }
        private void UpdateStage()
        {
            ++_stage;

            if (_stage == STAGE_FLOWERED)
            {
                GenerateResult();
                _ownerInterface.GetPlayer().SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_CRAFTING, Localized_text.TEXT_CULTIVATION_PLOT_FLOWERING_COMPLETED);
            }
            else
            {
                switch (_stage)
                {
                case STAGE_GERMINATION: _nextUpdateTime = TCPManager.GetTimeStampMS() + 1000;
                    break;

                case STAGE_SEEDLING: _currentStageTime = _stage2Time; _stage2Time = 0;
                    break;

                case STAGE_FLOWERING: _currentStageTime = _stage3Time; _stage3Time = 0;
                    break;
                }
                _ownerInterface.GetPlayer().SendLocalizeString("", ChatLogFilters.CHATLOGFILTERS_CRAFTING, Localized_text.TEXT_CULTIVATION_PLOT_FLOWERING_ADVANCED);
            }
        }
Beispiel #4
0
        public override void Update(long tick)
        {
            if (BuffState != (byte)EBuffState.Running)
            {
                return;
            }

            long curTime = TCPManager.GetTimeStampMS();

            if (EndTime > 0 && curTime >= EndTime)
            {
                BuffEnded(false, false);
            }
            else if (NextTickTime > 0 && curTime >= NextTickTime)
            {
                NextTickTime += _buffInfo.Interval;

                OnUpdate?.Invoke(this, HeldObject, tick);

                if (_buffInfo.CommandInfo != null)
                {
                    foreach (BuffCommandInfo command in _buffInfo.CommandInfo)
                    {
                        if ((command.InvokeOn & (byte)EBuffState.Running) > 0)
                        {
                            BuffEffectInvoker.InvokeCommand(this, command, Target);
                        }
                    }
                }
            }
        }
        private void BattlePopulationDistributionData()
        {
            long tick = TCPManager.GetTimeStampMS();

            RecalculatePopFactor();

            foreach (ProximityFlag flag in _Objectives)
            {
                if (flag.OwningRealm != Realms.REALMS_REALM_NEUTRAL)
                {
                    ; //Console.Error.WriteLine("TODO flag ccontribution"); // flag.TickDefense(tick / 1000);
                }
            }

            _contributionTracker.TickContribution(tick / 1000);

            UpdatePopulationDistribution();

            //if (Tier > 1)
            //{
            //    if (!PairingLocked)
            //        UpdateVictoryPoints();
            //    UpdateRationing();
            //}

            //// Unlocking
            //if (PairingUnlockTime > 0 && PairingUnlockTime < TCPManager.GetTimeStampMS())
            //    ResetPairing();
        }
Beispiel #6
0
        public override void StartBuff()
        {
            if (_buffInfo.CommandInfo != null)
            {
                for (byte i = 0; i < _buffInfo.CommandInfo.Count; ++i)
                {
                    if ((_buffInfo.CommandInfo[i].InvokeOn & BuffState) > 0)
                    {
                        BuffEffectInvoker.InvokeCommand(this, _buffInfo.CommandInfo[i], Target);
                    }
                }
            }

            BuffState = (byte)EBuffState.Running;

            NextTickTime = TCPManager.GetTimeStampMS() + _buffInfo.Interval;

            if (BuffLines.Count != 0)
            {
                SendBounceStart();
            }
            else
            {
                BuffHasExpired = true;
            }
        }
Beispiel #7
0
        private void TrySetback()
        {
            List <byte> locSetbacks = new List <byte>();

            Player plr = _caster as Player;

            if (plr == null)
            {
                return;
            }

            lock (_setbacks)
            {
                locSetbacks.AddRange(_setbacks);
                _setbacks.Clear();
            }

            if (AbInfo.ConstantInfo.Fragile == 2) // breaks immediately
            {
                CancelCast(1);
                return;
            }

            byte setbackChance = (byte)((AbInfo.ConstantInfo.Fragile == 1 ? 50 : 25) * _caster.StsInterface.GetStatPercentageModifier(Stats.SetbackChance));

            if (setbackChance == 0)
            {
                return;
            }

            ushort setbackAmount = 0;

            foreach (byte amount in locSetbacks)
            {
                if (amount <= setbackChance)
                {
                    setbackAmount += 250;
                }
            }

            if (setbackAmount == 0)
            {
                return;
            }

            _castStartTime = Math.Min(TCPManager.GetTimeStampMS(), _castStartTime + setbackAmount);

            PacketOut Out = new PacketOut((byte)Opcodes.F_SET_ABILITY_TIMER, 12);

            Out.WriteUInt16(1);
            Out.WriteByte(1);
            Out.WriteByte(3); // setback event
            Out.WriteUInt16(0);
            Out.WriteUInt16((ushort)(AbInfo.CastTime - (TCPManager.GetTimeStampMS() - _castStartTime)));
            Out.WriteUInt16(AbInfo.Entry);
            Out.WriteByte(_castSequence);
            Out.WriteByte(0);

            plr.SendPacket(Out);
        }
        private void checkcombatgroups()
        {
            if (_Spawns == null || _Spawns.Count == 0)
            {
                return;
            }

            lock (GroupsinCombat)
            {
                for (int i = 0; i < GroupsinCombat.Count; i++)
                {
                    List <InstanceSpawn> sp = new List <InstanceSpawn>();
                    _Spawns.TryGetValue(GroupsinCombat[i], out sp);
                    ushort death = 0;

                    foreach (InstanceSpawn IS in sp)
                    {
                        if (IS.IsDead)
                        {
                            death++;
                        }
                    }
                    if (death == sp.Count)
                    {
                        Respawns.Add(new Respawn(TCPManager.GetTimeStampMS() + (Info.TrashRespawnTimer * 1000), GroupsinCombat[i]));
                        GroupsinCombat.Remove(GroupsinCombat[i]);
                        i--;
                    }
                }
            }
        }
        private void StartChannel()
        {
            if (_channelInfo.CastTime == 0)
            {
                throw new InvalidOperationException("A channel's cast time must never be zero.");
            }
            _channelStartTime = TCPManager.GetTimeStampMS();
            _nextTickTime     = _channelStartTime + 1000;
            InvokeChannelBuff();
            _host.AbtInterface.SetCooldown(_baseEntry, _channelInfo.Cooldown * 1000);
            if (_playerHost != null && _channelInfo.SpecialCost > 5)
            {
                _playerHost.CrrInterface.ConsumeResource((byte)_channelInfo.SpecialCost, false);
            }
            else if (_channelInfo.SpecialCost < 0)
            {
                Player playerCaster = _host as Player;

                if (playerCaster != null)
                {
                    playerCaster.ResetMorale();

                    PacketOut Out = new PacketOut((byte)Opcodes.F_SET_ABILITY_TIMER, 12);
                    Out.WriteHexStringBytes("000002000000EA6000000000");
                    playerCaster.SendPacket(Out);
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Drops a currently carried weapon to the ground.
        /// </summary>
        /// <param name="player"></param>
        public void Drop(Player player)
        {
            lock (Players)
            {
                for (byte i = 0; i < Players.Count; i++)
                {
                    if (i == 0)
                    {
                        Players.RemoveAt(i);
                    }
                    player.CurrentSiege = null;
                }
            }

            player.SendClientMessage($"No longer carrying the {_Owner.Name}.");

            player.Speed = 100;
            player.UpdateSpeed();

            _leader = null;

            _weapon.MvtInterface.StopMove();

            _deathTime = TCPManager.GetTimeStampMS() + 300 * 1000;

            player.OSInterface.RemoveEffect(0xB);

            IsDeployed = true;

            _weapon.IsActive = true;
        }
Beispiel #11
0
        public override void Update(long tick)
        {
            if (BuffState != (byte)EBuffState.Running)
            {
                return;
            }

            long curTime = TCPManager.GetTimeStampMS();

            if (EndTime > 0 && curTime >= EndTime)
            {
                BuffEnded(false, false);
            }
            else
            {
                if (NextTickTime > 0 && curTime >= NextTickTime)
                {
                    NextTickTime += _buffInfo.Interval;

                    foreach (BuffCommandInfo command in _buffInfo.CommandInfo)
                    {
                        if ((command.InvokeOn & (byte)EBuffState.Running) > 0)
                        {
                            BuffEffectInvoker.InvokeCommand(this, command, Target);
                        }
                    }
                }

                if (_nextAuraPropagationTime <= tick)
                {
                    _nextAuraPropagationTime = tick + _propInterval;
                    SpreadAura();
                }
            }
        }
Beispiel #12
0
        // TRANQ
        public override bool ConsumeResource(byte amount, bool blockEvent)
        {
            _lastResourceTime = TCPManager.GetTimeStampMS();
            if (_careerResource == _healMax)
            {
                return(true); // AM / Shaman resource is non-blocking
            }
            _lastResource = _careerResource;


            //consume one
            if (_careerResource <= _damageMin)
            {
                _careerResource = _healMin;
            }
            else if (_careerResource <= _damageMax)
            {
                --_careerResource;
            }
            else
            {
                ++_careerResource;
            }

            /*
             * //consume all
             * if (_careerResource <= _damageMax)
             *  _careerResource = _healMin;
             * else _careerResource++;
             *
             */
            SendResource();
            return(true);
        }
Beispiel #13
0
        public virtual bool StartCombat(Unit fighter)
        {
            if (_unit.IsDead)
            {
                return(false);
            }

            // We try to buff NPC here
            BuffAtCombatStart();

            CombatStart = TCPManager.GetTimeStampMS();

            GetAggro(fighter.Oid).DamageReceived += 100;

            AI.Debugger?.SendClientMessage("[MR]: Started combat with " + fighter.Name + ".");

            Combat.SetTarget(fighter, TargetTypes.TARGETTYPES_TARGET_ENEMY);

            //if (fighter != null && _unit.IsKeepLord)
            //_unit.Say("Die " + fighter.Name + "!");

            Chase(fighter);

            return(true);
        }
        public void Resend()
        {
            if (!IsEnabled)
            {
                return;
            }

            PacketOut Out = new PacketOut((byte)Opcodes.F_INIT_EFFECTS, 30);

            Out.WriteByte(1); // effect count
            Out.WriteByte(1); // update operation
            Out.WriteUInt16(0);
            Out.WriteUInt16(Target.Oid);
            Out.WriteUInt16(BuffId);
            Out.WriteUInt16R(_buffInfo.Entry);
            Out.WriteZigZag(EndTime != 0 ? (int)((EndTime - TCPManager.GetTimeStampMS()) / 1000) : 0);
            Out.WriteUInt16R(Caster.Oid);

            Out.WriteByte((byte)BuffLines.Count);
            foreach (Tuple <byte, int> lineInfo in BuffLines)
            {
                Out.WriteByte(lineInfo.Item1);
                Out.WriteZigZag(lineInfo.Item2);
            }

            Out.WriteByte(0);

            DispatchBuffPacket(Out);
        }
        public virtual void Initialize(Unit caster, Unit target, ushort buffId, byte buffLevel, byte stackLevel, BuffInfo myBuffInfo, BuffInterface parentInterface)
        {
            Caster         = caster;
            Target         = target;
            _buffInfo      = myBuffInfo;
            StackLevel     = stackLevel;
            BuffLevel      = buffLevel;
            BuffId         = buffId;
            _buffInterface = parentInterface;

            uint leadMs = 0;

            // Fixed lead-in (Oil channel)
            if (_buffInfo.LeadInDelay < 0)
            {
                leadMs = (uint)-_buffInfo.LeadInDelay;
            }
            // Variable lead-in with range (Rapid Fire channel)
            else if (_buffInfo.LeadInDelay > 0)
            {
                leadMs = (uint)(_buffInfo.LeadInDelay * Caster.GetDistanceTo(Target) * 0.01f);
            }

            NextTickTime = TCPManager.GetTimeStampMS() + _buffInfo.Interval + leadMs;

            if (Duration > 0)
            {
                DurationMs = (uint)(_buffInfo.Duration * 1000 + leadMs);
                EndTime    = TCPManager.GetTimeStampMS() + DurationMs;
            }
        }
        public virtual void WalkTo(IPoint3D target, int speed)
        {
            if (speed <= 0)
            {
                return;
            }

            TargetPosition.X = target.X;
            TargetPosition.Y = target.Y;
            TargetPosition.Z = target.Z;

            if (Obj.IsWithinRadius(TargetPosition, CONST_WALKTOTOLERANCE))
            {
                Obj.EvtInterface.Notify("ArriveAtTarget", Obj, null);
                return;
            }

            CancelWalkTo();

            TurnTo(Obj.GetHeading(TargetPosition), false);

            MovementStart   = TCPManager.GetTimeStampMS();
            CurrentSpeed    = speed;
            Obj.IsMoving    = true;
            StartPosition.X = Obj.X;
            StartPosition.Y = Obj.Y;
            StartPosition.Z = Obj.Z;

            UpdateTickSpeed();
            Obj.EvtInterface.Notify("WalkTo", Obj, null);
            StartArriveAtTargetAction(GetMsTimeToArriveAt(TargetPosition, speed));
        }
        public override void InvokeDamageEvent(byte eventId, AbilityDamageInfo damageInfo, Unit eventInstigator)
        {
            if (BuffState != (byte)EBuffState.Running)
            {
                return;
            }

            if (Interlocked.CompareExchange(ref BuffTimerLock, 1, 0) != 0)
            {
                return;
            }

            if (_nextResTime > TCPManager.GetTimeStampMS())
            {
                Interlocked.Exchange(ref BuffTimerLock, 0);
                return;
            }

            _nextResTime = TCPManager.GetTimeStampMS() + 1000;
            Interlocked.Exchange(ref BuffTimerLock, 0);

            if (Caster.Region == Target.Region && Caster.Get2DDistanceToObject(Target) <= 300)
            {
                _masterInterface?.Notify_DarkProtectorHit();
            }
        }
        public virtual bool AddResourceOverride(byte amount, bool blockEvent, bool noTimer)
        {
            _lastResourceTime = TCPManager.GetTimeStampMS();

            if (!blockEvent)
            {
                myPlayer.BuffInterface.NotifyResourceEvent((byte)BuffCombatEvents.ResourceGained, _careerResource, ref amount);
            }

            if (_careerResource == _maxResource)
            {
                return(false);
            }
            _lastResource   = _careerResource;
            _careerResource = (byte)Math.Min(_maxResource, _careerResource + amount);

            SendResource();

            if (!blockEvent)
            {
                myPlayer.BuffInterface.NotifyResourceEvent((byte)BuffCombatEvents.ResourceSet, _lastResource, ref _careerResource);
            }

            return(true);
        }
 public void Update(long tick)
 {
     if (TCPManager.GetTimeStampMS() >= _channelStartTime + _channelInfo.CastTime)
     {
         SendChannelEnd();
         _parent.NotifyChannelEnded();
         _channelInfo = null;
         _channelBuff = null;
     }
     else if (TCPManager.GetTimeStampMS() >= _nextTickTime)
     {
         if (_channelInfo.ApCost > 0 && !_host.ConsumeActionPoints(_channelInfo.ApCost))
         {
             _parent.CancelCast((byte)GameData.AbilityResult.ABILITYRESULT_AP);
         }
         else if (_playerHost != null && _channelInfo.SpecialCost > 3 && !_playerHost.CrrInterface.ConsumeResource((byte)_channelInfo.SpecialCost, true))
         {
             _parent.CancelCast(1);
         }
         else if (_target != _host && !_host.IsInCastRange(_target, Math.Max((uint)25, _channelInfo.Range)))
         {
             _parent.CancelCast((byte)GameData.AbilityResult.ABILITYRESULT_OUTOFRANGE);
         }
         else if (_checkVisibility && !_host.LOSHit(_target))
         {
             _parent.CancelCast((byte)GameData.AbilityResult.ABILITYRESULT_NOT_VISIBLE);
         }
         else
         {
             _nextTickTime += 1000;
         }
     }
 }
Beispiel #20
0
        public override bool AddResourceOverride(byte amount, bool blockEvent, bool noTimer)
        {
            Now = TCPManager.GetTimeStampMS();
            if (noTimer == false)
            {
                if (Now < _nextOTimer)
                {
                    return(true);
                }

                _nextOTimer = Now + 2;
            }

            _lastResourceTime = TCPManager.GetTimeStampMS();

            if (!blockEvent)
            {
                myPlayer.BuffInterface.NotifyResourceEvent((byte)BuffCombatEvents.ResourceGained, _careerResource, ref amount);
            }

            lock (_resourceLock)
            {
                _lastResource   = _careerResource;
                _careerResource = (byte)Math.Min(_maxResource, _careerResource + amount);
            }

            if (!blockEvent)
            {
                myPlayer.BuffInterface.NotifyResourceEvent((byte)BuffCombatEvents.ResourceSet, _lastResource, ref _careerResource);
            }

            return(true);
        }
Beispiel #21
0
        public override void Stop()
        {
            Stopping = true;

            lock (_queuedInfo)
                _queuedInfo.Clear();

            _buffRWLock.EnterReadLock();

            try
            {
                if (_buffs.Count > 0)
                {
                    foreach (NewBuff buff in _buffs)
                    {
                        buff.BuffHasExpired = true;


#pragma warning disable CS1030 // Директива #warning
#warning Danger of lock recursion exception.
                        buff.RemoveBuff(true);
#pragma warning restore CS1030 // Директива #warning
                    }
                }
            }

            finally { _buffRWLock.ExitReadLock(); }

            Update(TCPManager.GetTimeStampMS());

            base.Stop();
        }
Beispiel #22
0
 public Siege(Creature_spawn spawn, Player owner, SiegeType type, BattleFrontKeep keep = null) : base(spawn)
 {
     _type                    = type;
     SiegeInterface           = AddInterface <SiegeInterface>();
     SiegeInterface.Creator   = owner;
     AssignedKeep             = keep; // Only need to assign keep for oil
     SiegeInterface.DeathTime = TCPManager.GetTimeStampMS() + SiegeLifeSpan;
 }
Beispiel #23
0
        public void Update()
        {
            while (_running)
            {
                long start = TCPManager.GetTimeStampMS();

                if (start - _lastRegionUpdate > 500)
                {
                    Log.Error("RegionMgr", "[" + RegionId + "] - Region inter-update period too long - took " + (start - _lastRegionUpdate) + " ms.");
                }

                else if (start - _lastRegionUpdate > 250)
                {
                    Log.Notice("RegionMgr", "[" + RegionId + "] - Region inter-update period too long - took " + (start - _lastRegionUpdate) + " ms.");
                }

                try
                {
                    WorldMgr.UpdateScripts(start);

                    AddNewObjects();

                    RemoveOldObjects();

                    UpdateActors(start);

                    //Bttlfront?.Update(start);
                    ndbf?.Update(start);
                }

                catch (Exception e)
                {
                    Log.Error("Error", e.ToString());
                }

                long elapsed = TCPManager.GetTimeStampMS() - start;

                _lastRegionUpdate = TCPManager.GetTimeStampMS();

                if (elapsed < RegionUpdateInterval)
                {
                    Thread.Sleep((int)(RegionUpdateInterval - elapsed));
                }
                else
                {
                    if (elapsed > 500)
                    {
                        Log.Error("RegionMgr", "[" + RegionId + "] - Region update took too long. " + GetObjects() + " objects. " + elapsed + "ms.");
                    }
                    else if (elapsed > 250)
                    {
                        Log.Notice("RegionMgr", "[" + RegionId + "] - Region update took too long. " + GetObjects() + " objects. " + elapsed + "ms.");
                    }
                }
            }

            DisposeActors();
        }
        public override void OnTakeHeal(Unit caster)
        {
            _Owner.EvtInterface.Notify(EventName.OnReceiveHeal, caster, null);

            if (caster != _Owner && IsInCombat)
            {
                LastInteractionTime = TCPManager.GetTimeStampMS();
            }
        }
        public Siege(Creature_spawn spawn, Player owner, Keep k, SiegeType type) : base(spawn)
        {
            Keep = k;

            _type                    = type;
            SiegeInterface           = AddInterface <SiegeInterface>();
            SiegeInterface.Creator   = owner;
            SiegeInterface.DeathTime = TCPManager.GetTimeStampMS() + 300 * 1000;
        }
Beispiel #26
0
 public void DisableMovements(long MSTime)
 {
     NextAllowedMovements = TCPManager.GetTimeStampMS() + MSTime;
     Log.Info("DisableMovements", "NextAllowedMovements: " + NextAllowedMovements + ",Time=" + MSTime);
     if (IsPlayer())
     {
         GetPlayer().SendSpeed(0);
     }
 }
Beispiel #27
0
        public void SetCooldown(ushort Slot, long Tick)
        {
            Item Itm = GetItemInSlot(Slot);

            if (Itm != null)
            {
                Itm.Cooldown = TCPManager.GetTimeStampMS() + Tick;
            }
        }
Beispiel #28
0
        public void ResetPvpTime()
        {
            EnablePvp();

            if (IsPvp)
            {
                NextAllowedDisable = TCPManager.GetTimeStampMS() + 60000 * 10;
            }
        }
        public override void TryAttack()
        {
            if (!_petOwner.CanAutoAttack || CurrentTarget.IsStaggered)
            {
                return;
            }

            long tick = TCPManager.GetTimeStampMS();

            if (NextAttackTime >= tick)
            {
                return;
            }

            if (_petOwner.IsStationary)
            {
                _petOwner.MvtInterface.TurnTo(CurrentTarget.WorldPosition);
            }

            if (_petOwner.Spawn.Proto.Ranged > 0)
            {
                if (_petOwner.AbtInterface.IsCasting() || !_petOwner.IsInCastRange(CurrentTarget, (uint)(_petOwner.Spawn.Proto.Ranged * _petOwner.StsInterface.GetStatPercentageModifier(Stats.Range))))
                {
                    if (_petOwner.AiInterface.Debugger != null)
                    {
                        _petOwner.AiInterface.Debugger.SendClientMessage("[MR] Unable to auto attack target, casting ability or too far away.");
                    }
                    NextAttackTime = tick + 200;
                    return;
                }
                if (_petOwner.LOSHit(CurrentTarget))
                {
                    if (_petOwner.Owner.Info.CareerLine == (byte)CareerLine.CAREERLINE_MAGUS)
                    {
                        _petOwner.Strike(CurrentTarget, EquipSlot.NONE);
                    }
                    else
                    {
                        _petOwner.Strike(CurrentTarget, EquipSlot.RANGED_WEAPON);
                    }
                }
                else if (_petOwner.AiInterface.Debugger != null)
                {
                    _petOwner.AiInterface.Debugger.SendClientMessage("[MR] Unable to auto attack target due to lack of LOS.");
                }
                NextAttackTime = tick + 2000;
            }
            else
            {
                if (!_petOwner.IsInCastRange(CurrentTarget, 5))
                {
                    return;
                }
                _petOwner.Strike(CurrentTarget);
                NextAttackTime = tick + 2000;
            }
        }
Beispiel #30
0
        public void OnDealHeal(Unit Target, UInt32 DamageCount)
        {
            ResetFightingState(TCPManager.GetTimeStampMS());
            _Owner.EvtInterface.Notify(EventName.ON_DEAL_HEAL, Target, null);

            if (_Owner.IsPlayer() && Target.IsPlayer() && Target.GetPlayer().CbtInterface.IsPvp)
            {
                ResetPvpTime();
            }
        }