Beispiel #1
0
        /// <summary>
        /// Returns an instance of ErinnTime that's set to the next time the
        /// given hour and minute is.
        /// </summary>
        /// <example>
        /// If it's 00:00:00 in real-time (00:00 in Erinn-time), then
        /// GetNextTime(12, 00) would return Erinn-time 12:00, with a
        /// DateTime of 00:18:00.
        /// </example>
        /// <param name="hour"></param>
        /// <param name="minutes"></param>
        /// <returns></returns>
        public static ErinnTime GetNextTime(DateTime now, int hour, int minute)
        {
            if (hour < 0 || hour > 23)
            {
                throw new ArgumentException("Invalid hour.");
            }
            if (minute < 0 || minute > 59)
            {
                throw new ArgumentException("Invalid minute.");
            }

            var nowErinn = new ErinnTime(now);

            var hours   = hour - nowErinn.Hour;
            var minutes = minute - nowErinn.Minute;

            if (hours <= 0)
            {
                hours += 24;
            }

            if (minutes < 0)
            {
                minutes = 60 + minutes;
                hours  -= 1;
            }

            var thenDateTime = now.AddTicks(hours * TicksPerHour).AddTicks(minutes * TicksPerMinute);

            return(new ErinnTime(thenDateTime));
        }
Beispiel #2
0
		/// <summary>
		/// Called every 5 minutes to synchronize guild information.
		/// </summary>
		/// <param name="now"></param>
		private void OnMabiTick(ErinnTime now)
		{
			// Synchronizing the guilds can take a few milliseconds if there
			// are many in the db. Run it in a thread so we don't block
			// the world thread.
			// Should this be the default for all time events...?
			Task.Factory.StartNew(SynchronizeGuilds);
		}
Beispiel #3
0
		public void ErinnTimeToString()
		{
			var time1 = new ErinnTime(DateTime.Parse("2015-01-01 00:00"));
			
			Assert.Equal("550-4-01 00:00", time1.ToString());
			Assert.Equal("0550-04-01 0:0", time1.ToString("yyyy-MM-dd H:m"));
			Assert.Equal("00:00 AM", time1.ToString("HH:mm tt"));
			
			var time2 = new ErinnTime(DateTime.Parse("2015-01-01 23:59"));

			Assert.Equal("23:20 PM", time2.ToString("HH:mm tt"));
		}
Beispiel #4
0
		/// <summary>
		/// Called once a minute, used for custom weather and the change weather event.
		/// </summary>
		/// <param name="time"></param>
		private void OnMinutesTimeTick(ErinnTime time)
		{
			if (time.DateTime.Minute % 20 == 0)
			{
				var ev = this.WeatherChange;
				if (ev != null)
				{
					foreach (var provider in _providers)
						ev(provider.Key, provider.Value.GetWeather(time.DateTime));
				}
			}

			// TODO: Custom weather?
		}
Beispiel #5
0
        public void BeginOfTimeCap()
        {
            var time1 = new ErinnTime(ErinnTime.BeginOfTime);
            Assert.Equal("1-1-01 00:00", time1.ToString());

            var time2 = new ErinnTime(DateTime.MinValue);
            Assert.Equal("1-1-01 00:00", time2.ToString());

            var time3 = new ErinnTime(new DateTime(2000, 1, 1));
            Assert.Equal("1-1-01 00:00", time3.ToString());

            var time4 = new ErinnTime(DateTime.MaxValue);
            Assert.Equal("417187-6-40 23:59", time4.ToString());
        }
