public static bool ResearchNode_Draw_Prefix(object __instance, Rect visibleRect, bool forceDetailedMode = false) { //Reflected objects Rect rect = (Rect)RectInfo.GetValue(__instance); ResearchProjectDef Research = (ResearchProjectDef)ResearchInfo.GetValue(__instance); bool available = (bool)AvailableInfo.GetValue(__instance); bool completed = Research.IsFinished; //simplified // if (!(bool)IsVisibleInfo.Invoke(__instance, new object[] { visibleRect })) { HighlightedProxy(__instance, false); return(false); } bool detailedMode = forceDetailedMode || (float)ZoomLevelInfo.GetValue(InstanceInfo.GetValue(__instance)) < DetailedModeZoomLevelCutoff; bool mouseOver = Mouse.IsOver(rect); bool highlighted = HighlightedProxy(__instance); if (Event.current.type == EventType.Repaint) { //researches that are completed or could be started immediately, and that have the required building(s) available GUI.color = mouseOver ? BrightColor : (Color)ColorInfo.GetValue(__instance); if (mouseOver || highlighted) { GUI.DrawTexture(rect, ResearchTree_Assets.ButtonActive); } else { GUI.DrawTexture(rect, ResearchTree_Assets.Button); } //grey out center to create a progress bar effect, completely greying out research not started. if (available) { var progressBarRect = rect.ContractedBy(3f); GUI.color = ResearchTree_Assets.ColorAvailable[Research.techLevel]; progressBarRect.xMin += Research.ProgressPercent * progressBarRect.width; GUI.DrawTexture(progressBarRect, BaseContent.WhiteTex); } HighlightedProxy(__instance, interest == Research); //draw the research label if (!completed && !available) { GUI.color = Color.grey; } else { GUI.color = Color.white; } if (detailedMode) { Text.Anchor = TextAnchor.UpperLeft; Text.WordWrap = false; Text.Font = (bool)largeLabelInfo.GetValue(__instance) ? GameFont.Tiny : GameFont.Small; Widgets.Label((Rect)LabelRectInfo.GetValue(__instance), Research.LabelCap); } else { Text.Anchor = TextAnchor.MiddleCenter; Text.WordWrap = false; Text.Font = GameFont.Medium; Widgets.Label(rect, Research.LabelCap); } //draw research cost and icon if (detailedMode) { Text.Anchor = TextAnchor.UpperRight; Text.Font = Research.CostApparent > 1000000 ? GameFont.Tiny : GameFont.Small; Widgets.Label((Rect)CostLabelRectInfo.GetValue(__instance), Research.CostApparent.ToStringByStyle(ToStringStyle.Integer)); GUI.DrawTexture((Rect)CostIconRectInfo.GetValue(__instance), !completed && !available ? ResearchTree_Assets.Lock : ResearchTree_Assets.ResearchIcon, ScaleMode.ScaleToFit); } Text.WordWrap = true; //attach description and further info to a tooltip string root = HarmonyPatches.ResearchPal ? "ResearchPal" : "Fluffy.ResearchTree"; TooltipHandler.TipRegion(rect, new Func <string>(() => (string)GetResearchTooltipStringInfo.Invoke(__instance, new object[] { })), Research.GetHashCode()); if (!BuildingPresentProxy(Research)) { string languageKey = root + ".MissingFacilities"; TooltipHandler.TipRegion(rect, languageKey.Translate(string.Join(", ", MissingFacilities(Research).Select(td => td.LabelCap).ToArray()))); } else if (!TechprintAvailable(Research)) { string languageKey = root + ".MissingTechprints"; TooltipHandler.TipRegion(rect, languageKey.Translate(Research.TechprintsApplied, Research.techprintCount)); } //draw unlock icons if (detailedMode) { Rect IconsRect = (Rect)IconsRectInfo.GetValue(__instance); var unlocks = GetUnlockDefsAndDescs(Research); for (var i = 0; i < unlocks.Count; i++) { var iconRect = new Rect( IconsRect.xMax - (i + 1) * (IconSize.x + 4f), IconsRect.yMin + (IconsRect.height - IconSize.y) / 2f, IconSize.x, IconSize.y); if (iconRect.xMin - 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; GUI.DrawTexture(iconRect, ResearchTree_Assets.MoreIcon, ScaleMode.ScaleToFit); var 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); } } if (mouseOver) { if (interest != null && interest != Research) { DeInterest(); } //highlight prerequisites if research available if (available) { HighlightedProxy(__instance, true); foreach (var prerequisite in (IEnumerable <object>)GetMissingRequiredRecursiveInfo.Invoke(__instance, new object[] { })) { HighlightedProxy(Convert.ChangeType(prerequisite, ResearchNodeType()), true); } } //highlight children if completed else if (completed) { foreach (var child in (IEnumerable <object>)ChildrenInfo.GetValue(__instance)) { HighlightedProxy(Convert.ChangeType(child, ResearchNodeType()), true); } } } } //CUSTOM: a bunch of things on top Research.DrawExtras(rect, mouseOver || highlighted); if (Widgets.ButtonInvisible(rect)) { //CUSTOM: replaced queue operations for assignment menu if (Event.current.button == 0) { Research.SelectMenu(completed); } if (DebugSettings.godMode && Prefs.DevMode && Event.current.button == 1 && !Research.IsFinished) { Find.ResearchManager.FinishProject(Research); Research.WipeAssignments(); } } return(false); }