diff --git a/DLL_Project/CommunityCoreLibrary.csproj b/DLL_Project/CommunityCoreLibrary.csproj index 4e85fcf..169b8bc 100644 --- a/DLL_Project/CommunityCoreLibrary.csproj +++ b/DLL_Project/CommunityCoreLibrary.csproj @@ -1,266 +1,257 @@ - - - - - Debug - AnyCPU - {A36BEEB2-7379-475B-B537-827E34571962} - Library - Properties - CommunityCoreLibrary - 512 - - 0.12.7 - v3.5 - Community Core Library - - - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - true - - - true - bin\Release\ - RELEASE;TRACE - prompt - 4 - true - - - false - bin\Debug - 4 - true - true - TRACE;DEBUG;DEVELOPER - - - - Source-DLLs\Assembly-CSharp.dll - False - - - - - - - - - Source-DLLs\UnityEngine.dll - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - call "$(ProjectDir)PostBuild.bat" $(ConfigurationName) "$(TargetPath)" $(SolutionDir) - - - - + + + + + Debug + AnyCPU + {A36BEEB2-7379-475B-B537-827E34571962} + Library + Properties + CommunityCoreLibrary + 512 + + 0.12.7 + v3.5 + Community Core Library + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + true + + + true + bin\Release\ + RELEASE;TRACE + prompt + 4 + true + + + false + bin\Debug + 4 + true + true + TRACE;DEBUG;DEVELOPER + + + + Source-DLLs\Assembly-CSharp.dll + False + + + + + + + + + Source-DLLs\UnityEngine.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + call "$(ProjectDir)PostBuild.bat" $(ConfigurationName) "$(TargetPath)" $(SolutionDir) + + + + \ No newline at end of file diff --git a/DLL_Project/Extensions/ResearchProjectDef_Extensions.cs b/DLL_Project/Extensions/ResearchProjectDef_Extensions.cs index f1a29f4..4ccdc9e 100644 --- a/DLL_Project/Extensions/ResearchProjectDef_Extensions.cs +++ b/DLL_Project/Extensions/ResearchProjectDef_Extensions.cs @@ -1,16 +1,13 @@ -using CommunityCoreLibrary.ResearchTree; -using System; +using System; using System.Collections.Generic; using System.Linq; using Verse; namespace CommunityCoreLibrary { - [StaticConstructorOnStartup] public static class ResearchProjectDef_Extensions { - #region Static Data private static Dictionary isLockedOut; @@ -21,10 +18,9 @@ static ResearchProjectDef_Extensions() { isLockedOut = new Dictionary(); _unlocksCache = new Dictionary>>(); - } - #endregion + #endregion Static Data #region Availability @@ -42,7 +38,7 @@ public static bool IsLockedOut( this ResearchProjectDef researchProjectDef ) internal static bool _IsLockedOut( this ResearchProjectDef researchProjectDef, ResearchProjectDef initialDef ) { bool rVal = false; - if( !isLockedOut.TryGetValue( researchProjectDef.shortHash, out rVal ) ) + if ( !isLockedOut.TryGetValue( researchProjectDef.shortHash, out rVal ) ) { #if DEBUG CCL_Log.TraceMod( @@ -107,7 +103,7 @@ public static bool HasResearchRequirement( this ResearchProjectDef researchProje ) ); } - #endregion + #endregion Availability #region Lists of affected data @@ -199,11 +195,6 @@ public static List> GetUnlockDefsAndDescs( this ResearchProjec return unlocks; } - public static Node Node( this ResearchProjectDef research ) - { - return ResearchTree.ResearchTree.Forest.FirstOrDefault( node => node.Research == research ); - } - public static List GetResearchRequirements( this ResearchProjectDef researchProjectDef ) { #if DEBUG @@ -314,8 +305,8 @@ public static List GetThingsUnlocked( this ResearchProjectDef research var thingsOn = new List(); var researchThings = DefDatabase.AllDefsListForReading.Where( t => ( ( !t.IsLockedOut() )&& - (t.GetResearchRequirements() != null) && - (t.GetResearchRequirements().Contains(researchProjectDef)) + ( t.GetResearchRequirements() != null ) && + ( t.GetResearchRequirements().Contains( researchProjectDef ) ) ) ).ToList(); if ( !researchThings.NullOrEmpty() ) @@ -357,7 +348,7 @@ public static List GetTerrainUnlocked( this ResearchProjectDef resea var researchThings = DefDatabase.AllDefsListForReading.Where( t => ( ( !t.IsLockedOut() )&& ( t.GetResearchRequirements() != null )&& - ( t.GetResearchRequirements().Contains(researchProjectDef)) + ( t.GetResearchRequirements().Contains( researchProjectDef ) ) ) ).ToList(); if ( !researchThings.NullOrEmpty() ) @@ -389,7 +380,7 @@ public static List GetRecipesUnlocked( this ResearchProjectDef resear ( d.researchPrerequisite == researchProjectDef ) ) ).ToList(); - if( !researchRecipes.NullOrEmpty() ) + if ( !researchRecipes.NullOrEmpty() ) { recipes.AddRangeUnique( researchRecipes ); } @@ -397,9 +388,9 @@ public static List GetRecipesUnlocked( this ResearchProjectDef resear if ( thingDefs != null ) { // Add buildings for those recipes - foreach( var r in recipes ) + foreach ( var r in recipes ) { - if( !r.recipeUsers.NullOrEmpty() ) + if ( !r.recipeUsers.NullOrEmpty() ) { thingDefs.AddRangeUnique( r.recipeUsers ); } @@ -407,7 +398,7 @@ public static List GetRecipesUnlocked( this ResearchProjectDef resear ( !d.recipes.NullOrEmpty() )&& ( d.recipes.Contains( r ) ) ) ).ToList(); - if( !recipeThings.NullOrEmpty() ) + if ( !recipeThings.NullOrEmpty() ) { thingDefs.AddRangeUnique( recipeThings ); } @@ -423,12 +414,12 @@ public static List GetRecipesUnlocked( this ResearchProjectDef resear ) ).ToList(); // Aggregate research - if( !advancedResearch.NullOrEmpty() ) + if ( !advancedResearch.NullOrEmpty() ) { - foreach( var a in advancedResearch ) + foreach ( var a in advancedResearch ) { recipes.AddRangeUnique( a.recipeDefs ); - if( thingDefs != null ) + if ( thingDefs != null ) { thingDefs.AddRangeUnique( a.thingDefs ); } @@ -500,13 +491,13 @@ public static List GetSowTagsUnlocked( this ResearchProjectDef researchP ( d.plant.sowResearchPrerequisites.Contains( researchProjectDef ) ) ) ).ToList(); - if( !researchPlants.NullOrEmpty() ) + if ( !researchPlants.NullOrEmpty() ) { - foreach( var plant in researchPlants ) + foreach ( var plant in researchPlants ) { sowTags.AddRangeUnique( plant.plant.sowTags ); } - if( thingDefs != null ) + if ( thingDefs != null ) { thingDefs.AddRangeUnique( researchPlants ); } diff --git a/DLL_Project/MainTabs/MainTabWindow_Research.cs b/DLL_Project/MainTabs/MainTabWindow_Research.cs deleted file mode 100644 index 736154b..0000000 --- a/DLL_Project/MainTabs/MainTabWindow_Research.cs +++ /dev/null @@ -1,551 +0,0 @@ -using RimWorld; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using Verse; -using Verse.Sound; - -namespace CommunityCoreLibrary -{ - /// - /// This thing is broken. - Fluffy - /// This needs a complete re-do for A13. - 1000101 - /// - public class MainTabWindow_Research : MainTabWindow, IHelpDefView - { - // UI settings - private const float LeftAreaWidth = 330f; - - private const int ProjectIntervalY = 25; - private Vector2 _projectListScrollPosition = Vector2.zero; - private Vector2 _contentScrollPos = Vector2.zero; - private Vector2 _margin = new Vector2(6f, 6f); - private Vector2 _buttonSize = new Vector2(100f, 50f); - private float _contentHeight = 9999f; - - // Progress bar textures - private static readonly Texture2D BarFillTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.85f)); - - private static readonly Texture2D BarBgTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f)); - - // toggles and resources - private IEnumerable _researchDefs = DefDatabase.AllDefsListForReading.Where( rpd => rpd.GetHelpDef() != null); - - private IEnumerable _advancedHelpDefs = DefDatabase.AllDefsListForReading.Where(hd => hd.keyDef is AdvancedResearchDef); - private IEnumerable _source; - private SortOptions _sortBy = SortOptions.Cost; - private bool _asc = true; - private string _filter = ""; - private string _oldFilter; - protected HelpDef SelectedProject; - private ShowResearch _showResearchedProjects = ShowResearch.Available; - private bool _noBenchWarned; - - // enums - private enum ShowResearch - { - All, - Completed, - Available, - Advanced - } - - public enum SortOptions - { - Name, - Cost - } - - public override float TabButtonBarPercent - { - get - { - ResearchProjectDef currentProj = Find.ResearchManager.currentProj; - if ( currentProj == null ) - { - return 0f; - } - return currentProj.PercentComplete; - } - } - - private List _sourceTabs; - - // The tab definitions for the research lists. - private List SourceTabs - { - get - { - if ( _sourceTabs == null ) - { - _sourceTabs = new List(); - TabRecord item = new TabRecord( "RI.All".Translate(), delegate - { - this._showResearchedProjects = ShowResearch.All; - RefreshSource(); - }, _showResearchedProjects == ShowResearch.All ); - _sourceTabs.Add( item ); - - TabRecord item2 = new TabRecord( "Researched".Translate(), delegate - { - this._showResearchedProjects = ShowResearch.Completed; - RefreshSource(); - }, _showResearchedProjects == ShowResearch.Completed ); - _sourceTabs.Add( item2 ); - - TabRecord item3 = new TabRecord( "RI.Available".Translate(), delegate - { - this._showResearchedProjects = ShowResearch.Available; - RefreshSource(); - }, _showResearchedProjects == ShowResearch.Available ); - _sourceTabs.Add( item3 ); - - // Add Advanced Research tab if there are any helpdefs for it. - // This ensures we don't grab any that didn't pass the 'relevancy' check. - if ( DefDatabase.AllDefsListForReading.Any( hd => hd.keyDef is AdvancedResearchDef ) ) - { - TabRecord AR = new TabRecord( "AutoHelpSubCategoryAdvanced".Translate(), delegate - { - _showResearchedProjects = ShowResearch.Advanced; - RefreshSource(); - }, _showResearchedProjects == ShowResearch.Advanced ); - _sourceTabs.Add( AR ); - } - } - - return _sourceTabs; - } - } - - public override void PreOpen() - { - base.PreOpen(); - if( Find.ResearchManager.currentProj != null ) - { - SelectedProject = Find.ResearchManager.currentProj.GetHelpDef(); - } - _filter = ""; - _oldFilter = ""; - RefreshSource(); - MainTabWindow_ModHelp.Recache(); - } - - public override void DoWindowContents( Rect inRect ) - { - base.DoWindowContents( inRect ); - - // warn the player if no research bench is built - if ( !_noBenchWarned ) - { - if ( !Find.ListerBuildings.allBuildingsColonist.Any( b => ( - ( b.def.thingClass == typeof( Building_ResearchBench ) )|| - ( b.def.thingClass.IsSubclassOf( typeof( Building_ResearchBench ) ) ) - ) ) ) - { - Find.WindowStack.Add( new Dialog_Message( "ResearchMenuWithoutBench".Translate() ) ); - } - _noBenchWarned = true; - } - - // Title - Text.Font = GameFont.Medium; - Text.Anchor = TextAnchor.UpperCenter; - Widgets.Label( new Rect( 0f, 0f, inRect.width, 300f ), "Research".Translate() ); - Text.Anchor = TextAnchor.UpperLeft; - Text.Font = GameFont.Small; - - // create content areas - Rect sidebar = new Rect( 0f, 75f, LeftAreaWidth, inRect.height - 75f ); - Rect content = new Rect( sidebar.xMax + _margin.x, 45f, inRect.width - sidebar.width - _margin.x, inRect.height - 45f ); - - // draw boxes around content areas - Widgets.DrawMenuSection( sidebar, false ); - Widgets.DrawMenuSection( content ); - - // plop in extra row for input + sort buttons - // set up rects - Rect sortFilterRow = sidebar.ContractedBy( 10f ); - sortFilterRow.height = 30f; - Rect filterRect = new Rect( sortFilterRow ); - filterRect.width = sortFilterRow.width - 110f; - Rect deleteFilter = new Rect( filterRect.xMax + _margin.x, filterRect.yMin + 3f, 24f, 24f ); - Rect sortByName = new Rect( deleteFilter.xMax + _margin.x, filterRect.yMin + 3f, 24f, 24f ); - Rect sortByCost = new Rect( sortByName.xMax + _margin.x, filterRect.yMin + 3f, 24f, 24f ); - - // tooltips - TooltipHandler.TipRegion( filterRect, "RI.filterTooltip".Translate() ); - if ( _filter != "" ) - { - TooltipHandler.TipRegion( deleteFilter, "RI.deleteFilterTooltip".Translate() ); - } - TooltipHandler.TipRegion( sortByName, "RI.sortByNameTooltip".Translate() ); - TooltipHandler.TipRegion( sortByCost, "RI.sortByCostTooltip".Translate() ); - - // filter input, update in realtime - it's not a very expensive op, and we're paused anyway. - _filter = Widgets.TextField( filterRect, _filter ); - if ( _oldFilter != _filter ) - { - _oldFilter = _filter; - RefreshSource(); - } - if ( _filter != "" ) - { - if ( Widgets.ImageButton( deleteFilter, Widgets.CheckboxOffTex ) ) - { - _filter = ""; - RefreshSource(); - } - } - - // sort options - if ( Widgets.ImageButton( sortByName, Icon.SortByName ) ) - { - if ( _sortBy != SortOptions.Name ) - { - _sortBy = SortOptions.Name; - _asc = false; - RefreshSource(); - } - else - { - _asc = !_asc; - RefreshSource(); - } - } - if ( Widgets.ImageButton( sortByCost, Icon.SortByCost ) ) - { - if ( _sortBy != SortOptions.Cost ) - { - _sortBy = SortOptions.Cost; - _asc = true; - RefreshSource(); - } - else - { - _asc = !_asc; - RefreshSource(); - } - } - - // contract sidebar area for margins, bump down to compensate for filter. - Rect sidebarInner = sidebar.ContractedBy( 10f ); - sidebarInner.yMin += ProjectIntervalY + _margin.y; - sidebarInner.height -= ProjectIntervalY + _margin.y; - - // set height - float height = ProjectIntervalY * _source.Count(); - - // begin scrollview and group - Rect sidebarContent = new Rect( 0f, 0f, sidebarInner.width - 16f, height ); - Widgets.BeginScrollView( sidebarInner, ref _projectListScrollPosition, sidebarContent ); - Rect position = sidebarContent.ContractedBy( _margin.x ); - GUI.BeginGroup( position ); - - // Draw the list of researches in the source chosen. - int curY = 0; - - foreach ( HelpDef current in from rp in _source - select rp ) - { - Rect sidebarRow = new Rect( 0f, curY, position.width, ProjectIntervalY ); - DrawResearchRow( current, sidebarRow ); - curY += ProjectIntervalY; - } - GUI.EndGroup(); - Widgets.EndScrollView(); - - // Draw the source selection tabs. - TabDrawer.DrawTabs( sidebar, SourceTabs ); - - // Draw the content area. - DrawResearchContent( content ); - } - - private void DrawResearchContent( Rect rect ) - { - if ( SelectedProject == null ) - { - return; - } - - // Set up rects - Rect titleRect = new Rect( rect.xMin, rect.yMin, rect.width, 60f ); - Rect descRect = rect.ContractedBy( _margin.x * 2 ); - descRect.yMin = titleRect.yMax; - descRect.yMax -= _buttonSize.y * 2 + _margin.y * 2; - Rect controlRect = rect.ContractedBy( _margin.x * 2 ); - controlRect.yMin = descRect.yMax + _margin.y; - - // description - float paragraphMargin = 8f; - - Text.Font = GameFont.Medium; - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( titleRect, SelectedProject.LabelCap ); - Text.Font = GameFont.Small; - Text.Anchor = TextAnchor.UpperLeft; - - Rect viewRect = descRect; - viewRect.width -= 16f; - viewRect.height = _contentHeight; - - Widgets.BeginScrollView( descRect, ref _contentScrollPos, viewRect.AtZero() ); - - Vector2 cur = Vector2.zero; - - HelpDetailSectionHelper.DrawText( ref cur, viewRect.width - cur.x, SelectedProject.description ); - - cur.y += paragraphMargin; - - foreach ( HelpDetailSection section in SelectedProject.HelpDetailSections ) - { - section.Draw( ref cur, viewRect.width, this ); - } - - _contentHeight = cur.y; - - Widgets.EndScrollView(); - - // controls - GUI.BeginGroup( controlRect ); - Rect buttonRect = new Rect( controlRect.width / 2f - _buttonSize.x / 2, 0f, _buttonSize.x, _buttonSize.y ); - - Def selectedProjectDef = SelectedProject.keyDef; - - // regular research - if ( selectedProjectDef is ResearchProjectDef ) - { - ResearchProjectDef selectedResearchProjectDef = (ResearchProjectDef)selectedProjectDef; - if ( selectedResearchProjectDef.IsFinished ) - { - Widgets.DrawMenuSection( buttonRect ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( buttonRect, "Finished".Translate() ); - Text.Anchor = TextAnchor.UpperLeft; - } - else if ( selectedResearchProjectDef == Find.ResearchManager.currentProj ) - { - Widgets.DrawMenuSection( buttonRect ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( buttonRect, "InProgress".Translate() ); - Text.Anchor = TextAnchor.UpperLeft; - } - else if ( !selectedResearchProjectDef.ResearchPrereqsFulfilled ) - { - Widgets.DrawMenuSection( buttonRect ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( buttonRect, "RI.PreReqLocked".Translate() ); - Text.Anchor = TextAnchor.UpperLeft; - } - else - { - if ( Widgets.TextButton( buttonRect, "Research".Translate() ) ) - { - SoundDef.Named( "ResearchStart" ).PlayOneShotOnCamera(); - Find.ResearchManager.currentProj = selectedResearchProjectDef; - } - if ( Prefs.DevMode ) - { - Rect devButtonRect = buttonRect; - devButtonRect.x += devButtonRect.width + _margin.x; - if ( Widgets.TextButton( devButtonRect, "Debug Insta-finish" ) ) - { - Find.ResearchManager.currentProj = selectedResearchProjectDef; - Find.ResearchManager.InstantFinish( selectedResearchProjectDef ); - } - } - } - Rect progressRect = new Rect( _margin.x, _buttonSize.y + _margin.y, controlRect.width - 2 * _margin.x, _buttonSize.y ); - Widgets.FillableBar( progressRect, selectedResearchProjectDef.PercentComplete, BarFillTex, BarBgTex, true ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( progressRect, selectedResearchProjectDef.ProgressNumbersString ); - } - - // advanced research - if ( selectedProjectDef is AdvancedResearchDef ) - { - AdvancedResearchDef selectedAdvancedResearchDef = (AdvancedResearchDef)selectedProjectDef; - List prereqs = selectedAdvancedResearchDef.researchDefs; - - if ( selectedAdvancedResearchDef.IsFinished ) - { - Widgets.DrawMenuSection( buttonRect ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( buttonRect, "Finished".Translate() ); - Text.Anchor = TextAnchor.UpperLeft; - } - else if ( prereqs.Any( rd => rd.IsFinished ) ) - { - Widgets.DrawMenuSection( buttonRect ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( buttonRect, "InProgress".Translate() ); - Text.Anchor = TextAnchor.UpperLeft; - } - else if ( selectedAdvancedResearchDef.IsLockedOut() ) - { - Widgets.DrawMenuSection( buttonRect ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( buttonRect, "RI.PreReqLocked".Translate() ); - Text.Anchor = TextAnchor.UpperLeft; - } - - // progress, slightly different for advanced research def - Rect progressRect = new Rect( _margin.x, _buttonSize.y + _margin.y, controlRect.width - 2 * _margin.x, _buttonSize.y ); - float percentComplete = prereqs.Count( rd => rd.IsFinished ) / prereqs.Count; - Widgets.FillableBar( progressRect, percentComplete, BarFillTex, BarBgTex, true ); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( progressRect, prereqs.Count( rd => rd.IsFinished ) + " / " + prereqs.Count ); - } - - Text.Anchor = TextAnchor.UpperLeft; - GUI.EndGroup(); - } - - private void DrawResearchRow( HelpDef helpDef, Rect sidebarRow ) - { - if ( SelectedProject == helpDef ) - { - GUI.DrawTexture( sidebarRow, TexUI.HighlightTex ); - } - string text = helpDef.LabelCap; - - Def def = helpDef.keyDef; - - if ( def is ResearchProjectDef ) - { - text += " (" + ( (ResearchProjectDef)def ).totalCost.ToString( "F0" ) + ")"; - } - else if ( def is AdvancedResearchDef ) - { - text += " (" + ( (AdvancedResearchDef)def ).TotalCost.ToString( "F0" ) + ")"; - } -#if DEBUG - else - { - text += " (" + def.GetType() + ")"; - } -#endif - Rect sidebarRowInner = new Rect( sidebarRow ); - sidebarRowInner.x += 6f; - sidebarRowInner.width -= 6f; - float num2 = Text.CalcHeight( text, sidebarRowInner.width ); - if ( sidebarRowInner.height < num2 ) - { - sidebarRowInner.height = num2 + 3f; - } - // give the label a color if we're in the all tab. - Color textColor = new Color( .8f, .85f, 1f ); - ; - if ( def is ResearchProjectDef ) - { - if ( ( (ResearchProjectDef)def ).IsFinished ) - { - textColor = new Color( 1f, 1f, 1f ); - } - else if ( !( (ResearchProjectDef)def ).ResearchPrereqsFulfilled) - { - textColor = new Color( .6f, .6f, .6f ); - } - } - else if ( def is AdvancedResearchDef ) - { - if ( ( (AdvancedResearchDef)def ).IsFinished ) - { - textColor = new Color( 1f, 1f, 1f ); - } - else if ( ( (AdvancedResearchDef)def ).IsLockedOut() ) - { - textColor = new Color( .6f, .6f, .6f ); - } - } - - if ( Widgets.TextButton( sidebarRowInner, text, false, true, textColor ) ) - { - SoundDefOf.Click.PlayOneShotOnCamera(); - SelectedProject = helpDef; - } - } - - private void RefreshSource() - { - if ( _showResearchedProjects == ShowResearch.All ) - { - _source = from hd in _researchDefs - where !hd.prerequisites.Contains( hd ) && hd.GetHelpDef() != null - select hd.GetHelpDef(); - } - else if ( _showResearchedProjects == ShowResearch.Completed ) - { - _source = from hd in _researchDefs - where hd.IsFinished && hd.GetHelpDef() != null - select hd.GetHelpDef(); - } - else if ( _showResearchedProjects == ShowResearch.Available ) - { - _source = from hd in _researchDefs - where !hd.IsFinished && hd.ResearchPrereqsFulfilled && hd.GetHelpDef() != null - select hd.GetHelpDef(); - } - else if ( _showResearchedProjects == ShowResearch.Advanced ) - { - _source = from hd in _advancedHelpDefs - where hd.keyDef is AdvancedResearchDef - select hd; - } - - // just to make sure _source is a valid IEnumerable at this point - if ( _source == null ) - _source = new List(); - - if ( _filter != "" ) - { - _source = _source.Where( rpd => rpd.label.ToUpper().Contains( _filter.ToUpper() ) ); - } - - if ( _source.Count() > 2 ) - { - switch ( _sortBy ) - { - case SortOptions.Cost: - if ( _showResearchedProjects != ShowResearch.Advanced ) - { - _source = _source.OrderBy( hd => ( (ResearchProjectDef)hd.keyDef ).totalCost ); - } - else - { - _source = - _source.OrderBy( - hd => ( (AdvancedResearchDef)hd.keyDef ).TotalCost ); - } - break; - - case SortOptions.Name: - _source = _source.OrderBy( rpd => rpd.LabelCap ?? string.Empty ); - break; - } - - if ( _asc ) - _source = _source.Reverse(); - } - } - - public void JumpTo( HelpDef def ) - { - Find.MainTabsRoot.SetCurrentTab( this.def, false ); - _showResearchedProjects = ShowResearch.All; - RefreshSource(); - SelectedProject = def; - } - - public bool Accept( HelpDef def ) - { - return def.keyDef is ResearchProjectDef; - } - - public IHelpDefView SecondaryView( HelpDef def ) - { - MainTabDef helpTab = DefDatabase.GetNamed( "CCL_ModHelp", false ); - return helpTab.Window as MainTabWindow_ModHelp; - } - } -} \ No newline at end of file diff --git a/DLL_Project/MainTabs/MainTabWindow_ResearchTree.cs b/DLL_Project/MainTabs/MainTabWindow_ResearchTree.cs deleted file mode 100644 index b5e037f..0000000 --- a/DLL_Project/MainTabs/MainTabWindow_ResearchTree.cs +++ /dev/null @@ -1,173 +0,0 @@ -// ResearchTree/LogHeadDB.cs -// -// Copyright Karel Kroeze, 2015. -// -// Created 2015-12-21 13:30 - -using CommunityCoreLibrary; -using CommunityCoreLibrary.ResearchTree; -using RimWorld; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using UnityEngine; -using Verse; - -namespace CommunityCoreLibrary -{ - public class MainTabWindow_ResearchTree : MainTabWindow - { - #region Fields - - public static List> connections = new List>(); - public static List> highlightedConnections = new List>(); - public static Dictionary> hubTips = new Dictionary>(); - public static List nodes = new List(); - - internal static Vector2 _scrollPosition = Vector2.zero; - - #endregion Fields - - #region Properties - - public override float TabButtonBarPercent - { - get - { - if ( Find.ResearchManager.currentProj != null ) - { - return Find.ResearchManager.currentProj.PercentComplete; - } - return 0; - } - } - - #endregion Properties - - #region Methods - - public override void DoWindowContents( Rect canvas ) - { - PrepareTreeForDrawing(); - DrawTree( canvas ); - } - - public void DrawTree( Rect canvas ) - { - // get total size of Research Tree - int maxDepth = 0, totalWidth = 0; - - if ( ResearchTree.ResearchTree.Trees.Any() ) - { - maxDepth = ResearchTree.ResearchTree.Trees.Max( tree => tree.MaxDepth ); - totalWidth = ResearchTree.ResearchTree.Trees.Sum( tree => tree.Width ); - } - - maxDepth = Math.Max( maxDepth, ResearchTree.ResearchTree.Orphanage.MaxDepth ); - totalWidth += ResearchTree.ResearchTree.Orphanage.Width; - - float width = ( maxDepth + 1 ) * ( Settings.NodeSize.x + Settings.NodeMargins.x ); // zero based - float height = totalWidth * ( Settings.NodeSize.y + Settings.NodeMargins.y ); - - // main view rect - Rect view = new Rect( 0f, 0f, width, height ); - Widgets.BeginScrollView( canvas, ref _scrollPosition, view ); - GUI.BeginGroup( view ); - - Text.Anchor = TextAnchor.MiddleCenter; - - // draw regular connections, not done first to better highlight done. - foreach ( Pair connection in connections.Where( pair => !pair.Second.Research.IsFinished ) ) - { - ResearchTree.ResearchTree.DrawLine( connection, connection.First.Tree.GreyedColor ); - } - - // draw connections from completed nodes - foreach ( Pair connection in connections.Where( pair => pair.Second.Research.IsFinished ) ) - { - ResearchTree.ResearchTree.DrawLine( connection, connection.First.Tree.MediumColor ); - } - connections.Clear(); - - // draw highlight connections on top - foreach ( Pair connection in highlightedConnections ) - { - ResearchTree.ResearchTree.DrawLine( connection, GenUI.MouseoverColor, true ); - } - highlightedConnections.Clear(); - - // draw nodes on top of lines - foreach ( Node node in nodes ) - { - node.Draw(); - } - nodes.Clear(); - - // register hub tooltips - foreach ( KeyValuePair> pair in hubTips ) - { - string text = string.Join( "\n", pair.Value.ToArray() ); - TooltipHandler.TipRegion( pair.Key, text ); - } - hubTips.Clear(); - - // draw Queue labels - Queue.DrawLabels(); - - // reset anchor - Text.Anchor = TextAnchor.UpperLeft; - - GUI.EndGroup(); - Widgets.EndScrollView(); - } - - public override void PreOpen() - { - base.PreOpen(); - - if ( !ResearchTree.ResearchTree.Initialized ) - { - // initialize tree - ResearchTree.ResearchTree.Initialize(); - } - - // set to topleft (for some reason vanilla alignment overlaps bottom buttons). - currentWindowRect.x = 0f; - currentWindowRect.y = 0f; - currentWindowRect.width = Screen.width; - currentWindowRect.height = Screen.height - 35f; - } - - private void PrepareTreeForDrawing() - { - // loop through trees - foreach ( ResearchTree.Tree tree in ResearchTree.ResearchTree.Trees ) - { - foreach ( Node node in tree.Trunk.Concat( tree.Leaves ) ) - { - nodes.Add( node ); - - foreach ( Node parent in node.Parents ) - { - connections.Add( new Pair( node, parent ) ); - } - } - } - - // add orphans - foreach ( Node node in ResearchTree.ResearchTree.Orphanage.Leaves ) - { - nodes.Add( node ); - - foreach ( Node parent in node.Parents ) - { - connections.Add( new Pair( node, parent ) ); - } - } - } - - #endregion Methods - } -} \ No newline at end of file diff --git a/DLL_Project/ResearchTree/Detours.cs b/DLL_Project/ResearchTree/Detours.cs deleted file mode 100644 index 8196c4a..0000000 --- a/DLL_Project/ResearchTree/Detours.cs +++ /dev/null @@ -1,146 +0,0 @@ -using CommunityCoreLibrary; -using RimWorld; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; - -using UnityEngine; -using Verse; - -// ReSharper disable PossibleNullReferenceException -// reflection is dangerous - deal with it. Fluffy. - -// Fixed dangerous jump across instance classes. 1000101. - -namespace CommunityCoreLibrary.ResearchTree.Detour -{ - - internal static class _ResearchManager - { - - internal static FieldInfo __progress; - internal static FieldInfo __GlobalProgress; - - private static List storeQueue = null; - - internal static Dictionary _progress( this ResearchManager researchManager ) - { - if( __progress == null ) - { - __progress = typeof( ResearchManager ).GetField( "progress", BindingFlags.Instance | BindingFlags.NonPublic ); - } - return (Dictionary) __progress.GetValue( researchManager ); - } - - internal static float _GlobalProgress( this ResearchManager researchManager ) - { - if( __GlobalProgress == null ) - { - __GlobalProgress = typeof( ResearchManager ).GetField( "GlobalProgressFactor", BindingFlags.Instance | BindingFlags.NonPublic ); - } - return (float) __GlobalProgress.GetValue( researchManager ); - } - - /// - /// Override for Verse.ResearchMananager.MakeProgress - /// - /// Changes default pop-up when research is complete to an inbox message, and starts the next research in the queue - if available. - /// - /// - internal static void _MakeProgress( this ResearchManager researchManager, float amount ) - { - // get research manager instance - //ResearchManager researchManager = Find.ResearchManager; - - // get progress dictionary - var progress = researchManager._progress(); - - // get global progress constant - var globalProgressFactor = researchManager._GlobalProgress(); - - // make progress - if ( researchManager.currentProj == null ) - { - Log.Error( "Researched without having an active project." ); - } - else - { - amount *= globalProgressFactor; - if ( DebugSettings.fastResearch ) - { - amount *= 500f; - } - float curProgress = researchManager.ProgressOf( researchManager.currentProj ); - curProgress += amount; - progress[researchManager.currentProj] = curProgress; - - // do message if finished - if ( researchManager.currentProj.IsFinished ) - { - string label = "ResearchFinished".Translate( researchManager.currentProj.LabelCap ); - string text = "ResearchFinished".Translate( researchManager.currentProj.LabelCap ) + "\n\n" + researchManager.currentProj.DescriptionDiscovered; - - // remove from queue - Queue.Pop(); - - // if the completed research locks anything, notify it. - researchManager.currentProj.Node().Locks.ForEach( node => { node.Notify_LockedOut( true ); node.Notify_WillBeLockedOut( false ); } ); - - // if there's something on the queue start it, and push an appropriate message - if ( Queue.Count > 0 ) - { - researchManager.currentProj = Queue.First().Research; - text += "\n\nNext in queue: " + researchManager.currentProj.LabelCap; - Find.LetterStack.ReceiveLetter( label, text, LetterType.Good ); - } - else - { - researchManager.currentProj = null; - text += "\n\nNext in queue: none"; - Find.LetterStack.ReceiveLetter( label, text, LetterType.BadNonUrgent ); - } - - // apply research mods (Why this isn't being done in a targeted way I don't know, but it's core behaviour...) - researchManager.ReapplyAllMods(); - } - } - } - - internal static void _ExposeData( this ResearchManager researchManager ) - { - if( !ResearchTree.Initialized ) - { - // initialize tree - ResearchTree.Initialize(); - - } - - // get progress dictionary - var progress = researchManager._progress(); - - // Expose base data - Scribe_Defs.LookDef( ref researchManager.currentProj, "currentProj" ); - Scribe_Collections.LookDictionary( ref progress, "progress", LookMode.DefReference, LookMode.Value ); - - // Store research defs as these are the defining elements - if( Scribe.mode == LoadSaveMode.Saving ) - { - storeQueue = Queue.ToList(); - } - else if( storeQueue == null ) - { - storeQueue = new List(); - } - - Scribe_Collections.LookList( ref storeQueue, "Queue", LookMode.DefReference ); - - if( Scribe.mode == LoadSaveMode.PostLoadInit ) - { - Queue.FromList( storeQueue ); - } - } - - } - -} diff --git a/DLL_Project/ResearchTree/Node.cs b/DLL_Project/ResearchTree/Node.cs deleted file mode 100644 index 2d02549..0000000 --- a/DLL_Project/ResearchTree/Node.cs +++ /dev/null @@ -1,722 +0,0 @@ -// ResearchTree/Node.cs -// -// Copyright Karel Kroeze, 2015. -// -// Created 2015-12-28 17:55 - -using CommunityCoreLibrary; -using RimWorld; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using Verse; - -namespace CommunityCoreLibrary.ResearchTree -{ - public enum LockedState - { - notLockedOut, - willBeLockedOut, - LockedOut - } - - public class Node - { - #region Fields - - public List Children = new List(); - public int Depth; - public string Genus; - public List Locks = new List(); - public List Parents = new List(); - public IntVec2 Pos; - public ResearchProjectDef Research; - public Tree Tree; - - private const float LabSize = 30f; - private const float Offset = 2f; - - private static MainTabWindow_ModHelp _helpWindow = DefDatabase.GetNamed( "CCL_ModHelp", false ).Window as MainTabWindow_ModHelp; - - private bool _isLockedOut = false, - _willBeLockedOut = false; - - private bool _largeLabel = false; - private Vector2 _left = Vector2.zero; - - private Rect _queueRect, - _rect, - _labelRect, - _costLabelRect, - _costIconRect, - _iconsRect; - - private bool _rectSet; - private Vector2 _right = Vector2.zero; - - #endregion Fields - - #region Constructors - - public Node( ResearchProjectDef research ) - { - Research = research; - - // get the Genus, this is the research family name, and will be used to group research together. - // First see if we have a ":" in the name - List parts = research.LabelCap.Split( ":".ToCharArray() ).ToList(); - if ( parts.Count > 1 ) - { - Genus = parts.First(); - } - else - { - parts = research.LabelCap.Split( " ".ToCharArray() ).ToList(); - - // otherwise, strip the last word (intended to catch 1,2,3/ I,II,III,IV suffixes) - if ( parts.Count > 1 ) - { - parts.Remove( parts.Last() ); - } - Genus = string.Join( " ", parts.ToArray() ); - } - Parents = new List(); - Children = new List(); - } - - #endregion Constructors - - #region Properties - - public Rect CostIconRect - { - get - { - if ( !_rectSet ) - { - CreateRects(); - } - return _costIconRect; - } - } - - public Rect CostLabelRect - { - get - { - if ( !_rectSet ) - { - CreateRects(); - } - return _costLabelRect; - } - } - - public Rect IconsRect - { - get - { - if ( !_rectSet ) - { - CreateRects(); - } - return _iconsRect; - } - } - - public Rect LabelRect - { - get - { - if ( !_rectSet ) - { - CreateRects(); - } - return _labelRect; - } - } - - /// - /// Middle of left node edge - /// - public Vector2 Left - { - get - { - if ( _left == Vector2.zero ) - { - _left = new Vector2( Pos.x * ( Settings.NodeSize.x + Settings.NodeMargins.x ) + Offset, - Pos.z * ( Settings.NodeSize.y + Settings.NodeMargins.y ) + Offset + Settings.NodeSize.y / 2 ); - } - return _left; - } - } - - public LockedState LockedState - { - get - { - if ( _isLockedOut ) - return LockedState.LockedOut; - if ( _willBeLockedOut ) - return LockedState.willBeLockedOut; - return LockedState.notLockedOut; - } - } - - /// - /// Tag UI Rect - /// - public Rect QueueRect - { - get - { - if ( !_rectSet ) - { - CreateRects(); - } - return _queueRect; - } - } - - /// - /// Static UI rect for this node - /// - public Rect Rect - { - get - { - if ( !_rectSet ) - { - CreateRects(); - } - return _rect; - } - } - - /// - /// Middle of right node edge - /// - public Vector2 Right - { - get - { - if ( _right == Vector2.zero ) - { - _right = new Vector2( Pos.x * ( Settings.NodeSize.x + Settings.NodeMargins.x ) + Offset + Settings.NodeSize.x, - Pos.z * ( Settings.NodeSize.y + Settings.NodeMargins.y ) + Offset + Settings.NodeSize.y / 2 ); - } - return _right; - } - } - - #endregion Properties - - #region Methods - - /// - /// Determine the closest tree by moving along parents and then children until a tree has been found. Returns first tree encountered, or NULL. - /// - /// - public Tree ClosestTree() - { - // go up through all Parents until we find a parent that is in a Tree - Queue parents = new Queue(); - parents.Enqueue( this ); - - while ( parents.Count > 0 ) - { - Node current = parents.Dequeue(); - if ( current.Tree != null ) - { - return current.Tree; - } - - // otherwise queue up the Parents to be checked - foreach ( Node parent in current.Parents ) - { - parents.Enqueue( parent ); - } - } - - // if that didn't work, try seeing if a child is in a Tree (unlikely, but whateva). - Queue children = new Queue(); - children.Enqueue( this ); - - while ( children.Count > 0 ) - { - Node current = children.Dequeue(); - if ( current.Tree != null ) - { - return current.Tree; - } - - // otherwise queue up the Children to be checked. - foreach ( Node child in current.Children ) - { - children.Enqueue( child ); - } - } - - // finally, if nothing stuck, return null - return null; - } - - /// - /// Set all prerequisites as parents of this node, and for each parent set this node as a child. - /// - public void CreateLinks() - { - // 'vanilla' prerequisites - foreach ( ResearchProjectDef prerequisite in Research.prerequisites ) - { - if ( prerequisite != Research ) - { - var parent = ResearchTree.Forest.FirstOrDefault( node => node.Research == prerequisite ); - if ( parent != null ) - { - Parents.Add( parent ); - } - } - } - - // CCL advanced research, inclusive unlocks. - foreach ( AdvancedResearchDef ard in DefDatabase.AllDefsListForReading - .Where( ard => ard.IsResearchToggle && - !ard.HideDefs && - ard.effectedResearchDefs.Contains( Research ) ) ) - { - foreach ( ResearchProjectDef prerequisite in ard.researchDefs ) - { - if ( prerequisite != Research ) - { - var parent = ResearchTree.Forest.FirstOrDefault( node => node.Research == prerequisite ); - if ( parent != null ) - { - Parents.Add( parent ); - } - } - } - } - - // CCL advanced research, locks. - foreach ( AdvancedResearchDef ard in DefDatabase.AllDefsListForReading - .Where( ard => ard.IsResearchToggle && - ard.HideDefs && - ard.researchDefs.Contains( Research ) ) ) - { - foreach ( ResearchProjectDef locked in ard.effectedResearchDefs ) - { - if ( locked != Research ) - { - var lockedNode = ResearchTree.Forest.FirstOrDefault( node => node.Research == locked ); - if ( lockedNode != null ) - { - Locks.Add( lockedNode ); - } - } - } - } - - foreach ( Node parent in Parents ) - { - parent.Children.Add( this ); - } - } - -#if DEVELOPER - /// - /// Prints debug information. - /// - public string Debug() - { - StringBuilder text = new StringBuilder(); - text.AppendLine( Research.LabelCap + " (" + Depth + ", " + Genus + "):" ); - text.AppendLine( "- Parents" ); - foreach ( Node parent in Parents ) - { - text.AppendLine( "-- " + parent.Research.LabelCap ); - } - text.AppendLine( "- Children" ); - foreach ( Node child in Children ) - { - text.AppendLine( "-- " + child.Research.LabelCap ); - } - text.AppendLine( "" ); - return text.ToString(); - } -#endif - - /// - /// Draw the node, including interactions. - /// - public void Draw() - { - // set color - GUI.color = !Research.ResearchPrereqsFulfilled ? Tree.GreyedColor : Tree.MediumColor; - if ( LockedState == LockedState.LockedOut ) - GUI.color = new Color( .4f, .4f, .4f ); - bool prereqLocks = false; - - // cop out if off-screen - Rect screen = new Rect( MainTabWindow_ResearchTree._scrollPosition.x, MainTabWindow_ResearchTree._scrollPosition.y, Screen.width, Screen.height - 35 ); - if ( Rect.xMin > screen.xMax || - Rect.xMax < screen.xMin || - Rect.yMin > screen.yMax || - Rect.yMax < screen.yMin ) - { - return; - } - - // mouseover highlights - if ( Mouse.IsOver( Rect ) && LockedState != LockedState.LockedOut ) - { - // active button - GUI.DrawTexture( Rect, ResearchTree.ButtonActive ); - - // highlight this and all prerequisites if research not completed - if ( !Research.IsFinished ) - { - List prereqs = GetMissingRequiredRecursive(); - Highlight( GenUI.MouseoverColor, true, false ); - if ( !Locks.NullOrEmpty() ) - { - foreach ( Node locked in Locks ) - { - locked.Highlight( Color.red, false, true ); - } - } - foreach ( Node prerequisite in prereqs ) - { - prerequisite.Highlight( GenUI.MouseoverColor, true, false ); - if ( !prerequisite.Locks.NullOrEmpty() ) - { - prereqLocks = true; - foreach ( Node locked in prerequisite.Locks ) - { - locked.Highlight( Color.red, false, false ); - } - } - } - } - else // highlight followups - { - foreach ( Node child in Children ) - { - MainTabWindow_ResearchTree.highlightedConnections.Add( new Pair( this, child ) ); - child.Highlight( GenUI.MouseoverColor, false, false ); - - if ( !child.Locks.NullOrEmpty() ) - { - foreach ( Node locked in child.Locks ) - { - locked.Highlight( Color.red, false, false ); - } - } - } - } - } - // if not moused over, just draw the default button state - else - { - GUI.DrawTexture( Rect, ResearchTree.Button ); - } - - // grey out center to create a progress bar effect, completely greying out research not started. - if ( !Research.IsFinished && LockedState != LockedState.LockedOut ) - { - Rect progressBarRect = Rect.ContractedBy( 2f ); - GUI.color = Tree.GreyedColor; - progressBarRect.xMin += Research.PercentComplete * progressBarRect.width; - GUI.DrawTexture( progressBarRect, BaseContent.WhiteTex ); - } - - // draw the research label - GUI.color = Color.white; - Text.Anchor = TextAnchor.UpperLeft; - Text.WordWrap = false; - Text.Font = _largeLabel ? GameFont.Tiny : GameFont.Small; - Widgets.Label( LabelRect, Research.LabelCap ); - - // draw research cost and icon - Text.Anchor = TextAnchor.UpperRight; - Text.Font = GameFont.Small; - if ( LockedState == LockedState.LockedOut ) - { - Widgets.Label( CostLabelRect, "Fluffy.ResearchTree.LockedOut".Translate() ); - } - else - { - Widgets.Label( CostLabelRect, Research.totalCost.ToStringByStyle( ToStringStyle.Integer ) ); - GUI.DrawTexture( CostIconRect, ResearchTree.ResearchIcon ); - } - Text.WordWrap = true; - - // attach description and further info to a tooltip - TooltipHandler.TipRegion( Rect, GetResearchTooltipString() ); // new TipSignal( GetResearchTooltipString(), Settings.TipID ) ); - - // draw unlock icons - List> unlocks = Research.GetUnlockDefsAndDescs(); - for ( int i = 0; i < unlocks.Count; i++ ) - { - Rect iconRect = new Rect( IconsRect.xMax - ( i + 1 ) * ( Settings.IconSize.x + 4f ), - IconsRect.yMin + ( IconsRect.height - Settings.IconSize.y ) / 2f, - Settings.IconSize.x, - Settings.IconSize.y ); - - if ( iconRect.xMin - Settings.IconSize.x < IconsRect.xMin && - i + 1 < unlocks.Count ) - { - // stop the loop if we're about to overflow and have 2 or more unlocks yet to print. - iconRect.x = IconsRect.x + 4f; - ResearchTree.MoreIcon.DrawFittedIn( iconRect ); - string tip = string.Join( "\n", unlocks.GetRange( i, unlocks.Count - i ).Select( p => p.Second ).ToArray() ); - TooltipHandler.TipRegion( iconRect, tip ); // new TipSignal( tip, Settings.TipID, TooltipPriority.Pawn ) ); - break; - } - - // draw icon - unlocks[i].First.DrawColouredIcon( iconRect ); - - // tooltip - TooltipHandler.TipRegion( iconRect, unlocks[i].Second ); // new TipSignal( unlocks[i].Second, Settings.TipID, TooltipPriority.Pawn ) ); - } - - // draw a big warning label if about to be locked. - if ( LockedState == LockedState.willBeLockedOut ) - { - Color color = GUI.color; - GUI.color = Color.red; - GUI.DrawTexture( Rect, ResearchTree.WarningIcon, ScaleMode.ScaleToFit ); - GUI.color = color; - } - - // if clicked and not yet finished, queue up this research and all prereqs. - if ( LockedState != LockedState.LockedOut && Widgets.InvisibleButton( Rect ) ) - { - // LMB is queue operations, RMB is info - if ( Event.current.button == 0 && !Research.IsFinished ) - { - if ( !Queue.IsQueued( this ) ) - { - if ( prereqLocks ) - { - foreach ( Node node in GetMissingRequiredRecursive() ) - { - if ( !node.Locks.NullOrEmpty() && !( Event.current.shift && Queue.IsQueued( node ) ) ) - { - Messages.Message( "Fluffy.ResearchTree.CannotQueueXLocksY".Translate( node.Research.LabelCap, - string.Join( ", ", node.Locks.Select( n => n.Research.LabelCap ).ToArray() ) ) + " " + - "Fluffy.ResearchTree.CannotQueueOneByOne".Translate(), - MessageSound.RejectInput ); - return; - } - } - } - // if shift is held, add to queue, otherwise replace queue - Queue.EnqueueRange( GetMissingRequiredRecursive().Concat( new List( new[] { this } ) ), Event.current.shift ); - } - else - { - Queue.Dequeue( this ); - } - } - else if ( Event.current.button == 1 ) - { - // right click links to CCL help def. - _helpWindow.JumpTo( Research.GetHelpDef() ); - } - } - } - - /// - /// Get recursive list of all incomplete prerequisites - /// - /// List prerequisites - public List GetMissingRequiredRecursive() - { - List parents = new List( Parents.Where( node => !node.Research.IsFinished ) ); - List allParents = new List( parents ); - foreach ( Node current in parents ) - { - if ( current.LockedState != LockedState.LockedOut ) - { - // check advanced researches - List advancedResearches = Controller.Data.AdvancedResearchDefs.Where( ard => ( - ( ard.IsResearchToggle )&& - ( !ard.IsLockedOut() )&& - ( !ard.HideDefs )&& - ( ard.effectedResearchDefs.Contains( current.Research ) ) - ) ).ToList(); - - if ( !advancedResearches.NullOrEmpty() ) - { - Dictionary> options = new Dictionary>(); - foreach ( ResearchProjectDef option in advancedResearches.SelectMany( ard => ard.researchDefs ).Where( rd => rd.Node() != null ) ) - { - options.Add( option.Node(), option.Node().GetMissingRequiredRecursive() ); - } - allParents.AddRange( options.MinBy( option => option.Value.Count ).Value ); - } - else - { - allParents.AddRange( current.GetMissingRequiredRecursive() ); - } - } - } - return allParents.Distinct().ToList(); - } - - /// - /// Draw highlights around node, and optionally highlight links to parents/children of this node. - /// - /// color to use - /// should links to parents be drawn? - /// should links to children be drawn? - public void Highlight( Color color, bool linkParents, bool linkChildren ) - { - GUI.color = color; - Widgets.DrawBox( Rect.ContractedBy( -2f ), 2 ); - GUI.color = Color.white; - if ( linkParents ) - { - foreach ( Node parent in Parents ) - { - MainTabWindow_ResearchTree.highlightedConnections.Add( new Pair( parent, this ) ); - } - } - if ( linkChildren ) - { - foreach ( Node child in Children ) - { - MainTabWindow_ResearchTree.highlightedConnections.Add( new Pair( this, child ) ); - } - } - } - - public void Notify_LockedOut( bool state ) - { - _isLockedOut = state; - Research.ExclusiveDescendants().Select( res => res.Node() ).ToList().ForEach( node => node.Notify_LockedOut( state ) ); - } - - public void Notify_WillBeLockedOut( bool state ) - { - _willBeLockedOut = state; - Research.ExclusiveDescendants().Select( res => res.Node() ).ToList().ForEach( node => node.Notify_WillBeLockedOut( state ) ); - } - - /// - /// Recursively determine the depth of this node. - /// - public void SetDepth() - { - List level = new List(); - level.Add( this ); - while ( level.Count > 0 && - level.Any( node => node.Parents.Count > 0 ) ) - { - // has any parent, increment level. - Depth++; - - // set level to next batch of distinct Parents, where Parents may not be itself. - level = level.SelectMany( node => node.Parents ).Distinct().Where( node => node != this ).ToList(); - - // stop infinite recursion with loops of size greater than 2 - if ( Depth > 100 ) - { - Log.Error( Research.LabelCap + - " has more than 100 levels of prerequisites. Is the Research Tree defined as a loop?" ); - } - } - } - - public override string ToString() - { - return this.Research.LabelCap + this.Pos; - } - - private void CreateRects() - { - // main rect - _rect = new Rect( Pos.x * ( Settings.NodeSize.x + Settings.NodeMargins.x ) + Offset, - Pos.z * ( Settings.NodeSize.y + Settings.NodeMargins.y ) + Offset, - Settings.NodeSize.x, - Settings.NodeSize.y ); - - // queue rect - _queueRect = new Rect( _rect.xMax - LabSize / 2f, - _rect.yMin + ( _rect.height - LabSize ) / 2f, - LabSize, - LabSize ); - - // label rect - _labelRect = new Rect( _rect.xMin + 6f, - _rect.yMin + 3f, - _rect.width * 2f / 3f - 6f, - _rect.height * .5f - 3f ); - - // research cost rect - _costLabelRect = new Rect( _rect.xMin + _rect.width * 2f / 3f, - _rect.yMin + 3f, - _rect.width * 1f / 3f - 16f - 3f, - _rect.height * .5f - 3f ); - - // research icon rect - _costIconRect = new Rect( _costLabelRect.xMax, - _rect.yMin + ( _costLabelRect.height - 16f ) / 2, - 16f, - 16f ); - - // icon container rect - _iconsRect = new Rect( _rect.xMin, - _rect.yMin + _rect.height * .5f, - _rect.width, - _rect.height * .5f ); - - // see if the label is too big - _largeLabel = Text.CalcHeight( Research.LabelCap, _labelRect.width ) > _labelRect.height; - - // done - _rectSet = true; - } - - /// - /// Creates text version of research description and additional unlocks/prereqs/etc sections. - /// - /// string description - private string GetResearchTooltipString() - { - // start with the descripton - StringBuilder text = new StringBuilder(); - text.AppendLine( Research.description ); - text.AppendLine(); - - if ( LockedState != LockedState.LockedOut ) - { - if ( LockedState == LockedState.willBeLockedOut ) - { - text.AppendLine( "Fluffy.ResearchTree.WillBeLockedOut".Translate() ); - } - if ( Queue.IsQueued( this ) ) - { - text.AppendLine( "Fluffy.ResearchTree.LClickRemoveFromQueue".Translate() ); - } - else - { - text.AppendLine( "Fluffy.ResearchTree.LClickReplaceQueue".Translate() ); - text.AppendLine( "Fluffy.ResearchTree.SLClickAddToQueue".Translate() ); - } - text.AppendLine( "Fluffy.ResearchTree.RClickForDetails".Translate() ); - } - else - { - text.AppendLine( "Fluffy.ResearchTree.LockedOut".Translate().ToUpper() ); - } - return text.ToString(); - } - - #endregion Methods - } -} \ No newline at end of file diff --git a/DLL_Project/ResearchTree/Queue.cs b/DLL_Project/ResearchTree/Queue.cs deleted file mode 100644 index 0e828d4..0000000 --- a/DLL_Project/ResearchTree/Queue.cs +++ /dev/null @@ -1,237 +0,0 @@ -using CommunityCoreLibrary; -using RimWorld; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; -using Verse; - -// ReSharper disable PossibleNullReferenceException -// reflection is dangerous - deal with it. Fluffy. - -// Moved dangerous cross-instance class jump to it's own detour class. -// Created required static methods to perform the same access. 1000101. - -namespace CommunityCoreLibrary.ResearchTree -{ - public static class Queue - { - #region Internal Fields - - internal static readonly Texture2D CircleFill = ContentFinder.Get("UI/ResearchTree/circle-fill"); - - #endregion Internal Fields - - #region Private Fields - - private static readonly List _queue = new List(); - - #endregion Private Fields - - #region Public Properties - - public static int Count - { - get - { - return _queue.Count; - } - } - - #endregion Public Properties - - #region Public Methods - - public static void Dequeue( Node node ) - { - _queue.Remove( node ); - List followUps = _queue.Where( n => n.GetMissingRequiredRecursive().Contains( node ) ).ToList(); - foreach ( Node followUp in followUps ) - { - _queue.Remove( followUp ); - } - } - - public static void DrawLabels() - { - int i = 1; - foreach ( Node node in _queue ) - { - // draw coloured tag - GUI.color = node.Tree.MediumColor; - GUI.DrawTexture( node.QueueRect, CircleFill ); - - // if this is not first in line, grey out centre of tag - if ( i > 1 ) - { - GUI.color = node.Tree.GreyedColor; - GUI.DrawTexture( node.QueueRect.ContractedBy( 2f ), CircleFill ); - } - - // draw queue number - GUI.color = Color.white; - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label( node.QueueRect, i++.ToString() ); - Text.Anchor = TextAnchor.UpperLeft; - } - } - - public static void Enqueue( Node node, bool add ) - { - // if we're not adding, clear the current queue and current research project - if ( !add ) - { - NotifyAll(); - _queue.Clear(); - Find.ResearchManager.currentProj = null; - } - else - { - foreach ( Node queuedNode in _queue ) - { - if ( queuedNode.Locks.Contains( node ) ) - { - Messages.Message( "Fluffy.ResearchTree.CannotQueueXLocksY".Translate( - "Fluffy.ResearchTree.QueuedNode".Translate() + " " + queuedNode.Research.LabelCap, - node.Research.LabelCap ) + " " + - "Fluffy.ResearchTree.CannotQueueDequeue".Translate(), - MessageSound.RejectInput ); - return; - } - if ( node.Locks.Contains( queuedNode ) && !_queue.Contains( node ) ) - { - Messages.Message( "Fluffy.ResearchTree.CannotQueueXLocksY".Translate( - node.Research.LabelCap, - "Fluffy.ResearchTree.QueuedNode".Translate() + " " + queuedNode.Research.LabelCap ) + " " + - "Fluffy.ResearchTree.CannotQueueDequeue".Translate(), - MessageSound.RejectInput ); - return; - } - } - } - - // add to the queue if not already in it - if ( !_queue.Contains( node ) ) - { - node.Locks.ForEach( n => n.Notify_WillBeLockedOut( true ) ); - _queue.Add( node ); - } - - // try set the first research in the queue to be the current project. - Node next = _queue.First(); - if ( - ( next != null )&& - ( next.Research != null ) - ) - { - Find.ResearchManager.currentProj = next.Research; // null if next is null. - } - else - { - Find.ResearchManager.currentProj = null; - } - } - - public static void EnqueueRange( IEnumerable nodes, bool add ) - { - // clear current Queue if not adding - if ( !add ) - { - NotifyAll(); - _queue.Clear(); - Find.ResearchManager.currentProj = null; - } - else - { - foreach ( Node queuedNode in _queue ) - { - foreach ( Node newNode in nodes ) - { - if ( queuedNode.Locks.Contains( newNode ) ) - { - Messages.Message( "Fluffy.ResearchTree.CannotQueueXLocksY".Translate( - "Fluffy.ResearchTree.QueuedNode".Translate() + " " + queuedNode.Research.LabelCap, - newNode.Research.LabelCap ) + " " + - "Fluffy.ResearchTree.CannotQueueDequeue".Translate(), - MessageSound.RejectInput ); - return; - } - if ( newNode.Locks.Contains( queuedNode ) && !_queue.Contains( newNode ) ) - { - Messages.Message( "Fluffy.ResearchTree.CannotQueueXLocksY".Translate( - newNode.Research.LabelCap, - "Fluffy.ResearchTree.QueuedNode".Translate() + " " + queuedNode.Research.LabelCap ) + " " + - "Fluffy.ResearchTree.CannotQueueDequeue".Translate(), - MessageSound.RejectInput ); - return; - } - } - } - } - - // sorting by depth ensures prereqs are met - cost is just a bonus thingy. - foreach ( Node node in nodes.OrderBy( node => node.Depth ).ThenBy( node => node.Research.totalCost ) ) - { - Enqueue( node, true ); - } - Node first = _queue.First(); - Find.ResearchManager.currentProj = first?.Research; - } - - public static Node First() - { - return _queue.First(); - } - - public static void FromList( List loadQueue ) - { - // initialize the queue - foreach ( ResearchProjectDef research in loadQueue ) - { - // find a node that matches the research - or null if none found - Node node = ResearchTree.Forest.FirstOrDefault( n => n.Research == research ); - - // enqueue the node - if ( node != null ) - { - Enqueue( node, true ); - } - } - } - - public static bool IsQueued( Node node ) - { - return _queue.Contains( node ); - } - - public static void NotifyAll() - { - foreach ( Node node in _queue ) - { - node.Locks.ForEach( n => n.Notify_WillBeLockedOut( false ) ); - } - } - - /// - /// Removes and returns the first node in the queue. - /// - /// - public static Node Pop() - { - if ( !_queue.NullOrEmpty() ) - { - Node node = _queue[0]; - _queue.RemoveAt( 0 ); - return node; - } - return null; - } - - public static List ToList() - { - return _queue.Select( node => node.Research ).ToList(); - } - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/DLL_Project/ResearchTree/ResearchTree.cs b/DLL_Project/ResearchTree/ResearchTree.cs deleted file mode 100644 index 77277ce..0000000 --- a/DLL_Project/ResearchTree/ResearchTree.cs +++ /dev/null @@ -1,536 +0,0 @@ -// ResearchTree/ResearchTree.cs -// -// Copyright Karel Kroeze, 2015. -// -// Created 2015-12-21 13:45 -// -// Note: CCL is using unlicense which invalidates copyright - 1000101 - -using CommunityCoreLibrary.ColorPicker; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using UnityEngine; -using Verse; - -namespace CommunityCoreLibrary.ResearchTree -{ - // TODO: Needs static constructor to fetch textures - public static class ResearchTree - { - #region Public Fields - - public static Texture2D Button = ContentFinder.Get( "UI/ResearchTree/button" ); - public static Texture2D ButtonActive = ContentFinder.Get( "UI/ResearchTree/button-active" ); - public static Texture2D Circle = ContentFinder.Get( "UI/ResearchTree/circle" ); - public static Texture2D End = ContentFinder.Get( "UI/ResearchTree/end" ); - public static Texture2D EW = ContentFinder.Get( "UI/ResearchTree/ew" ); - public static List Forest; - public static bool Initialized; - public static Texture2D MoreIcon = ContentFinder.Get( "UI/ResearchTree/more" ); - public static Texture2D NS = ContentFinder.Get( "UI/ResearchTree/ns" ); - public static IntVec2 OrphanDepths; - public static Tree Orphanage; - public static int OrphanWidth; - public static Texture2D ResearchIcon = ContentFinder.Get( "UI/ResearchTree/Research" ); - public static List Trees; - public static Texture2D WarningIcon = ContentFinder.Get( "UI/ResearchTree/warning_shield" ); - - #endregion Public Fields - - #region Public Methods - - public static void DrawLine( Pair connection, Color color, bool reverseDirection = false ) - { - Vector2 a, b; - - if ( reverseDirection ) - { - a = connection.First.Right; - b = connection.Second.Left; - } - else - { - a = connection.First.Left; - b = connection.Second.Right; - } - - GUI.color = color; - bool isHubLink = false; - - Vector2 left, right; - // make sure line goes left -> right - if ( a.x < b.x ) - { - left = a; - right = b; - } - else - { - left = b; - right = a; - } - - // if left and right are on the same level, just draw a straight line. - if ( Math.Abs( left.y - right.y ) < 0.1f ) - { - Rect line = new Rect( left.x, left.y - 2f, right.x - left.x, 4f ); - GUI.DrawTexture( line, EW ); - } - - // draw three line pieces and two curves. - else - { - // determine top and bottom y positions - float top = Math.Min( left.y, right.y ) + Settings.NodeMargins.x / 4f; - float bottom = Math.Max( left.y, right.y ) - Settings.NodeMargins.x / 4f; - - // if these positions are more than X nodes apart, draw an invisible 'hub' link. - if ( Math.Abs( top - bottom ) > Settings.LineMaxLengthNodes * Settings.NodeSize.y ) - { - isHubLink = true; - - // left to hub - Rect leftToHub = new Rect( left.x, left.y + 15f, Settings.NodeMargins.x / 4f, 4f ); - GUI.DrawTexture( leftToHub, EW ); - - // hub to right - Rect hubToRight = new Rect( right.x - Settings.NodeMargins.x / 4f, right.y + 15f, Settings.NodeMargins.x / 4f, 4f ); - GUI.DrawTexture( hubToRight, EW ); - - // left hub - Rect hub = new Rect( left.x + Settings.NodeMargins.x / 4f - Settings.HubSize / 2f, - left.y + 17f - Settings.HubSize / 2f, - Settings.HubSize, - Settings.HubSize ); - GUI.DrawTexture( hub, Queue.CircleFill ); - - // add tooltip - if ( !MainTabWindow_ResearchTree.hubTips.ContainsKey( hub ) ) - { - MainTabWindow_ResearchTree.hubTips.Add( hub, new List() ); - MainTabWindow_ResearchTree.hubTips[hub].Add( "Fluffy.ResearchTree.LeadsTo".Translate() ); - } - MainTabWindow_ResearchTree.hubTips[hub].Add( connection.First.Research.LabelCap ); - - // right hub - hub.position = new Vector2( right.x - Settings.NodeMargins.x / 4f - Settings.HubSize / 2f, - right.y + 17f - Settings.HubSize / 2f ); - GUI.DrawTexture( hub, Queue.CircleFill ); - - // add tooltip - if ( !MainTabWindow_ResearchTree.hubTips.ContainsKey( hub ) ) - { - MainTabWindow_ResearchTree.hubTips.Add( hub, new List() ); - MainTabWindow_ResearchTree.hubTips[hub].Add( "Fluffy.ResearchTree.Requires".Translate() ); - } - MainTabWindow_ResearchTree.hubTips[hub].Add( connection.Second.Research.LabelCap ); - } - // but when nodes are close together, just draw the link as usual. - else - { - // left to curve - Rect leftToCurve = new Rect( left.x, left.y - 2f, Settings.NodeMargins.x / 4f, 4f ); - GUI.DrawTexture( leftToCurve, EW ); - - // curve to curve - Rect curveToCurve = new Rect( left.x + Settings.NodeMargins.x / 2f - 2f, top, 4f, bottom - top ); - GUI.DrawTexture( curveToCurve, NS ); - - // curve to right - Rect curveToRight = new Rect( left.x + Settings.NodeMargins.x / 4f * 3, right.y - 2f, right.x - left.x - Settings.NodeMargins.x / 4f * 3, 4f ); - GUI.DrawTexture( curveToRight, EW ); - - // curve positions - Rect curveLeft = new Rect( left.x + Settings.NodeMargins.x / 4f, left.y - Settings.NodeMargins.x / 4f, Settings.NodeMargins.x / 2f, Settings.NodeMargins.x / 2f ); - Rect curveRight = new Rect( left.x + Settings.NodeMargins.x / 4f, right.y - Settings.NodeMargins.x / 4f, Settings.NodeMargins.x / 2f, Settings.NodeMargins.x / 2f ); - - // going down - if ( left.y < right.y ) - { - GUI.DrawTextureWithTexCoords( curveLeft, Circle, new Rect( 0.5f, 0.5f, 0.5f, 0.5f ) ); // bottom right quadrant - GUI.DrawTextureWithTexCoords( curveRight, Circle, new Rect( 0f, 0f, 0.5f, 0.5f ) ); // top left quadrant - } - // going up - else - { - GUI.DrawTextureWithTexCoords( curveLeft, Circle, new Rect( 0.5f, 0f, 0.5f, 0.5f ) ); // top right quadrant - GUI.DrawTextureWithTexCoords( curveRight, Circle, new Rect( 0f, 0.5f, 0.5f, 0.5f ) ); // bottom left quadrant - } - } - } - - // draw the end arrow (if not hub link) - Rect end = new Rect( right.x - 16f, right.y - 8f, 16f, 16f ); - - if ( !isHubLink ) - GUI.DrawTexture( end, End ); - - // reset color - GUI.color = Color.white; - } - - private static void FixPositions() - { - int curY = 0; - - foreach ( Tree tree in Trees ) - { - tree.StartY = curY; - - foreach ( Node node in tree.Trunk ) - { - int bestPos = curY; - - // trunks can have (but shouldn't have) more than one node at each depth. - while ( tree.Trunk.Any( otherNode => otherNode.Pos.z == bestPos && otherNode.Depth == node.Depth ) ) - { - bestPos++; - } - node.Pos = new IntVec2( node.Depth, bestPos ); - - // extend tree width if necessary - tree.Width = Math.Max( tree.Width, bestPos - curY + 1 ); - } - - // position child nodes as close to their parents as possible - for ( int x = tree.MinDepth; x <= tree.MaxDepth; x++ ) - { - // put nodes that are children of the trunk first. - List nodes = tree.NodesAtDepth( x ).OrderBy( node => node.Parents.Any( parent => node.Tree.Trunk.Contains( parent ) ) ? 0 : 1 ).ToList(); - List allNodesAtCurrentDepth = tree.NodesAtDepth( x, true ); - - foreach ( Node node in nodes ) - { - // try find the closest matching position, default to right below trunk - int bestPos = curY + 1; - - // if we have any parent research in this trunk, try to get positioned next to it. - if ( node.Parents.Any( parent => parent.Tree == node.Tree ) ) - bestPos = node.Parents.Where( parent => parent.Tree == node.Tree ).Select( parent => parent.Pos.z ).Min(); - - // bump down if taken by any node in tree - while ( allNodesAtCurrentDepth.Any( n => n.Pos.z == bestPos ) || bestPos == curY ) - bestPos++; - - // extend tree width if necessary - tree.Width = Math.Max( tree.Width, bestPos - tree.StartY + 1 ); - - // set position - node.Pos = new IntVec2( node.Depth, bestPos ); - } - } - - // sort all nodes by their depths, then by their z position. - if ( !tree.Leaves.NullOrEmpty() ) - { - tree.Leaves = tree.Leaves.OrderBy( node => node.Depth ).ThenBy( node => node.Pos.z ).ToList(); - } - - // do a reverse pass to position parent nodes next to their children - for ( int x = tree.MaxDepth; x >= tree.MinDepth; x-- ) - { - Queue nodes = new Queue( tree.NodesAtDepth( x ) ); - List allNodesAtCurrentDepth = tree.NodesAtDepth( x, true ); - Dictionary switched = new Dictionary(); - - while ( nodes.Count > 0 ) - { - Node node = nodes.Dequeue(); - - // if this node has non-trunk children in the same tree; - var children = node.Children.Where( child => child.Tree == node.Tree && - !child.Tree.Trunk.Contains( child ) ); - if ( children.Count() > 0 ) - { - // ideal position would be right next to top child, but we won't allow it to go out of tree bounds - Node topChild = children.OrderBy( child => child.Pos.z ).First(); - int bestPos = Math.Max( topChild.Pos.z, node.Tree.StartY + 1 ); - - // keep checking until we have a decent position - // if that is indeed the current position, great, move to next - if ( bestPos == node.Pos.z ) - continue; - - // otherwise, check if position is taken by any node, or if the new position falls outside of tree bounds (exclude this node itself from matches) - while ( allNodesAtCurrentDepth.Any( n => n.Pos.z == bestPos && n != node ) ) - { - // do we have a child at this location, and does the node at that position not have the same child? - Node otherNode = allNodesAtCurrentDepth.First( n => n.Pos.z == bestPos && n != node ); - if ( bestPos == topChild.Pos.z && - !otherNode.Children.Contains( topChild ) ) - { - // if not, switch the nodes and re-do the other node. - if ( !switched.ContainsKey( node ) ) - { - switched.Add( node, 0 ); - } - if ( switched[node] < 5 ) - { - //Log.Message( "switched " + node.Research.LabelCap + "(" + node.Pos.z + ") and " + otherNode.Research.LabelCap + "(" + otherNode.Pos.z + ")" ); - otherNode.Pos.z = node.Pos.z; - nodes.Enqueue( otherNode ); - switched[node]++; - continue; - } - } - // or just bump it down otherwise - bestPos++; - } - - // we should now have a decent position - // extend tree width if necessary - tree.Width = Math.Max( tree.Width, bestPos - tree.StartY + 1 ); - - // set position - node.Pos = new IntVec2( node.Depth, bestPos ); - } - } - } - curY += tree.Width; - } - - // deal with non-tree nodes - // try and get root nodes first - IEnumerable roots = Orphanage.Leaves.Where( node => node.Children.Any() && !node.Parents.Any() ).OrderBy( node => node.Depth ); - int rootYOffset = 0; - - foreach ( Node root in roots ) - { - // set position - root.Pos = new IntVec2( root.Depth, curY + rootYOffset ); - - // recursively go through all children - // width at depths - Dictionary widthAtDepth = new Dictionary(); - Stack children = new Stack( root.Children ); - while ( children.Any() ) - { - // get node - Node child = children.Pop(); - - // get width at current depth - int width; - if ( !widthAtDepth.ContainsKey( child.Depth ) ) - { - widthAtDepth.Add( child.Depth, 0 ); - } - width = widthAtDepth[child.Depth]++; - - // continue if already positioned - if ( child.Pos != IntVec2.Zero ) - continue; - - // set position - child.Pos = new IntVec2( child.Depth, curY + rootYOffset + width ); - - // enqueue child's children - foreach ( Node grandchild in child.Children ) - { - children.Push( grandchild ); - } - } - - // next root - rootYOffset += widthAtDepth.Select( p => p.Value ).Max(); - } - - // update orphan width for mini tree(s) - ResearchTree.Orphanage.Width = rootYOffset; - curY += rootYOffset; - - // create orphan grid - int nodesPerRow = (int)( Screen.width / ( Settings.NodeSize.x + Settings.NodeMargins.x ) ); - List orphans = Orphanage.Leaves.Where( node => !node.Parents.Any() && !node.Children.Any() ).OrderBy( node => node.Research.LabelCap ).ToList(); - - // set positions - for ( int i = 0; i < orphans.Count; i++ ) - { - orphans[i].Pos = new IntVec2( i % nodesPerRow, i / nodesPerRow + curY ); - } - - // update width + depth - Orphanage.Width += Mathf.CeilToInt( (float)orphans.Count / (float)nodesPerRow ); - Orphanage.MaxDepth = Math.Max( Orphanage.MaxDepth, nodesPerRow - 1 ); // zero-based - } - - public static bool Initialize() - { - // populate all nodes - Forest = new List( DefDatabase.AllDefsListForReading - // exclude projects that can never be researched (it, or one of it's prerequisites has a prereq of itself, and no unlocks) - .Where( def => !def.IsLockedOut() ) - .Select( def => new Node( def ) ) ); - - // mark, but do not remove redundant prerequisites. - foreach ( Node node in Forest ) - { - if ( !node.Research.prerequisites.NullOrEmpty() ) - { - var ancestors = node.Research.prerequisites.SelectMany( r => r.GetPrerequisitesRecursive() ).ToList(); - if ( !ancestors.NullOrEmpty() && - ( !node.Research.prerequisites?.Intersect( ancestors ).ToList().NullOrEmpty() ?? false ) ) - { - Log.Warning( "ResearchTree :: redundant prerequisites for " + node.Research.LabelCap + ", has as prerequisites: " + - string.Join( ", ", node.Research.prerequisites.Intersect( ancestors ).Select( r => r.LabelCap ).ToArray() ) ); - } - } - } - - // create links between nodes - foreach ( Node node in Forest ) - { - node.CreateLinks(); - } - - // calculate Depth of each node - foreach ( Node node in Forest ) - { - node.SetDepth(); - } - - // get the main 'Trees', looping over all defs, find strings of Research named similarly. - // We're aiming for finding things like Construction I/II/III/IV/V here. - Dictionary> trunks = new Dictionary>(); - List orphans = new List(); // temp - foreach ( Node node in Forest ) - { - // try to remove the amount of random hits by requiring Trees to be directly linked. - if ( node.Parents.Any( parent => parent.Genus == node.Genus ) || - node.Children.Any( child => child.Genus == node.Genus ) ) - { - if ( !trunks.ContainsKey( node.Genus ) ) - { - trunks.Add( node.Genus, new List() ); - } - trunks[node.Genus].Add( node ); - } - else - { - orphans.Add( node ); - } - } - - // Assign the working dictionary to Tree objects, culling stumps. - Trees = trunks.Where( trunk => trunk.Value.Count >= Settings.MinTrunkSize ) - .Select( trunk => new Tree( trunk.Key, trunk.Value ) ) - .ToList(); - - // add too small Trees back into orphan list - orphans.AddRange( trunks.Where( trunk => trunk.Value.Count < Settings.MinTrunkSize ).SelectMany( trunk => trunk.Value ) ); - - // Attach orphan nodes to the nearest Trunk, or the orphanage trunk - Orphanage = new Tree( "orphans", new List() ) { Color = Color.grey }; - - // keep trying to attach orphans to trees until we make no more progress - // ( deals with a scenario where A -> C, B -> C; if B has a family but A does not, C will resolve to B's family but A will not. ) - bool progress; - do - { - // assume we make no progress - progress = false; - - // loop down to avoid having to deal with size changes in the orphans list. - for ( int i = orphans.Count - 1; i >= 0; i-- ) - { - // find closest tree (in this iteration) - Tree closest = orphans[i].ClosestTree(); - - // we have a winner! - if ( closest != null ) - { - // we made some progress in this iteration - progress = true; - - // add leaf to tree (which also handles setting the tree field on the leaf) - closest.AddLeaf( orphans[i] ); - - // remove from orphans list - orphans.RemoveAt( i ); - } - } - } - while ( progress ); - - // add any orphans we couldn't deal with to orphanage - foreach ( Node orphan in orphans ) - { - Orphanage.AddLeaf( orphan ); - } - - // The order in which Trees should appear; ideally we want Trees with lots of cross-references to appear together. - OrderTrunks(); - - // Assign colors to trunks - int n = Trees.Count; - for ( int i = 1; i <= Trees.Count; i++ ) - { - Trees[i - 1].Color = ColorHelper.HSVtoRGB( (float)i / n, 1, 1 ); - } - - // update nodes with position info - FixPositions(); - - // some debug output -#if DEVELOPER - var stringBuilder = new StringBuilder(); - CCL_Log.CaptureBegin( stringBuilder ); - CCL_Log.Message( "Duplicated positions:\n " + string.Join( "\n", Forest.Where( _node => Forest.Any( _otherNode => _node.Pos == _otherNode.Pos && _node != _otherNode ) ).Select( _node => _node.Pos + _node.Research.LabelCap + " (" + _node.Genus + ")" ).ToArray() ) ); - foreach ( Tree tree in Trees ) - { - CCL_Log.Message( tree.ToString() ); - } - CCL_Log.Message( Orphanage.ToString() ); - CCL_Log.CaptureEnd( stringBuilder, "Associations" ); - CCL_Log.Message( stringBuilder.ToString(), "Research Tree" ); -#endif - - // Done! - Initialized = true; - return Initialized; - } - - #endregion Public Methods - - #region Private Methods - - private static void OrderTrunks() - { - // if two or less Trees, optimization is pointless - if ( Trees.Count < 3 ) - return; - - // This is a form of the travelling salesman problem, but let's simplify immensely by taking a nearest-neighbour approach. - List trees = Trees.OrderBy( tree => -tree.Leaves.Count ).ToList(); - Trees.Clear(); - - // initialize list of Trees with the largest - Tree first = trees.First(); - Trees.Add( first ); - trees.Remove( first ); - - // Set up a weighting system to keep 2nd highest affinity closer to 1st highest affinity - Dictionary weights = - new Dictionary( trees.ToDictionary( tree => tree, tree => first.AffinityWith( tree ) ) ); - - // add other Trees - while ( trees.Count > 0 ) - { - // get tree with highest accumulated weight - Tree next = weights.Where( pair => trees.Contains( pair.Key ) ).MaxBy( pair => pair.Value ).Key; - Trees.Add( next ); - trees.Remove( next ); - - // add weights for next set - foreach ( Tree tree in trees ) - { - weights[tree] += next.AffinityWith( tree ); - } - } - } - - #endregion Private Methods - } -} \ No newline at end of file diff --git a/DLL_Project/ResearchTree/Settings.cs b/DLL_Project/ResearchTree/Settings.cs deleted file mode 100644 index 7e214d2..0000000 --- a/DLL_Project/ResearchTree/Settings.cs +++ /dev/null @@ -1,24 +0,0 @@ -using UnityEngine; - -namespace CommunityCoreLibrary.ResearchTree -{ - public static class Settings - { - #region tuning parameters - - public static int LineMaxLengthNodes = 10; - public static int MinTrunkSize = 2; - - #endregion tuning parameters - - #region UI elements - - public static float HubSize = 16f; - public static Vector2 IconSize = new Vector2( 18f, 18f ); - public static Vector2 NodeMargins = new Vector2( 50f, 10f ); - public static Vector2 NodeSize = new Vector2( 200f, 50f ); - public static int TipID = 24 * 1271; - - #endregion UI elements - } -} \ No newline at end of file diff --git a/DLL_Project/ResearchTree/Tree.cs b/DLL_Project/ResearchTree/Tree.cs deleted file mode 100644 index 6cdbf57..0000000 --- a/DLL_Project/ResearchTree/Tree.cs +++ /dev/null @@ -1,182 +0,0 @@ -using CommunityCoreLibrary.ColorPicker; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; - -namespace CommunityCoreLibrary.ResearchTree -{ - public class Tree - { - #region Fields - - public string Genus; - public Color GreyedColor; - public List Leaves; - public int MaxDepth; - public Color MediumColor; - public int MinDepth; - public int StartY; - public List Trunk; - public int Width; - private Color _color; - - #endregion Fields - - #region Constructors - - public Tree( string genus, List trunk ) - { - Genus = genus; - Trunk = trunk.OrderBy( node => node.Depth ).ToList(); - Leaves = new List(); - - if ( trunk.Any() ) - { - MinDepth = trunk.Select( node => node.Depth ).Min(); - MaxDepth = trunk.Select( node => node.Depth ).Max(); - Width = 1; - } - else - { - MinDepth = MaxDepth = Width = 0; - } - - // make all Trunk nodes a part of this Tree - foreach ( Node node in trunk ) - { - node.Tree = this; - } - } - - #endregion Constructors - - #region Properties - - public Color Color - { - get { return _color; } - set - { - _color = value; - - float h, s, v; - - ColorHelper.RGBtoHSV( value, out h, out s, out v ); - GreyedColor = ColorHelper.HSVtoRGB( h, 0.1f, 0.25f ); - MediumColor = ColorHelper.HSVtoRGB( h, 0.7f, 0.8f ); - } - } - - #endregion Properties - - #region Methods - - public void AddLeaf( Node leaf ) - { - // add it - Leaves.Add( leaf ); - - // mark it a part of this Tree - leaf.Tree = this; - - // update depths and Width if necessary - Width = Math.Max( Width, NodesAtDepth( leaf.Depth, true ).Count ); - MinDepth = Math.Min( MinDepth, leaf.Depth ); - MaxDepth = Math.Max( MaxDepth, leaf.Depth ); - } - - public float AffinityWith( Tree otherTree ) - { - // get the number of relations between the two extended families. - List family = new List(); - family.AddRange( Leaves ); - family.AddRange( Trunk ); - List otherFamily = otherTree.Children().Concat( otherTree.Parents() ).Distinct().ToList(); - - // count of nodes that are a member of both families, divided by family size to get small child trees to be closer to 'main' tree. - return (float)family.Intersect( otherFamily ).Count() / (float)Math.Sqrt( otherFamily.Count() ); - } - - public List Children( int depth = 2 ) - { - List children = new List( Trunk ); - List curLevel = new List( Trunk ); - - while ( depth-- > 0 ) - { - curLevel = curLevel.SelectMany( node => node.Children ).Distinct().ToList(); - children.AddRange( curLevel ); - } - - return children; - } - - public List NodesAtDepth( int depth, bool includeTrunk = false ) - { - List nodes = new List(); - if ( includeTrunk ) - nodes.AddRange( Trunk.Where( node => node.Depth == depth ) ); - nodes.AddRange( Leaves.Where( node => node.Depth == depth ) ); - return nodes; - } - - public List Parents( int depth = 2 ) - { - List parents = new List( Trunk ); - List curLevel = new List( Trunk ); - - while ( depth-- > 0 ) - { - curLevel = curLevel.SelectMany( node => node.Parents ).Distinct().ToList(); - parents.AddRange( curLevel ); - } - - return parents; - } - -#if DEVELOPER - public override string ToString() - { - StringBuilder text = new StringBuilder(); - - text.AppendLine( Genus.ToUpper() ); - text.AppendLine( "Trunk:" ); - foreach ( Node node in Trunk ) - { - text.AppendFormat( node.ToString() ); - } - - text.AppendLine( "\n\nLeaves:" ); - foreach ( Node node in Leaves ) - { - text.AppendFormat( node.ToString() + ", " ); - } - - text.AppendLine( "\n\nAffinities:" ); - foreach ( Tree tree in ResearchTree.Trees ) - { - if ( tree != this ) - { - text.AppendLine( tree.Genus + ": " + AffinityWith( tree ) ); - } - } - - text.AppendLine( "\n\nNode research details:" ); - foreach ( Node node in Trunk ) - { - text.AppendLine( node.Debug() ); - } - foreach ( Node node in Leaves ) - { - text.AppendLine( node.Debug() ); - } - - return text.ToString(); - } -#endif - - #endregion Methods - } -} \ No newline at end of file diff --git a/DLL_Project/SpecialInjectors/ResearchTreeDetourInjector.cs b/DLL_Project/SpecialInjectors/ResearchTreeDetourInjector.cs deleted file mode 100644 index e5739a6..0000000 --- a/DLL_Project/SpecialInjectors/ResearchTreeDetourInjector.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Reflection; -using System.Security.Permissions; - -using RimWorld; -using Verse; - -namespace CommunityCoreLibrary.ResearchTree -{ - - public class DetourInjector : SpecialInjector - { - - public override bool Inject() - { - // Override base ResearchManager methods to expand functionality - - // Detour RimWorld.ResearchManager.MakeProgress - MethodInfo RimWorld_ResearchManager_MakeProgress = typeof( ResearchManager ).GetMethod( "MakeProgress", BindingFlags.Instance | BindingFlags.Public ); - MethodInfo CCL_ResearchTree_ResearchManager_MakeProgress = typeof( Detour._ResearchManager ).GetMethod( "_MakeProgress", BindingFlags.Static | BindingFlags.NonPublic ); - if( !Detours.TryDetourFromTo( RimWorld_ResearchManager_MakeProgress, CCL_ResearchTree_ResearchManager_MakeProgress ) ) - return false; - - // Detour RimWorld.ResearchManager.ExposeData - MethodInfo RimWorld_ResearchManager_ExposeData = typeof( ResearchManager ).GetMethod( "ExposeData", BindingFlags.Instance | BindingFlags.Public ); - MethodInfo CCL_ResearchTree_ResearchManager_ExposeData = typeof( Detour._ResearchManager ).GetMethod( "_ExposeData", BindingFlags.Static | BindingFlags.NonPublic ); - if( !Detours.TryDetourFromTo( RimWorld_ResearchManager_ExposeData, CCL_ResearchTree_ResearchManager_ExposeData ) ) - return false; - - // Initialize the research tree - //ResearchTree.Initialize(); - - return true; - } - - } - -} diff --git a/Forum/1_Release_Post.bbc b/Forum/1_Release_Post.bbc index d773ab9..8ba5b6e 100644 --- a/Forum/1_Release_Post.bbc +++ b/Forum/1_Release_Post.bbc @@ -1,5 +1,5 @@ [center][img]https://github.com/RimWorldCCLTeam/CommunityCoreLibrary/blob/master/WebGraphics/CCL_Logo_Long.png?raw=true[/img] -v0.13.1 +v0.13.1.1 [glow=red,2,300]This forum thread and the first 10 posts serve as the documentation/manual. @@ -40,7 +40,6 @@ If you are a modder, download the modders resource or the source package. [li]Extract both the folders in the zip into your Mods folder.[/li] [li]Enable "Community Core Library" immediately after "Core" - This is [b][i]REQUIRED[/i][/b] and an error will be thrown if the library does not detect the correct load order position.[/li] [li]The "Community Core Library - Vanilla Tweaks" is entirely optional but highly recommended. It does not matter where in your load order it is but other mods may make changes to the same game objects. Enable the tweaks before or after those mods depending on the functional changes you want to use.[/li] -[li]The "Community Core Library - Research Tree" - Forthcoming - is also optional and also highly recommended. This will replace the research menu with a graphical tree depicting all research in the game. Research projects can also be queued using this menu replacer. Note, this will save additional queuing information in your save file and will need to be removed by manually editing your save game.[/li] [/list] [size=12pt]Modders download the "Modders Resource" package.[/size] diff --git a/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/About/About.xml b/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/About/About.xml deleted file mode 100644 index ca46a95..0000000 --- a/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/About/About.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - Community Core Library - Enhanced Research Menu - - RimWorld CCL Team - - https://ludeon.com/forums/index.php?topic=14172.0 - - Community Core Library v0.13.0 - - This keeps the same style as the vanilla research menu but adds additional information. - - \ No newline at end of file diff --git a/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/Defs/MainTabDefs/MainTabs.xml b/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/Defs/MainTabDefs/MainTabs.xml deleted file mode 100644 index c087f33..0000000 --- a/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/Defs/MainTabDefs/MainTabs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Research - - Examine and decide on research projects. - CommunityCoreLibrary.MainTabWindow_Research - 90 - - - \ No newline at end of file diff --git a/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/Defs/ModHelperDefs/ModHelper_ResearchMenu.xml b/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/Defs/ModHelperDefs/ModHelper_ResearchMenu.xml deleted file mode 100644 index 709401b..0000000 --- a/_Mod/Modders Resource/Community Core Library - Enhanced Research Menu/Defs/ModHelperDefs/ModHelper_ResearchMenu.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - CommunityCoreLibraryResearchMenu - - Community Core Library - Research Menu - - 0.13.0 - - - - \ No newline at end of file diff --git a/_Mod/Modders Resource/Community Core Library - Research Tree/About/About.xml b/_Mod/Modders Resource/Community Core Library - Research Tree/About/About.xml deleted file mode 100644 index 123f419..0000000 --- a/_Mod/Modders Resource/Community Core Library - Research Tree/About/About.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - Community Core Library - Research Tree - - RimWorld CCL Team - - https://ludeon.com/forums/index.php?topic=14172.0 - - Community Core Library v0.13.0 - - Replaces the vanilla research menu with a research tree giving a graphic representation of the research tree. - - \ No newline at end of file diff --git a/_Mod/Modders Resource/Community Core Library - Research Tree/Defs/MainTabDefs/MainTabs.xml b/_Mod/Modders Resource/Community Core Library - Research Tree/Defs/MainTabDefs/MainTabs.xml deleted file mode 100644 index e440122..0000000 --- a/_Mod/Modders Resource/Community Core Library - Research Tree/Defs/MainTabDefs/MainTabs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Research - - Examine and decide on research projects. - CommunityCoreLibrary.MainTabWindow_ResearchTree - 90 - - - \ No newline at end of file diff --git a/_Mod/Modders Resource/Community Core Library - Research Tree/Defs/ModHelperDefs/ModHelper_ResearchTree.xml b/_Mod/Modders Resource/Community Core Library - Research Tree/Defs/ModHelperDefs/ModHelper_ResearchTree.xml deleted file mode 100644 index c32e97c..0000000 --- a/_Mod/Modders Resource/Community Core Library - Research Tree/Defs/ModHelperDefs/ModHelper_ResearchTree.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - CommunityCoreLibraryResearchTree - - Community Core Library - Research Tree - - 0.13.0 - - -
  • CommunityCoreLibrary.ResearchTree.DetourInjector
  • -
    - -
    - -
    \ No newline at end of file diff --git a/_Mod/Modders Resource/Community Core Library/Assemblies/Community Core Library.dll b/_Mod/Modders Resource/Community Core Library/Assemblies/Community Core Library.dll index 85b60bc..7cde76c 100644 Binary files a/_Mod/Modders Resource/Community Core Library/Assemblies/Community Core Library.dll and b/_Mod/Modders Resource/Community Core Library/Assemblies/Community Core Library.dll differ diff --git a/_Mod/User Release/Community Core Library/Assemblies/Community Core Library.dll b/_Mod/User Release/Community Core Library/Assemblies/Community Core Library.dll index 2b4584f..ac014c8 100644 Binary files a/_Mod/User Release/Community Core Library/Assemblies/Community Core Library.dll and b/_Mod/User Release/Community Core Library/Assemblies/Community Core Library.dll differ