Beispiel #6
0
		public void ErinnTimeCalculation()
		{
			var time1 = new ErinnTime(DateTime.Parse("2015-01-01 00:00"));
			Assert.Equal(550, time1.Year);
			Assert.Equal(4, time1.Month);
			Assert.Equal(1, time1.Day);
			Assert.Equal(0, time1.Hour);
			Assert.Equal(0, time1.Minute);

			var time2 = new ErinnTime(DateTime.Parse("2015-01-01 23:59"));
			Assert.Equal(550, time2.Year);
			Assert.Equal(4, time2.Month);
			Assert.Equal(40, time2.Day);
			Assert.Equal(23, time2.Hour);
			Assert.Equal(20, time2.Minute);

			var time3 = new ErinnTime(ErinnTime.BeginOfTime);
			Assert.Equal(1, time3.Year);
			Assert.Equal(2, time3.Month);
			Assert.Equal(1, time3.Day);
			Assert.Equal(0, time3.Hour);
			Assert.Equal(0, time3.Minute);
		}
Beispiel #7
0
		/// <summary>
		/// Raised once ever RL hour.
		/// </summary>
		/// <param name="now"></param>
		private void OnHoursTimeTick(ErinnTime now)
		{
			// Update on midnight, for Erinn month checks
			if (now.DateTime.Hour == 0)
				this.UpdateStatBonuses();
		}
Beispiel #8
0
		/// <summary>
		/// Applies regens to creature.
		/// </summary>
		/// <remarks>
		/// (Should be) called once a second.
		/// - Hunger doesn't go beyond 50% of max stamina.
		/// - Stamina regens at 20% efficiency from StaminaHunger onwards.
		/// </remarks>
		public void OnSecondsTimeTick(ErinnTime time)
		{
			if (this.Creature.Region == Region.Limbo || this.Creature.IsDead)
				return;

			lock (_regens)
			{
				var toRemove = new List<int>();

				foreach (var regen in _regens.Values)
				{
					if (regen.TimeLeft == 0)
					{
						toRemove.Add(regen.Id);
						continue;
					}

					switch (regen.Stat)
					{
						// TODO: Triple mana automatically at night?

						case Stat.Life: this.Creature.Life += regen.Change; break;
						case Stat.Mana: this.Creature.Mana += regen.Change; break;
						case Stat.Stamina:
							// Only positve regens are affected by the hunger multiplicator.
							this.Creature.Stamina += regen.Change * (regen.Change > 0 ? this.Creature.StaminaRegenMultiplicator : 1);
							break;
						case Stat.Hunger:
							// Regen can't lower hunger below a certain amount.
							this.Creature.Hunger += regen.Change;
							if (this.Creature.Hunger > this.Creature.StaminaMax / 2)
								this.Creature.Hunger = this.Creature.StaminaMax / 2;
							break;
						case Stat.LifeInjured: this.Creature.Injuries -= regen.Change; break;
					}
				}

				foreach (var id in toRemove)
					this.Remove(id);
			}
		}
		/// <summary>
		/// Removes overdue conditions.
		/// </summary>
		/// <param name="time"></param>
		public void OnSecondsTimeTick(ErinnTime time)
		{
			lock (_durations)
			{
				var deactivate = _durations.Where(a => time.DateTime > a.Value).Select(a => a.Key).ToArray();

				foreach (var conditionId in deactivate)
				{
					this.Deactivate(conditionId);
					_durations.Remove(conditionId);
				}
			}
		}
Beispiel #10
0
        /// <summary>
        /// Raised every 5 minutes, removes empty dungeons.
        /// </summary>
        /// <remarks>
        /// TODO: Is removing on MabiTick what we want? How long do dungeons
        ///   stay active before they're removed? This could remove a dungeon
        ///   the minute, even the second, the last player leaves it.
        /// </remarks>
        /// <param name="time"></param>
        private void OnMabiTick(ErinnTime time)
        {
            lock (_createAndCleanUpLock)
            {
                List<long> remove;
                lock (_syncLock)
                    remove = _dungeons.Values.Where(a => a.CountPlayers() == 0).Select(b => b.InstanceId).ToList();

                foreach (var instanceId in remove)
                    this.Remove(instanceId);
            }
        }
