From 0e8d7ab8944ec533bbd893c6ec8a0e0dd3615e19 Mon Sep 17 00:00:00 2001 From: astat Date: Thu, 19 May 2016 21:57:33 +1000 Subject: [PATCH] Added settings GUI + changed science cashout to a button --- KSPCasher.version | 4 +- KSPCasher/FrameworkExt/Extensions.cs | 19 + KSPCasher/FrameworkExt/KSPDateStructure.cs | 166 +++++ KSPCasher/FrameworkExt/KSPDateTime.cs | 687 +++++++++++++++++++++ KSPCasher/FrameworkExt/KSPTimeSpan.cs | 558 +++++++++++++++++ KSPCasher/KSPCasher.cs | 332 ++++++++-- KSPCasher/KSPCasher.csproj | 4 + KSPCasher/Properties/AssemblyInfo.cs | 8 +- 8 files changed, 1722 insertions(+), 56 deletions(-) create mode 100644 KSPCasher/FrameworkExt/Extensions.cs create mode 100644 KSPCasher/FrameworkExt/KSPDateStructure.cs create mode 100644 KSPCasher/FrameworkExt/KSPDateTime.cs create mode 100644 KSPCasher/FrameworkExt/KSPTimeSpan.cs diff --git a/KSPCasher.version b/KSPCasher.version index 60e5e27..fe08936 100644 --- a/KSPCasher.version +++ b/KSPCasher.version @@ -1,7 +1,7 @@ { "NAME":"KSPCasher", "URL":"https://raw.githubusercontent.com/a-stat/kspcasher/master/KSPCasher.version", - "DOWNLOAD":"https://github.com/a-stat/kspcasher/releases/download/0.1.0/KSPCasher_0.1.0.zip", + "DOWNLOAD":"https://github.com/a-stat/kspcasher/releases/download/0.2.0/KSPCasher_0.2.0.zip", "GITHUB": { "USERNAME":"a-stat", @@ -11,7 +11,7 @@ "VERSION": { "MAJOR":0, - "MINOR":1, + "MINOR":2, "PATCH":0, "BUILD":0 }, diff --git a/KSPCasher/FrameworkExt/Extensions.cs b/KSPCasher/FrameworkExt/Extensions.cs new file mode 100644 index 0000000..3b3907d --- /dev/null +++ b/KSPCasher/FrameworkExt/Extensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + + +namespace KSPPluginFramework +{ + public static class EnumExtensions + { + public static T Clamp(this T val, T min, T max) where T : IComparable + { + if (val.CompareTo(min) < 0) return min; + else if (val.CompareTo(max) > 0) return max; + else return val; + } + } +} \ No newline at end of file diff --git a/KSPCasher/FrameworkExt/KSPDateStructure.cs b/KSPCasher/FrameworkExt/KSPDateStructure.cs new file mode 100644 index 0000000..cac1303 --- /dev/null +++ b/KSPCasher/FrameworkExt/KSPDateStructure.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace KSPPluginFramework +{ + + /// + /// Static class to control the Calendar used by KSPDateTime and KSPTimeSpan + /// + public static class KSPDateStructure + { + //Define the Epoch + /// What Day does UT 0 represent + static public Int32 EpochDayOfYear { get; private set; } + /// What Year does UT 0 represent + static public Int32 EpochYear { get; private set; } + + //Define the Calendar + /// How many seconds (game UT) make up a minute + static public Int32 SecondsPerMinute { get; private set; } + /// How many minutes make up an hour + static public Int32 MinutesPerHour { get; private set; } + /// How many hours make up a day + static public Int32 HoursPerDay { get; private set; } + /// How many days make up a year + static public Int32 DaysPerYear { get; private set; } + + /// How many seconds (game UT) make up an hour + static public Int32 SecondsPerHour { get { return SecondsPerMinute * MinutesPerHour; } } + /// How many seconds (game UT) make up a day + static public Int32 SecondsPerDay { get { return SecondsPerHour * HoursPerDay; } } + /// How many seconds (game UT) make up a year - not relevant for Earth time + static public Int32 SecondsPerYear { get { return SecondsPerDay * DaysPerYear; } } + + /// What Earth date does UT 0 represent + static public DateTime CustomEpochEarth { get; private set; } + + /// What type of Calendar is being used - KSPStock, Earth, or custom + static public CalendarTypeEnum CalendarType { get; private set; } + + /// Sets the Date Structure to be stock KSP + static public void SetKSPStockCalendar() + { + CalendarType = CalendarTypeEnum.KSPStock; + + EpochYear = 1; + EpochDayOfYear = 1; + SecondsPerMinute = 60; + MinutesPerHour = 60; + + HoursPerDay = GameSettings.KERBIN_TIME ? 6 : 24; + DaysPerYear = GameSettings.KERBIN_TIME ? 426 : 365; + } + + /// Sets the Date Structure to be Earth based - Epoch of 1/1/1951 (RSS default) + static public void SetEarthCalendar() + { + SetEarthCalendar(1951, 1, 1); + } + /// Sets the Date Structure to be Earth based - With an epoch date supplied + /// year represented by UT0 + /// month represented by UT0 + /// day represented by UT0 + static public void SetEarthCalendar(Int32 epochyear, Int32 epochmonth, Int32 epochday) + { + CalendarType = CalendarTypeEnum.Earth; + + CustomEpochEarth = new DateTime(epochyear, epochmonth, epochday); + + EpochYear = epochyear; + EpochDayOfYear = CustomEpochEarth.DayOfYear; + SecondsPerMinute = 60; + MinutesPerHour = 60; + + HoursPerDay = 24; + DaysPerYear = 365; + + } + + /// Set Calendar type to be a custom type + static public void SetCustomCalendar() + { + SetKSPStockCalendar(); + CalendarType = CalendarTypeEnum.Custom; + } + + /// Set Calendar type be a custom type with the supplied values + /// Year represented by UT 0 + /// DayOfYear represented by UT 0 + /// How many days per year in this calendar + /// How many hours per day in this calendar + /// How many minutes per hour in this calendar + /// How many seconds per minute in this calendar + static public void SetCustomCalendar(Int32 CustomEpochYear, Int32 CustomEpochDayOfYear, Int32 CustomDaysPerYear, Int32 CustomHoursPerDay, Int32 CustomMinutesPerHour, Int32 CustomSecondsPerMinute) + { + CalendarType = CalendarTypeEnum.Custom; + + EpochYear = CustomEpochYear; + EpochDayOfYear = CustomEpochDayOfYear; + SecondsPerMinute = CustomSecondsPerMinute; + MinutesPerHour = CustomMinutesPerHour; + HoursPerDay = CustomHoursPerDay; + DaysPerYear = CustomDaysPerYear; + + } + + /// Default Constructor + static KSPDateStructure() + { + SetKSPStockCalendar(); + + Months = new List(); + //LeapDays = new List(); + } + + /// List of KSPMonth objects representing the months in the year + static public List Months { get; set; } + /// How many months have been defined + static public Int32 MonthCount { get { return Months.Count; } } + + //static public List LeapDays { get; set; } + //static public Int32 LeapDaysCount { get { return LeapDays.Count; } } + } + + /// + /// options for KSPDateStructure Calendar Type + /// + public enum CalendarTypeEnum + { + [Description("KSP Stock Calendar")] + KSPStock, + [Description("Earth Calendar")] + Earth, + [Description("Custom Calendar")] + Custom + } + + /// + /// Definition of a calendar month + /// + public class KSPMonth + { + public KSPMonth(String name, Int32 days) { Name = name; Days = days; } + + /// + /// Name of the month + /// + public String Name { get; set; } + /// + /// How many days in this month + /// + public Int32 Days { get; set; } + } + + //public class KSPLeapDay + //{ + // public Int32 Frequency { get; set; } + // public String MonthApplied { get; set; } + // public Int32 DaysToAdd { get; set; } + //} + + +} \ No newline at end of file diff --git a/KSPCasher/FrameworkExt/KSPDateTime.cs b/KSPCasher/FrameworkExt/KSPDateTime.cs new file mode 100644 index 0000000..99a4b3a --- /dev/null +++ b/KSPCasher/FrameworkExt/KSPDateTime.cs @@ -0,0 +1,687 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Text.RegularExpressions; + +namespace KSPPluginFramework +{ + /// Represents an instant in time, typically expressed as a date and time of day. + public class KSPDateTime : IFormattable + { + //Shortcut to the Calendar Type + private CalendarTypeEnum CalType { get { return KSPDateStructure.CalendarType; } } + + + //Descriptors of DateTime - uses UT as the Root value + + /// Gets the year component of the date represented by this instance. + public int Year + { + get + { + if (CalType == CalendarTypeEnum.Earth) + return _EarthDateTime.Year; + else + return KSPDateStructure.EpochYear + (Int32)UT / KSPDateStructure.SecondsPerYear; + } + } + + /// Gets the day of the year represented by this instance. + /// The day of the year, expressed as a value between 1 and . + public int DayOfYear + { + get + { + if (CalType == CalendarTypeEnum.Earth) + return _EarthDateTime.DayOfYear; + else + return KSPDateStructure.EpochDayOfYear + (Int32)UT / KSPDateStructure.SecondsPerDay % KSPDateStructure.DaysPerYear; + } + } + + /// Gets the day of the month represented by this instance. + /// The day component, expressed as a value between 1 and the number of days in the month. + public int Day + { + get + { + if (CalType == CalendarTypeEnum.Earth) + return _EarthDateTime.Day; + else + return DayOfMonth; + } + } + + + /// Gets the month component of the date represented by this instance. + /// + /// The day component, expressed as a value between 1 and the months in the year. + /// If the Defined calendar has no months then this will be 0 + /// + public int Month + { + get + { + if (CalType == CalendarTypeEnum.Earth) + return _EarthDateTime.Month; + else + { + if (KSPDateStructure.MonthCount < 1) + return 0; + else + return KSPDateStructure.Months.IndexOf(MonthObj) + 1; + } + } + } + + private KSPMonth MonthObj + { + get + { + if (KSPDateStructure.MonthCount < 1) + return null; + Int32 monthMaxDay = 0; + for (int i = 0; i < KSPDateStructure.MonthCount; i++) + { + if (DayOfYear <= monthMaxDay + KSPDateStructure.Months[i].Days) + return KSPDateStructure.Months[i]; + } + return KSPDateStructure.Months.Last(); + } + } + private Int32 DayOfMonth + { + get + { + if (KSPDateStructure.MonthCount < 1) + return DayOfYear; + + Int32 monthMaxDay = 0; + for (int i = 0; i < KSPDateStructure.MonthCount; i++) + { + if (DayOfYear <= monthMaxDay + KSPDateStructure.Months[i].Days) + return DayOfYear - monthMaxDay; + } + return DayOfYear; + } + } + + + /// Gets the hour component of the date represented by this instance. + /// The hour component, expressed as a value between 1 and . + public int Hour { get { if (CalType == CalendarTypeEnum.Earth) return _EarthDateTime.Hour; else return _TimeSpanFromEpoch.Hours; } } + /// Gets the minute Component of the date represented by this instance. + /// The minute component, expressed as a value between 1 and . + public int Minute { get { if (CalType == CalendarTypeEnum.Earth) return _EarthDateTime.Minute; else return _TimeSpanFromEpoch.Minutes; } } + /// Gets the second component of the date represented by this instance. + /// The second component, expressed as a value between 1 and . + public int Second { get { if (CalType == CalendarTypeEnum.Earth) return _EarthDateTime.Second; else return _TimeSpanFromEpoch.Seconds; } } + /// Gets the millisecond component of the date represented by this instance. + /// The hour component, expressed as a value between 1 and 999. + public int Millisecond { get { if (CalType == CalendarTypeEnum.Earth) return _EarthDateTime.Millisecond; else return _TimeSpanFromEpoch.Milliseconds; } } + + /// Replaces the normal "Ticks" function. This is Seconds of UT since game time 0 + /// The number of seconds of game UT since Epoch + public Double UT + { + get + { + //if (KSPDateStructure.CalendarType== CalendarTypeEnum.Earth) + // return _EarthDateTime.Subtract(KSPDateStructure.CustomEpochEarth).TotalSeconds; + //else + return _TimeSpanFromEpoch.UT; + } + set + { + _TimeSpanFromEpoch = new KSPTimeSpan(value); + //if (KSPDateStructure.CalendarType == CalendarTypeEnum.Earth) + // _EarthDateTime = KSPDateStructure.CustomEpochEarth.AddSeconds(value); + } + } + + private KSPTimeSpan _TimeSpanFromEpoch; + private DateTime _EarthDateTime { get { return KSPDateStructure.CustomEpochEarth.AddSeconds(UT); } } + private DateTime _EarthDateTimeEpoch { get { return new DateTime(KSPDateStructure.EpochYear, 1, KSPDateStructure.EpochDayOfYear); } } + + #region Constructors + //public KSPDateTime() + //{ + // UT = 0; + //} + + /// Initializes a new instance of the System.DateTime structure to the specified year and day. + /// The year + /// The day of the year + public KSPDateTime(int year, int dayofyear) + { + UT = new KSPDateTime(year, dayofyear, 0, 0, 0).UT; + } + /// Initializes a new instance of the System.DateTime structure to the specified year and day. + /// The year + /// The day of the year + public KSPDateTime(String year, String dayofyear) + { + UT = new KSPDateTime(year, dayofyear, "0", "0", "0").UT; + } + + /// Initializes a new instance of the System.DateTime structure to the specified year, day, hour, minute, and second. + /// The year + /// The day of the year + /// The hour + /// The minute + /// The second + public KSPDateTime(String year, String day, String hour, String minute, String second) + { + UT = new KSPDateTime(Convert.ToInt32(year), Convert.ToInt32(day), Convert.ToInt32(hour), Convert.ToInt32(minute), Convert.ToInt32(second), 0).UT; + } + /// Initializes a new instance of the System.DateTime structure to the specified year, day, hour, minute, and second. + /// The year + /// The day of the year + /// The hour + /// The minute + /// The second + public KSPDateTime(int year, int day, int hour, int minute, int second) + { + UT = new KSPDateTime(year, day, hour, minute, second, 0).UT; + } + /// Initializes a new instance of the System.DateTime structure to the specified year, day, hour, minute, and second. + /// The year + /// The day of the year + /// The hour + /// The minute + /// The second + /// The milliseconds + public KSPDateTime(int year, int day, int hour, int minute, int second, int millisecond) + { + //Test for entering values outside the norm - eg 25 hours, day 600 + + UT = new KSPTimeSpan((year - KSPDateStructure.EpochYear) * KSPDateStructure.DaysPerYear + + (day - KSPDateStructure.EpochDayOfYear), + hour, + minute, + second, + millisecond + ).UT; + } + + /// Initializes a new instance of the System.DateTime structure to a specified number to the specified number of seconds of Game UT. + /// a time period expressed in seconds + public KSPDateTime(Double ut) + { + UT = ut; + } + #endregion + + + #region Calculated Properties + /// Gets the date component of this instance. + /// A new System.DateTime with the same date as this instance, and the time value set to 00:00:00. + public KSPDateTime Date { get { return new KSPDateTime(Year, DayOfYear); } } + + + /// Gets the time of day for this instance. + /// A System.TimeSpan that represents the fraction of the day that has elapsed since midnight. + public KSPTimeSpan TimeOfDay { get { return new KSPTimeSpan(UT % KSPDateStructure.SecondsPerDay); } } + + + /// Gets a System.DateTime object that is set to the current date and time of the game. + /// A System.DateTime whose value is the current game date and time. + public static KSPDateTime Now + { + get { return new KSPDateTime(Planetarium.GetUniversalTime()); } + } + /// Gets the current date. + /// A System.DateTime set to today's date, with the time component set to 00:00:00. + public static KSPDateTime Today + { + get { return new KSPDateTime(Planetarium.GetUniversalTime()).Date; } + } + #endregion + + + #region String Formatter + + private AMPMEnum AMPM + { + get + { + if (KSPDateStructure.HoursPerDay % 2 == 0) + { + if (Hour < (KSPDateStructure.HoursPerDay / 2)) + return AMPMEnum.AM; + else + return AMPMEnum.PM; + } + else + return AMPMEnum.OddHoursPerDay; + } + } + private enum AMPMEnum + { + AM, PM, OddHoursPerDay + } + + /// Generates some standard Templated versions of output + /// Enum of some common formats + /// A string that represents the value of this instance. + public String ToStringStandard(DateStringFormatsEnum DateFormat) + { + switch (DateFormat) + { + case DateStringFormatsEnum.TimeAsUT: + String strReturn = ""; + if (UT < 0) strReturn += "+ "; + strReturn += String.Format("{0:N0}s", Math.Abs(UT)); + return strReturn; + case DateStringFormatsEnum.KSPFormat: + return ToString(); + case DateStringFormatsEnum.KSPFormatWithSecs: + return ToString("Year y, Da\\y d - H\\h, m\\m, s\\s"); + case DateStringFormatsEnum.DateTimeFormat: + if (KSPDateStructure.CalendarType == CalendarTypeEnum.Earth) + return ToString("d MMM yyyy, HH:mm:ss"); + else + return ToString("Year y, Da\\y d, HH:mm:ss"); + default: + return ToString(); + } + } + + /// Returns the string representation of the value of this instance. + /// A string that represents the value of this instance. + public override String ToString() + { + if (CalType == CalendarTypeEnum.Earth) + { + return ToString(System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern + " " + System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern); + } + else + { + return ToString("Year y, Da\\y d - H\\h, m\\m", null); + } + } + /// Returns the string representation of the value of this instance. + /// Format string using the usual characters to interpret custom datetime - as per standard DateTime custom formats + /// A string that represents the value of this instance. + public String ToString(String format) + { + return ToString(format, null); + } + /// Returns the string representation of the value of this instance. + /// Format string using the usual characters to interpret custom datetime - as per standard DateTime custom formats + /// A string that represents the value of this instance. + public String ToString(String format, IFormatProvider provider) + { + //parse and replace the format stuff + MatchCollection matches = Regex.Matches(format, "([a-zA-z])\\1{0,}"); + for (int i = matches.Count - 1; i >= 0; i--) + { + Match m = matches[i]; + Int32 mIndex = m.Index, mLength = m.Length; + + if (mIndex > 0 && format[m.Index - 1] == '\\') + { + if (m.Length == 1) + continue; + else + { + mIndex++; + mLength--; + } + } + switch (m.Value[0]) + { + case 'y': + format = format.Substring(0, mIndex) + Year.ToString("D" + mLength) + format.Substring(mIndex + mLength); + break; + case 'M': + if (mLength < 3) + { + String input2 = Month.ToString("D" + mLength); + format = format.Substring(0, mIndex) + input2 + format.Substring(mIndex + mLength); + } + else if (mLength == 3) + { + if (KSPDateStructure.CalendarType == CalendarTypeEnum.Earth) + format = format.Substring(0, mIndex) + System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(Month) + format.Substring(mIndex + mLength); + else + if (KSPDateStructure.MonthCount < 1) + { + String input2 = Month.ToString("D" + mLength); + format = format.Substring(0, mIndex) + input2 + format.Substring(mIndex + mLength); + } + else + { + format = format.Substring(0, mIndex) + KSPDateStructure.Months[Month].ToString().Substring(0, 3) + format.Substring(mIndex + mLength); + } + } + else + { + if (KSPDateStructure.CalendarType == CalendarTypeEnum.Earth) + format = format.Substring(0, mIndex) + System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(Month) + format.Substring(mIndex + mLength); + else + if (KSPDateStructure.MonthCount < 1) + { + String input2 = Month.ToString("D" + mLength); + format = format.Substring(0, mIndex) + input2 + format.Substring(mIndex + mLength); + } + else + { + format = format.Substring(0, mIndex) + KSPDateStructure.Months[Month] + format.Substring(mIndex + mLength); + } + } + break; + case 'd': + format = format.Substring(0, mIndex) + Day.ToString("D" + mLength) + format.Substring(mIndex + mLength); + break; + case 'h': + //how to do this one AM/PM Hours + String HalfDayTime = ""; + switch (AMPM) + { + case AMPMEnum.AM: + HalfDayTime = Hour.ToString("D" + mLength.Clamp(1, (KSPDateStructure.HoursPerDay / 2).ToString().Length)); + break; + case AMPMEnum.PM: + HalfDayTime = (Hour - (KSPDateStructure.HoursPerDay / 2)).ToString("D" + mLength.Clamp(1, (KSPDateStructure.HoursPerDay / 2).ToString().Length)); + break; + case AMPMEnum.OddHoursPerDay: + default: + HalfDayTime = Hour.ToString("D" + mLength.Clamp(1, KSPDateStructure.HoursPerDay.ToString().Length)); + break; + } + + format = format.Substring(0, mIndex) + HalfDayTime + format.Substring(mIndex + mLength); + break; + case 't': + if (AMPM != AMPMEnum.OddHoursPerDay) + format = format.Substring(0, mIndex) + AMPM.ToString().ToLower() + format.Substring(mIndex + mLength); + break; + case 'T': + if (AMPM != AMPMEnum.OddHoursPerDay) + format = format.Substring(0, mIndex) + AMPM.ToString().ToUpper() + format.Substring(mIndex + mLength); + break; + case 'H': + format = format.Substring(0, mIndex) + Hour.ToString("D" + mLength.Clamp(1, KSPDateStructure.HoursPerDay.ToString().Length)) + format.Substring(mIndex + mLength); + break; + case 'm': + format = format.Substring(0, mIndex) + Minute.ToString("D" + mLength.Clamp(1, KSPDateStructure.MinutesPerHour.ToString().Length)) + format.Substring(mIndex + mLength); + break; + case 's': + format = format.Substring(0, mIndex) + Second.ToString("D" + mLength.Clamp(1, KSPDateStructure.SecondsPerMinute.ToString().Length)) + format.Substring(mIndex + mLength); + break; + + default: + break; + } + } + + //Now strip out the \ , but not multiple \\ + format = Regex.Replace(format, "\\\\(?=[a-z])", ""); + + return format; + //if (KSPDateStructure.CalendarType == CalendarTypeEnum.Earth) + // return String.Format(format, _EarthDateTime); + //else + // return String.Format(format, this); //"TEST"; + } + + #endregion + + + #region Instance Methods + #region Mathematic Methods + /// Returns a new KSPPluginFramework.KSPDateTime object whose value is the sum of the specified KSPPluginFramework.KSPTimeSpan object and this instance. + /// A KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the time interval represented by value. + public KSPDateTime Add(KSPTimeSpan value) + { + return new KSPDateTime(UT + value.UT); + } + /// Returns a new KSPPluginFramework.KSPDateTime that adds the specified years to the value of this instance. + /// a number of whole or fractional years. Can be positive or negative. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the number of years represented by value. + public KSPDateTime AddYears(Int32 value) + { + if (CalType != CalendarTypeEnum.Earth) + return new KSPDateTime(UT + value * KSPDateStructure.SecondsPerYear); + else + { + DateTime newDate = _EarthDateTime.AddYears(value); + return new KSPDateTime(newDate.Subtract(_EarthDateTimeEpoch).TotalSeconds); + } + } + /// Returns a new KSPPluginFramework.KSPDateTime that adds the specified days to the value of this instance. + /// a number of whole or fractional days. Can be positive or negative. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the number of days represented by value. + public KSPDateTime AddDays(Double value) + { + return new KSPDateTime(UT + value * KSPDateStructure.SecondsPerDay); + } + /// Returns a new KSPPluginFramework.KSPDateTime that adds the specified hours to the value of this instance. + /// a number of whole or fractional hours. Can be positive or negative. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the number of hours represented by value. + public KSPDateTime AddHours(Double value) + { + return new KSPDateTime(UT + value * KSPDateStructure.SecondsPerHour); + } + /// Returns a new KSPPluginFramework.KSPDateTime that adds the specified minutes to the value of this instance. + /// a number of whole or fractional minutes. Can be positive or negative. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the number of minutes represented by value. + public KSPDateTime AddMinutes(Double value) + { + return new KSPDateTime(UT + value * KSPDateStructure.SecondsPerMinute); + } + /// Returns a new KSPPluginFramework.KSPDateTime that adds the specified seconds to the value of this instance. + /// a number of whole or fractional seconds. Can be positive or negative. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the number of seconds represented by value. + public KSPDateTime AddSeconds(Double value) + { + return new KSPDateTime(UT + value); + } + /// Returns a new KSPPluginFramework.KSPDateTime that adds the specified milliseconds to the value of this instance. + /// a number of whole or fractional milliseconds. Can be positive or negative. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the number of milliseconds represented by value. + public KSPDateTime AddMilliSeconds(Double value) + { + return new KSPDateTime(UT + value / 1000); + } + + /// Returns a new KSPPluginFramework.KSPDateTime that adds the specified seconds to the value of this instance. + /// a number of whole or fractional seconds. Can be positive or negative. + /// A KSPPluginFramework.KSPDateTime whose value is the sum of the date and time represented by this instance and the number of seconds represented by value. + public KSPDateTime AddUT(Double value) + { + return new KSPDateTime(UT + value); + } + + /// Subtracts the specified date and time from this instance. + /// An instance of System.DateTime. + /// A System.DateTime equal to the date and time represented by this instance minus the date and time represented by value. + public KSPDateTime Subtract(KSPDateTime value) + { + return new KSPDateTime(UT - value.UT); + } + /// Subtracts the specified duration from this instance. + /// An instance of System.TimeSpan. + /// A System.DateTime equal to the date and time represented by this instance minus the time interval represented by value. + public KSPTimeSpan Subtract(KSPTimeSpan value) + { + return new KSPTimeSpan(UT - value.UT); + } + + #endregion + + + #region Comparison Methods + /// Compares this instance to a specified KSPPluginFramework.KSPDateTime object and returns an integer that indicates whether this instance is shorter than, equal to, or longer than the KSPPluginFramework.KSPDateTime object. + /// A KSPPluginFramework.KSPDateTime object to compare to this instance. + /// A signed number indicating the relative values of this instance and value.Value Description A negative integer This instance is shorter than value. Zero This instance is equal to value. A positive integer This instance is longer than value. + public Int32 CompareTo(KSPDateTime value) + { + return KSPDateTime.Compare(this, value); + } + /// Value Condition -1 This instance is shorter than value. 0 This instance is equal to value. 1 This instance is longer than value.-or- value is null. + /// An object to compare, or null. + /// Value Condition -1 This instance is shorter than value. 0 This instance is equal to value. 1 This instance is longer than value.-or- value is null. + public Int32 CompareTo(System.Object value) + { + if (value == null) return 1; + return this.CompareTo((KSPDateTime)value); + } + /// Returns a value indicating whether this instance is equal to a specified KSPPluginFramework.KSPDateTime object. + /// An KSPPluginFramework.KSPDateTime object to compare with this instance. + /// true if obj represents the same time interval as this instance; otherwise, false. + public Boolean Equals(KSPDateTime value) + { + return KSPDateTime.Equals(this, value); + } + /// Returns a value indicating whether this instance is equal to a specified object. + /// An object to compare with this instance + /// true if value is a KSPPluginFramework.KSPDateTime object that represents the same time interval as the current KSPPluginFramework.KSPDateTime structure; otherwise, false. + public override bool Equals(System.Object value) + { + return (value.GetType() == this.GetType()) && this.Equals((KSPDateTime)value); + } + #endregion + + + /// Returns a hash code for this instance. + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return UT.GetHashCode(); + } + #endregion + + + #region Static Methods + /// Compares two KSPPluginFramework.KSPDateTime values and returns an integer that indicates whether the first value is shorter than, equal to, or longer than the second value. + /// A KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPDateTime. + /// Value Condition -1 t1 is shorter than t20 t1 is equal to t21 t1 is longer than t2 + public static Int32 Compare(KSPDateTime t1, KSPDateTime t2) + { + if (t1.UT < t2.UT) + return -1; + else if (t1.UT > t2.UT) + return 1; + else + return 0; + } + /// Returns a value indicating whether two specified instances of KSPPluginFramework.KSPDateTime are equal. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime. + /// true if the values of t1 and t2 are equal; otherwise, false. + public static Boolean Equals(KSPDateTime t1, KSPDateTime t2) + { + return t1.UT == t2.UT; + } + + public static KSPDateTime FromEarthValues(Int32 Year, Int32 Month, Int32 Day) + { + return new KSPDateTime(new DateTime(Year, Month, Day).Subtract(KSPDateStructure.CustomEpochEarth).TotalSeconds); + } + public static KSPDateTime FromEarthValues(String Year, String Month, String Day) + { + return FromEarthValues(Convert.ToInt32(Year), Convert.ToInt32(Month), Convert.ToInt32(Day)); + } + + #endregion + + + #region Operators + /// Subtracts a specified date and time from another specified date and time and returns a time interval. + /// A KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime whose value is the result of the value of d1 minus the value of d2. + public static KSPTimeSpan operator -(KSPDateTime d1, KSPDateTime d2) + { + return new KSPTimeSpan(d1.UT - d2.UT); + } + /// Subtracts a specified duration from another specified date and time and returns a time interval. + /// A KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPTimeSpan. + /// A DateTime whose value is the result of the value of d minus the value of t. + public static KSPDateTime operator -(KSPDateTime d, KSPTimeSpan t) + { + return new KSPDateTime(d.UT - t.UT); + } + /// Adds a specified duration from another specified date and time and returns a time interval. + /// A KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPTimeSpan. + /// A DateTime whose value is the result of the value of d plus the value of t. + public static KSPDateTime operator +(KSPDateTime d, KSPTimeSpan t) + { + return new KSPDateTime(d.UT + t.UT); + } + + /// Indicates whether two KSPPluginFramework.KSPDateTime instances are not equal. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime. + /// true if the values of d1 and d2 are not equal; otherwise, false. + public static Boolean operator !=(KSPDateTime d1, KSPDateTime d2) + { + return !(d1 == d2); + } + /// Indicates whether two KSPPluginFramework.KSPDateTime instances are equal. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime. + /// true if the values of d1 and d2 are equal; otherwise, false. + public static Boolean operator ==(KSPDateTime d1, KSPDateTime d2) + { + return d1.UT == d2.UT; + } + + + + /// Indicates whether a specified KSPPluginFramework.KSPDateTime is less than or equal to another specified KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime. + /// true if the value of d1 is less than or equal to the value of d2; otherwise, false. + public static Boolean operator <=(KSPDateTime d1, KSPDateTime d2) + { + return d1.CompareTo(d2) <= 0; + } + /// Indicates whether a specified KSPPluginFramework.KSPDateTime is less than another specified KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime. + /// true if the value of d1 is less than the value of d2; otherwise, false. + public static Boolean operator <(KSPDateTime d1, KSPDateTime d2) + { + return d1.CompareTo(d2) < 0; + } + /// Indicates whether a specified KSPPluginFramework.KSPDateTime is greater than or equal to another specified KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime. + /// true if the value of d1 is greater than or equal to the value of d2; otherwise, false. + public static Boolean operator >=(KSPDateTime d1, KSPDateTime d2) + { + return d1.CompareTo(d2) >= 0; + } + /// Indicates whether a specified KSPPluginFramework.KSPDateTime is greater than another specified KSPPluginFramework.KSPDateTime. + /// A KSPPluginFramework.KSPDateTime. + /// A DateTime. + /// true if the value of d1 is greater than the value of d2; otherwise, false. + public static Boolean operator >(KSPDateTime d1, KSPDateTime d2) + { + return d1.CompareTo(d2) > 0; + } + #endregion + + } + + + /// + /// Enum of standardised outputs for DateTimes as strings + /// + public enum DateStringFormatsEnum + { + TimeAsUT, + KSPFormat, + KSPFormatWithSecs, + DateTimeFormat + } +} \ No newline at end of file diff --git a/KSPCasher/FrameworkExt/KSPTimeSpan.cs b/KSPCasher/FrameworkExt/KSPTimeSpan.cs new file mode 100644 index 0000000..dcc6c92 --- /dev/null +++ b/KSPCasher/FrameworkExt/KSPTimeSpan.cs @@ -0,0 +1,558 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Text.RegularExpressions; + +namespace KSPPluginFramework +{ + /// Represents a time interval. + public class KSPTimeSpan : IFormattable + { + //Shortcut to the Calendar Type + private CalendarTypeEnum CalType { get { return KSPDateStructure.CalendarType; } } + + //Descriptors of Timespan - uses UT as the Root value + + + /// Gets the years component of the time interval represented by the current KSPPluginFramework.KSPTimeSpan structure + /// + /// Returns 0 if the == + /// otherwise + /// Returns the year component of this instance. The return value can be positive or negative. + /// + public Int32 Years + { + get + { + if (CalType != CalendarTypeEnum.Earth) + { + return (Int32)UT / KSPDateStructure.SecondsPerYear; + } + else + { + return 0; + } + } + } + + /// Gets the days component of the time interval represented by the current KSPPluginFramework.KSPTimeSpan structure. + /// + /// Returns Total Number of Days for the current component if the == + /// otherwise + /// The day component of the current KSPPluginFramework.KSPTimeSpan structure. The return value ranges between +/- + /// + public Int32 Days + { + get + { + if (CalType != CalendarTypeEnum.Earth) + { + return (Int32)UT / KSPDateStructure.SecondsPerDay % KSPDateStructure.DaysPerYear; + } + else + { + return (Int32)UT / KSPDateStructure.SecondsPerDay; + } + } + } + + /// Gets the hours component of the time interval represented by the current KSPPluginFramework.KSPTimeSpan structure. + /// The hour component of the current KSPPluginFramework.KSPTimeSpan structure. The return value ranges between +/- + public int Hours + { + get { return (Int32)UT / KSPDateStructure.SecondsPerHour % KSPDateStructure.HoursPerDay; } + } + + /// Gets the minutes component of the time interval represented by the current KSPPluginFramework.KSPTimeSpan structure. + /// + /// The minute component of the current KSPPluginFramework.KSPTimeSpan structure. The return value ranges between +/- + /// + public int Minutes + { + get { return (Int32)UT / KSPDateStructure.SecondsPerMinute % KSPDateStructure.MinutesPerHour; } + } + + /// Gets the seconds component of the time interval represented by the current KSPPluginFramework.KSPTimeSpan structure. + /// + /// The second component of the current KSPPluginFramework.KSPTimeSpan structure. The return value ranges between +/- + /// + public int Seconds + { + get { return (Int32)UT % KSPDateStructure.SecondsPerMinute; } + } + + /// Gets the milliseconds component of the time interval represented by the current KSPPluginFramework.KSPTimeSpan structure. + /// The millisecond component of the current KSPPluginFramework.KSPTimeSpan structure. The return value ranges from -999 through 999. + public int Milliseconds + { + get { return (Int32)(Math.Round(UT - Math.Floor(UT), 3) * 1000); } + } + + + + + /// Replaces the normal "Ticks" function. This is Seconds of UT + /// The number of seconds of game UT in this instance + public Double UT { get; set; } + + #region Constructors + //public KSPTimeSpan() + //{ + // UT = 0; + //} + + /// Initializes a new KSPPluginFramework.KSPTimeSpan to a specified number of hours, minutes, and seconds. + /// Number of hours. + /// Number of minutes. + /// Number of seconds. + public KSPTimeSpan(int hours, int minutes, int seconds) + { + UT = new KSPTimeSpan(0, hours, minutes, seconds, 0).UT; + } + + /// Initializes a new KSPPluginFramework.KSPTimeSpan to a specified number of days, hours, minutes, and seconds. + /// Number of days. + /// Number of hours. + /// Number of minutes. + /// Number of seconds. + public KSPTimeSpan(String days, String hours, String minutes, String seconds) + { + UT = new KSPTimeSpan(Convert.ToInt32(days), Convert.ToInt32(hours), Convert.ToInt32(minutes), Convert.ToInt32(seconds), 0).UT; + } + /// Initializes a new KSPPluginFramework.KSPTimeSpan to a specified number of days, hours, minutes, and seconds. + /// Number of days. + /// Number of hours. + /// Number of minutes. + /// Number of seconds. + public KSPTimeSpan(int days, int hours, int minutes, int seconds) + { + UT = new KSPTimeSpan(days, hours, minutes, seconds, 0).UT; + } + + /// Initializes a new KSPPluginFramework.KSPTimeSpan to a specified number of days, hours, minutes, seconds, and milliseconds. + /// Number of days. + /// Number of hours. + /// Number of minutes. + /// Number of seconds. + /// Number of milliseconds. + public KSPTimeSpan(int days, int hours, int minutes, int seconds, int milliseconds) + { + UT = days * KSPDateStructure.SecondsPerDay + + hours * KSPDateStructure.SecondsPerHour + + minutes * KSPDateStructure.SecondsPerMinute + + seconds + + (Double)milliseconds / 1000; + } + + /// Initialises a new KSPPluginFramework.KSPTimeSpan to the specified number of seconds of Game UT + /// a time period expressed in seconds + public KSPTimeSpan(Double ut) + { + UT = ut; + } + #endregion + + + #region Calculated Properties + /// Gets the value of the current KSPPluginFramework.KSPTimeSpan structure expressed in whole and fractional milliseconds. + /// The total number of milliseconds represented by this instance. + public Double TotalMilliseconds { get { return UT * 1000; } } + /// Gets the value of the current KSPPluginFramework.KSPTimeSpan structure expressed in whole and fractional seconds. + /// The total number of seconds represented by this instance. + public Double TotalSeconds { get { return UT; } } + /// Gets the value of the current KSPPluginFramework.KSPTimeSpan structure expressed in whole and fractional minutes. + /// The total number of minutes represented by this instance. + public Double TotalMinutes { get { return UT / KSPDateStructure.SecondsPerMinute; } } + /// Gets the value of the current KSPPluginFramework.KSPTimeSpan structure expressed in whole and fractional hours. + /// The total number of hours represented by this instance. + public Double TotalHours { get { return UT / KSPDateStructure.SecondsPerHour; } } + /// Gets the value of the current KSPPluginFramework.KSPTimeSpan structure expressed in whole and fractional days. + /// The total number of days represented by this instance. + public Double TotalDays { get { return UT / KSPDateStructure.SecondsPerDay; } } + #endregion + + #region String Formatter + + /// Generates some standard Templated versions of output + /// Enum of some common formats + /// A string that represents the value of this instance. + public String ToStringStandard(TimeSpanStringFormatsEnum TimeSpanFormat) + { + switch (TimeSpanFormat) + { + case TimeSpanStringFormatsEnum.TimeAsUT: + String strReturn = ""; + if (UT < 0) strReturn += "+ "; + strReturn += String.Format("{0:N0}s", Math.Abs(UT)); + return strReturn; + case TimeSpanStringFormatsEnum.KSPFormat: + return ToString(5); + case TimeSpanStringFormatsEnum.IntervalLong: + return ToString("y Year\\s, d Da\\y\\s, hh:mm:ss"); + case TimeSpanStringFormatsEnum.IntervalLongTrimYears: + return ToString("y Year\\s, d Da\\y\\s, hh:mm:ss").Replace("0 Years, ", ""); + case TimeSpanStringFormatsEnum.DateTimeFormat: + String strFormat = ""; + if (Years > 0) strFormat += "y\\y"; + if (Days > 0) strFormat += (strFormat.EndsWith("y") ? ", " : "") + "d\\d"; + if (strFormat != "") strFormat += " "; + strFormat += "hh:mm:ss"; + + if (UT < 0) strFormat = "+ " + strFormat; + + return ToString(strFormat); + default: + return ToString(); + } + } + + /// Returns the string representation of the value of this instance. + /// A string that represents the value of this instance. + public override String ToString() + { + return ToString(1); + } + + /// Returns the string representation of the value of this instance. + /// How many parts of the timespane to return (of year, Day, hour, minute, second) + /// A string that represents the value of this instance. + public String ToString(Int32 Precision) + { + Int32 Displayed = 0; + String format = ""; + + if (UT < 0) format += "+"; + + + if (CalType != CalendarTypeEnum.Earth) + { + if ((Years > 0 || Precision > 4) && Displayed < Precision) + { + format = "y\\y,"; + Displayed++; + } + } + + if ((Days > 0 || Precision > 3) && Displayed < Precision) + { + format = "d\\d,"; + Displayed++; + } + if ((Hours > 0 || Precision > 2) && Displayed < Precision) + { + format += (format == "" ? "" : " ") + "h\\h,"; + Displayed++; + + } + if ((Minutes > 0 || Precision > 1) && Displayed < Precision) + { + format += (format == "" ? "" : " ") + "m\\m,"; + Displayed++; + + } + if ((Seconds > 0 || Precision > 0) && Displayed < Precision) + { + format += (format == "" ? "" : " ") + "s\\s,"; + Displayed++; + + } + + format = format.TrimEnd(','); + + return ToString(format, null); + } + + /// Returns the string representation of the value of this instance. + /// Format string using the usual characters to interpret custom datetime - as per standard Timespan custom formats + /// A string that represents the value of this instance. + public String ToString(String format) + { + return ToString(format, null); + } + /// Returns the string representation of the value of this instance. + /// Format string using the usual characters to interpret custom datetime - as per standard Timespan custom formats + /// A string that represents the value of this instance. + public String ToString(String format, IFormatProvider provider) + { + //parse and replace the format stuff + MatchCollection matches = Regex.Matches(format, "([a-zA-z])\\1{0,}"); + for (int i = matches.Count - 1; i >= 0; i--) + { + Match m = matches[i]; + Int32 mIndex = m.Index, mLength = m.Length; + + if (mIndex > 0 && format[m.Index - 1] == '\\') + { + if (m.Length == 1) + continue; + else + { + mIndex++; + mLength--; + } + } + switch (m.Value[0]) + { + case 'y': + format = format.Substring(0, mIndex) + Years.ToString("D" + mLength) + format.Substring(mIndex + mLength); + break; + case 'd': + format = format.Substring(0, mIndex) + Days.ToString("D" + mLength) + format.Substring(mIndex + mLength); + break; + case 'h': + format = format.Substring(0, mIndex) + Hours.ToString("D" + mLength.Clamp(1, KSPDateStructure.HoursPerDay.ToString().Length)) + format.Substring(mIndex + mLength); + break; + case 'm': + format = format.Substring(0, mIndex) + Minutes.ToString("D" + mLength.Clamp(1, KSPDateStructure.MinutesPerHour.ToString().Length)) + format.Substring(mIndex + mLength); + break; + case 's': + format = format.Substring(0, mIndex) + Seconds.ToString("D" + mLength.Clamp(1, KSPDateStructure.SecondsPerMinute.ToString().Length)) + format.Substring(mIndex + mLength); + break; + + default: + break; + } + } + + //Now strip out the \ , but not multiple \\ + format = Regex.Replace(format, "\\\\(?=[a-z])", ""); + + return format; + //if (KSPDateStructure.CalendarType == CalendarTypeEnum.Earth) + // return String.Format(format, _EarthDateTime); + //else + // return String.Format(format, this); //"TEST"; + } + + #endregion + + #region Instance Methods + #region Mathematic Methods + /// Returns a new KSPPluginFramework.KSPTimeSpan object whose value is the sum of the specified KSPPluginFramework.KSPTimeSpan object and this instance. + /// A KSPPluginFramework.KSPTimeSpan. + /// A new object that represents the value of this instance plus the value of the timespan supplied. + public KSPTimeSpan Add(KSPTimeSpan value) + { + return new KSPTimeSpan(UT + value.UT); + } + /// Returns a new KSPPluginFramework.KSPTimeSpan object whose value is the absolute value of the current KSPPluginFramework.KSPTimeSpan object. + /// A new object whose value is the absolute value of the current KSPPluginFramework.KSPTimeSpan object. + public KSPTimeSpan Duration() + { + return new KSPTimeSpan(Math.Abs(UT)); + } + /// Returns a new KSPPluginFramework.KSPTimeSpan object whose value is the negated value of this instance. + /// A new object with the same numeric value as this instance, but with the opposite sign. + public KSPTimeSpan Negate() + { + return new KSPTimeSpan(UT * -1); + } + #endregion + + #region Comparison Methods + /// Compares this instance to a specified KSPPluginFramework.KSPTimeSpan object and returns an integer that indicates whether this instance is shorter than, equal to, or longer than the KSPPluginFramework.KSPTimeSpan object. + /// A KSPPluginFramework.KSPTimeSpan object to compare to this instance. + /// A signed number indicating the relative values of this instance and value.Value Description A negative integer This instance is shorter than value. Zero This instance is equal to value. A positive integer This instance is longer than value. + public Int32 CompareTo(KSPTimeSpan value) + { + return KSPTimeSpan.Compare(this, value); + } + /// Value Condition -1 This instance is shorter than value. 0 This instance is equal to value. 1 This instance is longer than value.-or- value is null. + /// An object to compare, or null. + /// Value Condition -1 This instance is shorter than value. 0 This instance is equal to value. 1 This instance is longer than value.-or- value is null. + public Int32 CompareTo(System.Object value) + { + if (value == null) return 1; + + return this.CompareTo((KSPTimeSpan)value); + } + /// Returns a value indicating whether this instance is equal to a specified KSPPluginFramework.KSPTimeSpan object. + /// An KSPPluginFramework.KSPTimeSpan object to compare with this instance. + /// true if obj represents the same time interval as this instance; otherwise, false. + public Boolean Equals(KSPTimeSpan value) + { + return KSPTimeSpan.Equals(this, value); + } + /// Returns a value indicating whether this instance is equal to a specified object. + /// An object to compare with this instance + /// true if value is a KSPPluginFramework.KSPTimeSpan object that represents the same time interval as the current KSPPluginFramework.KSPTimeSpan structure; otherwise, false. + public override bool Equals(System.Object value) + { + return (value.GetType() == this.GetType()) && this.Equals((KSPTimeSpan)value); + } + #endregion + + + /// Returns a hash code for this instance. + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return UT.GetHashCode(); + } + + #endregion + + + #region Static Methods + /// Compares two KSPPluginFramework.KSPTimeSpan values and returns an integer that indicates whether the first value is shorter than, equal to, or longer than the second value. + /// A KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// Value Condition -1 t1 is shorter than t20 t1 is equal to t21 t1 is longer than t2 + public static Int32 Compare(KSPTimeSpan t1, KSPTimeSpan t2) + { + if (t1.UT < t2.UT) + return -1; + else if (t1.UT > t2.UT) + return 1; + else + return 0; + } + /// Returns a value indicating whether two specified instances of KSPPluginFramework.KSPTimeSpan are equal. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// true if the values of t1 and t2 are equal; otherwise, false. + public static Boolean Equals(KSPTimeSpan t1, KSPTimeSpan t2) + { + return t1.UT == t2.UT; + } + + + /// Returns a KSPPluginFramework.KSPTimeSpan that represents a specified number of days, where the specification is accurate to the nearest millisecond. + /// A number of days, accurate to the nearest millisecond. + /// A KSPPluginFramework.KSPTimeSpan that represents value. + public static KSPTimeSpan FromDays(Double value) + { + return new KSPTimeSpan(value * KSPDateStructure.SecondsPerDay); + } + /// Returns a KSPPluginFramework.KSPTimeSpan that represents a specified number of hours, where the specification is accurate to the nearest millisecond. + /// A number of hours, accurate to the nearest millisecond. + /// A KSPPluginFramework.KSPTimeSpan that represents value. + public static KSPTimeSpan FromHours(Double value) + { + return new KSPTimeSpan(value * KSPDateStructure.SecondsPerHour); + } + /// Returns a KSPPluginFramework.KSPTimeSpan that represents a specified number of minutes, where the specification is accurate to the nearest millisecond. + /// A number of minutes, accurate to the nearest millisecond. + /// A KSPPluginFramework.KSPTimeSpan that represents value. + public static KSPTimeSpan FromMinutes(Double value) + { + return new KSPTimeSpan(value * KSPDateStructure.SecondsPerMinute); + } + /// Returns a KSPPluginFramework.KSPTimeSpan that represents a specified number of seconds, where the specification is accurate to the nearest millisecond. + /// A number of seconds, accurate to the nearest millisecond. + /// A KSPPluginFramework.KSPTimeSpan that represents value. + public static KSPTimeSpan FromSeconds(Double value) + { + return new KSPTimeSpan(value); + } + /// Returns a KSPPluginFramework.KSPTimeSpan that represents a specified number of milliseconds. + /// A number of milliseconds. + /// A KSPPluginFramework.KSPTimeSpan that represents value. + public static KSPTimeSpan FromMilliseconds(Double value) + { + return new KSPTimeSpan(value / 1000); + } + + #endregion + + + #region Operators + /// Subtracts a specified KSPPluginFramework.KSPTimeSpan from another specified KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// A TimeSpan whose value is the result of the value of t1 minus the value of t2. + public static KSPTimeSpan operator -(KSPTimeSpan t1, KSPTimeSpan t2) + { + return new KSPTimeSpan(t1.UT - t2.UT); + } + /// Returns a KSPPluginFramework.KSPTimeSpan whose value is the negated value of the specified instance. + /// A KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan with the same numeric value as this instance, but the opposite sign. + public static KSPTimeSpan operator -(KSPTimeSpan t) + { + return new KSPTimeSpan(t.UT).Negate(); + } + /// Adds two specified KSPPluginFramework.KSPTimeSpan instances. + /// A KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan whose value is the sum of the values of t1 and t2. + public static KSPTimeSpan operator +(KSPTimeSpan t1, KSPTimeSpan t2) + { + return new KSPTimeSpan(t1.UT + t2.UT); + } + /// Returns the specified instance of KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// Returns t. + public static KSPTimeSpan operator +(KSPTimeSpan t) + { + return new KSPTimeSpan(t.UT); + } + + /// Indicates whether two KSPPluginFramework.KSPTimeSpan instances are not equal. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// true if the values of t1 and t2 are not equal; otherwise, false. + public static Boolean operator !=(KSPTimeSpan t1, KSPTimeSpan t2) + { + return !(t1 == t2); + } + /// Indicates whether two KSPPluginFramework.KSPTimeSpan instances are equal. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// true if the values of t1 and t2 are equal; otherwise, false. + public static Boolean operator ==(KSPTimeSpan t1, KSPTimeSpan t2) + { + return t1.UT == t2.UT; + } + + + + /// Indicates whether a specified KSPPluginFramework.KSPTimeSpan is less than another specified KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// true if the value of t1 is less than the value of t2; otherwise, false. + public static Boolean operator <=(KSPTimeSpan t1, KSPTimeSpan t2) + { + return t1.CompareTo(t2) <= 0; + } + /// Indicates whether a specified KSPPluginFramework.KSPTimeSpan is less than or equal to another specified KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// true if the value of t1 is less than or equal to the value of t2; otherwise, false. + public static Boolean operator <(KSPTimeSpan t1, KSPTimeSpan t2) + { + return t1.CompareTo(t2) < 0; + } + /// Indicates whether a specified KSPPluginFramework.KSPTimeSpan is greater than or equal to another specified KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// true if the value of t1 is greater than or equal to the value of t2; otherwise, false. + public static Boolean operator >=(KSPTimeSpan t1, KSPTimeSpan t2) + { + return t1.CompareTo(t2) >= 0; + } + /// Indicates whether a specified KSPPluginFramework.KSPTimeSpan is greater than another specified KSPPluginFramework.KSPTimeSpan. + /// A KSPPluginFramework.KSPTimeSpan. + /// A TimeSpan. + /// true if the value of t1 is greater than the value of t2; otherwise, false. + public static Boolean operator >(KSPTimeSpan t1, KSPTimeSpan t2) + { + return t1.CompareTo(t2) > 0; + } + #endregion + } + + /// + /// Enum of standardised outputs for Timespans as strings + /// + public enum TimeSpanStringFormatsEnum + { + TimeAsUT, + KSPFormat, + IntervalLong, + IntervalLongTrimYears, + DateTimeFormat + } +} \ No newline at end of file diff --git a/KSPCasher/KSPCasher.cs b/KSPCasher/KSPCasher.cs index 61d968d..0f8afbc 100644 --- a/KSPCasher/KSPCasher.cs +++ b/KSPCasher/KSPCasher.cs @@ -3,8 +3,10 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using KSPPluginFramework; using UnityEngine; +using KSP.UI.Screens; namespace KSPCasher { @@ -15,7 +17,10 @@ public override void OnSave(ConfigNode node) base.OnSave(node); ConfigNode n = new ConfigNode("KSPCasher"); - n.SetValue("LastBudget", KSPCasher.instance.LastBudget.ToString()); + n.SetValue("LastBudget", KSPCasher.instance.LastBudget); + n.SetValue("Multiplier", KSPCasher.BudgetMultiplier.ToString()); + n.SetValue("SciBuy", KSPCasher.ScienceBuyMultiplier.ToString()); + n.SetValue("SciSell", KSPCasher.ScienceSellMultiplier.ToString()); node.AddNode(n); } @@ -24,10 +29,25 @@ public override void OnLoad(ConfigNode node) base.OnLoad(node); var n = node.GetNode("KSPCasher"); - string lb = n.GetValue("LastBudget"); - if (n != null && lb != null) - KSPCasher.instance.LastBudget = double.Parse(lb); - + + if (n != null) + { + string param = n.GetValue("LastBudget"); + if(param != null) + KSPCasher.instance.LastBudget = param; + + param = n.GetValue("Multiplier"); + if (param != null) + KSPCasher.BudgetMultiplier = double.Parse(param); + + param = n.GetValue("SciBuy"); + if (param != null) + KSPCasher.ScienceBuyMultiplier = double.Parse(param); + + param = n.GetValue("SciSell"); + if (param != null) + KSPCasher.ScienceSellMultiplier = double.Parse(param); + } } } @@ -50,43 +70,31 @@ public class CasherTS : KSPCasher public class CasherEditor : KSPCasher { } - - + + public class KSPCasher : MonoBehaviour { public static KSPCasher instance; - internal KSPCasher() - { - instance = this; - } + ApplicationLauncherButton ToolbarButton; - public void TechDisableEvent() - { - Log("Giving back " +giveBack.ToString() + " sci"); - ResearchAndDevelopment.Instance.AddScience(giveBack,TransactionReasons.None); - giveBack = 0; - foreach (RDTech item in relock) - { - ProtoTechNode protoNode = ResearchAndDevelopment.Instance.GetTechState(item.techID); - protoNode.state = RDTech.State.Unavailable; - ResearchAndDevelopment.Instance.SetTechState(item.techID, protoNode); - } - relock.Clear(); - Save(); - } + public static double BudgetMultiplier = 10; + public static double ScienceBuyMultiplier = 10000; + public static double ScienceSellMultiplier = 10000; - private void Save() + private bool CasherDebug = true; + + internal KSPCasher() { - GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE); + instance = this; } - static IEnumerable techConfigs; - public void Start() { GameEvents.OnTechnologyResearched.Add(TechUnlockEvent); GameEvents.onGUIRnDComplexDespawn.Add(TechDisableEvent); + GameEvents.onGUIRnDComplexSpawn.Add(HideGUI); + GameEvents.onGUIApplicationLauncherReady.Add(OnGUIApplicationLauncherReady); var game = HighLogic.CurrentGame; ProtoScenarioModule psm = game.scenarios.Find(s => s.moduleName == typeof(KSPCasherData).Name); @@ -96,47 +104,271 @@ public void Start() } } - public void OnDestroy() + public void OnDisable() { GameEvents.OnTechnologyResearched.Remove(TechUnlockEvent); GameEvents.onGUIRnDComplexDespawn.Remove(TechDisableEvent); + GameEvents.onGUIRnDComplexSpawn.Remove(HideGUI); + GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIApplicationLauncherReady); + ApplicationLauncher.Instance.RemoveModApplication(ToolbarButton); + GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIApplicationLauncherReady); } - public double LastBudget = 0; - public List BudgetsDone = new List(); + #region GUI + private bool stylesSetup = false; + private Rect windowPos = new Rect(580f, 40f, 1f, 1f); + private bool ShowSettings = false; + private bool ShowGUI = false; + private static GUIStyle headerText; + private static GUIStyle bigHeaderText; + private static GUIStyle normalText; - public void Update() + private void SetupStyles() + { + stylesSetup = true; + + headerText = new GUIStyle(GUI.skin.label); + headerText.normal.textColor = Color.white; + headerText.fontStyle = FontStyle.Bold; + headerText.alignment = TextAnchor.MiddleLeft; + + bigHeaderText = new GUIStyle(GUI.skin.label); + bigHeaderText.normal.textColor = Color.white; + bigHeaderText.fontSize = 18; + bigHeaderText.fontStyle = FontStyle.Bold; + bigHeaderText.alignment = TextAnchor.MiddleCenter; + + normalText = new GUIStyle(GUI.skin.label); + normalText.normal.textColor = Color.white; + normalText.fontStyle = FontStyle.Normal; + normalText.alignment = TextAnchor.MiddleLeft; + } + + private void OnGUIApplicationLauncherReady() + { + if (ToolbarButton == null) + { + ToolbarButton = ApplicationLauncher.Instance.AddModApplication(GUISwitch, GUISwitch, null, null, null, null, ApplicationLauncher.AppScenes.SPACECENTER, + GameDatabase.Instance.GetTexture("KSPCasher/Icon", false)); + } + } + + public void HideGUI() { + ShowGUI = false; + } + + public void GUISwitch() + { + if (ShowGUI == false) + { + ShowGUI = true; + } + else + { + ShowGUI = !ShowGUI; + } + } + + //OnDraw Shows the MainGUI Window + private void OnGUI() + { + GUI.skin.window.richText = true; + if (ShowGUI == true) + { + if (!stylesSetup) + { + SetupStyles(); + } + + GUI.skin = HighLogic.Skin; + + windowPos.xMin = Screen.width - 336 - 14; + windowPos.yMin = Screen.height - windowPos.height - 40f; + windowPos.yMax = Screen.height - 40f; + windowPos = GUILayout.Window( + typeof(KSPCasher).FullName.GetHashCode(), + windowPos, + MainGUI, + "KSP-Casher"); + + GUI.depth = 0; + } + } + + //MainGUI Window Content + private void MainGUI(int WindowID) + { + double budget = (Reputation.Instance.reputation * BudgetMultiplier); + double bonus = (ResearchAndDevelopment.Instance.Science * ScienceSellMultiplier); + double time = Planetarium.GetUniversalTime(); - double since = time - LastBudget; - if(since > 21600) { - Log("Doing budget " + time.ToString()); - LastBudget = time; + KSPDateTime dt = new KSPDateTime(time); + KSPDateTime next = dt.AddDays(1); + next = next.AddHours(4-next.Hour); + next = next.AddMinutes(-next.Minute); + next = next.AddSeconds(-next.Second); + + KSPDateTime span = next.Subtract(dt); + GUILayout.BeginVertical(GUILayout.Width(300), GUILayout.ExpandWidth(false)); + + if (ShowSettings) + { + GUILayout.BeginHorizontal(); + GUILayout.Label("Budget Multiplier", headerText, GUILayout.Width(150)); + string text = GUILayout.TextField(BudgetMultiplier.ToString()); + int temp = 0; + if (int.TryParse(text, out temp)) + { + BudgetMultiplier = Mathf.Clamp(temp,0,1000000); + } + else if (text == "") BudgetMultiplier = 10; + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Science Bonus", headerText, GUILayout.Width(150)); + text = GUILayout.TextField(ScienceSellMultiplier.ToString()); + temp = 0; + if (int.TryParse(text, out temp)) + { + ScienceSellMultiplier = Mathf.Clamp(temp, 0, 1000000); + } + else if (text == "") ScienceSellMultiplier = 10000; + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Tech Multiplier", headerText, GUILayout.Width(150)); + text = GUILayout.TextField(ScienceBuyMultiplier.ToString()); + temp = 0; + if (int.TryParse(text, out temp)) + { + ScienceBuyMultiplier = Mathf.Clamp(temp, 0, 1000000); + } + else if (text == "") ScienceBuyMultiplier = 10000; + GUILayout.EndHorizontal(); + + if (GUILayout.Button("< Back")) + { + ShowSettings = false; + } + } + else + { + GUILayout.BeginHorizontal(); + GUILayout.Label("Next Budget", headerText, GUILayout.Width(100)); + GUILayout.Label(budget.ToString("C"), normalText); + if (GUILayout.Button("$", GUILayout.Width(20), GUILayout.ExpandHeight(false))) + { + ShowSettings = true; + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Due In", headerText, GUILayout.Width(100)); + GUILayout.Label(span.ToString("H\\h m\\m s\\s"), normalText); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.Label("Science Bonus", headerText, GUILayout.Width(100)); + GUILayout.Label(bonus.ToString("C"), normalText); + GUILayout.EndHorizontal(); + + GUILayout.Label("Cash out science", bigHeaderText); + + GUILayout.BeginHorizontal(); + if (GUILayout.Button("1")) + { + CashOutScience(1); + } + if (GUILayout.Button("10")) + { + CashOutScience(10); + } + if (GUILayout.Button("100")) + { + CashOutScience(100); + } + GUILayout.EndHorizontal(); + + if (GUILayout.Button("All")) + { + CashOutScience(ResearchAndDevelopment.Instance.Science); + } + } + + GUILayout.EndVertical(); + + } + + #endregion + - double budget = (Reputation.Instance.reputation * 10); + + public void TechDisableEvent() + { + Log("Giving back " +giveBack.ToString() + " sci"); + ResearchAndDevelopment.Instance.AddScience(giveBack,TransactionReasons.None); + giveBack = 0; + foreach (RDTech item in relock) + { + ProtoTechNode protoNode = ResearchAndDevelopment.Instance.GetTechState(item.techID); + protoNode.state = RDTech.State.Unavailable; + ResearchAndDevelopment.Instance.SetTechState(item.techID, protoNode); + } + relock.Clear(); + Save(); + } + + private void Save() + { + GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE); + } + + public string LastBudget = ""; + + public void Update() + { + if (BudgetMultiplier <= 0 || BudgetMultiplier > 1000000) return; //overflow protection + + double time = Planetarium.GetUniversalTime(); + KSPDateTime dt = new KSPDateTime(time); + if (dt.Hour != 4) return; //We do budgets at 4am (so you can warp to next morning for it) + string budgetCode = dt.Year.ToString() + dt.Month.ToString() + dt.Day.ToString(); + + if(budgetCode != LastBudget) { + Log("Doing budget " + budgetCode); + LastBudget = budgetCode; + if (CasherDebug) + ScreenMessages.PostScreenMessage("[Casher] " + budgetCode); + double budget = (Reputation.Instance.reputation * BudgetMultiplier); if (budget > 0) { - ScreenMessages.PostScreenMessage("[Casher] Budget Receieved: " + budget.ToString("C")); + ScreenMessages.PostScreenMessage("[Casher] Budget received: " + budget.ToString("C")); Funding.Instance.AddFunds(budget, TransactionReasons.None); }else { - ScreenMessages.PostScreenMessage("[Casher] No Budget Receieved, you need to work on your reputation."); - } + ScreenMessages.PostScreenMessage("[Casher] No budget received, you need to work on your reputation."); + } + } + } - double bonus = (double)ResearchAndDevelopment.Instance.Science * 10000; - if(bonus > 0) - { - ScreenMessages.PostScreenMessage("[Casher] Science Bonus: " + bonus.ToString("C")); - Funding.Instance.AddFunds(bonus, TransactionReasons.None); - //And take the science - ResearchAndDevelopment.Instance.AddScience(-ResearchAndDevelopment.Instance.Science, TransactionReasons.None); - } + private void CashOutScience(float amt) + { + if (ResearchAndDevelopment.Instance.Science < amt) amt = ResearchAndDevelopment.Instance.Science; + double bonus = (double)amt * ScienceSellMultiplier; + if (bonus > 0) + { + ScreenMessages.PostScreenMessage("[Casher] Science Bonus: " + bonus.ToString("C")); + Funding.Instance.AddFunds(bonus, TransactionReasons.None); + //And take the science + ResearchAndDevelopment.Instance.AddScience(-amt, TransactionReasons.None); } } private void Log(string msg) { - //Debug.Log("[Casher] " + msg); + if(CasherDebug) + Debug.Log("[Casher] " + msg); } int giveBack = 0; List relock = new List(); diff --git a/KSPCasher/KSPCasher.csproj b/KSPCasher/KSPCasher.csproj index b898aa6..cb78ffe 100644 --- a/KSPCasher/KSPCasher.csproj +++ b/KSPCasher/KSPCasher.csproj @@ -49,7 +49,11 @@ + + + + diff --git a/KSPCasher/Properties/AssemblyInfo.cs b/KSPCasher/Properties/AssemblyInfo.cs index 3190201..f56ecc0 100644 --- a/KSPCasher/Properties/AssemblyInfo.cs +++ b/KSPCasher/Properties/AssemblyInfo.cs @@ -5,10 +5,10 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("KSP-CashER")] +[assembly: AssemblyTitle("KSP-Casher")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("astat")] [assembly: AssemblyProduct("KSP-CashER")] [assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyTrademark("")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.0.2.0")] +[assembly: AssemblyFileVersion("0.0.0.0")]