Beispiel #11
0
		/// <summary>
		/// Returns true if the player can do a PTJ of type, because he hasn't
		/// done one of the same type today.
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		public bool CanDoPtj(PtjType type, int remaining = 99)
		{
			// Always allow devCATs
			//if (this.Title == TitleId.devCAT)
			//	return true;

			// Check remaining
			if (remaining <= 0)
				return false;

			// Check if PTJ has already been done this Erinn day
			var ptj = this.Player.Quests.GetPtjTrackRecord(type);
			var change = new ErinnTime(ptj.LastChange);
			var now = ErinnTime.Now;

			return (now.Day != change.Day || now.Month != change.Month || now.Year != change.Year);
		}
Beispiel #12
0
		/// <summary>
		/// Called every 9 minutes, increases play points.
		/// </summary>
		/// <param name="now"></param>
		private void OnPlayTimeTick(ErinnTime now)
		{
			this.PlayPoints++;
		}
Beispiel #13
0
		/// <summary>
		/// 5 min tick, global var saving.
		/// </summary>
		/// <param name="time"></param>
		public void OnMabiTick(ErinnTime time)
		{
			try
			{
				ChannelServer.Instance.Database.SaveVars("Aura System", 0, this.GlobalVars.Perm);
				Log.Info("Saved global script variables.");
			}
			catch (Exception ex)
			{
				Log.Exception(ex, "Failed to save global script variables.");
			}
		}
Beispiel #14
0
        /// <summary>
        /// Called once a second, updates stat mods with timeout.
        /// </summary>
        /// <param name="time"></param>
        public void OnSecondsTimeTick(ErinnTime time)
        {
            lock (_mods)
            {
                foreach (var mod in _mods)
                {
                    var stat = mod.Key;
                    var list = mod.Value;
                    var creature = _creature;

                    var count = mod.Value.RemoveAll(a => a.TimeoutReached);
                    if (count != 0)
                    {
                        this.UpdateCache(stat);

                        Send.StatUpdate(creature, StatUpdateType.Private, stat);
                        if (stat >= Stat.Life && stat <= Stat.LifeMaxMod)
                            Send.StatUpdate(creature, StatUpdateType.Public, Stat.Life, Stat.LifeInjured, Stat.LifeMaxMod, Stat.LifeMax);
                    }
                }
            }
        }
Beispiel #15
0
		/// <summary>
		/// Returns an instance of ErinnTime that's set to the next time the
		/// given hour and minute is.
		/// </summary>
		/// <example>
		/// If it's 00:00:00 in real-time (00:00 in Erinn-time), then
		/// GetNextTime(12, 00) would return Erinn-time 12:00, with a
		/// DateTime of 00:18:00.
		/// </example>
		/// <param name="hour"></param>
		/// <param name="minutes"></param>
		/// <returns></returns>
		public static ErinnTime GetNextTime(DateTime now, int hour, int minute)
		{
			if (hour < 0 || hour > 23)
				throw new ArgumentException("Invalid hour.");
			if (minute < 0 || minute > 59)
				throw new ArgumentException("Invalid minute.");

			var nowErinn = new ErinnTime(now);

			var hours = hour - nowErinn.Hour;
			var minutes = minute - nowErinn.Minute;

			if (hours <= 0)
			{
				hours += 24;
			}

			if (minutes < 0)
			{
				minutes = 60 + minutes;
				hours -= 1;
			}

			var thenDateTime = now.AddTicks(hours * TicksPerHour).AddTicks(minutes * TicksPerMinute);

			return new ErinnTime(thenDateTime);
		}
Beispiel #16
0
		/// <summary>
		/// Adds additional mana regen at night.
		/// </summary>
		/// <param name="time"></param>
		public void OnErinnDaytimeTick(ErinnTime time)
		{
			if (time.IsNight)
			{
				this.Add("NightMana", Stat.Mana, 0.1f, this.Creature.ManaMax);
			}
			else
			{
				this.Remove("NightMana");
			}
		}
Beispiel #17
0
		/// <summary>
		/// Handles regularly occuring events and raises time events.
		/// </summary>
		/// <remarks>
		/// On the first call all time events are raised,
		/// because lastHeartbeat is 0, and the events depend on the time
		/// since the last heartbeat. This also ensures that they aren't
		/// called multiple times.
		/// </remarks>
		private void Heartbeat(object _)
		{
			var now = new ErinnTime(DateTime.Now);
			var diff = (now.DateTime - _lastHeartbeat).TotalMilliseconds;

			if (diff != HeartbeatTime && Math.Abs(HeartbeatTime - diff) > HeartbeatTime && diff < 100000000)
			{
				Log.Debug("OMG, the server has an irregular heartbeat! ({0})", diff.ToInvariant());
			}

			// Seconds event
			if ((_secondsTime += diff) >= Second)
			{
				_secondsTime = 0;
				ChannelServer.Instance.Events.OnSecondsTimeTick(now);
			}

			// Minutes event
			if ((_minutesTime += diff) >= Minute)
			{
				_minutesTime = (now.DateTime.Second * Second + now.DateTime.Millisecond);
				ChannelServer.Instance.Events.OnMinutesTimeTick(now);

				// Mabi tick event
				if (++_mabiTickCount >= 5)
				{
					ChannelServer.Instance.Events.OnMabiTick(now);
					_mabiTickCount = 0;
				}
			}

			// Hours event
			if ((_hoursTime += diff) >= Hour)
			{
				_hoursTime = (now.DateTime.Minute * Minute + now.DateTime.Second * Second + now.DateTime.Millisecond);
				ChannelServer.Instance.Events.OnHoursTimeTick(now);
			}

			// Erinn time event
			if ((_erinnTime += diff) >= ErinnMinute)
			{
				_erinnTime = 0;
				ChannelServer.Instance.Events.OnErinnTimeTick(now);

				// TODO: Dawn/Dusk/Midnight wouldn't be called if the server had a 500+ ms hickup.

				// Erinn daytime event
				if (now.IsDawn || now.IsDusk)
				{
					ChannelServer.Instance.Events.OnErinnDaytimeTick(now);
					this.OnErinnDaytimeTick(now);
				}

				// Erinn midnight event
				if (now.IsMidnight)
					ChannelServer.Instance.Events.OnErinnMidnightTick(now);
			}

			this.UpdateEntities();

			_lastHeartbeat = now.DateTime;
		}
Beispiel #18
0
		/// <summary>
		/// Called once per second, running updates on different
		/// creature components.
		/// </summary>
		/// <param name="obj"></param>
		private void OnSecondsTimeTick(ErinnTime time)
		{
			// TODO: General creature components in a list, with Update interface?
			this.Regens.OnSecondsTimeTick(time);
			this.StatMods.OnSecondsTimeTick(time);
			this.Conditions.OnSecondsTimeTick(time);
			this.Skills.OnSecondsTimeTick(time);

			this.PlayTime++;
		}
Beispiel #19
0
		/// <summary>
		/// Broadcasts Eweca notice, called at 6:00 and 18:00.
		/// </summary>
		/// <param name="now"></param>
		private void OnErinnDaytimeTick(ErinnTime now)
		{
			var notice = now.IsNight
				? Localization.Get("Eweca is rising.\nMana is starting to fill the air all around.")
				: Localization.Get("Eweca has disappeared.\nThe surrounding Mana is starting to fade away.");
			Send.Notice(NoticeType.MiddleTop, notice);
		}
Beispiel #20
0
		/// <summary>
		/// Called at midnight (Erinn time).
		/// </summary>
		/// <param name="time"></param>
		protected virtual void OnErinnMidnightTick(ErinnTime time)
		{
			this.RandomizeItemColors();
		}
Beispiel #21
0
		/// <summary>
		/// Checks for skills to auto cancel.
		/// </summary>
		/// <param name="time"></param>
		public void OnSecondsTimeTick(ErinnTime time)
		{
			if (_autoCancel == SkillId.None)
				return;

			if (!this.IsActive(_autoCancel))
			{
				_autoCancel = SkillId.None;
				return;
			}

			if (time.DateTime < _autoCancelTime)
				return;

			_autoCancel = SkillId.None;
			this.CancelActiveSkill();
		}
Beispiel #22
0
        /// <summary>
        /// Applies regens to creature.
        /// </summary>
        /// <remarks>
        /// (Should be) called once a second.
        /// - Hunger doesn't go beyond 50% of max stamina.
        /// - Stamina regens at 20% efficiency from StaminaHunger onwards.
        /// </remarks>
        public void OnSecondsTimeTick(ErinnTime time)
        {
            if (this.Creature.Region == Region.Limbo || this.Creature.IsDead)
                return;

            // Recover from knock back/down after stun ended
            if (this.Creature.WasKnockedBack && !this.Creature.IsStunned)
            {
                Send.RiseFromTheDead(this.Creature);
                this.Creature.WasKnockedBack = false;
            }

            lock (_regens)
            {
                var toRemove = new List<int>();

                foreach (var regen in _regens.Values)
                {
                    if (regen.TimeLeft == 0)
                    {
                        toRemove.Add(regen.Id);
                        continue;
                    }

                    switch (regen.Stat)
                    {
                        case Stat.Life: this.Creature.Life += regen.Change; break;
                        case Stat.Mana: this.Creature.Mana += regen.Change; break;
                        case Stat.Stamina:
                            // Only positve regens are affected by the hunger multiplicator.
                            this.Creature.Stamina += regen.Change * (regen.Change > 0 ? this.Creature.StaminaRegenMultiplicator : 1);
                            break;
                        case Stat.Hunger:
                            // Regen can't lower hunger below a certain amount.
                            this.Creature.Hunger += regen.Change;
                            if (this.Creature.Hunger > this.Creature.StaminaMax / 2)
                                this.Creature.Hunger = this.Creature.StaminaMax / 2;
                            break;
                        case Stat.LifeInjured: this.Creature.Injuries -= regen.Change; break;
                    }
                }

                foreach (var id in toRemove)
                    this.Remove(id);
            }

            // Add additional mana regen at night
            if (_night != time.IsNight)
            {
                if (time.IsNight)
                    this.Add("NightMana", Stat.Mana, 0.1f, this.Creature.ManaMax);
                else
                    this.Remove("NightMana");

                _night = time.IsNight;
            }

            this.UpdateToxicity();
        }
Beispiel #23
0
        public void ErinnTimeToString()
        {
            var time1 = new ErinnTime(DateTime.Parse("2015-01-01 00:00"));

            Assert.Equal("550-5-01 00:00", time1.ToString());
            Assert.Equal("0550-05-01 0:0", time1.ToString("yyyy-MM-dd H:m"));
            Assert.Equal("00:00 AM", time1.ToString("HH:mm tt"));

            Assert.Equal("01 Lughnasadh 550", time1.ToString("dd MMMM yyy"));
            ErinnTime.SetMonthNames("0", "1", "2", "3", "Foobar", "5", "6");
            Assert.Equal("01 Foobar 550", time1.ToString("dd MMMM yyy"));

            var time2 = new ErinnTime(DateTime.Parse("2015-01-01 23:59"));

            Assert.Equal("23:20 PM", time2.ToString("HH:mm tt"));

            var dt3 = DateTime.Parse("2016-06-26 00:00");
            for (int year = 0; year < 2; ++year)
            {
                for (int month = 0; month < 7; ++month)
                {
                    for (int day = 0; day < 40; ++day)
                    {
                        for (int hour = 0; hour < 24; ++hour)
                        {
                            for (int minute = 0; minute < 60; ++minute)
                            {
                                var time = new ErinnTime(dt3.AddMilliseconds((year * (7 * 40 * 24 * 60 * 1500)) + (month * (40 * 24 * 60 * 1500)) + (day * (24 * 60 * 1500)) + (hour * (60 * 1500)) + (minute * 1500)));
                                Assert.Equal(string.Format("{0}-{1}-{2:00} {3:00}:{4:00}", 628 + year, month + 1, day + 1, hour, minute), time.ToString());
                            }
                        }
                    }
                }
            }
        }
Beispiel #24
0
		/// <summary>
		/// Raised once every minute.
		/// </summary>
		/// <param name="time"></param>
		private void OnMinutesTimeTick(ErinnTime time)
		{
			if (this.Type == PartyType.Dungeon && this.IsOpen)
			{
				if ((_adTimer++) < 5)
					return;

				Send.PartyAdChat(this);
			}

			_adTimer = 0;
		}
Beispiel #25
0
        public void ErinnTimeCalculation()
        {
            var time1 = new ErinnTime(DateTime.Parse("2015-01-01 00:00"));
            Assert.Equal(550, time1.Year);
            Assert.Equal(5, time1.Month);
            Assert.Equal(1, time1.Day);
            Assert.Equal(0, time1.Hour);
            Assert.Equal(0, time1.Minute);

            var time2 = new ErinnTime(DateTime.Parse("2015-01-01 23:59"));
            Assert.Equal(550, time2.Year);
            Assert.Equal(5, time2.Month);
            Assert.Equal(40, time2.Day);
            Assert.Equal(23, time2.Hour);
            Assert.Equal(20, time2.Minute);

            var time3 = new ErinnTime(ErinnTime.BeginOfTime);
            Assert.Equal(1, time3.Year);
            Assert.Equal(1, time3.Month);
            Assert.Equal(1, time3.Day);
            Assert.Equal(0, time3.Hour);
            Assert.Equal(0, time3.Minute);

            var dt4 = DateTime.Parse("2016-06-26 00:00");
            for (int i = 0; i < 10; ++i)
            {
                var time = new ErinnTime(dt4.AddDays(i * 7));
                Assert.Equal(628 + i * 1, time.Year);
                Assert.Equal(1, time.Month);
                Assert.Equal(1, time.Day);
                Assert.Equal(0, time.Hour);
                Assert.Equal(0, time.Minute);
            }

            var dt5 = DateTime.Parse("2016-06-26 00:00");
            for (int i = 0; i < 7; ++i)
            {
                var time = new ErinnTime(dt5.AddDays(i));
                Assert.Equal(628, time.Year);
                Assert.Equal(i + 1, time.Month);
                Assert.Equal(1, time.Day);
                Assert.Equal(0, time.Hour);
                Assert.Equal(0, time.Minute);
            }

            var dt6 = DateTime.Parse("2016-06-26 00:00");
            for (int i = 0; i < 24; ++i)
            {
                var time = new ErinnTime(dt6.AddMilliseconds(i * (24 * 60 * 1500)));
                Assert.Equal(628, time.Year);
                Assert.Equal(1, time.Month);
                Assert.Equal(i + 1, time.Day);
                Assert.Equal(0, time.Hour);
                Assert.Equal(0, time.Minute);
            }

            var dt7 = DateTime.Parse("2016-06-26 00:00");
            for (int i = 0; i < 24; ++i)
            {
                for (int j = 0; j < 60; ++j)
                {
                    var time = new ErinnTime(dt6.AddMilliseconds((i * (60 * 1500)) + (j * 1500)));
                    Assert.Equal(628, time.Year);
                    Assert.Equal(1, time.Month);
                    Assert.Equal(1, time.Day);
                    Assert.Equal(i, time.Hour);
                    Assert.Equal(j, time.Minute);
                }
            }
        }
Beispiel #26
0
		/// <summary>
		/// Called every 5 minutes, checks changes through food.
		/// </summary>
		/// <param name="time"></param>
		public void OnMabiTick(ErinnTime time)
		{
			this.UpdateBody();
			this.EquipmentDecay();
		}
Beispiel #27
0
		/// <summary>
		/// 5 min tick, global var saving.
		/// </summary>
		/// <param name="time"></param>
		public void OnMabiTick(ErinnTime time)
		{
			ChannelServer.Instance.Database.SaveVars("Aura System", 0, this.GlobalVars.Perm);
			Log.Info("Saved global script variables.");
		}