├── .gitignore ├── About ├── About.xml ├── Manifest.xml ├── ModSync.xml ├── Preview.png ├── PublishedFileId.txt └── dependencies.json ├── Assemblies ├── 0MultiplayerAPI.dll ├── FluffyUI.dll └── WorkTab.dll ├── Defs └── PawnColumnDefs.xml ├── LICENSE ├── Languages ├── ChineseSimplified │ ├── DefInjected │ │ └── PawnColumnDef │ │ │ └── PawnColumnDefs.xml │ └── Keyed │ │ └── Keyed-English.xml ├── ChineseTraditional │ ├── DefInjected │ │ └── PawnColumnDef │ │ │ └── PawnColumnDefs.xml │ └── Keyed │ │ └── Keyed-English.xml ├── English │ └── Keyed │ │ └── Keyed-English.xml ├── French │ ├── DefInjected │ │ └── PawnColumnDefs.xml │ └── Keyed-French.xml ├── German │ ├── DefInjected │ │ └── PawnColumnDef │ │ │ └── PawnColumnDefs.xml │ ├── Keyed │ │ └── WorkTab-German-Keyed.xml │ └── LanguageInfo.xml ├── Korean │ ├── DefInjected │ │ └── PawnColumnDef │ │ │ └── PawnColumnDefs.xml │ └── Keyed │ │ └── Keyed-English.xml ├── Russian │ ├── DefInjected │ │ └── PawnColumnDef │ │ │ └── PawnColumnDefs.xml │ └── Keyed │ │ └── Keyed-Russian.xml └── Spanish │ ├── DefInjected │ └── PawnColumnDef │ │ └── PawnColumnDefs.xml │ └── Keyed │ └── Keyed-Spanish.xml ├── Readme.md ├── Source ├── Core │ ├── Constants.cs │ ├── Controller.cs │ ├── MapComponent_TimeKeeper.cs │ ├── Resources.cs │ ├── Settings.cs │ └── VanillaWorkSettings.cs ├── Extensions │ ├── Int_Extensions.cs │ ├── Job_Extensions.cs │ ├── Listing_Extensions.cs │ ├── Pawn_Extensions.cs │ ├── String_Extensions.cs │ ├── WorkGiver_Extensions.cs │ └── WorkType_Extensions.cs ├── Favourites │ ├── Dialog_CreateFavourite.cs │ ├── Dialog_EditFavourite.cs │ ├── Dialog_Favourite.cs │ ├── Favourite.cs │ └── FavouriteManager.cs ├── HarmonyPatches │ ├── DefGenerator_GenerateImpliedDefs_PreResolve.cs │ ├── PawnTable │ │ ├── PawnTable_PawnTableOnGUI.cs │ │ └── PawnTable_RecacheIfDirty.cs │ └── Worksettings │ │ ├── Pawn_WorkSettings_CacheWorkGiversInOrder.cs │ │ ├── Pawn_WorkSettings_DisableAll.cs │ │ ├── Pawn_WorkSettings_EnableAndInitialize.cs │ │ ├── Pawn_WorkSettings_GetPriority.cs │ │ └── Pawn_WorkSettings_SetPriority.cs ├── PawnColumns │ ├── IAlternatingColumn.cs │ ├── IExpandableColumn.cs │ ├── PawnColumnDef_WorkGiver.cs │ ├── PawnColumnWorker_CopyPasteDetailedWorkPriorities.cs │ ├── PawnColumnWorker_Favourite.cs │ ├── PawnColumnWorker_Job.cs │ ├── PawnColumnWorker_Mood.cs │ ├── PawnColumnWorker_WorkGiver.cs │ ├── PawnColumnWorker_WorkTabLabel.cs │ └── PawnColumnWorker_WorkType.cs ├── PawnTable │ └── MainTabWindow_WorkTab.cs ├── Priorities │ ├── PawnPriorityTracker.cs │ ├── PriorityManager.cs │ ├── PriorityTracker.cs │ └── WorkPriority.cs ├── Utilities │ ├── DefOf.cs │ ├── DrawUtilities.cs │ ├── InteractionUtilities.cs │ ├── LabelUtilities.cs │ ├── Logger.cs │ └── TimeUtilities.cs ├── WorkTab.csproj ├── WorkTab.sln ├── description.md └── preview.svg ├── Textures └── UI │ └── Icons │ ├── LeftArrow.png │ ├── Mood │ ├── broken.png │ ├── content.png │ ├── discontent.png │ ├── happy.png │ └── unhappy.png │ ├── RightArrow.png │ ├── Various │ ├── 3d-hammer.png │ ├── anvil.png │ ├── art.png │ ├── blood.png │ ├── bow.png │ ├── box.png │ ├── brickwall.png │ ├── briefcase.png │ ├── bullseye.png │ ├── business.png │ ├── chef.png │ ├── chess-pawn.png │ ├── clean.png │ ├── cleaver-knife.png │ ├── clock.png │ ├── cog.png │ ├── combat.png │ ├── dice.png │ ├── drop.png │ ├── eat.png │ ├── extinguish.png │ ├── eye.png │ ├── farming.png │ ├── fist.png │ ├── flower.png │ ├── gardening-rake.png │ ├── gun.png │ ├── ham-leg.png │ ├── hammer.png │ ├── hand.png │ ├── handcuffs.png │ ├── haul.png │ ├── health.png │ ├── hunt.png │ ├── ingots.png │ ├── livestock.png │ ├── mine.png │ ├── money.png │ ├── move.png │ ├── oil-drum.png │ ├── paint-brush.png │ ├── paw-print.png │ ├── pencil.png │ ├── pray.png │ ├── research.png │ ├── reset.png │ ├── rings.png │ ├── saw.png │ ├── science.png │ ├── shepherds-crook.png │ ├── shirt.png │ ├── shovel.png │ ├── sick.png │ ├── sickle.png │ ├── signs.png │ ├── social.png │ ├── spanner.png │ ├── star.png │ ├── suits-clubs.png │ ├── suits-diamonds.png │ ├── suits-hearts.png │ ├── suits-spades.png │ ├── syringe.png │ ├── take.png │ ├── thread-ball.png │ ├── undress.png │ ├── unknown.png │ ├── wear.png │ ├── wood-axe.png │ ├── wrench.png │ └── zzz.png │ ├── checks.png │ ├── clock-scheduler.png │ ├── clock.png │ ├── collapse.png │ ├── edit.png │ ├── expand.png │ ├── half.png │ ├── now.png │ ├── numbers.png │ ├── pin-clock.png │ ├── pin-eye.png │ ├── star-hollow.png │ ├── star.png │ └── whole-day.png └── modinfo.json /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | packages/ 5 | .vscode 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | .idea 13 | 14 | # User-specific files (MonoDevelop/Xamarin Studio) 15 | *.userprefs 16 | 17 | # Build results 18 | [Dd]ebug/ 19 | [Dd]ebugPublic/ 20 | [Rr]elease/ 21 | [Rr]eleases/ 22 | x64/ 23 | x86/ 24 | bld/ 25 | [Bb]in/ 26 | [Oo]bj/ 27 | [Ll]og/ 28 | 29 | # Visual Studio 2015 cache/options directory 30 | .vs/ 31 | # Uncomment if you have tasks that create the project's static files in wwwroot 32 | #wwwroot/ 33 | 34 | # MSTest test Results 35 | [Tt]est[Rr]esult*/ 36 | [Bb]uild[Ll]og.* 37 | 38 | # NUNIT 39 | *.VisualState.xml 40 | TestResult.xml 41 | 42 | # Build Results of an ATL Project 43 | [Dd]ebugPS/ 44 | [Rr]eleasePS/ 45 | dlldata.c 46 | 47 | # DNX 48 | project.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | *.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.pfx 196 | *.publishsettings 197 | node_modules/ 198 | orleans.codegen.cs 199 | 200 | # Since there are multiple workflows, uncomment next line to ignore bower_components 201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 202 | #bower_components/ 203 | 204 | # RIA/Silverlight projects 205 | Generated_Code/ 206 | 207 | # Backup & report files from converting an old project file 208 | # to a newer Visual Studio version. Backup files are not needed, 209 | # because we have git ;-) 210 | _UpgradeReport_Files/ 211 | Backup*/ 212 | UpgradeLog*.XML 213 | UpgradeLog*.htm 214 | 215 | # SQL Server files 216 | *.mdf 217 | *.ldf 218 | 219 | # Business Intelligence projects 220 | *.rdl.data 221 | *.bim.layout 222 | *.bim_*.settings 223 | 224 | # Microsoft Fakes 225 | FakesAssemblies/ 226 | 227 | # GhostDoc plugin setting file 228 | *.GhostDoc.xml 229 | 230 | # Node.js Tools for Visual Studio 231 | .ntvs_analysis.dat 232 | 233 | # Visual Studio 6 build log 234 | *.plg 235 | 236 | # Visual Studio 6 workspace options file 237 | *.opt 238 | 239 | # Visual Studio LightSwitch build output 240 | **/*.HTMLClient/GeneratedArtifacts 241 | **/*.DesktopClient/GeneratedArtifacts 242 | **/*.DesktopClient/ModelManifest.xml 243 | **/*.Server/GeneratedArtifacts 244 | **/*.Server/ModelManifest.xml 245 | _Pvt_Extensions 246 | 247 | # Paket dependency manager 248 | .paket/paket.exe 249 | paket-files/ 250 | 251 | # FAKE - F# Make 252 | .fake/ 253 | 254 | # JetBrains Rider 255 | .idea/ 256 | *.sln.iml 257 | /.mailmap 258 | /Source/StuffedFloors.sln 259 | /Source/ModConfig.json 260 | .vscode/ -------------------------------------------------------------------------------- /About/About.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Work Tab 4 | Fluffy 5 | Fluffy.WorkTab 6 | Provides a vastly more customizable work tab. 7 | 8 | <size=24>Important</size> 9 | 10 | Work Tab completely takes over job priorities from the vanilla game. In order to support core functionalities and other mods, it intercepts calls to get/set priorities. However, when it is told to set priorities by other modded code that is not aware of the time schedule or detailed priorities, the priority will be set for the whole day, and/or for all workgivers in a worktype. 11 | 12 | <size=24>Features</size> 13 | 14 | Various usability extentions to the 'vanilla' work tab; 15 | 16 | - Work types can be expanded (by Ctrl+clicking the column header) to allow you to set priorities for the individual tasks within each work type. 17 | - Time scheduler to set priorities for a given time slot only - allowing you to designate a cleaning hour, or have your cook prepare meals right before dinner, etc. etc. 18 | - Up to 9 priority levels (configurable in mod options) 19 | - Various small UX tweaks; scrolling to increase/decrease/toggle priorities, increase/decrease priorities for whole columns/rows (by holding shift and clicking/scrolling while hovering over the column header/pawn name respectively). 20 | - <i>All functions are detailed in the tooltips, take a moment to hover over and read them!</i> 21 | 22 | <size=24>Known Issues</size> 23 | 24 | - <mspace>"Star Wars -- The Force"</mspace> versions prior to 1.21.1 cause priorities to reset for force users. <b>THIS INCLUDES THE CURRENT STEAM VERSION OF STAR WARS -- THE FORCE!</b> (as of 25/3/20). There is an official update available by one of the collaborators on the mod on <b>GitHub</b>. 25 | - <mspace>Better Pawn Control</mspace> has added support for <mspace>Work Tab</mspace> and <mspace>Animal Tab</mspace>, but there currently (as of 27/7/21) still is an issue where work settings may reset. 26 | 27 | <size=24>Notes</size> 28 | 29 | With great power comes great responsibility. The default priorities of tasks within a job is set for a good reason; it's (usually) a sensible default. Changing these can lead to deadlock situations, so change the priorities of individual jobs at your own risk! 30 | 31 | Finally, there will never be an 'autolabour' mode where a mod sets priorities for you. Due to the way the AI is handled (e.g. pawns actively look for work, instead of there being a 'bulletin board' of jobs that need doing), it's not feasible to get the complete list of work that needs doing that would be needed to make this a reality, without extreme overhead and loads of special exception coding. 32 | 33 | <size=24>Powered by Harmony</size> 34 | 35 | 36 | https://github.com/fluffy-mods/WorkTab 37 | 38 |
  • 1.3
  • 39 |
    40 |
    -------------------------------------------------------------------------------- /About/Manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 3.21.303 4 | https://raw.githubusercontent.com/fluffy-mods/WorkTab/1.2/About/Manifest.xml 5 | https://github.com/fluffy-mods/WorkTab/releases/v3.21.303 6 | -------------------------------------------------------------------------------- /About/ModSync.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 409d0f02-7e1c-4411-b2eb-ac213c19d51c 4 | Work Tab 5 | v0.18.1.0 6 | false 7 | 8 | -------------------------------------------------------------------------------- /About/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/About/Preview.png -------------------------------------------------------------------------------- /About/PublishedFileId.txt: -------------------------------------------------------------------------------- 1 | 725219116 -------------------------------------------------------------------------------- /About/dependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "depends": [ 3 | { 4 | "id": "brrainz.harmony", 5 | "name": "Harmony", 6 | "steam": 2009463077, 7 | "url": "https://github.com/pardeike/HarmonyRimWorld/releases/latest" 8 | } 9 | ], 10 | "after": [ 11 | "brrainz.harmony" 12 | ] 13 | } -------------------------------------------------------------------------------- /Assemblies/0MultiplayerAPI.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Assemblies/0MultiplayerAPI.dll -------------------------------------------------------------------------------- /Assemblies/FluffyUI.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Assemblies/FluffyUI.dll -------------------------------------------------------------------------------- /Assemblies/WorkTab.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Assemblies/WorkTab.dll -------------------------------------------------------------------------------- /Defs/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mood 6 | WorkTab.PawnColumnWorker_Mood 7 | true 8 | Mood 9 | UI/Icons/Mood/happy 10 | (16,16) 11 | 12 | 13 | 14 | Job 15 | WorkTab.PawnColumnWorker_Job 16 | true 17 | Current job 18 | UI/Icons/Various/cog 19 | (16,16) 20 | 21 | 22 | 23 | CopyPasteDetailedWorkPriorities 24 | WorkTab.PawnColumnWorker_CopyPasteDetailedWorkPriorities 25 | 26 | 27 | 28 | Favourite 29 | WorkTab.PawnColumnWorker_Favourite 30 | Favourite 31 | UI/Icons/star 32 | (16,16) 33 | 34 | 35 | 36 | WorkTabLabel 37 | WorkTab.PawnColumnWorker_WorkTabLabel 38 | true 39 | 100 40 | 41 | 42 | -------------------------------------------------------------------------------- /Languages/ChineseSimplified/DefInjected/PawnColumnDef/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 心情 5 | 当前任务 6 | 偏好工作 7 | 8 | 9 | -------------------------------------------------------------------------------- /Languages/ChineseSimplified/Keyed/Keyed-English.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 更好的工作页 4 | 5 | 6 | 当前显示数值型优先级\n\n点击切换至开关型优先级 7 | 当前显示开关型优先级\n\n点击切换至数值型优先级 8 | 当前显示计划型优先级\n\n点击切换至全天型优先级 9 | 当前显示全天型优先级\n\n点击切换至计划型优先级 10 | 点击以展开为详细优先级\n按住Ctrl点击工作可切换显示详细优先级 11 | 点击以折叠为简要优先级\n按住Ctrl点击工作可切换显示简要优先级 12 | 13 | 14 | Shift+左键点击或滚轮上滚以提升优先级\nShift+右键点击或滚轮下滚以降低优先级 15 | Shift+左键点击或滚轮上滚以开启优先级\nShift+右键点击或滚轮下滚以关闭优先级 16 | Ctrl+点击以展开详细优先级列表 17 | Ctrl+点击以收起详细优先级列表 18 | 19 | 20 | 24小时模式 21 | 时间显示是以12小时制(比如:中午、9p.m.)或24小时制(比如:12:00、21:00)。 22 | 优先级等级 23 | 优先级使用多少个等级(限制在4至9之间)。 24 | 提示音 25 | 更改优先级时播放提示音吗? 26 | 嘎吱声 27 | 当给小人分配不熟练的工作时,是否播放嘎吱声吗? 28 | 禁用滚轮代替点击 29 | 禁用滚轮代替点击功能(当鼠标悬停在技能上时) 30 | 垂直显示并旋转标签字体 31 | 垂直显示并旋转标签字体 32 | 修复旋转显示字体 33 | Unity(RimWorld的引擎)不能很好地处理旋转字体从而导致模糊。此修复程序消除了模糊,但可能会导致字体位置稍微有些奇怪。 34 | 35 | 36 | {0}-{1}当前{2} 37 | 已选择 38 | 未选择 39 | 点击以选择\n按住Shift点击以取消所有其他选择 40 | 点击以聚焦 41 | 右键点击以取消 42 | 午夜 43 | 中午 44 | 选择整天 45 | 选择当前小时 46 | 47 | 48 | {0} 被指派了 {1} 49 | 50 | 51 | 点击跳转到\n按住Shift点击或滚轮向上以增加优先级\n按住Shift点击右键或滚轮向下以减小优先级 52 | 53 | 54 | 创建偏好工作 55 | 读取偏好工作 56 | 清空偏好工作 57 | 取消读取 58 | 取消读取并删除 59 | 偏好工作配置名称 60 | 创建新的偏好工作 61 | 编辑 "{0}" 62 | 63 | 偏好工作配置名称不可为空 64 | "{0}" 不是一个可用的配置名称,必须是一个合法的文件名。 65 | 已有同名偏好工作配置名称。 66 | 67 | -------------------------------------------------------------------------------- /Languages/ChineseTraditional/DefInjected/PawnColumnDef/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 心情 5 | 當前任務 6 | 偏愛 7 | 8 | 9 | -------------------------------------------------------------------------------- /Languages/ChineseTraditional/Keyed/Keyed-English.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | Work Tab 4 | 5 | 6 | 當前顯示數值型優先級\n\n點擊切換至開關型優先級 7 | 當前顯示開關型優先級\n\n點擊切換至數值型優先級 8 | 當前顯示計畫型優先級\n\n點擊切換至全天型優先級 9 | 當前顯示全天型優先級\n\n點擊切換至計畫型優先級 10 | 當前顯示詳細優先級\nCtrl+點擊以切换詳細優先級 11 | 當前顯示縮略優先級\nCtrl+點擊以切换縮略優先級 12 | 13 | 14 | Shift+左鍵點擊或滾輪上滾以提升優先級\nShift+右鍵點擊或滾輪下滾以降低優先級 15 | Shift+左鍵點擊或滾輪上滾以開啟優先級\nShift+右鍵點擊或滾輪下滾以關閉優先級 16 | Ctrl+點擊以展開詳細優先級列表 17 | Ctrl+點擊以收起詳細優先級列表 18 | 19 | 20 | 24小時模式 21 | 時間顯示是以12小時制(比如:中午、9p.m.)或24小時制(比如:12:00、21:00)。 22 | 優先級等級 23 | 優先級使用多少個等級(限制在4至9之間)。 24 | 音效 25 | 當優先級變更時播放音效? 26 | 嘎吱聲 27 | 當為殖民者分配不擅長的工作時,是否要播放嘎吱聲? 28 | 禁用滾輪代替點擊 29 | 禁用滾輪代替點擊(當滑鼠懸停在技能上時) 30 | 垂直顯示字體 31 | 垂直顯示字體 32 | 修復垂直顯示字體 33 | Unity (Rimworld的引擎)不能很好地處理垂直字體并導致模糊。此修復程序消除了模糊,但可能導致字體位置稍微有些奇怪。 34 | 35 | 36 | {0}-{1}當前{2} 37 | 已選擇 38 | 未選擇 39 | 點擊以選擇\nShift+點擊來取消其他選擇 40 | 點擊以聚焦 41 | 右鍵點擊來取消 午夜 42 | 中午 43 | 選擇全天 44 | 選擇當前小時 45 | 46 | 47 | {0} 負責 {1} 48 | 49 | 50 | 點擊來跳轉\nShift+點擊或滾輪向上來增加優先級\nShift+右鍵點擊或滾輪向下來減少優先級 51 | 52 | 53 | 創建偏愛 54 | 讀取偏愛 55 | 清理偏愛 56 | 取消讀取 57 | 取消讀取并刪除 58 | 偏愛 59 | 創建偏愛 60 | 編輯 "{0}" 61 | 62 | 偏愛名不可為空 63 | "{0}" 不是一個可用的偏愛名,必須使用可作為文件名的名稱。 64 | 同名偏愛已存在 65 | 66 | -------------------------------------------------------------------------------- /Languages/English/Keyed/Keyed-English.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Work Tab 4 | 5 | 6 | Currently showing numeric priorities\n\nClick to switch to on/off priorities 7 | Currently showing on/off priorities\n\nClick to switch to numeric priorities 8 | Currently showing all-day priorities\n\nClick to switch to scheduled priorities 9 | Currently showing scheduled priorities\n\nClick to switch to all-day priorities 10 | Click to expand all priorities\nCtrl-click headers to toggle expanding individual priorities 11 | Click to collapse all priorities\nCtrl-click headers to toggle expanding individual priorities 12 | 13 | 14 | Shift + left-click or scroll up to increase priorities\nShift + right click or scroll down to decrease priorities 15 | Shift + left-click or scroll up to toggle priorities on\nShift + right click or scroll down to toggle priorities off 16 | Ctrl + click to expand list of detailed priorities 17 | Ctrl + click to collapse list of detailed priorities 18 | 19 | 20 | 24 hour mode 21 | Should times be shown in 12h (e.g. noon, 9p.m.) or 24h (e.g. 12:00, 21:00) mode? 22 | Levels of priority 23 | How many levels of priority should we use? (Limited to between 4 and 9) 24 | Sounds 25 | Play sounds when a priority is changed? 26 | Crunchy sounds 27 | Play a crunchy sound when a pawn is assigned to a job they are not skilled at? 28 | Disable Scrollwheel 29 | Disable the scrollwheel functions (when hovering over skills) 30 | Vertical labels 31 | Display work labels vertically 32 | Fix vertical fonts 33 | Unity (the engine RimWorld is built on) does not deal well with rotated fonts, causing a blur. This fix removes the blur, but can cause slightly odd letter positioning. 34 | 35 | 36 | {0}-{1} is currently {2}\n\n{3} 37 | selected 38 | not selected 39 | Click to select\nShift-click to deselect all others 40 | Click to focus 41 | Right click to deselect 42 | midnight 43 | noon 44 | Select whole day 45 | Select current hour 46 | 47 | 48 | {0} is assigned to {1} 49 | 50 | 51 | Click to jump to\nShift-left-click or scroll up to increment priorities\nShift-right-click or scroll down to decrement priorities 52 | 53 | 54 | Create new favourite 55 | Load favourite 56 | Clear favourite 57 | Unload 58 | Unload and delete 59 | Favourite 60 | Create new favourite 61 | Editing "{0}" 62 | No favourites stored 63 | 64 | Favourite name cannot be empty 65 | "{0}" is not a valid name, favourite names must be valid file names 66 | A favourite of that name already exists 67 | 68 | 69 | Will not do 70 | Top priority 71 | Very high priority 72 | High priority 73 | Above normal priority 74 | Normal priority 75 | Below normal priority 76 | Low priority 77 | Very low priority 78 | Lowest priority 79 | 80 | -------------------------------------------------------------------------------- /Languages/French/DefInjected/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Humeur 5 | Travail actuel 6 | 7 | 8 | -------------------------------------------------------------------------------- /Languages/French/Keyed-French.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Onglet Travail 4 | 5 | 6 | Montre actuellement les priorités numériques\n\nClic pour passer aux priorités activées/désactivées 7 | Montre actuellement les priorités activées/désactivées\n\nClic pour passer aux priorités numériques 8 | Montre actuellement les priorités pour toutes la journée\n\nClic pour passer aux priorités programmées 9 | Montre actuellement les priorités programmées\n\nClic pour passer aux priorités pour toute la journée 10 | Clic pour développer toutes les priorités\nCtrl-clic sur les entêtes pour développer des priorités individuellement 11 | Clic pour masquer toutes les priorités\nCtrl-clic sur les entêtes pour masquer des priorités individuellement 12 | 13 | 14 | Shift + clic-gauche ou scroller vers le haut pour augmenter les priorités\nShift + clic-droit ou scroller vers le bas pour diminuer les priorités 15 | Shift + clic-gauche ou scroller vers le haut pour activer une priorité\nShift + clic-droit ou scroller vers le bas pour désactiver une priorité 16 | Ctrl + clic pour afficher la liste détaillée des priorités 17 | Ctrl + clic pour masquer la liste détaillée des priorités 18 | 19 | 20 | Mode 24 heure 21 | Les heures devraient-elles être affiché en mode 12h (ex. 9p.m.) ou en mode 24h (ex. 12:00, 21:00) ? 22 | Niveaux de priorité 23 | Combien de niveaux de priorité devrait-être utiliser ? (Limité entre 4 et 9) 24 | Sons 25 | Jouer un son quand une priorité est changé ? 26 | Craquemments 27 | Jouer un son de craquemment quand un colons est assigné à un métier pour lequed il n'est pas qualifié ? 28 | Désactiver la mollette 29 | Désactive les fonctions de la molette (en passant au dessus des compétences) 30 | Intitulés verticaux 31 | Affiche les intitulés des métiers verticalement 32 | Réparer les polices verticales 33 | Unity (le moteur de jeu de Rimworld) ne gère pas les polices verticales, et crée du flou. Cette réparation enlève ce flou, mais peut un positionnement des lettres assez étrange. 34 | 35 | 36 | {0}-{1} est actuellement {2}\n\n{3} 37 | sélectionné 38 | non sélectionné 39 | Clic pour sélectionner\nShift-clic pour désélectionner tout le reste 40 | Clic pour faire la mise au point 41 | Clic-droit pour désélectionner 42 | miniut 43 | midi 44 | Sélectionner toute la journée 45 | Selectionner l'heure actuelle 46 | 47 | 48 | {0} est assigné à {1} 49 | 50 | 51 | Clic pour passer directement\nShift-clic-gauche ou scrollez vers le haut pour incrémenter les priorités\nShift-clic-droit ou scroll or scrollez vers le bas pour décrémenter les priorités 52 | 53 | 54 | Créer un nouveau favori 55 | Charger un favouri 56 | Purger un favori 57 | Décharger 58 | Décharger et supprimer 59 | Favoris 60 | Créer un nouveau favori 61 | Modification de "{0}" 62 | 63 | Le nom du favori ne peut être vide 64 | "{0}" n'est pas un nom valide, les noms des favoris doivent être des noms de fichiers valides 65 | Un favori de ce nom existe déja 66 | 67 | -------------------------------------------------------------------------------- /Languages/German/DefInjected/PawnColumnDef/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Stimmung 5 | Aktueller Job 6 | 7 | 8 | -------------------------------------------------------------------------------- /Languages/German/Keyed/WorkTab-German-Keyed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Arbeitsplan 4 | 5 | 6 | Numerische Priorisierung wird angezeigt\n\nKlick, um zur an/aus Priorisierung zu wechseln 7 | An/Aus Priorisierung wird angezeigt\n\nKlick, um zur numerischen Priorisierung zu wechseln 8 | Zeitunabhängige Priorisierung wird angezeigt\n\nKlick, um zur zeitbasierten Priorisierung zu wechseln 9 | Zeitbasierte Priorisierung wird angezeigt\n\nKlick, um zur zeitunabhängigen Priorisierung zu wechseln 10 | Klick, um alle Prioritäten auszuklappen\nStrg-klick auf Kopfzeile, um individuell die Prioritäten ein- und auszuklappen 11 | Klick, um alle Prioritäten einzuklappen\nStrg-klick auf Kopfzeile, um individuell die Prioritäten ein- und auszuklappen 12 | 13 | 14 | Shift + Linksklick oder hochscrollen, um die Prioritäten zu erhöhen\nShift + Rechtsklick oder runterscrollen, um die Prioritäten zu verringern 15 | Shift + Linksklick oder hochscrollen, um die Prioritäten anzuschalten\nShift + Rechtsklick oder runterscrollen, um die Prioritäten auszuschalten 16 | Strg + klick, um die detailierte Priorisierungsliste auszuklappen 17 | Strg + klick, um die detailierte Priorisierungsliste einzuklappen 18 | 19 | 20 | 24 Stunden Modus 21 | Sollen Zeiten in 12h (z.B. 9a.m, 9p.m.) der in 24h (z.B. 12:00, 21:00) Modus angezeigt werden? 22 | Anzahl Stufen von Prioritäten 23 | Wie viele Stufen von Prioritäten sollen eingestellt werden? (Wähle zwischen 4 und 9) 24 | Geräusche 25 | Soll ein Geräusch abgespielt werden, wenn die Priorität verändert wird? 26 | Knackige Geräusche 27 | Soll ein knackiges Geräusch abgespielt werden, wenn ein Koloniest einem Job zugeordnet wird, welches er nicht beherrscht? 28 | Scrollrad deaktivieren 29 | Deaktiviert die Scrollradfunktion (wenn die Maus sich über Prioritäten befindet) 30 | Vertikale Beschriftung 31 | Zeigt Arbeitsbeschriftungen vertikal an 32 | Feste vertikale Schriftart 33 | Unity (die Engine womit RimWorld mit erstellt worden ist) kann nicht gut mit rotierten Schriftarten umgehen und verursacht ein verwischen. Dieser Fix entfernt das verwischen, aber es kann zu einer leichten Verschiebung der Buchstaben führen 34 | 35 | 36 | {0}-{1} ist aktuell {2}\n\n{3} 37 | ausgewählt 38 | nicht ausgewählt 39 | Klick, um ausgewählen\nShift-klick, um alle anderen zu deselektieren 40 | Klick für Fokus 41 | Rechts klick zum deselektieren 42 | Mitternacht 43 | Mittag 44 | Wähle ganzen Tag 45 | Wähle aktuelle Stunde 46 | 47 | 48 | {0} ist zugeordnet zu {1} 49 | 50 | 51 | Klick, um hinzuspringen\nShift-Linksklick oder hochscrollen, um die Prioritäten zu erhöhen\nShift-Rechtsklick oder runterscrollen, um die Prioritäten zu verringern 52 | 53 | -------------------------------------------------------------------------------- /Languages/German/LanguageInfo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Deutsch 4 | German 5 | true 6 | 7 |
  • 8 | Credit_Translator 9 | Chaos 10 |
  • 11 |
    12 |
    13 | -------------------------------------------------------------------------------- /Languages/Korean/DefInjected/PawnColumnDef/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 기분 5 | 작업 6 | 7 | 8 | -------------------------------------------------------------------------------- /Languages/Korean/Keyed/Keyed-English.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 작업 탭 4 | 5 | 6 | 현재 숫자 방식 우선 순위 정책을 보고 있습니다.\n\n클릭해 토글 방식 우선 순위 정책 보기로 전환합니다. 7 | 현재 토글 방식 우선 순위 정책을 보고 있습니다.\n\n클릭해 숫자 방식 우선 순위 정책 보기로 전환합니다. 8 | 현재 24시간 적용되는 우선 순위 정책을 보고 있습니다.\n\n클릭해 시간대별 우선 순위 정책 보기로 전환합니다. 9 | 현재 시간대별 우선 순위 정책을 보고 있습니다.\n\n클릭해 24시간 적용되는 우선 순위 정책 보기로 전환합니다. 10 | 클릭해 세부적인 우선 순위 정책을 확장합니다.\n해더를 Ctrl-click 하여 개별 우선 순위 정책에 대한 상세 보기를 확장합니다. 11 | 클릭해 세부적인 우선 순위 정책을 축소합니다.\n해더를 Ctrl-click 해서 개별 우선 순위 정책에 대한 상세 보기를 축소합니다. 12 | 13 | 14 | Shift + 왼쪽 클릭 혹은 휠 업으로 우선 순위를 올립니다.\nShift + 오른쪽 클릭 혹은 휠 다운으로 우선 순위를 낮춥니다. 15 | Shift + 왼쪽 클릭 혹은 휠 업으로 우선 순위를 토글을 켭니다.\nShift + 오른쪽 클릭 혹은 휠 다운으로 우선 순위 토글을 끕니다. 16 | Ctrl + 클릭으로 상세 우선 순위 리스트를 확장합니다. 17 | Ctrl + 클릭으로 상세 우선 순위 이스트를 축소합니다. 18 | 19 | 20 | 24 시간 모드 21 | 활성화 시 시간을 24시간 형식(예. 12:00, 21:00)보기로 전환합니다. 22 | 우선 순위 구분 단계 23 | 우선 순위를 얼마나 많은 단계로 나누길 원하시나요? (4에서 9사이 값으로 제한됨) 24 | 소리 25 | 우선 순위가 변경되면 소리로 알릴까요? 26 | 바삭한 소리 27 | 림이 할당된 작업에 스킬이 모자른 경우 소리로 알릴까요? 28 | 마우스 휠 비활성화 29 | 기술 위에 마우스를 호버했을 때 동작하는 휠 기능을 비활성화 합니다. 30 | 수직 레이블 31 | 일 레이블을 수직으로 배치합니다. 32 | 수직 폰트 수정 33 | 유니티(림월드를 만든 엔진)은 회전된 폰트에 대해 제대로 처리하지 못해 블러 효과를 일으킵니다. 이 수정은 블러를 제거하지만 글자가 약간 이상한 곳에 위치할 수 있습니다. 34 | 35 | 36 | {0}-{1} 은 현재 {2}\n\n{3} 37 | 선택됨 38 | 선택되지 않음 39 | 클릭해 선택\nShift-클릭으로 나머지 선택 해제 40 | 클릭한 시간대 보기 41 | 오른쪽 클릭으로 선택 해제 42 | 자정 43 | 정오 44 | 하루 전체 선택 45 | 현시간 선택 46 | 47 | 48 | {0}은/는 {1}에 할당되었습니다. 49 | 50 | 51 | 클릭하여 이동\nShift-왼쪽 클릭 혹은 휠 업으로 우선 순위 올림\nShift-오른쪽 클릭 혹은 휠 다운으로 우선 순위 낮춤 52 | 53 | -------------------------------------------------------------------------------- /Languages/Russian/DefInjected/PawnColumnDef/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Настроение 5 | Текущая задача 6 | 7 | 8 | -------------------------------------------------------------------------------- /Languages/Russian/Keyed/Keyed-Russian.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Вкладка работы 4 | 5 | 6 | Сейчас отображается точная (числовая) настройка приоритетов\n\nНажмите для переключения на простую (вкл/выкл) настройку приоритетов 7 | Сейчас отображается простая (вкл/выкл) настройка приоритетов\n\nНажмите для переключения на точную (числовую) настройку приоритетов 8 | Сейчас отображается обычная (полнодневная) приоритизация\n\nНажмите для переключения на приоритизацию с учётом времени 9 | Сейчас отображается приоритизация с учётом времени\n\nНажмите для переключения на обычную (полнодневную) приоритизацию 10 | Нажмите, чтобы развернуть все приоритеты\nCtrl+ЛКМ по заголовку развернёт только его 11 | Нажмите, чтобы свернуть все приоритеты\nCtrl+ЛКМ по заголовку свернёт только его 12 | 13 | 14 | Shift+ЛКМ или Shift+прокрутка вверх повысит приоритет этой задачи для всех поселенцев\nShift+ПКМ или Shift+прокрутка вниз понизит приоритет этой задачи для всех поселенцев 15 | Shift+ЛКМ или Shift+прокрутка вверх назначит эту задачу всем поселенцам\nShift+ПКМ или Shift+прокрутка вниз освободит всех поселенцев от этой задачи 16 | Ctrl+ЛКМ развернёт подробный список приоритетов 17 | Ctrl+ЛКМ свернёт подробный список приоритетов 18 | 19 | 20 | 24-часовой режим 21 | Отображать время в 12-часовом (например полдень, 9p.m.) или 24-часовом (например 12:00, 21:00) режиме? 22 | Уровни приоритета 23 | Сколько нужно уровней приоритета? (от 4 до 9) 24 | Звук 25 | Воспроизводить звук при изменении приоритета? 26 | Хруст 27 | Воспроизводить хрустящий звук при назначении поселенцу работы, в которой он ничего не смыслит 28 | Отключить прокрутку 29 | Отключить функцию прокрутки колёсиком мыши (при наведении курсора на навыки) 30 | Вертикальные метки 31 | Отображение меток работ по вертикали 32 | Исправление шрифтов 33 | Unity (движок, на котором основан RimWorld) не очень хорошо справляется с повернутыми шрифтами, вызывая размытие. Эта опция устраняет размытие, но может вызвать странное позиционирование букв. 34 | 35 | 36 | Временной интервал {0}-{1} сейчас {2}\n\n{3} 37 | выделен 38 | не выделен 39 | Нажмите для выделения\nShift+ЛКМ выделит только этот интервал 40 | Нажмите для перехода 41 | ПКМ снимет выделение 42 | полночь 43 | полдень 44 | Выделить весь день 45 | Выделить текущий час 46 | 47 | 48 | {0} назначен(а) {1} 49 | 50 | 51 | Нажмите для перехода к поселенцу\nShift+ЛКМ или Shift+прокрутка вверх — повысить приоритеты всех задач для поселенца\nShift+ПКМ или Shift+прокрутка вниз — понизить приоритеты всех задач для поселенца 52 | 53 | 54 | -------------------------------------------------------------------------------- /Languages/Spanish/DefInjected/PawnColumnDef/PawnColumnDefs.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Humor 5 | Trabajo actual 6 | 7 | 8 | -------------------------------------------------------------------------------- /Languages/Spanish/Keyed/Keyed-Spanish.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Work Tab 5 | 6 | 7 | Actualmente se muestra las prioridades numéricas\n\nHaga clic para cambiar a las prioridades de encendido/apagado 8 | Actualmente muestra las prioridades de encendido/apagado\n\nHaga clic para cambiar a las prioridades numéricas 9 | Actualmente mostrando las prioridades de todo el día\n\nHaga clic para cambiar a las prioridades programadas 10 | Actualmente muestra las prioridades programadas\n\nHaga clic para cambiar a las prioridades de todo el día 11 | Haga clic para expandir todas las prioridades\nCtrl-clic encabezados para alternar la expansión de las prioridades individuales 12 | Haga clic para contraer todas las prioridades\nCtrl-clic encabezados para alternar la expansión de las prioridades individuales 13 | 14 | 15 | Shift + clic izquierdo o desplazarse hacia arriba para aumentar las prioridades\nShift + clic derecho o desplácese hacia abajo para disminuir las prioridades 16 | Shift + clic izquierdo o desplazarse hacia arriba para alternar prioridades en\nShift + clic derecho o desplácese hacia abajo para alternar las prioridades 17 | Ctrl + clic para ampliar la lista de prioridades detalladas 18 | Ctrl + clic para colapsar la lista de prioridades detalladas 19 | 20 | 21 | Modo 24 horas 22 | En caso de que se quieran mostrar las horas en formato de 12h (e.j. mediodía, 9p.m.) o 24h (e.j. 12:00, 21:00) 23 | Niveles de prioridad 24 | ¿Cuántos niveles de prioridad deberíamos usar? (Limitado entre 4 y 9) 25 | Sonidos 26 | Reproducir sonido cuando se cambia una prioridad 27 | Sonidos crujientes 28 | Reproduce un sonido crujiente cuando se asigna un peón a un trabajo para el que no son expertos 29 | Disable Scrollwheel 30 | Disable the scrollwheel functions (when hovering over skills) 31 | Vertical labels 32 | Display work labels vertically 33 | Fix vertical fonts 34 | Unity (the engine RimWorld is built on) does not deal well with rotated fonts, causing a blur. This fix removes the blur, but can cause slightly odd letter positioning. 35 | 36 | 37 | {0}-{1} está actualmente {2}\n\n{3} 38 | seleccionado 39 | no seleccionado 40 | Clic para seleccionar\nShift-clic para anular la selección de todos los demás 41 | Clic para enfocar 42 | Haga clic derecho para deseleccionar 43 | medianoche 44 | mediodia 45 | Seleccionar todo el día 46 | Seleccione la hora actual 47 | 48 | 49 | {0} está asignado a {1} 50 | 51 | 52 | Clic para saltar a\nHaga clic con el botón izquierdo del mouse o desplácese hacia arriba para aumentar las prioridades\nHaga clic con el botón derecho del ratón o desplácese hacia abajo para disminuir las prioridades 53 | 54 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Provides a vastly more customizable work tab. 2 | 3 | ![Important](https://headers.karel-kroeze.nl/title/Important.png) 4 | 5 | Work Tab completely takes over job priorities from the vanilla game. In order to support core functionalities and other mods, it intercepts calls to get/set priorities. However, when it is told to set priorities by other modded code that is not aware of the time schedule or detailed priorities, the priority will be set for the whole day, and/or for all workgivers in a worktype. 6 | 7 | ![Features](https://headers.karel-kroeze.nl/title/Features.png) 8 | 9 | Various usability extentions to the 'vanilla' work tab; 10 | 11 | - Work types can be expanded (by Ctrl+clicking the column header) to allow you to set priorities for the individual tasks within each work type. 12 | - Time scheduler to set priorities for a given time slot only - allowing you to designate a cleaning hour, or have your cook prepare meals right before dinner, etc. etc. 13 | - Up to 9 priority levels (configurable in mod options) 14 | - Various small UX tweaks; scrolling to increase/decrease/toggle priorities, increase/decrease priorities for whole columns/rows (by holding shift and clicking/scrolling while hovering over the column header/pawn name respectively). 15 | - _All functions are detailed in the tooltips, take a moment to hover over and read them!_ 16 | 17 | ![Known Issues](https://headers.karel-kroeze.nl/title/Known%20Issues.png) 18 | 19 | - `"Star Wars -- The Force"` versions prior to 1.21.1 cause priorities to reset for force users. **THIS INCLUDES THE CURRENT STEAM VERSION OF STAR WARS -- THE FORCE!** (as of 25/3/20). There is an official update available by one of the collaborators on the mod on [GitHub](https://github.com/jecrell/Star-Wars---The-Force/releases). 20 | 21 | - `Better Pawn Control` has added support for `Work Tab` and `Animal Tab`, but there currently (as of 27/7/21) still is an issue where work settings may reset. 22 | 23 | ![Notes](https://headers.karel-kroeze.nl/title/Notes.png) 24 | 25 | With great power comes great responsibility. The default priorities of tasks within a job is set for a good reason; it's (usually) a sensible default. Changing these can lead to deadlock situations, so change the priorities of individual jobs at your own risk! 26 | 27 | Finally, there will never be an 'autolabour' mode where a mod sets priorities for you. Due to the way the AI is handled (e.g. pawns actively look for work, instead of there being a 'bulletin board' of jobs that need doing), it's not feasible to get the complete list of work that needs doing that would be needed to make this a reality, without extreme overhead and loads of special exception coding. 28 | 29 | ![Powered by Harmony](https://headers.karel-kroeze.nl/title/Powered%20by%20Harmony.png) 30 | 31 | ![Powered by Harmony](https://raw.githubusercontent.com/pardeike/Harmony/master/HarmonyLogo.png) 32 | 33 | ![Think you found a bug?](https://headers.karel-kroeze.nl/title/Think%20you%20found%20a%20bug%3F.png) 34 | 35 | Please read [this guide](http://steamcommunity.com/sharedfiles/filedetails/?id=725234314) before creating a bug report, 36 | and then create a bug report [here](https://github.com/fluffy-mods/WorkTab/issues) 37 | 38 | ![Older versions](https://headers.karel-kroeze.nl/title/Older%20versions.png) 39 | 40 | All current and past versions of this mod can be downloaded from [GitHub](https://github.com/fluffy-mods/WorkTab/releases). 41 | 42 | ![License](https://headers.karel-kroeze.nl/title/License.png) 43 | 44 | All original code in this mod is licensed under the [MIT license](https://opensource.org/licenses/MIT). Do what you want, but give me credit. 45 | All original content (e.g. text, imagery, sounds) in this mod is licensed under the [CC-BY-SA 4.0 license](http://creativecommons.org/licenses/by-sa/4.0/). 46 | 47 | Parts of the code in this mod, and some of the content may be licensed by their original authors. If this is the case, the original author & license will either be given in the source code, or be in a LICENSE file next to the content. Please do not decompile my mods, but use the original source code available on [GitHub](https://github.com/fluffy-mods/WorkTab/), so license information in the source code is preserved. 48 | 49 | Parts of this mod were created by, or derived from works created by; 50 | - Freepik / flaticon.com: helmet preview image ([BY-NC](https://www.freepik.com/)) 51 | 52 | 53 | ![Are you enjoying my mods?](https://headers.karel-kroeze.nl/title/Are%20you%20enjoying%20my%20mods%3F.png) 54 | 55 | Normally, this is where I ask you to show you appreciation by buying me a coffee. 56 | 57 | These are not normal times. Ukraine is being invaded by Russia, at the whim of a ruthless dictator. Innocent people are loosing their lives, and fighting for their continued freedom. 58 | 59 | This is not a matter of politics. This is not a debate. Putins' bloody campaign in Ukraine is illegal, and he will stop at nothing to get what he wants, when he wants it, no matter the cost. The Russian army is invading a country without provocation, bombing civilians and murdering innocents. 60 | 61 | The prospect of waking up to see my country at war is alien to me, as it must have seemed to most Ukrainians. I can do little to influence the outcome of current affairs, but I will do whatever I can. 62 | 63 | **I ask you to join me in supporting the people of Ukraine** 64 | 65 | ![Humanitarian Aid](https://headers.karel-kroeze.nl/title/Humanitarian%20Aid.png) 66 | 67 | If you can, donate to the various charities providing humanitarian aid. If you don't know where to donate, Global Citizen maintains a list of charitable organizations active in the region. 68 | 69 | 70 | 71 | ![Speak up](https://headers.karel-kroeze.nl/title/Speak%20up.png) 72 | 73 | Leaders around the world are deciding on how to respond to Putins' aggression. They are balancing their conscience, and their desire to be re-elected. Many are afraid to impose heavy sanctions because the economic repercussions might loose them votes. The Dutch government, my government, has hinted that they are unwilling to accept Ukranian refugees, and has played a part in allowing Russia to have continued access to international finance. I am ashamed of these actions, taken in my name. 74 | 75 | Whereever your live, please let your government know you care more about supporting the people of Ukraine than you do about the price of gas. Join a protest, write letters, call your representatives, and show them that you care about justice! 76 | -------------------------------------------------------------------------------- /Source/Core/Constants.cs: -------------------------------------------------------------------------------- 1 | // Constants.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | 7 | namespace WorkTab 8 | { 9 | public static class Constants 10 | { 11 | public const int ExtraTopSpace = 40; 12 | public const int HorizontalHeaderHeight = 50; 13 | public const int Margin = 4; 14 | public const float MinTimeBarLabelSpacing = 50f; 15 | public const int TimeBarHeight = 40; 16 | public const int VerticalHeaderHeight = 100; 17 | public const int WorkGiverBoxSize = 20; 18 | public const int WorkGiverWidth = 25; 19 | public const int WorkTypeBoxSize = 25; 20 | public const int WorkTypeWidth = 32; 21 | public static readonly Vector2 PriorityLabelSize = new Vector2( 160, 30 ); 22 | public static Dictionary TruncationCache = new Dictionary(); 23 | public static Dictionary VerticalTruncationCache = new Dictionary(); 24 | } 25 | } -------------------------------------------------------------------------------- /Source/Core/Controller.cs: -------------------------------------------------------------------------------- 1 | // Controller.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using System.Reflection; 6 | using HarmonyLib; 7 | using RimWorld; 8 | using UnityEngine; 9 | using Verse; 10 | 11 | namespace WorkTab 12 | { 13 | public class Controller : Mod 14 | { 15 | public static List allColumns; 16 | 17 | public Controller( ModContentPack content ) : base( content ) 18 | { 19 | // initialize settings 20 | GetSettings(); 21 | 22 | // prefix implied PawnColumnWorker_WorkType generation 23 | // prefix get/set workPriorities 24 | #if DEBUG 25 | Harmony.DEBUG = true; 26 | #endif 27 | var harmony = new Harmony( "fluffy.worktab" ); 28 | harmony.PatchAll( Assembly.GetExecutingAssembly() ); 29 | 30 | // if ( MP.enabled ) 31 | // MP.RegisterAll(); 32 | } 33 | 34 | public override void DoSettingsWindowContents( Rect inRect ) 35 | { 36 | base.DoSettingsWindowContents( inRect ); 37 | Settings.DoWindowContents( inRect ); 38 | } 39 | 40 | public override string SettingsCategory() 41 | { 42 | return "WorkTab".Translate(); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Source/Core/MapComponent_TimeKeeper.cs: -------------------------------------------------------------------------------- 1 | // MapComponent_TimeKeeper.cs 2 | // Copyright Karel Kroeze, 2018-2020 3 | 4 | using RimWorld; 5 | using UnityEngine; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public class MapComponent_TimeKeeper : MapComponent 11 | { 12 | private int currentHour = -1; 13 | 14 | public MapComponent_TimeKeeper( Map map ) : base( map ) 15 | { 16 | } 17 | 18 | #if DEBUG 19 | public override void MapComponentOnGUI() 20 | { 21 | base.MapComponentOnGUI(); 22 | var statusRect = new Rect( 6f, UI.screenHeight / 2f, 150f, 50f ); 23 | Widgets.Label( statusRect, typeof( MainTabWindow_WorkTab ).Assembly.GetName().Version.ToString() ); 24 | } 25 | #endif 26 | 27 | public override void MapComponentTick() 28 | { 29 | base.MapComponentTick(); 30 | 31 | // check if an hour passed every second, staggering out maps 32 | if ( ( Find.TickManager.TicksGame + GetHashCode() ) % 60 == 0 33 | && GenLocalDate.HourOfDay( map ) != currentHour ) 34 | { 35 | // update our current hour 36 | currentHour = GenLocalDate.HourOfDay( map ); 37 | 38 | Logger.Debug( "forcing priority refresh for " + currentHour.FormatHour() ); 39 | 40 | // make pawns update their priorities 41 | foreach ( var pawn in map.mapPawns.FreeColonistsSpawned ) 42 | pawn.workSettings.Notify_UseWorkPrioritiesChanged(); 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Source/Core/Resources.cs: -------------------------------------------------------------------------------- 1 | // Resources.cs 2 | // Copyright Karel Kroeze, 2018-2020 3 | 4 | using System.Linq; 5 | using UnityEngine; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | [StaticConstructorOnStartup] 11 | public static class Resources 12 | { 13 | public static readonly Texture2D[] Icons; 14 | 15 | public static readonly Texture2D 16 | SortingIcon, 17 | SortingDescendingIcon, 18 | MoodHappy, 19 | MoodContent, 20 | MoodDiscontent, 21 | MoodUnhappy, 22 | MoodBroken, 23 | PrioritiesDetailed, 24 | PrioritiesSimple, 25 | PrioritiesTimed, 26 | PrioritiesWholeDay, 27 | PinEye, 28 | PinClock, 29 | Clock, 30 | Half, 31 | Now, 32 | Expand, 33 | Collapse, 34 | LeftArrow, 35 | RightArrow, 36 | StarHollow, 37 | Star, 38 | Edit; 39 | 40 | static Resources() 41 | { 42 | SortingIcon = ContentFinder.Get( "UI/Icons/Sorting" ); 43 | SortingDescendingIcon = ContentFinder.Get( "UI/Icons/SortingDescending" ); 44 | MoodHappy = ContentFinder.Get( "UI/Icons/Mood/happy" ); 45 | MoodContent = ContentFinder.Get( "UI/Icons/Mood/content" ); 46 | MoodDiscontent = ContentFinder.Get( "UI/Icons/Mood/discontent" ); 47 | MoodUnhappy = ContentFinder.Get( "UI/Icons/Mood/unhappy" ); 48 | MoodBroken = ContentFinder.Get( "UI/Icons/Mood/broken" ); 49 | PrioritiesDetailed = ContentFinder.Get( "UI/Icons/numbers" ); 50 | PrioritiesSimple = ContentFinder.Get( "UI/Icons/checks" ); 51 | PrioritiesTimed = ContentFinder.Get( "UI/Icons/clock-scheduler" ); 52 | PrioritiesWholeDay = ContentFinder.Get( "UI/Icons/whole-day" ); 53 | PinEye = ContentFinder.Get( "UI/Icons/pin-eye" ); 54 | PinClock = ContentFinder.Get( "UI/Icons/pin-clock" ); 55 | Clock = ContentFinder.Get( "UI/Icons/clock" ); 56 | Half = ContentFinder.Get( "UI/Icons/half" ); 57 | Now = ContentFinder.Get( "UI/Icons/now" ); 58 | Expand = ContentFinder.Get( "UI/Icons/expand" ); 59 | Collapse = ContentFinder.Get( "UI/Icons/collapse" ); 60 | LeftArrow = ContentFinder.Get( "UI/Icons/LeftArrow" ); 61 | RightArrow = ContentFinder.Get( "UI/Icons/RightArrow" ); 62 | StarHollow = ContentFinder.Get( "UI/Icons/star-hollow" ); 63 | Star = ContentFinder.Get( "UI/Icons/star" ); 64 | Edit = ContentFinder.Get( "UI/Icons/edit" ); 65 | Icons = ContentFinder.GetAllInFolder( "UI/Icons/Various" ).ToArray(); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /Source/Core/Settings.cs: -------------------------------------------------------------------------------- 1 | // Settings.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using UnityEngine; 5 | using Verse; 6 | 7 | namespace WorkTab 8 | { 9 | public class Settings : ModSettings 10 | { 11 | public static int defaultPriority = 3; 12 | public static bool disableScrollwheel; 13 | public static int maxPriority = 9; 14 | public static bool playCrunch = true; 15 | public static bool playSounds = true; 16 | public static bool TwentyFourHourMode = true; 17 | public static bool verticalLabels = true; 18 | private static string _defaultPriorityBuffer = defaultPriority.ToString(); 19 | 20 | // public static bool sharedFavourites = true; 21 | private static bool _fontFix = true; 22 | 23 | // buffers 24 | private static string _maxPriorityBuffer = maxPriority.ToString(); 25 | 26 | public Settings() 27 | { 28 | ApplyFontFix( _fontFix ); 29 | } 30 | 31 | public static void ApplyFontFix( bool state ) 32 | { 33 | LongEventHandler.ExecuteWhenFinished( delegate 34 | { 35 | Logger.Debug( state ? "Applying font fix" : "Disabling font fix" ); 36 | _fontFix = state; 37 | Text.fontStyles[0].font.material.mainTexture.filterMode = 38 | state ? FilterMode.Point : FilterMode.Trilinear; 39 | } ); 40 | } 41 | 42 | public static void DoWindowContents( Rect rect ) 43 | { 44 | var options = new Listing_Standard(); 45 | options.Begin( rect ); 46 | options.TextFieldNumericLabeled( "WorkTab.MaxPriority".Translate(), ref maxPriority, ref _maxPriorityBuffer, 47 | 4, 9, "WorkTab.MaxPriorityTip".Translate(), 1 / 8f ); 48 | options.TextFieldNumericLabeled( "WorkTab.DefaultPriority".Translate(), ref defaultPriority, 49 | ref _defaultPriorityBuffer, 1, 9, "WorkTab.DefaultPriorityTip".Translate(), 50 | 1 / 8f ); 51 | options.CheckboxLabeled( "WorkTab.24HourMode".Translate(), ref TwentyFourHourMode, 52 | "WorkTab.24HourModeTip".Translate() ); 53 | options.CheckboxLabeled( "WorkTab.PlaySounds".Translate(), ref playSounds, 54 | "WorkTab.PlaySoundsTip".Translate() ); 55 | playCrunch = playSounds && playCrunch; // disabling sounds also disables crunch. 56 | options.CheckboxLabeled( "WorkTab.PlayCrunch".Translate(), ref playCrunch, !playSounds, 57 | "WorkTab.PlayCrunchTip".Translate() ); 58 | options.CheckboxLabeled( "WorkTab.DisableScrollwheel".Translate(), ref disableScrollwheel, 59 | "WorkTab.DisableScrollwheelTip".Translate() ); 60 | var verticalLabelsBuffer = verticalLabels; 61 | options.CheckboxLabeled( "WorkTab.VerticalLabels".Translate(), ref verticalLabelsBuffer, 62 | "WorkTab.VerticalLabelsTip".Translate() ); 63 | // options.CheckboxLabeled( "WorkTab.SharedFavourites".Translate(), ref sharedFavourites, 64 | // "WorkTab.SharedFavouritesTip".Translate() ); 65 | 66 | // vertical labels mess up unity's font positioning, and causes anti-aliasing blur 67 | // setting the filtermode to point removes the blur, but causes slight jitter in letter positioning. 68 | // I still think it's the lesser of two evils... 69 | var _fontFixBuffer = _fontFix; 70 | options.CheckboxLabeled( "WorkTab.FontFix".Translate(), ref _fontFixBuffer, 71 | "WorkTab.FontFixTip".Translate() ); 72 | _fontFixBuffer = 73 | verticalLabels && _fontFixBuffer; // disabling vertical labels makes the font fix unnecesary. 74 | 75 | // apply any changes. 76 | if ( _fontFixBuffer != _fontFix ) 77 | ApplyFontFix( _fontFixBuffer ); 78 | if ( verticalLabelsBuffer != verticalLabels ) 79 | { 80 | verticalLabels = verticalLabelsBuffer; 81 | MainTabWindow_WorkTab.Instance?.Table?.SetDirty(); 82 | } 83 | 84 | options.End(); 85 | } 86 | 87 | public override void ExposeData() 88 | { 89 | Scribe_Values.Look( ref maxPriority, "MaxPriority", 9 ); 90 | Scribe_Values.Look( ref defaultPriority, "DefaultPriority", 3 ); 91 | Scribe_Values.Look( ref TwentyFourHourMode, "TwentyFourHourMode", true ); 92 | Scribe_Values.Look( ref playSounds, "PlaySounds", true ); 93 | Scribe_Values.Look( ref playCrunch, "PlayCrunch", true ); 94 | Scribe_Values.Look( ref disableScrollwheel, "DisableScrollwheel" ); 95 | Scribe_Values.Look( ref verticalLabels, "VerticalLabels", true ); 96 | Scribe_Values.Look( ref _fontFix, "FontFix", true ); 97 | 98 | // apply font-fix on load 99 | if ( Scribe.mode == LoadSaveMode.PostLoadInit ) 100 | ApplyFontFix( _fontFix ); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /Source/Core/VanillaWorkSettings.cs: -------------------------------------------------------------------------------- 1 | // VanillaWorkSettings.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System; 5 | using System.Reflection; 6 | using HarmonyLib; 7 | using RimWorld; 8 | using Verse; 9 | 10 | namespace WorkTab 11 | { 12 | public static class VanillaWorkSettings 13 | { 14 | private static FieldInfo pawnFieldInfo; 15 | private static FieldInfo prioritiesFieldInfo; 16 | 17 | public static int GetVanillaPriority( this Pawn pawn, WorkTypeDef worktype ) 18 | { 19 | //public override float GetPriority(Pawn pawn) 20 | if ( pawn.workSettings == null || !pawn.workSettings.EverWork ) return 0; 21 | 22 | if ( prioritiesFieldInfo == null ) 23 | { 24 | prioritiesFieldInfo = typeof( Pawn_WorkSettings ).GetField( "priorities", AccessTools.all ); 25 | if ( prioritiesFieldInfo == null ) 26 | throw new NullReferenceException( "priorities field not found" ); 27 | } 28 | 29 | int priority; 30 | try 31 | { 32 | priority = ( prioritiesFieldInfo.GetValue( pawn.workSettings ) as DefMap )[worktype]; 33 | } 34 | catch ( ArgumentOutOfRangeException ) 35 | { 36 | priority = 0; 37 | Logger.Message( 38 | $"Priority requested for a workgiver that did not yet exist for {pawn.Name.ToStringShort}. Did you add mods in an existing game?" ); 39 | } 40 | catch ( TargetException ) 41 | { 42 | priority = 0; 43 | Logger.Message( 44 | $"Priority requested for a pawn that did not have worksettings ({pawn.Name.ToStringShort})" ); 45 | } 46 | 47 | return priority; 48 | } 49 | 50 | public static Pawn Pawn( this Pawn_WorkSettings worksettings ) 51 | { 52 | if ( pawnFieldInfo == null ) 53 | { 54 | pawnFieldInfo = typeof( Pawn_WorkSettings ).GetField( "pawn", AccessTools.all ); 55 | if ( pawnFieldInfo == null ) 56 | throw new NullReferenceException( "could not get pawn field" ); 57 | } 58 | 59 | return pawnFieldInfo.GetValue( worksettings ) as Pawn; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Source/Extensions/Int_Extensions.cs: -------------------------------------------------------------------------------- 1 | // Int_Extensions.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using RimWorld; 5 | using Verse; 6 | 7 | namespace WorkTab 8 | { 9 | public static class Int_Extensions 10 | { 11 | public static string FormatHour( this int hour ) 12 | { 13 | // 24-hour is simple 14 | if ( Settings.TwentyFourHourMode ) 15 | return hour.ToString( "D2" ) + ":00"; 16 | 17 | // noon/midnight are special 18 | var noon = GenDate.HoursPerDay / 2; 19 | if ( hour == 0 ) 20 | return "midnight".Translate(); 21 | if ( hour == noon ) 22 | return "noon".Translate(); 23 | 24 | // am/pm 25 | return hour % noon + ( hour > noon ? " p.m." : " a.m." ); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Source/Extensions/Listing_Extensions.cs: -------------------------------------------------------------------------------- 1 | // Listing_Extensions.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using Verse; 5 | 6 | namespace WorkTab 7 | { 8 | public static class Listing_Extensions 9 | { 10 | public static void CheckboxLabeled( this Listing_Standard listing, string label, ref bool checkOn, 11 | bool disabled, string tooltip = null ) 12 | { 13 | var rect = listing.GetRect( Text.LineHeight ); 14 | if ( !tooltip.NullOrEmpty() ) 15 | TooltipHandler.TipRegion( rect, tooltip ); 16 | Widgets.DrawHighlightIfMouseover( rect ); 17 | Widgets.CheckboxLabeled( rect, label, ref checkOn, disabled ); 18 | listing.Gap( listing.verticalSpacing ); 19 | } 20 | 21 | public static void TextFieldNumericLabeled( this Listing_Standard listing, string label, ref T value, 22 | ref string buffer, float min = 0, float max = float.MaxValue, 23 | string tooltip = null, float textfieldWidthFraction = 1 / 3f ) 24 | where T : struct 25 | { 26 | var rect = listing.GetRect( Text.LineHeight ); 27 | var fieldRect = rect; 28 | var labelRect = rect; 29 | fieldRect.xMin = rect.xMax - rect.width * textfieldWidthFraction; 30 | labelRect.xMax = fieldRect.xMin; 31 | if ( !tooltip.NullOrEmpty() ) 32 | TooltipHandler.TipRegion( rect, tooltip ); 33 | Widgets.DrawHighlightIfMouseover( rect ); 34 | Widgets.Label( labelRect, label ); 35 | Widgets.TextFieldNumeric( fieldRect, ref value, ref buffer, min, max ); 36 | listing.Gap( listing.verticalSpacing ); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Source/Extensions/Pawn_Extensions.cs: -------------------------------------------------------------------------------- 1 | // Pawn_Extensions.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using RimWorld; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public static class Pawn_Extensions 11 | { 12 | public static bool AllowedToDo(this Pawn pawn, WorkGiverDef workgiver) 13 | { 14 | if (pawn?.story == null) 15 | return true; 16 | if (pawn.IsSlave) 17 | return true; 18 | return !pawn.WorkTypeIsDisabled(workgiver.workType) && 19 | (pawn.CombinedDisabledWorkTags & workgiver.workTags) == WorkTags.None && 20 | (pawn.CombinedDisabledWorkTags & workgiver.workType.workTags) == WorkTags.None; 21 | } 22 | 23 | public static bool CapableOf(this Pawn pawn, WorkGiverDef workgiver) 24 | { 25 | return !workgiver.requiredCapacities.Any(c => !pawn.health.capacities.CapableOf(c)); 26 | } 27 | 28 | public static void DisableAll(this Pawn pawn) 29 | { 30 | foreach (var worktype in DefDatabase.AllDefsListForReading) 31 | pawn.SetPriority(worktype, 0, null); 32 | } 33 | 34 | public static int[] GetPriorities(this Pawn pawn, WorkTypeDef worktype) 35 | { 36 | return PriorityManager.Get[pawn].GetPriorities(worktype); 37 | } 38 | 39 | public static int[] GetPriorities(this Pawn pawn, WorkGiverDef workgiver) 40 | { 41 | return PriorityManager.Get[pawn][workgiver].Priorities; 42 | } 43 | 44 | public static int GetPriority(this Pawn pawn, WorkTypeDef worktype, int hour) 45 | { 46 | if (hour < 0) 47 | hour = GenLocalDate.HourOfDay(pawn); 48 | 49 | return PriorityManager.Get[pawn].GetPriority(worktype, hour); 50 | } 51 | 52 | public static int GetPriority(this Pawn pawn, WorkGiverDef workgiver, int hour) 53 | { 54 | if (hour < 0) 55 | hour = GenLocalDate.HourOfDay(pawn); 56 | 57 | return PriorityManager.Get[pawn].GetPriority(workgiver, hour); 58 | } 59 | 60 | public static void SetPriority(this Pawn pawn, WorkTypeDef worktype, int priority, List hours) 61 | { 62 | PriorityManager.Get[pawn].SetPriority(worktype, priority, hours); 63 | } 64 | 65 | public static void SetPriority(Pawn pawn, WorkTypeDef worktype, int priority, int hour, bool recache = true) 66 | { 67 | if (hour < 0) 68 | hour = GenLocalDate.HourOfDay(pawn); 69 | 70 | PriorityManager.Get[pawn].SetPriority(worktype, priority, hour, recache); 71 | } 72 | 73 | public static void SetPriority(this Pawn pawn, WorkGiverDef workgiver, int priority, List hours) 74 | { 75 | PriorityManager.Get[pawn].SetPriority(workgiver, priority, hours); 76 | } 77 | 78 | public static void SetPriority(this Pawn pawn, WorkGiverDef workgiver, int priority, int hour, 79 | bool recache = true) 80 | { 81 | if (hour < 0) 82 | hour = GenLocalDate.HourOfDay(pawn); 83 | 84 | PriorityManager.Get[pawn].SetPriority(workgiver, priority, hour, recache); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Source/Extensions/String_Extensions.cs: -------------------------------------------------------------------------------- 1 | // String_Extensions.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using System.Collections.Generic; 5 | using Verse; 6 | 7 | namespace WorkTab 8 | { 9 | public static class String_Extensions 10 | { 11 | private static readonly Dictionary _noWrapWidths = new Dictionary(); 12 | 13 | public static float NoWrapWidth( this string text ) 14 | { 15 | float width; 16 | if ( !_noWrapWidths.TryGetValue( text, out width ) ) 17 | { 18 | // store old WW setting 19 | var oldWW = Text.WordWrap; 20 | 21 | // set WW off, and calculate width 22 | Text.WordWrap = false; 23 | width = Text.CalcSize( text ).x; 24 | 25 | // restore WW setting 26 | Text.WordWrap = oldWW; 27 | 28 | // cache width 29 | _noWrapWidths.Add( text, width ); 30 | } 31 | 32 | return width; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Source/Extensions/WorkGiver_Extensions.cs: -------------------------------------------------------------------------------- 1 | // WorkGiver_Extensions.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using RimWorld; 7 | using Verse; 8 | using Verse.Sound; 9 | 10 | namespace WorkTab 11 | { 12 | public static class WorkGiver_Extensions 13 | { 14 | public static void DecrementPriority( this WorkGiverDef workgiver, Pawn pawn, int hour, 15 | List hours, bool playSound = true ) 16 | { 17 | // get default hour if not specified 18 | if ( hour < 0 ) 19 | hour = GenLocalDate.HourOfDay( pawn ); 20 | 21 | // get and decrement priority 22 | var priority = pawn.GetPriority( workgiver, hour ); 23 | pawn.SetPriority( workgiver, priority - 1, hours ); 24 | 25 | // play sounds 26 | if ( Settings.playSounds && playSound && priority > 1 ) 27 | SoundDefOf.Tick_High.PlayOneShotOnCamera(); 28 | if ( Settings.playSounds && playSound && priority == 1 ) 29 | SoundDefOf.Tick_Low.PlayOneShotOnCamera(); 30 | } 31 | 32 | public static void DecrementPriority( this WorkGiverDef workgiver, List pawns, int hour, 33 | List hours, bool playSound = true ) 34 | { 35 | // bail out on bad input 36 | if ( pawns.NullOrEmpty() ) 37 | return; 38 | 39 | // get default hour if not specified, we're assuming all pawns are on the same map/tile 40 | if ( hour < 0 ) 41 | hour = GenLocalDate.HourOfDay( pawns.FirstOrDefault() ); 42 | 43 | // play sounds 44 | if ( Settings.playSounds && playSound && pawns.Any( p => p.GetPriority( workgiver, hour ) != 1 ) ) 45 | SoundDefOf.Tick_High.PlayOneShotOnCamera(); 46 | 47 | // decrease priorities that are not 1 only (no wrapping around once we're at max priority) 48 | foreach ( var pawn in pawns.Where( p => p.GetPriority( workgiver, hour ) != 1 ).DistinctTrackers() ) 49 | DecrementPriority( workgiver, pawn, hour, hours, false ); 50 | } 51 | 52 | public static void IncrementPriority( this WorkGiverDef workgiver, Pawn pawn, int hour, 53 | List hours, bool playSound = true ) 54 | { 55 | // get default hour if not specified 56 | if ( hour < 0 ) 57 | hour = GenLocalDate.HourOfDay( pawn ); 58 | 59 | // get and increment priority 60 | var priority = pawn.GetPriority( workgiver, hour ); 61 | pawn.SetPriority( workgiver, priority + 1, hours ); 62 | 63 | // play sounds 64 | if ( Settings.playSounds && playSound && priority == 0 ) 65 | SoundDefOf.Tick_High.PlayOneShotOnCamera(); 66 | if ( Settings.playSounds && playSound && priority > 0 ) 67 | SoundDefOf.Tick_Low.PlayOneShotOnCamera(); 68 | } 69 | 70 | public static void IncrementPriority( this WorkGiverDef workgiver, List pawns, int hour, 71 | List hours, bool playSound = true ) 72 | { 73 | // bail out on bad input 74 | if ( pawns.NullOrEmpty() ) 75 | return; 76 | 77 | // get default hour if not specified, we're assuming all pawns are on the same map/tile 78 | if ( hour < 0 ) 79 | hour = GenLocalDate.HourOfDay( pawns.FirstOrDefault() ); 80 | 81 | // play sounds 82 | if ( Settings.playSounds && playSound && pawns.Any( p => p.GetPriority( workgiver, hour ) > 0 ) ) 83 | SoundDefOf.Tick_Low.PlayOneShotOnCamera(); 84 | 85 | // increase priorities that are > 0 only (no wrapping around once we're at min priority 86 | foreach ( var pawn in pawns.Where( p => p.GetPriority( workgiver, hour ) > 0 ).DistinctTrackers() ) 87 | IncrementPriority( workgiver, pawn, hour, hours, false ); 88 | } 89 | 90 | internal static IEnumerable DistinctTrackers( this IEnumerable pawns ) 91 | { 92 | var knownTrackers = new HashSet(); 93 | foreach ( var pawn in pawns ) 94 | if ( knownTrackers.Add( PriorityManager.Get[pawn] ) ) 95 | yield return pawn; 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Source/Extensions/WorkType_Extensions.cs: -------------------------------------------------------------------------------- 1 | // WorkType_Extensions.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using RimWorld; 8 | using Verse; 9 | using Verse.Sound; 10 | 11 | namespace WorkTab 12 | { 13 | public static class WorkType_Extensions 14 | { 15 | private static readonly Dictionary> _workgiversByType = 16 | new Dictionary>(); 17 | 18 | private static readonly Dictionary workListCache = new Dictionary(); 19 | 20 | public static void DecrementPriority( this WorkTypeDef worktype, Pawn pawn, int hour = -1, 21 | List hours = null, bool playSound = true ) 22 | { 23 | // get default hour if not specified 24 | if ( hour < 0 ) 25 | hour = GenLocalDate.HourOfDay( pawn ); 26 | 27 | // get and decrement priority 28 | var priority = pawn.GetPriority( worktype, hour ); 29 | pawn.SetPriority( worktype, priority - 1, hours ); 30 | 31 | // play sounds 32 | if ( Settings.playSounds && playSound && priority > 1 ) 33 | SoundDefOf.Tick_High.PlayOneShotOnCamera(); 34 | if ( Settings.playSounds && playSound && priority == 1 ) 35 | SoundDefOf.Tick_Low.PlayOneShotOnCamera(); 36 | } 37 | 38 | public static void DecrementPriority( this WorkTypeDef worktype, List pawns, int hour = -1, 39 | List hours = null, bool playSound = true ) 40 | { 41 | // bail out on bad input 42 | if ( pawns.NullOrEmpty() ) 43 | return; 44 | 45 | // get default hour if not specified, we're assuming all pawns are on the same map/tile 46 | if ( hour < 0 ) 47 | hour = GenLocalDate.HourOfDay( pawns.FirstOrDefault() ); 48 | 49 | // play sounds 50 | if ( Settings.playSounds && playSound && pawns.Any( p => p.GetPriority( worktype, hour ) != 1 ) ) 51 | SoundDefOf.Tick_High.PlayOneShotOnCamera(); 52 | 53 | // decrease priorities that are not 1 only (no wrapping around once we're at max priority) 54 | foreach ( var pawn in pawns.Where( p => p.GetPriority( worktype, hour ) != 1 ).DistinctTrackers() ) 55 | DecrementPriority( worktype, pawn, hour, hours, false ); 56 | } 57 | 58 | public static void IncrementPriority( this WorkTypeDef worktype, Pawn pawn, int hour = -1, 59 | List hours = null, bool playSound = true ) 60 | { 61 | // get default hour if not specified 62 | if ( hour < 0 ) 63 | hour = GenLocalDate.HourOfDay( pawn ); 64 | 65 | // get and increment priority 66 | var priority = pawn.GetPriority( worktype, hour ); 67 | pawn.SetPriority( worktype, priority + 1, hours ); 68 | 69 | // play sounds 70 | if ( Settings.playSounds && playSound && priority == 0 ) 71 | SoundDefOf.Tick_High.PlayOneShotOnCamera(); 72 | if ( Settings.playSounds && playSound && priority > 0 ) 73 | SoundDefOf.Tick_Low.PlayOneShotOnCamera(); 74 | } 75 | 76 | public static void IncrementPriority( this WorkTypeDef worktype, List pawns, int hour = -1, 77 | List hours = null, bool playSound = true ) 78 | { 79 | // bail out on bad input 80 | if ( pawns.NullOrEmpty() ) 81 | return; 82 | 83 | // get default hour if not specified, we're assuming all pawns are on the same map/tile 84 | if ( hour < 0 ) 85 | hour = GenLocalDate.HourOfDay( pawns.FirstOrDefault() ); 86 | 87 | // play sounds 88 | if ( Settings.playSounds && playSound && pawns.Any( p => p.GetPriority( worktype, hour ) > 0 ) ) 89 | SoundDefOf.Tick_Low.PlayOneShotOnCamera(); 90 | 91 | // increase priorities that are > 0 only (no wrapping around once we're at min priority 92 | foreach ( var pawn in pawns.Where( p => p.GetPriority( worktype, hour ) > 0 ).DistinctTrackers() ) 93 | IncrementPriority( worktype, pawn, hour, hours, false ); 94 | } 95 | 96 | public static string SpecificWorkListString( this WorkTypeDef def ) 97 | { 98 | string tip; 99 | if ( workListCache.TryGetValue( def, out tip ) ) 100 | return tip; 101 | 102 | var stringBuilder = new StringBuilder(); 103 | for ( var i = 0; i < def.workGiversByPriority.Count; i++ ) 104 | { 105 | stringBuilder.Append( def.workGiversByPriority[i].LabelCap ); 106 | if ( def.workGiversByPriority[i].emergency ) 107 | stringBuilder.Append( " (" + "EmergencyWorkMarker".Translate() + ")" ); 108 | if ( i < def.workGiversByPriority.Count - 1 ) stringBuilder.AppendLine(); 109 | } 110 | 111 | tip = stringBuilder.ToString(); 112 | workListCache.Add( def, tip ); 113 | return tip; 114 | } 115 | 116 | public static List WorkGivers( this WorkTypeDef worktype ) 117 | { 118 | List result; 119 | if ( !_workgiversByType.TryGetValue( worktype, out result ) ) 120 | { 121 | result = DefDatabase 122 | .AllDefsListForReading.Where( wg => wg.workType == worktype ).ToList(); 123 | _workgiversByType[worktype] = result; 124 | } 125 | 126 | return result; 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /Source/Favourites/Dialog_CreateFavourite.cs: -------------------------------------------------------------------------------- 1 | // Dialog_CreateFavourite.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using FluffyUI; 5 | using RimWorld; 6 | using UnityEngine; 7 | using Verse; 8 | using Widgets = FluffyUI.Widgets; 9 | 10 | namespace WorkTab 11 | { 12 | public class Dialog_CreateFavourite : Dialog_Favourite 13 | { 14 | private readonly Pawn pawn; 15 | 16 | public Dialog_CreateFavourite(Favourite favourite, Pawn pawn) : base(favourite) 17 | { 18 | this.pawn = pawn; 19 | } 20 | 21 | public void ApplyAndClose() 22 | { 23 | var valid = FavouriteManager.IsValidLabel(label, favourite.Label); 24 | if (!valid) 25 | { 26 | Messages.Message(valid.Reason, MessageTypeDefOf.RejectInput, false); 27 | return; 28 | } 29 | 30 | favourite.Icon = textureChooser.Choice; 31 | favourite.Label = label; 32 | 33 | FavouriteManager.Favourites.Add(favourite); 34 | FavouriteManager.Get[pawn] = favourite; 35 | FavouriteManager.Save(favourite); 36 | 37 | Close(); 38 | } 39 | 40 | public override void DoWindowContents(Rect canvas) 41 | { 42 | var rows = new FluffyUI.Grid(canvas).Rows(HEADER_HEIGHT, FIELD_HEIGHT, BUTTON_HEIGHT); 43 | var titleRect = rows[0].Rect; 44 | var nameRect = rows[1].Column(9); 45 | var iconRect = rows[1].Column(3); 46 | rows[2].Column(4); 47 | var cancelRect = rows[2].Column(4); 48 | var okRect = rows[2].Column(4); 49 | 50 | // title and a little text 51 | Widgets.Label(titleRect, "Fluffy.WorkTab.CreateFavouritesDialogTitle".Translate(), font: GameFont.Medium); 52 | 53 | // favourites label 54 | var valid = FavouriteManager.IsValidLabel(label); 55 | GUI.color = valid ? Color.white : Color.red; 56 | label = GUI.TextField(nameRect, label); 57 | GUI.color = Color.white; 58 | 59 | // icon tumbler 60 | textureChooser.DrawAt(iconRect); 61 | 62 | // ok/cancel button. 63 | if (Verse.Widgets.ButtonText(cancelRect, "CancelButton".Translate())) 64 | Close(); 65 | if (Verse.Widgets.ButtonText(okRect, "AcceptButton".Translate())) 66 | ApplyAndClose(); 67 | } 68 | 69 | public override void OnAcceptKeyPressed() 70 | { 71 | ApplyAndClose(); 72 | } 73 | 74 | public override void PostClose() 75 | { 76 | base.PostClose(); 77 | if (favourite.Label.NullOrEmpty() || favourite.Icon == null) 78 | FavouriteManager.Remove(favourite); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Source/Favourites/Dialog_EditFavourite.cs: -------------------------------------------------------------------------------- 1 | // Dialog_EditFavourite.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using FluffyUI; 6 | using RimWorld; 7 | using UnityEngine; 8 | using Verse; 9 | using Widgets = FluffyUI.Widgets; 10 | 11 | namespace WorkTab 12 | { 13 | public class Dialog_EditFavourite : Dialog_Favourite 14 | { 15 | public Dialog_EditFavourite(Favourite favourite) : base(favourite) 16 | { 17 | } 18 | 19 | public void ApplyAndClose() 20 | { 21 | var valid = FavouriteManager.IsValidLabel(label, favourite.Label); 22 | if (!valid) 23 | { 24 | Messages.Message(valid.Reason, MessageTypeDefOf.RejectInput, false); 25 | return; 26 | } 27 | 28 | if (label != favourite.Label) 29 | FavouriteManager.Delete(favourite); 30 | 31 | favourite.Icon = textureChooser.Choice; 32 | favourite.Label = label; 33 | FavouriteManager.Save(favourite); 34 | Close(); 35 | } 36 | 37 | public void DeleteAndClose() 38 | { 39 | var options = new List(); 40 | options.Add(new FloatMenuOption("Fluffy.WorkTab.UnloadFavourite".Translate(), 41 | () => 42 | { 43 | FavouriteManager.Remove(favourite); 44 | Close(); 45 | })); 46 | options.Add(new FloatMenuOption("Fluffy.WorkTab.DeleteFavourite".Translate(), 47 | () => 48 | { 49 | FavouriteManager.Delete(favourite, true); 50 | Close(); 51 | })); 52 | Find.WindowStack.Add(new FloatMenu(options)); 53 | } 54 | 55 | public override void DoWindowContents(Rect canvas) 56 | { 57 | var rows = new FluffyUI.Grid(canvas).Rows(HEADER_HEIGHT, FIELD_HEIGHT, BUTTON_HEIGHT); 58 | var titleRect = rows[0].Rect; 59 | var nameRect = rows[1].Column(9); 60 | var iconRect = rows[1].Column(3); 61 | var deleteRect = rows[2].Column(3); 62 | rows[2].Column(3); // skip 3 63 | var cancelRect = rows[2].Column(3); 64 | var okRect = rows[2].Column(3); 65 | 66 | // title and a little text 67 | Widgets.Label(titleRect, "Fluffy.WorkTab.EditFavouritesDialogTitle".Translate(favourite.Label), 68 | font: GameFont.Medium); 69 | 70 | // favourites label 71 | var valid = FavouriteManager.IsValidLabel(label, favourite.Label); 72 | GUI.color = valid ? Color.white : Color.red; 73 | label = GUI.TextField(nameRect, label); 74 | GUI.color = Color.white; 75 | 76 | // icon tumbler 77 | textureChooser.DrawAt(iconRect); 78 | 79 | // ok/cancel button. 80 | GUI.color = new Color(1f, 0.3f, 0.35f); 81 | if (Verse.Widgets.ButtonText(deleteRect, "Delete".Translate())) 82 | DeleteAndClose(); 83 | GUI.color = Color.white; 84 | if (Verse.Widgets.ButtonText(cancelRect, "CancelButton".Translate())) 85 | Close(); 86 | if (Verse.Widgets.ButtonText(okRect, "AcceptButton".Translate())) 87 | ApplyAndClose(); 88 | } 89 | 90 | public override void OnAcceptKeyPressed() 91 | { 92 | ApplyAndClose(); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /Source/Favourites/Dialog_Favourite.cs: -------------------------------------------------------------------------------- 1 | // Dialog_Favourite.cs 2 | // Copyright Karel Kroeze, 2018-2020 3 | 4 | using FluffyUI; 5 | using UnityEngine; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public abstract class Dialog_Favourite : Window 11 | { 12 | protected const float BUTTON_HEIGHT = 35f; 13 | protected const float FIELD_HEIGHT = 30f; 14 | 15 | protected const float HEADER_HEIGHT = 42f; 16 | 17 | protected Vector2 _size = 18 | new Vector2( 350f, HEADER_HEIGHT + FIELD_HEIGHT + BUTTON_HEIGHT + StandardMargin * 2 ); 19 | 20 | protected Favourite favourite; 21 | protected string label; 22 | protected TextureChooser textureChooser; 23 | 24 | public Dialog_Favourite( Favourite favourite ) 25 | { 26 | this.favourite = favourite; 27 | label = favourite.Label ?? "Fluffy.WorkTab.DefaultFavouriteLabel".Translate(); 28 | textureChooser = new TextureChooser( Resources.Icons ); 29 | } 30 | 31 | public override Vector2 InitialSize => _size; 32 | } 33 | } -------------------------------------------------------------------------------- /Source/Favourites/Favourite.cs: -------------------------------------------------------------------------------- 1 | // Favourite.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using RimWorld; 5 | using UnityEngine; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public class Favourite : PriorityTracker 11 | { 12 | private Texture2D _icon; 13 | private string _iconPath; 14 | private string _label; 15 | private int _loadId; 16 | 17 | public Texture2D Icon 18 | { 19 | get 20 | { 21 | if ( _icon == null && !_iconPath.NullOrEmpty() ) 22 | _icon = ContentFinder.Get( _iconPath ); 23 | return _icon; 24 | } 25 | set 26 | { 27 | _icon = value; 28 | _iconPath = "UI/Icons/Various/" + _icon.name; 29 | } 30 | } 31 | 32 | public string Label 33 | { 34 | get => _label; 35 | set => _label = value; 36 | } 37 | 38 | public static Favourite From( Pawn pawn, bool apply = false ) 39 | { 40 | // create from pawn 41 | var favourite = new Favourite(); 42 | var priorities = PriorityManager.Get[pawn]; 43 | foreach ( var workgiver in DefDatabase.AllDefsListForReading ) 44 | favourite.priorities[workgiver] = priorities[workgiver].Clone( favourite ); 45 | 46 | // open name/icon window 47 | Find.WindowStack.Add( new Dialog_CreateFavourite( favourite, pawn ) ); 48 | 49 | return favourite; 50 | } 51 | 52 | public void Apply( Pawn pawn ) 53 | { 54 | // apply to pawn 55 | var priorities = PriorityManager.Get[pawn]; 56 | foreach ( var workgiver in DefDatabase.AllDefsListForReading ) 57 | priorities[workgiver] = this[workgiver].Clone( priorities ); 58 | } 59 | 60 | public override void ExposeData() 61 | { 62 | base.ExposeData(); 63 | Scribe_Values.Look( ref _loadId, "ID" ); 64 | Scribe_Values.Look( ref _label, "Label" ); 65 | Scribe_Values.Look( ref _iconPath, "IconPath" ); 66 | } 67 | 68 | protected override void OnChange() 69 | { 70 | if ( Scribe.mode == LoadSaveMode.Inactive ) 71 | FavouriteManager.Save( this ); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Source/Favourites/FavouriteManager.cs: -------------------------------------------------------------------------------- 1 | // FavouriteManager.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using FluffyUI; 8 | using FluffyUI.FloatMenu; 9 | using UnityEngine; 10 | using Verse; 11 | using Widgets = Verse.Widgets; 12 | 13 | namespace WorkTab 14 | { 15 | public class FavouriteManager : GameComponent 16 | { 17 | public static List Favourites = new List(); 18 | private static Dictionary _favourites = new Dictionary(); 19 | 20 | public FavouriteManager() 21 | { 22 | Get = this; 23 | } 24 | 25 | public FavouriteManager(Game game) : this() 26 | { 27 | } 28 | 29 | public static FavouriteManager Get { get; private set; } 30 | 31 | private static string FavouriteBasePath 32 | { 33 | get 34 | { 35 | var path = Path.Combine(GenFilePaths.SaveDataFolderPath, "WorkTab_Favourites"); 36 | if (!Directory.Exists(path)) Directory.CreateDirectory(path); 37 | return path; 38 | } 39 | } 40 | 41 | public Favourite this[Pawn pawn] 42 | { 43 | get 44 | { 45 | if (_favourites.TryGetValue(pawn, out var favourite)) 46 | return favourite; 47 | return null; 48 | } 49 | set 50 | { 51 | if (value == null) 52 | _favourites.Remove(pawn); 53 | else 54 | _favourites[pawn] = value; 55 | } 56 | } 57 | 58 | public static void Delete(Favourite favourite, bool remove = false) 59 | { 60 | if (remove) Remove(favourite); 61 | var path = FavouritePath(favourite); 62 | if (File.Exists(path)) File.Delete(path); 63 | } 64 | 65 | 66 | public static void FavouriteFloatMenuFor(Pawn pawn) 67 | { 68 | // create new 69 | var options = new List(); 70 | options.Add(new FloatMenuOption( 71 | "Fluffy.WorkTab.CreateFavourite".Translate(), 72 | () => Favourite.From(pawn, true))); 73 | 74 | // load from disk 75 | options.Add(new FloatMenuOption( 76 | "Fluffy.WorkTab.LoadFavourite".Translate(), 77 | () => LoadFavouriteFloatMenu(pawn))); 78 | 79 | // clear 80 | if (Get[pawn] != null) 81 | options.Add(new FloatMenuOption( 82 | "Fluffy.WorkTab.ClearFavourite".Translate(), 83 | () => Get[pawn] = null)); 84 | 85 | // set favourite in favourites 86 | foreach (var favourite in Favourites) 87 | options.Add(new FloatMenuOption_Aligned( 88 | favourite.Label, 89 | () => Get[pawn] = favourite, 90 | extraPartWidth: 38, 91 | extraPartOnGUI: rect => ExtraPart(rect, favourite))); 92 | Find.WindowStack.Add(new FloatMenu(options)); 93 | } 94 | 95 | 96 | public static FailReason IsValidLabel(string label, string curLabel = null) 97 | { 98 | if (label.NullOrEmpty()) 99 | return "Fluffy.WorkTab.FavouriteLabelCannotBeEmpty".Translate().Resolve(); 100 | 101 | if (!IsValidFileName(label)) 102 | return "Fluffy.WorkTab.FavouriteInvalidFilename".Translate(label).Resolve(); 103 | 104 | if (curLabel != label && File.Exists(FavouritePath(label))) 105 | return "Fluffy.WorkTab.FavouriteAlreadyExists".Translate(label).Resolve(); 106 | 107 | return true; 108 | } 109 | 110 | public static void Remove(Favourite favourite) 111 | { 112 | Favourites.Remove(favourite); 113 | 114 | // remove from pawns 115 | var affected = _favourites 116 | .Where(f => f.Value == favourite) 117 | .Select(f => f.Key) 118 | .ToArray(); 119 | foreach (var pawn in affected) 120 | _favourites.Remove(pawn); 121 | } 122 | 123 | public static void Save(Favourite favourite) 124 | { 125 | Scribe.saver.InitSaving(FavouritePath(favourite), "Favourite"); 126 | favourite.ExposeData(); 127 | Scribe.saver.FinalizeSaving(); 128 | } 129 | 130 | private static bool ExtraPart(Rect rect, Favourite favourite) 131 | { 132 | var rects = new FluffyUI.Grid(rect, gutters: Vector2.zero).Columns(1, 1); 133 | var size = Mathf.Min(16f, rects[0].Rect.width, rects[0].Rect.height); 134 | var iconRect = new Rect(0f, 0f, size, size); 135 | GUI.DrawTexture(iconRect.CenteredIn(rects[0]), favourite.Icon); 136 | if (Widgets.ButtonImage(new Rect(0f, 0f, size, size).CenteredIn(rects[1]), Resources.Edit)) 137 | Find.WindowStack.Add(new Dialog_EditFavourite(favourite)); 138 | 139 | return false; 140 | } 141 | 142 | private static string FavouritePath(Favourite favourite) 143 | { 144 | return FavouritePath(favourite.Label); 145 | } 146 | 147 | private static string FavouritePath(string label) 148 | { 149 | return Path.Combine(FavouriteBasePath, $"{label}.xml"); 150 | } 151 | 152 | private static bool IsValidFileName(string label) 153 | { 154 | return GenFile.SanitizedFileName(label) == label; 155 | } 156 | 157 | private static void LoadFavourite(string path, Pawn pawn) 158 | { 159 | var favourite = new Favourite(); 160 | Scribe.loader.InitLoading(path); 161 | favourite.ExposeData(); 162 | Scribe.loader.crossRefs.RegisterForCrossRefResolve(favourite); 163 | Scribe.loader.initer.RegisterForPostLoadInit(favourite); 164 | Scribe.loader.FinalizeLoading(); 165 | 166 | favourite.SetLoadId(); 167 | Favourites.Add(favourite); 168 | if (pawn != null) 169 | Get[pawn] = favourite; 170 | } 171 | 172 | private static void LoadFavouriteFloatMenu(Pawn pawn) 173 | { 174 | var options = Directory.GetFiles(FavouriteBasePath) 175 | .Select(f => new { path = f, label = Path.GetFileNameWithoutExtension(f) }) 176 | .Where(f => !Favourites.Any(F => F.Label == f.label)) 177 | .Select(f => new FloatMenuOption(f.label, 178 | () => LoadFavourite(f.path, pawn))) 179 | .ToList(); 180 | if (options.Count == 0) 181 | { 182 | options.Add(new FloatMenuOption("Fluffy.WorkTab.NoStoredFavourites", null)); 183 | } 184 | Find.WindowStack.Add(new FloatMenu(options)); 185 | } 186 | 187 | public override void ExposeData() 188 | { 189 | base.ExposeData(); 190 | Scribe_Collections.Look(ref Favourites, "Favourites", LookMode.Deep); 191 | Scribe_Collections.Look(ref _favourites, "FavouriteAssignments", LookMode.Reference, LookMode.Reference); 192 | } 193 | } 194 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/DefGenerator_GenerateImpliedDefs_PreResolve.cs: -------------------------------------------------------------------------------- 1 | // Copyright Karel Kroeze, 2020-2021. 2 | // WorkTab/WorkTab/DefGenerator_GenerateImpliedDefs_PreResolve.cs 3 | 4 | using System.Collections.Generic; 5 | using HarmonyLib; 6 | using RimWorld; 7 | using Verse; 8 | 9 | namespace WorkTab 10 | { 11 | [HarmonyPatch(typeof(DefGenerator), nameof(DefGenerator.GenerateImpliedDefs_PreResolve))] 12 | public class DefGenerator_GenerateImpliedDefs_PreResolve 13 | { 14 | private static void Postfix() 15 | { 16 | // replace worker on Work MainButtonDef 17 | MainButtonDefOf.Work.tabWindowClass = typeof(MainTabWindow_WorkTab); 18 | 19 | // get our table 20 | var workTable = PawnTableDefOf.Work; 21 | 22 | // replace label column 23 | var labelIndex = workTable.columns.IndexOf(PawnColumnDefOf.Label); 24 | workTable.columns.RemoveAt(labelIndex); 25 | workTable.columns.Insert(labelIndex, PawnColumnDefOf.WorkTabLabel); 26 | 27 | // insert mood and job columns before first work column name 28 | var firstWorkindex = 29 | workTable.columns.FindIndex(d => d.workerClass == typeof(PawnColumnWorker_WorkPriority)); 30 | workTable.columns.Insert(firstWorkindex, PawnColumnDefOf.Job); 31 | workTable.columns.Insert(firstWorkindex + 1, PawnColumnDefOf.Mood); 32 | 33 | // go over PawnColumnDefs and replace all PawnColumnWorker_WorkPriority 34 | foreach (var column in DefDatabase.AllDefs) 35 | { 36 | if (column.workerClass == typeof(PawnColumnWorker_WorkPriority)) 37 | { 38 | column.workerClass = typeof(PawnColumnWorker_WorkType); 39 | } 40 | } 41 | 42 | // add PawnColumnDefs for all workgivers 43 | foreach (var workgiver in DefDatabase.AllDefsListForReading) 44 | { 45 | // prepare the def, note that we're not assigning label or tip, we'll get those from the def later. 46 | // we're also not adding the def to the table, we'll do that dynamically when a worktype is expanded. 47 | var column = new PawnColumnDef_WorkGiver(); 48 | column.defName = "WorkGiver_" + workgiver.defName; 49 | column.workgiver = workgiver; 50 | column.workerClass = typeof(PawnColumnWorker_WorkGiver); 51 | column.sortable = true; 52 | 53 | // finalize 54 | column.PostLoad(); 55 | DefDatabase.Add(column); 56 | } 57 | 58 | // replace and move copy/paste to the right 59 | var copyPasteColumnIndex = workTable.columns.IndexOf(PawnColumnDefOf.CopyPasteWorkPriorities); 60 | workTable.columns.RemoveAt(copyPasteColumnIndex); 61 | // Note; the far right column is a spacer to take all remaining available space, so index should be count - 2 (count - 1 before insert). 62 | workTable.columns.Insert(workTable.columns.Count - 1, 63 | PawnColumnDefOf.CopyPasteDetailedWorkPriorities); 64 | 65 | // add favourite column before copy paste 66 | workTable.columns.Insert(workTable.columns.Count - 2, PawnColumnDefOf.Favourite); 67 | 68 | // store this list of all columns 69 | Controller.allColumns = new List(workTable.columns); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/PawnTable/PawnTable_PawnTableOnGUI.cs: -------------------------------------------------------------------------------- 1 | // PawnTable_PawnTableOnGUI.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Reflection; 7 | using HarmonyLib; 8 | using RimWorld; 9 | using UnityEngine; 10 | using Verse; 11 | 12 | namespace WorkTab 13 | { 14 | [HarmonyPatch( typeof( PawnTable ), nameof( PawnTable.PawnTableOnGUI ) )] 15 | public class PawnTable_PawnTableOnGUI 16 | { 17 | private static int _hoveredColumnContent = -1; 18 | private static int _hoveredColumnLabel = -1; 19 | private static int _hoveredRowContent = -1; 20 | private static int _hoveredRowLabel = -1; 21 | private static readonly Type ptt = typeof( PawnTable ); 22 | private static readonly FieldInfo cachedColumnWidthsField = AccessTools.Field( ptt, "cachedColumnWidths" ); 23 | private static readonly FieldInfo cachedRowHeightsField = AccessTools.Field( ptt, "cachedRowHeights" ); 24 | 25 | 26 | private static readonly MethodInfo RecacheIfDirtyMethod = AccessTools.Method( ptt, "RecacheIfDirty" ); 27 | 28 | private static readonly FieldInfo standardMarginField = 29 | AccessTools.Field( typeof( Window ), "StandardMargin" ); 30 | 31 | static PawnTable_PawnTableOnGUI() 32 | { 33 | if ( RecacheIfDirtyMethod == null ) throw new NullReferenceException( "RecacheIfDirty field not found." ); 34 | if ( cachedColumnWidthsField == null ) 35 | throw new NullReferenceException( "cachedColumnWidths field not found." ); 36 | if ( cachedRowHeightsField == null ) 37 | throw new NullReferenceException( "cachedRowHeights field not found." ); 38 | if ( standardMarginField == null ) throw new NullReferenceException( "standardMargin field not found." ); 39 | } 40 | 41 | public static bool Prefix( PawnTable __instance, 42 | Vector2 position, 43 | PawnTableDef ___def, 44 | ref Vector2 ___scrollPosition ) 45 | //harmony 1.2.0.1 gives access to private fields by ___name. 46 | { 47 | if ( ___def != PawnTableDefOf.Work ) // only apply our changes on the work tab. 48 | return true; 49 | 50 | if ( Event.current.type == EventType.Layout ) 51 | return false; 52 | 53 | _hoveredRowLabel = -1; 54 | 55 | RecacheIfDirtyMethod.Invoke( __instance, null ); 56 | 57 | // get fields 58 | var cachedSize = __instance.Size; 59 | var columns = __instance.ColumnsListForReading; 60 | var cachedColumnWidths = cachedColumnWidthsField.GetValue( __instance ) as List; 61 | var cachedHeaderHeight = __instance.HeaderHeight; 62 | var cachedHeightNoScrollbar = __instance.HeightNoScrollbar; 63 | var headerScrollPosition = new Vector2( ___scrollPosition.x, 0f ); 64 | var labelScrollPosition = new Vector2( 0f, ___scrollPosition.y ); 65 | var cachedPawns = __instance.PawnsListForReading; 66 | var cachedRowHeights = cachedRowHeightsField.GetValue( __instance ) as List; 67 | var standardWindowMargin = (float) standardMarginField.GetRawConstantValue(); 68 | 69 | // this is the main change, vanilla hardcodes both outRect and viewRect to the cached size. 70 | // Instead, we want to limit outRect to the available view area, so a horizontal scrollbar can appear. 71 | var labelWidth = cachedColumnWidths[0]; 72 | var labelCol = columns[0]; 73 | var outWidth = Mathf.Min( cachedSize.x - labelWidth, UI.screenWidth - standardWindowMargin * 2f ); 74 | var viewWidth = cachedSize.x - labelWidth - 16f; 75 | 76 | var labelHeaderRect = new Rect( 77 | position.x, 78 | position.y, 79 | labelWidth, 80 | cachedHeaderHeight ); 81 | 82 | var headerOutRect = new Rect( 83 | position.x + labelWidth, 84 | position.y, 85 | outWidth, 86 | cachedHeaderHeight ); 87 | var headerViewRect = new Rect( 88 | 0f, 89 | 0f, 90 | viewWidth, 91 | cachedHeaderHeight ); 92 | 93 | var labelOutRect = new Rect( 94 | position.x, 95 | position.y + cachedHeaderHeight, 96 | labelWidth, 97 | cachedSize.y - cachedHeaderHeight ); 98 | var labelViewRect = new Rect( 99 | 0f, 100 | 0f, 101 | labelWidth, 102 | cachedHeightNoScrollbar - cachedHeaderHeight ); 103 | 104 | var tableOutRect = new Rect( 105 | position.x + labelWidth, 106 | position.y + cachedHeaderHeight, 107 | outWidth, 108 | cachedSize.y - cachedHeaderHeight ); 109 | var tableViewRect = new Rect( 110 | 0f, 111 | 0f, 112 | viewWidth, 113 | cachedHeightNoScrollbar - cachedHeaderHeight ); 114 | 115 | // increase height of table to accomodate scrollbar if necessary and possible. 116 | if ( viewWidth > outWidth && cachedSize.y + 16f < UI.screenHeight ) 117 | // NOTE: this is probably optimistic about the available height, but it appears to be what vanilla uses. 118 | tableOutRect.height += 16f; 119 | 120 | // we need to add a scroll area to the column headers to make sure they stay in sync with the rest of the table, but the first (labels) column should be frozen. 121 | labelCol.Worker.DoHeader( labelHeaderRect, __instance ); 122 | 123 | // scroll area for the rest of the columns - HORIZONTAL ONLY 124 | var pos = IntVec3.Zero; 125 | Widgets.BeginScrollView( headerOutRect, ref headerScrollPosition, headerViewRect, false ); 126 | for ( var i = 1; i < columns.Count; i++ ) 127 | { 128 | int colWidth; 129 | if ( i == columns.Count - 1 ) 130 | colWidth = (int) ( viewWidth - pos.x ); 131 | else 132 | colWidth = (int) cachedColumnWidths[i]; 133 | 134 | var rect = new Rect( pos.x, 0f, colWidth, (int) cachedHeaderHeight ); 135 | 136 | // column highlight sync 137 | if ( Mouse.IsOver( rect ) ) _hoveredColumnLabel = i; 138 | 139 | if ( _hoveredColumnContent == i ) Widgets.DrawHighlight( rect ); 140 | 141 | columns[i].Worker.DoHeader( rect, __instance ); 142 | pos.x += colWidth; 143 | } 144 | 145 | _hoveredColumnContent = -1; 146 | Widgets.EndScrollView(); 147 | ___scrollPosition.x = headerScrollPosition.x; 148 | 149 | // scrollview for label column - VERTICAL ONLY 150 | if ( _hoveredColumnLabel == 0 ) Widgets.DrawHighlight( labelOutRect ); 151 | Widgets.BeginScrollView( labelOutRect, ref labelScrollPosition, labelViewRect, false ); 152 | var labelRect = labelOutRect.AtZero(); 153 | for ( var j = 0; j < cachedPawns.Count; j++ ) 154 | { 155 | labelRect.height = (int) cachedRowHeights[j]; 156 | 157 | // only draw if on screen 158 | if ( tableViewRect.height <= tableOutRect.height || 159 | labelRect.y - ___scrollPosition.y + (int) cachedRowHeights[j] >= 0f && 160 | labelRect.y - ___scrollPosition.y <= tableOutRect.height ) 161 | { 162 | GUI.color = new Color( 1f, 1f, 1f, 0.2f ); 163 | Widgets.DrawLineHorizontal( 0f, pos.z, tableViewRect.width ); 164 | GUI.color = Color.white; 165 | 166 | labelCol.Worker.DoCell( labelRect, cachedPawns[j], __instance ); 167 | if ( _hoveredRowContent == j ) Widgets.DrawHighlight( labelRect ); 168 | 169 | if ( Mouse.IsOver( labelRect ) ) _hoveredRowLabel = j; 170 | 171 | if ( cachedPawns[j].Downed ) 172 | { 173 | GUI.color = new Color( 1f, 0f, 0f, 0.5f ); 174 | Widgets.DrawLineHorizontal( 0f, labelRect.center.y, labelWidth ); 175 | GUI.color = Color.white; 176 | } 177 | } 178 | 179 | labelRect.y += (int) cachedRowHeights[j]; 180 | } 181 | 182 | Widgets.EndScrollView(); 183 | ___scrollPosition.y = labelScrollPosition.y; 184 | 185 | _hoveredRowContent = -1; 186 | 187 | // And finally, draw the rest of the table - SCROLLS VERTICALLY AND HORIZONTALLY 188 | Widgets.BeginScrollView( tableOutRect, ref ___scrollPosition, tableViewRect ); 189 | pos.x = 0; 190 | for ( var k = 1; k < columns.Count; k++ ) 191 | { 192 | int columnWidth; 193 | if ( k == columns.Count - 1 ) 194 | columnWidth = (int) ( viewWidth - pos.x ); 195 | else 196 | columnWidth = (int) cachedColumnWidths[k]; 197 | 198 | var column = new Rect( pos.x, pos.y, columnWidth, (int) tableOutRect.height ); 199 | if ( Mouse.IsOver( column ) ) 200 | { 201 | Widgets.DrawHighlight( column ); 202 | _hoveredColumnContent = k; 203 | } 204 | 205 | if ( _hoveredColumnLabel == k ) Widgets.DrawHighlight( column ); 206 | pos.x += columnWidth; 207 | } 208 | 209 | _hoveredColumnLabel = -1; 210 | for ( var j = 0; j < cachedPawns.Count; j++ ) 211 | { 212 | pos.x = 0; 213 | // only draw if on screen 214 | if ( tableViewRect.height <= tableOutRect.height || 215 | pos.y - ___scrollPosition.y + (int) cachedRowHeights[j] >= 0f && 216 | pos.y - ___scrollPosition.y <= tableOutRect.height ) 217 | { 218 | GUI.color = new Color( 1f, 1f, 1f, 0.2f ); 219 | Widgets.DrawLineHorizontal( 0f, pos.y, tableViewRect.width ); 220 | GUI.color = Color.white; 221 | var rowRect = new Rect( 0f, pos.y, tableViewRect.width, (int) cachedRowHeights[j] ); 222 | 223 | // synchronize row highlights 224 | if ( Mouse.IsOver( rowRect ) ) 225 | { 226 | Widgets.DrawHighlight( rowRect ); 227 | _hoveredRowContent = j; 228 | } 229 | else if ( _hoveredRowLabel == j ) 230 | { 231 | Widgets.DrawHighlight( rowRect ); 232 | } 233 | 234 | for ( var k = 1; k < columns.Count; k++ ) 235 | { 236 | int cellWidth; 237 | if ( k == columns.Count - 1 ) 238 | cellWidth = (int) ( viewWidth - pos.x ); 239 | else 240 | cellWidth = (int) cachedColumnWidths[k]; 241 | 242 | var rect3 = new Rect( pos.x, pos.y, cellWidth, (int) cachedRowHeights[j] ); 243 | columns[k].Worker.DoCell( rect3, cachedPawns[j], __instance ); 244 | pos.x += cellWidth; 245 | } 246 | 247 | if ( cachedPawns[j].Downed ) 248 | { 249 | GUI.color = new Color( 1f, 0f, 0f, 0.5f ); 250 | Widgets.DrawLineHorizontal( 0f, rowRect.center.y, tableViewRect.width ); 251 | GUI.color = Color.white; 252 | } 253 | } 254 | 255 | pos.y += (int) cachedRowHeights[j]; 256 | } 257 | 258 | Widgets.EndScrollView(); 259 | 260 | return false; 261 | } 262 | } 263 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/PawnTable/PawnTable_RecacheIfDirty.cs: -------------------------------------------------------------------------------- 1 | // PawnTable_RecacheIfDirty.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Reflection; 7 | using HarmonyLib; 8 | using RimWorld; 9 | using UnityEngine; 10 | 11 | namespace WorkTab 12 | { 13 | [HarmonyPatch( typeof( PawnTable ), "RecacheIfDirty" )] 14 | public class PawnTable_RecacheIfDirty 15 | { 16 | private static readonly FieldInfo cachecColumnWidthsField = 17 | AccessTools.Field( typeof( PawnTable ), "cachedColumnWidths" ); 18 | 19 | private static readonly FieldInfo cachedSizeField = AccessTools.Field( typeof( PawnTable ), "cachedSize" ); 20 | private static readonly FieldInfo dirtyField = AccessTools.Field( typeof( PawnTable ), "dirty" ); 21 | 22 | static PawnTable_RecacheIfDirty() 23 | { 24 | if ( dirtyField == null ) throw new NullReferenceException( "PawnTable.dirty field not found." ); 25 | if ( cachedSizeField == null ) throw new NullReferenceException( "PawnTable.cachedSize field not found." ); 26 | if ( cachecColumnWidthsField == null ) 27 | throw new NullReferenceException( "PawnTable.cachecColumnWidths field not found." ); 28 | } 29 | 30 | private static void Postfix( PawnTable __instance, bool __state ) 31 | { 32 | // cop out if cache was not dirty. 33 | if ( !__state ) 34 | return; 35 | 36 | Logger.Debug( "Checking minimum column widths..." ); 37 | 38 | // loop over columns to check that they satisfy their minimum width. 39 | var columnWidths = cachecColumnWidthsField.GetValue( __instance ) as List; 40 | var columns = __instance.ColumnsListForReading; 41 | var anyColumnAdjusted = false; 42 | var tableWidth = 0f; 43 | for ( var i = 0; i < columns.Count; i++ ) 44 | { 45 | var minWidth = columns[i].Worker.GetMinWidth( __instance ); 46 | if ( columnWidths[i] < minWidth ) 47 | { 48 | columnWidths[i] = minWidth; 49 | anyColumnAdjusted = true; 50 | } 51 | 52 | tableWidth += columnWidths[i]; 53 | } 54 | 55 | // If any columns were adjusted, also adjust the table size. 56 | if ( anyColumnAdjusted ) 57 | { 58 | var size = new Vector2( tableWidth, __instance.Size.y ); 59 | if ( cachedSizeField == null ) throw new NullReferenceException( "PawnTable.cachedSize not found." ); 60 | cachedSizeField.SetValue( __instance, size ); 61 | } 62 | } 63 | 64 | private static void Prefix( PawnTable __instance, ref bool __state, PawnTableDef ___def ) 65 | { 66 | __state = (bool) dirtyField.GetValue( __instance ) && ___def == PawnTableDefOf.Work; 67 | if ( __state ) 68 | Logger.Debug( "ColumnWidths dirty" ); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/Worksettings/Pawn_WorkSettings_CacheWorkGiversInOrder.cs: -------------------------------------------------------------------------------- 1 | // Pawn_WorkSettings_CacheWorkGiversInOrder.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Reflection; 8 | using HarmonyLib; 9 | using RimWorld; 10 | using Verse; 11 | using static HarmonyLib.AccessTools; 12 | 13 | namespace WorkTab 14 | { 15 | [HarmonyPatch( typeof( Pawn_WorkSettings ), "CacheWorkGiversInOrder" )] 16 | public class Pawn_WorkSettings_CacheWorkGiversInOrder 17 | { 18 | public static FieldInfo pawnField = typeof( Pawn_WorkSettings ) 19 | .GetField( "pawn", all ); 20 | 21 | public static FieldInfo workgiversDirtyField = typeof( Pawn_WorkSettings ) 22 | .GetField( "workGiversDirty", all ); 23 | 24 | public static FieldInfo workgiversEmergencyField = typeof( Pawn_WorkSettings ) 25 | .GetField( "workGiversInOrderEmerg", all ); 26 | 27 | public static FieldInfo workgiversNormalField = typeof( Pawn_WorkSettings ) 28 | .GetField( "workGiversInOrderNormal", all ); 29 | 30 | static Pawn_WorkSettings_CacheWorkGiversInOrder() 31 | { 32 | if ( pawnField == null ) 33 | throw new NullReferenceException( "pawn field not found" ); 34 | if ( workgiversDirtyField == null ) 35 | throw new NullReferenceException( "workGiversDirty field not found" ); 36 | if ( workgiversEmergencyField == null ) 37 | throw new NullReferenceException( "workGiversInOrderEmerg field not found" ); 38 | if ( workgiversNormalField == null ) 39 | throw new NullReferenceException( "workGiversInOrderNormal field not found" ); 40 | } 41 | 42 | public static bool Prefix( Pawn_WorkSettings __instance ) 43 | { 44 | var pawn = pawnField.GetValue( __instance ) as Pawn; 45 | var allWorkgivers = DefDatabase.AllDefsListForReading 46 | .Select( wgd => wgd.Worker ) 47 | .Where( wg => pawn.GetPriority( wg.def, -1 ) > 0 ); 48 | var normalWorkgivers = new List(); 49 | var emergencyWorkgivers = new List(); 50 | 51 | // sort by player set workgiver priorities => worktype order => workgiver order 52 | if ( allWorkgivers.Any() ) 53 | { 54 | allWorkgivers = allWorkgivers 55 | .OrderBy( wg => pawn.GetPriority( wg.def, -1 ) ) 56 | .ThenByDescending( wg => wg.def.workType.naturalPriority ) 57 | .ThenByDescending( wg => wg.def.priorityInType ).ToList(); 58 | 59 | // lowest priority non-emergency job 60 | var maxEmergPrio = allWorkgivers 61 | .Where( wg => !wg.def.emergency ) 62 | .Min( wg => pawn.GetPriority( wg.def, -1 ) ); 63 | 64 | // create lists of workgivers 65 | normalWorkgivers = allWorkgivers 66 | .Where( wg => !wg.def.emergency || pawn.GetPriority( wg.def, -1 ) > maxEmergPrio ) 67 | .ToList(); 68 | emergencyWorkgivers = allWorkgivers 69 | .Where( wg => wg.def.emergency && pawn.GetPriority( wg.def, -1 ) <= maxEmergPrio ) 70 | .ToList(); 71 | } 72 | 73 | Logger.Debug( $"Updating priorities for {pawn.LabelShort};\n\t" + 74 | $"{string.Join( "\n\t", emergencyWorkgivers.Select( wg => wg.def.label ).ToArray() )}" + 75 | $"{string.Join( "\n\t", normalWorkgivers.Select( wg => wg.def.label ).ToArray() )}" ); 76 | 77 | // update cached lists of workgivers 78 | workgiversNormalField.SetValue( __instance, normalWorkgivers ); 79 | workgiversEmergencyField.SetValue( __instance, emergencyWorkgivers ); 80 | workgiversDirtyField.SetValue( __instance, false ); 81 | 82 | // stop vanilla execution 83 | return false; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/Worksettings/Pawn_WorkSettings_DisableAll.cs: -------------------------------------------------------------------------------- 1 | // Pawn_WorkSettings_DisableAll.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using HarmonyLib; 5 | using RimWorld; 6 | 7 | namespace WorkTab 8 | { 9 | [HarmonyPatch( typeof( Pawn_WorkSettings ), "DisableAll" )] 10 | public class Pawn_WorkSettings_DisableAll 11 | { 12 | public static void Prefix( Pawn_WorkSettings __instance ) 13 | { 14 | __instance.Pawn().DisableAll(); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/Worksettings/Pawn_WorkSettings_EnableAndInitialize.cs: -------------------------------------------------------------------------------- 1 | // Pawn_WorkSettings_EnableAndInitialize.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection.Emit; 7 | using HarmonyLib; 8 | using RimWorld; 9 | 10 | namespace WorkTab 11 | { 12 | [HarmonyPatch( typeof( Pawn_WorkSettings ), nameof( Pawn_WorkSettings.EnableAndInitialize ) )] 13 | public class Pawn_WorkSettings_EnableAndInitialize 14 | { 15 | private static int GetDefaultPriority() 16 | { 17 | return Settings.defaultPriority; 18 | } 19 | 20 | private static IEnumerable Transpiler( IEnumerable _instr ) 21 | { 22 | var instructions = _instr.ToList(); 23 | var setPriorityMI = 24 | AccessTools.Method( typeof( Pawn_WorkSettings ), nameof( Pawn_WorkSettings.SetPriority ) ); 25 | var getDefaultPriorityMI = 26 | AccessTools.Method( typeof( Pawn_WorkSettings_EnableAndInitialize ), nameof( GetDefaultPriority ) ); 27 | 28 | for ( var i = 0; i < instructions.Count; i++ ) 29 | { 30 | if ( instructions[i].opcode == OpCodes.Ldc_I4_3 ) 31 | if ( instructions[i + 1].Calls( setPriorityMI ) ) 32 | { 33 | yield return new CodeInstruction( OpCodes.Call, getDefaultPriorityMI ); 34 | continue; 35 | } 36 | 37 | yield return instructions[i]; 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/Worksettings/Pawn_WorkSettings_GetPriority.cs: -------------------------------------------------------------------------------- 1 | // Pawn_WorkSettings_GetPriority.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using HarmonyLib; 5 | using RimWorld; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | [HarmonyPatch( typeof( Pawn_WorkSettings ), "GetPriority" )] 11 | public class Pawn_WorkSettings_GetPriority 12 | { 13 | private static bool Prefix( WorkTypeDef w, Pawn_WorkSettings __instance, ref int __result ) 14 | { 15 | __result = __instance.Pawn().GetPriority( w, -1 ); 16 | return false; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Source/HarmonyPatches/Worksettings/Pawn_WorkSettings_SetPriority.cs: -------------------------------------------------------------------------------- 1 | // Pawn_WorkSettings_SetPriority.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using HarmonyLib; 5 | using RimWorld; 6 | using UnityEngine; 7 | using Verse; 8 | 9 | namespace WorkTab 10 | { 11 | [HarmonyPatch( typeof( Pawn_WorkSettings ), "SetPriority" )] 12 | public class Pawn_WorkSettings_SetPriority 13 | { 14 | private static void Prefix( Pawn_WorkSettings __instance, WorkTypeDef w, ref int priority ) 15 | { 16 | __instance.Pawn().SetPriority( w, priority, null ); 17 | 18 | // TODO: find a more elegant way to stop RW complaining about bad priorities. 19 | priority = Mathf.Min( priority, 4 ); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Source/PawnColumns/IAlternatingColumn.cs: -------------------------------------------------------------------------------- 1 | // IAlternatingColumn.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using UnityEngine; 5 | 6 | namespace WorkTab 7 | { 8 | public interface IAlternatingColumn 9 | { 10 | Vector2 LabelSize { get; } 11 | bool MoveDown { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Source/PawnColumns/IExpandableColumn.cs: -------------------------------------------------------------------------------- 1 | // IExpandableColumn.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using System.Collections.Generic; 5 | using RimWorld; 6 | 7 | namespace WorkTab 8 | { 9 | public interface IExpandableColumn 10 | { 11 | bool CanExpand { get; } 12 | List ChildColumns { get; } 13 | bool Expanded { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /Source/PawnColumns/PawnColumnDef_WorkGiver.cs: -------------------------------------------------------------------------------- 1 | // PawnColumnDef_WorkGiver.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using RimWorld; 5 | 6 | namespace WorkTab 7 | { 8 | public class PawnColumnDef_WorkGiver : PawnColumnDef 9 | { 10 | public WorkGiverDef workgiver; 11 | } 12 | } -------------------------------------------------------------------------------- /Source/PawnColumns/PawnColumnWorker_CopyPasteDetailedWorkPriorities.cs: -------------------------------------------------------------------------------- 1 | // PawnColumnWorker_CopyPasteDetailedWorkPriorities.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using RimWorld; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public class PawnColumnWorker_CopyPasteDetailedWorkPriorities : PawnColumnWorker_CopyPasteWorkPriorities 11 | { 12 | private static Dictionary clipboard; 13 | protected override bool AnythingInClipboard => clipboard != null; 14 | 15 | protected override void CopyFrom( Pawn pawn ) 16 | { 17 | if ( clipboard == null ) 18 | clipboard = new Dictionary(); 19 | 20 | foreach ( var workgiver in DefDatabase.AllDefsListForReading ) 21 | clipboard[workgiver] = pawn.GetPriorities( workgiver ); 22 | } 23 | 24 | protected override void PasteTo( Pawn pawn ) 25 | { 26 | foreach ( var worktype in DefDatabase.AllDefsListForReading ) 27 | { 28 | // do not even try setting priorities for disabled work types. 29 | if ( pawn.WorkTypeIsDisabled( worktype ) ) 30 | continue; 31 | 32 | // apply all workgivers for this type 33 | foreach ( var workgiver in worktype.WorkGivers() ) 34 | for ( var hour = 0; hour < GenDate.HoursPerDay; hour++ ) 35 | pawn.SetPriority( workgiver, clipboard[workgiver][hour], hour ); 36 | 37 | // recache the type (bubbles down to workgivers). 38 | PriorityManager.Get[pawn].InvalidateCache( worktype ); 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Source/PawnColumns/PawnColumnWorker_Favourite.cs: -------------------------------------------------------------------------------- 1 | // PawnColumnWorker_Favourite.cs 2 | // Copyright Karel Kroeze, 2018-2020 3 | 4 | using FluffyUI; 5 | using RimWorld; 6 | using UnityEngine; 7 | using Verse; 8 | using Widgets = Verse.Widgets; 9 | 10 | namespace WorkTab 11 | { 12 | public class PawnColumnWorker_Favourite : PawnColumnWorker_Icon 13 | { 14 | public override void DoCell( Rect rect, Pawn pawn, PawnTable table ) 15 | { 16 | var favourite = FavouriteManager.Get[pawn]; 17 | var size = GetIconSize( pawn ); 18 | var iconRect = new Rect( 0f, 0f, size.x, size.y ).CenteredIn( rect ); 19 | var icon = favourite?.Icon ?? ( Mouse.IsOver( iconRect ) ? Resources.Star : Resources.StarHollow ); 20 | 21 | if ( Widgets.ButtonImage( iconRect, icon ) ) 22 | ClickedIcon( pawn ); 23 | 24 | TooltipHandler.TipRegion( rect, GetIconTip( pawn ) ); 25 | } 26 | 27 | protected override void ClickedIcon( Pawn pawn ) 28 | { 29 | FavouriteManager.FavouriteFloatMenuFor( pawn ); 30 | } 31 | 32 | protected override Texture2D GetIconFor( Pawn pawn ) 33 | { 34 | return FavouriteManager.Get[pawn]?.Icon; 35 | } 36 | 37 | protected override Vector2 GetIconSize( Pawn pawn ) 38 | { 39 | return def.HeaderIconSize; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Source/PawnColumns/PawnColumnWorker_Job.cs: -------------------------------------------------------------------------------- 1 | // PawnColumnWorker_Job.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using RimWorld; 5 | using UnityEngine; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public class PawnColumnWorker_Job : PawnColumnWorker_Icon 11 | { 12 | public override int Compare( Pawn a, Pawn b ) 13 | { 14 | return GetValueToCompare( a ).CompareTo( GetValueToCompare( b ) ); 15 | } 16 | 17 | public string GetValueToCompare( Pawn pawn ) 18 | { 19 | return pawn.CurJob?.def?.label ?? ""; 20 | } 21 | 22 | protected override Texture2D GetIconFor( Pawn pawn ) 23 | { 24 | return pawn?.CurJob?.def.StatusIcon(); 25 | } 26 | 27 | protected override Vector2 GetIconSize( Pawn pawn ) 28 | { 29 | return def.HeaderIconSize; 30 | } 31 | 32 | protected override string GetIconTip( Pawn pawn ) 33 | { 34 | return pawn.jobs?.curDriver?.GetReport() ?? ""; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Source/PawnColumns/PawnColumnWorker_Mood.cs: -------------------------------------------------------------------------------- 1 | // PawnColumnWorker_Mood.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using RimWorld; 5 | using UnityEngine; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public class PawnColumnWorker_Mood : PawnColumnWorker_Icon 11 | { 12 | public override int Compare( Pawn a, Pawn b ) 13 | { 14 | return GetValueToCompare( a ).CompareTo( GetValueToCompare( b ) ); 15 | } 16 | 17 | public override void DoCell( Rect rect, Pawn pawn, PawnTable table ) 18 | { 19 | if ( pawn.needs?.mood == null ) 20 | return; 21 | base.DoCell( rect, pawn, table ); 22 | } 23 | 24 | public float GetValueToCompare( Pawn pawn ) 25 | { 26 | return pawn.needs.mood?.CurLevelPercentage - pawn.mindState.mentalBreaker.BreakThresholdMinor ?? 0f; 27 | } 28 | 29 | protected override Color GetIconColor( Pawn pawn ) 30 | { 31 | // broken 32 | if ( pawn.mindState?.mentalStateHandler?.CurStateDef != null ) 33 | switch ( pawn.mindState.mentalStateHandler.CurStateDef.category ) 34 | { 35 | case MentalStateCategory.Aggro: 36 | return Color.red; 37 | case MentalStateCategory.Malicious: 38 | return Color.yellow; 39 | case MentalStateCategory.Misc: 40 | case MentalStateCategory.Undefined: 41 | return new Color( 207 / 256f, 83 / 256f, 0f ); 42 | default: 43 | return Color.white; 44 | } 45 | 46 | if ( pawn.needs?.mood == null ) 47 | return Color.white; 48 | // current level 49 | var mood = pawn.needs.mood.CurLevelPercentage; 50 | var hardBreak = pawn.mindState.mentalBreaker.BreakThresholdExtreme; 51 | var softBreak = pawn.mindState.mentalBreaker.BreakThresholdMinor; 52 | 53 | // color 54 | if ( mood < hardBreak ) 55 | return Color.red; 56 | if ( mood < softBreak ) 57 | return Color.Lerp( Color.red, Color.yellow, ( mood - hardBreak ) / ( softBreak - hardBreak ) ); 58 | if ( mood < .5 ) 59 | return Color.Lerp( Color.yellow, Color.grey, ( mood - softBreak ) / ( .5f - softBreak ) ); 60 | if ( mood < .9 ) 61 | return Color.Lerp( Color.grey, Color.green, ( mood - .5f ) / .4f ); 62 | 63 | return Color.green; 64 | } 65 | 66 | protected override Texture2D GetIconFor( Pawn pawn ) 67 | { 68 | // broken 69 | if ( pawn.mindState.mentalStateHandler?.CurStateDef != null ) 70 | return Resources.MoodBroken; 71 | 72 | // current level 73 | var mood = pawn.needs.mood?.CurLevelPercentage; 74 | var softBreak = pawn.mindState.mentalBreaker.BreakThresholdMinor; 75 | 76 | // icon 77 | if ( mood < softBreak ) 78 | return Resources.MoodUnhappy; 79 | if ( mood < .5 ) 80 | return Resources.MoodDiscontent; 81 | if ( mood < .9 ) 82 | return Resources.MoodContent; 83 | return Resources.MoodHappy; 84 | } 85 | 86 | protected override Vector2 GetIconSize( Pawn pawn ) 87 | { 88 | return def.HeaderIconSize; 89 | } 90 | 91 | protected override string GetIconTip( Pawn pawn ) 92 | { 93 | return pawn.needs.mood?.GetTipString() ?? string.Empty; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Source/PawnColumns/PawnColumnWorker_WorkTabLabel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Karel Kroeze, 2020-2021. 2 | // WorkTab/WorkTab/PawnColumnWorker_WorkTabLabel.cs 3 | 4 | using System; 5 | using RimWorld; 6 | using UnityEngine; 7 | using Verse; 8 | using Verse.Sound; 9 | using static WorkTab.InteractionUtilities; 10 | 11 | namespace WorkTab 12 | { 13 | public class PawnColumnWorker_WorkTabLabel : PawnColumnWorker_Label 14 | { 15 | public override int Compare(Pawn a, Pawn b) 16 | { 17 | return string.Compare(a.Name.ToStringShort, b.Name.ToStringShort, 18 | StringComparison.CurrentCultureIgnoreCase); 19 | } 20 | 21 | public void Decrement(Pawn pawn) 22 | { 23 | var actionTaken = false; 24 | // just go over all workgivers and lower their priority number by one, with a minimum of 1 25 | foreach (var workgiver in DefDatabase.AllDefsListForReading) 26 | { 27 | if (pawn.WorkTypeIsDisabled(workgiver.workType)) 28 | { 29 | continue; 30 | } 31 | 32 | // get current priority 33 | var priority = pawn.GetPriority(workgiver, MainTabWindow_WorkTab.VisibleHour); 34 | 35 | // detailed mode 36 | if (PriorityManager.ShowPriorities) 37 | { 38 | if (priority == 0) 39 | { 40 | priority = Settings.maxPriority; 41 | actionTaken = true; 42 | } 43 | else if (priority != 1) 44 | { 45 | priority--; 46 | actionTaken = true; 47 | } 48 | } 49 | else // simple mode 50 | { 51 | if (priority == 0) 52 | { 53 | actionTaken = true; 54 | } 55 | 56 | priority = 3; 57 | } 58 | 59 | // apply new priority 60 | pawn.SetPriority(workgiver, priority, MainTabWindow_WorkTab.SelectedHours); 61 | } 62 | 63 | if (actionTaken && Settings.playSounds) 64 | { 65 | SoundDefOf.Tick_High.PlayOneShotOnCamera(); 66 | } 67 | } 68 | 69 | public override void DoCell(Rect rect, Pawn pawn, PawnTable table) 70 | { 71 | // intercept interactions before base has a chance to act on them 72 | if (Shift && Mouse.IsOver(rect)) 73 | { 74 | if (RightClicked(rect) || ScrolledUp(rect)) 75 | { 76 | Increment(pawn); 77 | return; 78 | } 79 | 80 | if (LeftClicked(rect) || ScrolledDown(rect)) 81 | { 82 | Decrement(pawn); 83 | return; 84 | } 85 | } 86 | 87 | // call base 88 | base.DoCell(rect, pawn, table); 89 | 90 | // override tooltip 91 | TooltipHandler.ClearTooltipsFrom(rect); 92 | TooltipHandler.TipRegion(rect, GetTooltip(pawn)); 93 | } 94 | 95 | public string GetTooltip(Pawn pawn) 96 | { 97 | return "WorkTab.LabelCellTip".Translate() + "\n\n" + pawn.GetTooltip().text; 98 | } 99 | 100 | public void Increment(Pawn pawn) 101 | { 102 | var actionTaken = false; 103 | // just go over all workgivers and increase their priority number by one, with a maximum of maxPriority 104 | foreach (var workgiver in DefDatabase.AllDefsListForReading) 105 | { 106 | if (pawn.WorkTypeIsDisabled(workgiver.workType)) 107 | { 108 | continue; 109 | } 110 | 111 | // get current priority 112 | var priority = pawn.GetPriority(workgiver, MainTabWindow_WorkTab.VisibleHour); 113 | 114 | // detailed mode 115 | if (PriorityManager.ShowPriorities) 116 | { 117 | if (priority == Settings.maxPriority) 118 | { 119 | priority = 0; 120 | actionTaken = true; 121 | } 122 | else if (priority != 0) 123 | { 124 | priority++; 125 | actionTaken = true; 126 | } 127 | } 128 | else // simple mode 129 | { 130 | if (priority != 0) 131 | { 132 | actionTaken = true; 133 | } 134 | 135 | priority = 0; 136 | } 137 | 138 | 139 | // apply new priority 140 | pawn.SetPriority(workgiver, priority, MainTabWindow_WorkTab.SelectedHours); 141 | } 142 | 143 | if (actionTaken && Settings.playSounds) 144 | { 145 | SoundDefOf.Tick_Low.PlayOneShotOnCamera(); 146 | } 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /Source/Priorities/PawnPriorityTracker.cs: -------------------------------------------------------------------------------- 1 | // PawnPriorityTracker.cs 2 | // Copyright Karel Kroeze, 2018-2020 3 | 4 | using RimWorld; 5 | using Verse; 6 | 7 | namespace WorkTab 8 | { 9 | // todo; implement IExposable 10 | public class PawnPriorityTracker : PriorityTracker 11 | { 12 | private Pawn pawn; 13 | 14 | public PawnPriorityTracker() 15 | { 16 | // Scribe 17 | } 18 | 19 | public PawnPriorityTracker( Pawn pawn ) 20 | { 21 | this.pawn = pawn; 22 | foreach ( var workgiver in DefDatabase.AllDefsListForReading ) 23 | priorities.Add( workgiver, new WorkPriority( this, workgiver ) ); 24 | } 25 | 26 | public override Pawn Pawn => pawn; 27 | 28 | public override void ExposeData() 29 | { 30 | Scribe_References.Look( ref pawn, "Pawn" ); 31 | base.ExposeData(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Source/Priorities/PriorityManager.cs: -------------------------------------------------------------------------------- 1 | // PriorityManager.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Verse; 8 | 9 | namespace WorkTab 10 | { 11 | public class PriorityManager : GameComponent 12 | { 13 | private static PriorityManager _instance; 14 | private static int _nextId; 15 | 16 | private static bool _showScheduler; 17 | private static Dictionary priorities = new Dictionary(); 18 | private List pawnPriorityTrackersScribe; 19 | private List pawnsScribe; 20 | 21 | public PriorityManager( Game game ) : this() 22 | { 23 | } 24 | 25 | public PriorityManager() 26 | { 27 | _instance = this; 28 | } 29 | 30 | public static PriorityManager Get 31 | { 32 | get 33 | { 34 | if ( _instance == null ) 35 | throw new NullReferenceException( "Accessing PriorityManager before it was constructed." ); 36 | return _instance; 37 | } 38 | } 39 | 40 | public static bool ShowPriorities 41 | { 42 | get => Find.PlaySettings.useWorkPriorities; 43 | set 44 | { 45 | if ( value == Find.PlaySettings.useWorkPriorities ) 46 | return; 47 | 48 | // update setting 49 | Find.PlaySettings.useWorkPriorities = value; 50 | 51 | // force re-cache of all pawns 52 | foreach ( var pawn in priorities.Keys.ToList() ) 53 | pawn?.workSettings?.Notify_UseWorkPrioritiesChanged(); 54 | } 55 | } 56 | 57 | public static bool ShowScheduler 58 | { 59 | get => _showScheduler; 60 | set 61 | { 62 | if ( value == _showScheduler ) 63 | return; 64 | 65 | _showScheduler = value; 66 | MainTabWindow_WorkTab.Instance.RecacheTimeBarRect(); 67 | } 68 | } 69 | 70 | public PriorityTracker this[ Pawn pawn ] 71 | { 72 | get 73 | { 74 | var favourite = FavouriteManager.Get[pawn]; 75 | if ( favourite != null ) return favourite; 76 | 77 | if ( priorities.TryGetValue( pawn, out var tracker ) ) 78 | return tracker; 79 | 80 | tracker = new PawnPriorityTracker( pawn ); 81 | priorities.Add( pawn, tracker ); 82 | return tracker; 83 | } 84 | } 85 | 86 | public static int GetNextID() 87 | { 88 | return _nextId++; 89 | } 90 | 91 | public override void ExposeData() 92 | { 93 | base.ExposeData(); 94 | 95 | // purge null pawn elements, note that this also neatly keeps track of periodic garbage collection on autosaves 96 | var pawns = priorities.Keys.ToList(); 97 | foreach ( var pawn in pawns ) 98 | if ( pawn?.Destroyed ?? true ) // null or destroyed 99 | priorities.Remove( pawn ); 100 | 101 | Scribe_Collections.Look( ref priorities, "Priorities", LookMode.Reference, LookMode.Deep, ref pawnsScribe, 102 | ref pawnPriorityTrackersScribe ); 103 | Scribe_Values.Look( ref _showScheduler, "ShowScheduler" ); 104 | Scribe_Values.Look( ref _nextId, "NextId" ); 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /Source/Priorities/PriorityTracker.cs: -------------------------------------------------------------------------------- 1 | // PriorityTracker.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using RimWorld; 7 | using Verse; 8 | 9 | namespace WorkTab 10 | { 11 | public class PriorityTracker : IExposable, ILoadReferenceable 12 | { 13 | // caches for ever/partially scheduled 14 | private readonly Dictionary _everScheduledWorkGiver = new Dictionary(); 15 | private readonly Dictionary _partScheduledWorkType = new Dictionary(); 16 | private readonly Dictionary _timeScheduledWorkGiver = new Dictionary(); 17 | 18 | private readonly Dictionary _timeScheduledWorkGiverTip = 19 | new Dictionary(); 20 | 21 | private readonly Dictionary _timeScheduledWorkType = new Dictionary(); 22 | 23 | private readonly Dictionary _timeScheduledWorkTypeTip = 24 | new Dictionary(); 25 | 26 | protected Dictionary priorities = new Dictionary(); 27 | protected List workPriorityTrackersScribe; 28 | private int _loadId; 29 | 30 | public PriorityTracker() 31 | { 32 | SetLoadId(); 33 | } 34 | 35 | public virtual WorkPriority this[ WorkGiverDef workgiver ] 36 | { 37 | get 38 | { 39 | if ( !priorities.ContainsKey( workgiver ) ) 40 | { 41 | Logger.Debug( 42 | $"requested {workgiver.defName} priorities for {Pawn?.LabelShort ?? ""}, which did not yet exist." ); 43 | priorities.Add( workgiver, new WorkPriority( this, workgiver ) ); 44 | } 45 | 46 | return priorities[workgiver]; 47 | } 48 | set => priorities[workgiver] = value; 49 | } 50 | 51 | public virtual Pawn Pawn => null; 52 | 53 | public virtual void ExposeData() 54 | { 55 | Logger.Assert( Scribe.mode, "Priority ScribeMode" ); 56 | if ( Scribe.mode == LoadSaveMode.Saving ) workPriorityTrackersScribe = priorities.Values.ToList(); 57 | Scribe_Collections.Look( ref workPriorityTrackersScribe, "Priorities", LookMode.Deep, this ); 58 | if ( Scribe.mode == LoadSaveMode.PostLoadInit ) 59 | priorities = workPriorityTrackersScribe 60 | // check if any workgivers were removed midgame (don't try this at home, kids!) 61 | .Where( k => k.Workgiver != null ) 62 | // reinstate the dictionary 63 | .ToDictionary( k => k.Workgiver ); 64 | 65 | Scribe_Values.Look( ref _loadId, "loadId" ); 66 | } 67 | 68 | public string GetUniqueLoadID() 69 | { 70 | return $"Fluffy.PriorityTracker.{_loadId}"; 71 | } 72 | 73 | // accessors 74 | public bool EverScheduled( WorkGiverDef workgiver ) 75 | { 76 | if ( !_everScheduledWorkGiver.ContainsKey( workgiver ) ) 77 | Recache( workgiver ); 78 | return _everScheduledWorkGiver[workgiver]; 79 | } 80 | 81 | public int[] GetPriorities( WorkGiverDef workgiver ) 82 | { 83 | return TimeUtilities.WholeDay.Select( h => GetPriority( workgiver, h ) ).ToArray(); 84 | } 85 | 86 | public int[] GetPriorities( WorkTypeDef worktype ) 87 | { 88 | return TimeUtilities.WholeDay.Select( h => GetPriority( worktype, h ) ).ToArray(); 89 | } 90 | 91 | public int GetPriority( WorkGiverDef workgiver, int hour ) 92 | { 93 | var priority = this[workgiver][hour]; 94 | if ( Find.PlaySettings.useWorkPriorities ) 95 | return priority; 96 | return priority > 0 ? 3 : 0; 97 | } 98 | 99 | public int GetPriority( WorkTypeDef worktype, int hour ) 100 | { 101 | var priorities = worktype.WorkGivers() 102 | .Select( wg => this[wg][hour] ) 103 | .Where( p => p > 0 ); 104 | 105 | if ( !priorities.Any() ) 106 | return 0; 107 | 108 | return Find.PlaySettings.useWorkPriorities ? priorities.Min() : 3; 109 | } 110 | 111 | public void InvalidateCache( WorkGiverDef workgiver, bool bubble = true ) 112 | { 113 | _everScheduledWorkGiver.Remove( workgiver ); 114 | _timeScheduledWorkGiver.Remove( workgiver ); 115 | _timeScheduledWorkGiverTip.Remove( workgiver ); 116 | 117 | if ( bubble ) 118 | InvalidateCache( workgiver.workType, false ); 119 | } 120 | 121 | public void InvalidateCache( WorkTypeDef worktype, bool bubble = true ) 122 | { 123 | _timeScheduledWorkType.Remove( worktype ); 124 | _timeScheduledWorkTypeTip.Remove( worktype ); 125 | 126 | if ( bubble ) 127 | worktype.WorkGivers().ForEach( wg => InvalidateCache( wg, false ) ); 128 | } 129 | 130 | public bool PartScheduled( WorkTypeDef worktype ) 131 | { 132 | if ( !_partScheduledWorkType.ContainsKey( worktype ) ) 133 | Recache( worktype ); 134 | return _partScheduledWorkType[worktype]; 135 | } 136 | 137 | public void Recache( WorkGiverDef workgiver ) 138 | { 139 | // recache workgiver stuff 140 | var priorities = this[workgiver].Priorities; 141 | _everScheduledWorkGiver[workgiver] = priorities.Any( p => p > 0 ); 142 | _timeScheduledWorkGiver[workgiver] = priorities.Distinct().Count() > 1; 143 | _timeScheduledWorkGiverTip[workgiver] = DrawUtilities.TimeScheduledTip( priorities, workgiver.label ); 144 | } 145 | 146 | public void Recache( WorkTypeDef worktype ) 147 | { 148 | var workgivers = worktype.WorkGivers(); 149 | var priorities = GetPriorities( worktype ); 150 | 151 | // first make sure all workgivers are cached 152 | foreach ( var workgiver in workgivers ) 153 | if ( !_everScheduledWorkGiver.ContainsKey( workgiver ) ) 154 | Recache( workgiver ); 155 | 156 | // recache worktype stuff 157 | _timeScheduledWorkType[worktype] = workgivers.Any( wg => _timeScheduledWorkGiver[wg] ); 158 | _timeScheduledWorkTypeTip[worktype] = DrawUtilities.TimeScheduledTip( priorities, worktype.gerundLabel ); 159 | 160 | // is any workgiver different from the whole at any time during the day? 161 | _partScheduledWorkType[worktype] = TimeUtilities.WholeDay 162 | .Any( hour => worktype 163 | .WorkGivers() 164 | .Any( wg => GetPriority( worktype, hour ) != 165 | GetPriority( wg, hour ) ) ); 166 | } 167 | 168 | public virtual void SetLoadId() 169 | { 170 | _loadId = PriorityManager.GetNextID(); 171 | } 172 | 173 | public void SetPriority( WorkGiverDef workgiver, int priority, int hour, bool recache = true ) 174 | { 175 | if ( priority > Settings.maxPriority ) 176 | priority = 0; 177 | if ( priority < 0 ) 178 | priority = Settings.maxPriority; 179 | 180 | this[workgiver][hour] = priority; 181 | 182 | if ( recache ) 183 | { 184 | InvalidateCache( workgiver ); 185 | OnChange(); 186 | } 187 | } 188 | 189 | public void SetPriority( WorkGiverDef workgiver, int priority, List hours ) 190 | { 191 | if ( hours.NullOrEmpty() ) 192 | hours = TimeUtilities.WholeDay; 193 | 194 | foreach ( var hour in hours ) 195 | SetPriority( workgiver, priority, hour, false ); 196 | 197 | InvalidateCache( workgiver ); 198 | OnChange(); 199 | } 200 | 201 | public void SetPriority( WorkTypeDef worktype, int priority, int hour, bool recache = true ) 202 | { 203 | foreach ( var workgiver in worktype.WorkGivers() ) 204 | SetPriority( workgiver, priority, hour, false ); 205 | 206 | if ( recache ) 207 | { 208 | InvalidateCache( worktype ); 209 | OnChange(); 210 | } 211 | } 212 | 213 | public void SetPriority( WorkTypeDef worktype, int priority, List hours ) 214 | { 215 | if ( hours.NullOrEmpty() ) 216 | hours = TimeUtilities.WholeDay; 217 | 218 | foreach ( var hour in hours ) 219 | SetPriority( worktype, priority, hour, false ); 220 | 221 | InvalidateCache( worktype ); 222 | OnChange(); 223 | } 224 | 225 | public bool TimeScheduled( WorkGiverDef workgiver ) 226 | { 227 | if ( !_timeScheduledWorkGiver.ContainsKey( workgiver ) ) 228 | Recache( workgiver ); 229 | return _timeScheduledWorkGiver[workgiver]; 230 | } 231 | 232 | public bool TimeScheduled( WorkTypeDef worktype ) 233 | { 234 | if ( !_timeScheduledWorkType.ContainsKey( worktype ) ) 235 | Recache( worktype ); 236 | return _timeScheduledWorkType[worktype]; 237 | } 238 | 239 | public string TimeScheduledTip( WorkGiverDef workgiver ) 240 | { 241 | if ( !_timeScheduledWorkGiverTip.ContainsKey( workgiver ) ) 242 | Recache( workgiver ); 243 | return _timeScheduledWorkGiverTip[workgiver]; 244 | } 245 | 246 | public string TimeScheduledTip( WorkTypeDef worktype ) 247 | { 248 | if ( !_timeScheduledWorkTypeTip.ContainsKey( worktype ) ) 249 | Recache( worktype ); 250 | return _timeScheduledWorkTypeTip[worktype]; 251 | } 252 | 253 | protected virtual void OnChange() 254 | { 255 | } 256 | } 257 | } -------------------------------------------------------------------------------- /Source/Priorities/WorkPriority.cs: -------------------------------------------------------------------------------- 1 | // WorkPriority.cs 2 | // Copyright Karel Kroeze, 2018-2020 3 | 4 | using System; 5 | using System.Linq; 6 | using RimWorld; 7 | using Verse; 8 | 9 | namespace WorkTab 10 | { 11 | public class WorkPriority : IExposable 12 | { 13 | protected internal PriorityTracker _parent; 14 | private WorkGiverDef workgiver; 15 | 16 | // Scribe 17 | public WorkPriority( PriorityTracker parent ) 18 | { 19 | _parent = parent; 20 | } 21 | 22 | public WorkPriority( PriorityTracker parent, WorkGiverDef workgiver ) : this( parent ) 23 | { 24 | this.workgiver = workgiver; 25 | Priorities = new int[GenDate.HoursPerDay]; 26 | var priority = parent.Pawn?.GetVanillaPriority( workgiver.workType ) ?? 0; 27 | Logger.Debug( 28 | $"Initiating worktracker for {parent.Pawn.LabelShort}, Priority: {priority}, default: {Settings.defaultPriority}" ); 29 | if ( priority > 0 ) priority = Settings.defaultPriority; 30 | for ( var hour = 0; hour < GenDate.HoursPerDay; hour++ ) Priorities[hour] = priority; 31 | } 32 | 33 | public bool EverAssigned => Priorities.Any( p => p > 0 ); 34 | 35 | public int this[ int hour ] 36 | { 37 | get => Priorities[hour]; 38 | set 39 | { 40 | // check if we're allowed to do this job 41 | if ( value > 0 && !_parent.Pawn.AllowedToDo( workgiver ) ) 42 | { 43 | Logger.Debug( 44 | $"Tried to set priority for {workgiver.label} to {_parent.Pawn?.LabelShort}, who is incapable of that work." ); 45 | return; 46 | } 47 | 48 | // update priority 49 | Priorities[hour] = value; 50 | 51 | // make pawn update its priorities 52 | _parent.Pawn?.workSettings.Notify_UseWorkPrioritiesChanged(); 53 | } 54 | } 55 | 56 | public int[] Priorities { get; private set; } 57 | 58 | public WorkGiverDef Workgiver => workgiver; 59 | 60 | public void ExposeData() 61 | { 62 | try 63 | { 64 | Scribe_Defs.Look( ref workgiver, "Workgiver" ); 65 | } 66 | catch ( Exception e ) 67 | { 68 | Log.Warning( 69 | "WorkTab :: failed to load priorities. Did you disable a mod? If so, this message can safely be ignored." + 70 | e.Message + 71 | "\n\n" + 72 | e.StackTrace ); 73 | } 74 | 75 | if ( Scribe.mode == LoadSaveMode.Saving ) 76 | { 77 | var _priorities = string.Join( "", Priorities.Select( i => i.ToString() ).ToArray() ); 78 | Scribe_Values.Look( ref _priorities, "Priorities" ); 79 | } 80 | 81 | if ( Scribe.mode == LoadSaveMode.LoadingVars ) 82 | { 83 | var _priorities = ""; 84 | Scribe_Values.Look( ref _priorities, "Priorities" ); 85 | Priorities = _priorities.ToArray().Select( c => int.Parse( c.ToString() ) ).ToArray(); 86 | } 87 | } 88 | 89 | public WorkPriority Clone( PriorityTracker newParent ) 90 | { 91 | var clone = new WorkPriority( newParent ) 92 | { 93 | Priorities = (int[]) Priorities.Clone(), 94 | workgiver = workgiver 95 | }; 96 | return clone; 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /Source/Utilities/DefOf.cs: -------------------------------------------------------------------------------- 1 | // Copyright Karel Kroeze, 2020-2021. 2 | // WorkTab/WorkTab/DefOf.cs 3 | 4 | using RimWorld; 5 | using Verse; 6 | 7 | namespace WorkTab 8 | { 9 | [DefOf] 10 | public static class PawnColumnDefOf 11 | { 12 | public static PawnColumnDef CopyPasteDetailedWorkPriorities; 13 | public static PawnColumnDef CopyPasteWorkPriorities; 14 | public static PawnColumnDef Faction; 15 | public static PawnColumnDef Favourite; 16 | [MayRequireIdeology] public static PawnColumnDef Guest; 17 | [MayRequireIdeology] public static PawnColumnDef Ideo; 18 | public static PawnColumnDef Job; 19 | public static PawnColumnDef Label; 20 | public static PawnColumnDef Mood; 21 | public static PawnColumnDef WorkTabLabel; 22 | } 23 | 24 | [DefOf] 25 | public static class JobDefOf2 26 | { 27 | public static JobDef BuildSnowman; 28 | public static JobDef GoForWalk; 29 | public static JobDef Meditate; 30 | public static JobDef Play_Billiards; 31 | public static JobDef Play_Chess; 32 | public static JobDef Play_Horseshoes; 33 | public static JobDef Pray; 34 | public static JobDef Skygaze; 35 | public static JobDef UseItem; 36 | public static JobDef UseTelescope; 37 | public static JobDef ViewArt; 38 | public static JobDef VisitGrave; 39 | public static JobDef WatchTelevision; 40 | } 41 | 42 | [DefOf] 43 | public static class MainButtonDefOf 44 | { 45 | public static MainButtonDef Work; 46 | } 47 | } -------------------------------------------------------------------------------- /Source/Utilities/InteractionUtilities.cs: -------------------------------------------------------------------------------- 1 | // InteractionUtilities.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using System; 5 | using UnityEngine; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public enum ScrollDirection 11 | { 12 | Up, 13 | Down 14 | } 15 | 16 | public static class InteractionUtilities 17 | { 18 | public static bool Alt => Input.GetKey( KeyCode.AltGr ) || Input.GetKey( KeyCode.LeftAlt ) || 19 | Input.GetKey( KeyCode.RightAlt ); 20 | 21 | public static bool Ctrl => Input.GetKey( KeyCode.LeftCommand ) || Input.GetKey( KeyCode.LeftControl ) || 22 | Input.GetKey( KeyCode.RightCommand ) || Input.GetKey( KeyCode.RightControl ); 23 | 24 | public static bool Shift => Input.GetKey( KeyCode.LeftShift ) || Input.GetKey( KeyCode.RightShift ); 25 | 26 | public static void ButtonImageToggle( Func getter, Action setter, Rect canvas, 27 | string tipOn, Texture2D texOn, 28 | string tipOff, Texture2D texOff ) 29 | { 30 | if ( setter == null || getter == null ) 31 | throw new NullReferenceException( "getter and setter must not be null" ); 32 | 33 | TooltipHandler.TipRegion( canvas, getter() ? tipOff : tipOn ); 34 | if ( Widgets.ButtonImage( canvas, getter() ? texOff : texOn, Color.white, GenUI.MouseoverColor ) ) 35 | setter( !getter() ); 36 | } 37 | 38 | public static bool Clicked( Rect rect, int button = 0 ) 39 | { 40 | return Event.current.type == EventType.MouseDown && Event.current.button == button && Mouse.IsOver( rect ); 41 | } 42 | 43 | public static bool LeftClicked( Rect rect ) 44 | { 45 | return Clicked( rect ); 46 | } 47 | 48 | public static bool RightClicked( Rect rect ) 49 | { 50 | return Clicked( rect, 1 ); 51 | } 52 | 53 | public static bool Scrolled( Rect rect, ScrollDirection direction, bool stopPropagation ) 54 | { 55 | if ( Settings.disableScrollwheel ) 56 | return false; 57 | 58 | var scrolled = Event.current.type == EventType.ScrollWheel && 59 | ( Event.current.delta.y > 0 && direction == ScrollDirection.Up || 60 | Event.current.delta.y < 0 && direction == ScrollDirection.Down ) && 61 | Mouse.IsOver( rect ); 62 | 63 | if ( scrolled && stopPropagation ) 64 | Event.current.Use(); 65 | 66 | return scrolled; 67 | } 68 | 69 | public static bool ScrolledDown( Rect rect, bool stopPropagation = false ) 70 | { 71 | return Scrolled( rect, ScrollDirection.Down, stopPropagation ); 72 | } 73 | 74 | public static bool ScrolledUp( Rect rect, bool stopPropagation = false ) 75 | { 76 | return Scrolled( rect, ScrollDirection.Up, stopPropagation ); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /Source/Utilities/LabelUtilities.cs: -------------------------------------------------------------------------------- 1 | // LabelUtilities.cs 2 | // Copyright Karel Kroeze, 2020-2020 3 | 4 | using UnityEngine; 5 | using Verse; 6 | 7 | namespace WorkTab 8 | { 9 | public static class LabelUtilities 10 | { 11 | public static void Label( Rect canvas, string text, Color color, string tip = "" ) 12 | { 13 | Label( canvas, text, color, GameFont.Small, TextAnchor.UpperLeft, tip ); 14 | } 15 | 16 | public static void Label( Rect canvas, string text, GameFont font, string tip = "" ) 17 | { 18 | Label( canvas, text, Color.white, font, TextAnchor.UpperLeft, tip ); 19 | } 20 | 21 | public static void Label( Rect canvas, string text, TextAnchor anchor, string tip = "" ) 22 | { 23 | Label( canvas, text, Color.white, GameFont.Small, anchor, tip ); 24 | } 25 | 26 | public static void Label( Rect canvas, string text, string tip = "" ) 27 | { 28 | Label( canvas, text, Color.white, GameFont.Small, TextAnchor.UpperLeft, tip ); 29 | } 30 | 31 | public static void Label( Rect canvas, string text, Color color, GameFont font, TextAnchor anchor, 32 | string tip = "" ) 33 | { 34 | // cache old font settings 35 | var oldColor = GUI.color; 36 | var oldFont = Text.Font; 37 | var oldAnchor = Text.Anchor; 38 | 39 | // set new ones 40 | GUI.color = color; 41 | Text.Font = font; 42 | Text.Anchor = anchor; 43 | 44 | // draw label and tip 45 | Widgets.Label( canvas, text ); 46 | if ( !tip.NullOrEmpty() ) 47 | TooltipHandler.TipRegion( canvas, tip ); 48 | 49 | // reset settings 50 | GUI.color = oldColor; 51 | Text.Font = oldFont; 52 | Text.Anchor = oldAnchor; 53 | } 54 | 55 | public static void VerticalLabel( Rect rect, string text, float margin = Constants.Margin ) 56 | { 57 | // store the scaling matrix 58 | var matrix = GUI.matrix; 59 | 60 | // rotate and then apply the scaling 61 | GUI.matrix = Matrix4x4.identity; 62 | GUIUtility.RotateAroundPivot( -90f, rect.center ); 63 | GUI.matrix = matrix * GUI.matrix; 64 | 65 | var flipped = new Rect( 0f, 0f, rect.height, rect.width ) {center = rect.center}; 66 | Widgets.Label( flipped, text ); 67 | 68 | // restore the original scaling matrix 69 | GUI.matrix = matrix; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Source/Utilities/Logger.cs: -------------------------------------------------------------------------------- 1 | // Logger.cs 2 | // Copyright Karel Kroeze, 2018-2020 3 | 4 | using System.Diagnostics; 5 | using Verse; 6 | 7 | namespace WorkTab 8 | { 9 | public static class Logger 10 | { 11 | public static string Identifier => "WorkTab"; 12 | 13 | [Conditional( "DEBUG" )] 14 | public static void Assert( object obj, string name ) 15 | { 16 | Debug( $"{name} :: {obj ?? "NULL"}" ); 17 | } 18 | 19 | [Conditional( "DEBUG" )] 20 | public static void Debug( string msg ) 21 | { 22 | Log.Message( FormatMessage( msg ) ); 23 | } 24 | 25 | public static void Error( string msg ) 26 | { 27 | Log.Error( FormatMessage( msg ) ); 28 | } 29 | 30 | public static string FormatMessage( string msg ) 31 | { 32 | return Identifier + " :: " + msg; 33 | } 34 | 35 | public static void Message( string msg ) 36 | { 37 | Log.Message( FormatMessage( msg ) ); 38 | } 39 | 40 | [Conditional( "TRACE" )] 41 | public static void Trace( string msg ) 42 | { 43 | Log.Error( FormatMessage( msg ) ); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Source/Utilities/TimeUtilities.cs: -------------------------------------------------------------------------------- 1 | // TimeUtilities.cs 2 | // Copyright Karel Kroeze, 2017-2020 3 | 4 | using System.Collections.Generic; 5 | using RimWorld; 6 | using Verse; 7 | 8 | namespace WorkTab 9 | { 10 | public static class TimeUtilities 11 | { 12 | private static List _day; 13 | 14 | public static List WholeDay 15 | { 16 | get 17 | { 18 | if ( _day.NullOrEmpty() ) 19 | { 20 | _day = new List(); 21 | for ( var hour = 0; hour < GenDate.HoursPerDay; hour++ ) 22 | _day.Add( hour ); 23 | } 24 | 25 | return new List( _day ); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Source/WorkTab.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472 4 | win 5 | WorkTab 6 | WorkTab 7 | Copyright © 2017-2021 8 | portable 9 | ..\Assemblies\ 10 | false 11 | false 12 | 13 | 14 | DEBUG 15 | 16 | 17 | 18 | 19 | 20 | mod update 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Source/WorkTab.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.6 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkTab", "WorkTab.csproj", "{5C909B0F-E82A-46B1-AE39-E56285B236A2}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicPawnTable", "..\..\..\TOOLS\DynamicPawnTable\DynamicPawnTable\DynamicPawnTable.csproj", "{E93B85A6-EEFF-4BDE-A6F4-CCE6D3487F9A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluffyUI", "..\..\..\TOOLS\FluffyUI\FluffyUI\FluffyUI.csproj", "{3E905175-2540-4C06-B4C6-F955836C0451}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {5C909B0F-E82A-46B1-AE39-E56285B236A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {5C909B0F-E82A-46B1-AE39-E56285B236A2}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {5C909B0F-E82A-46B1-AE39-E56285B236A2}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {5C909B0F-E82A-46B1-AE39-E56285B236A2}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {E93B85A6-EEFF-4BDE-A6F4-CCE6D3487F9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {E93B85A6-EEFF-4BDE-A6F4-CCE6D3487F9A}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {E93B85A6-EEFF-4BDE-A6F4-CCE6D3487F9A}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {E93B85A6-EEFF-4BDE-A6F4-CCE6D3487F9A}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {3E905175-2540-4C06-B4C6-F955836C0451}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {3E905175-2540-4C06-B4C6-F955836C0451}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {3E905175-2540-4C06-B4C6-F955836C0451}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {3E905175-2540-4C06-B4C6-F955836C0451}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {51452E04-8A4E-4166-9713-6B1B9CB12ED4} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /Source/description.md: -------------------------------------------------------------------------------- 1 | Provides a vastly more customizable work tab. 2 | 3 | ## Important 4 | 5 | Work Tab completely takes over job priorities from the vanilla game. In order to support core functionalities and other mods, it intercepts calls to get/set priorities. However, when it is told to set priorities by other modded code that is not aware of the time schedule or detailed priorities, the priority will be set for the whole day, and/or for all workgivers in a worktype. 6 | 7 | ## Features 8 | 9 | Various usability extentions to the 'vanilla' work tab; 10 | 11 | - Work types can be expanded (by Ctrl+clicking the column header) to allow you to set priorities for the individual tasks within each work type. 12 | - Time scheduler to set priorities for a given time slot only - allowing you to designate a cleaning hour, or have your cook prepare meals right before dinner, etc. etc. 13 | - Up to 9 priority levels (configurable in mod options) 14 | - Various small UX tweaks; scrolling to increase/decrease/toggle priorities, increase/decrease priorities for whole columns/rows (by holding shift and clicking/scrolling while hovering over the column header/pawn name respectively). 15 | - _All functions are detailed in the tooltips, take a moment to hover over and read them!_ 16 | 17 | ## Known Issues 18 | 19 | - `"Star Wars -- The Force"` versions prior to 1.21.1 cause priorities to reset for force users. **THIS INCLUDES THE CURRENT STEAM VERSION OF STAR WARS -- THE FORCE!** (as of 25/3/20). There is an official update available by one of the collaborators on the mod on [GitHub](https://github.com/jecrell/Star-Wars---The-Force/releases). 20 | 21 | - `Better Pawn Control` has added support for `Work Tab` and `Animal Tab`, but there currently (as of 27/7/21) still is an issue where work settings may reset. 22 | 23 | ## Notes 24 | 25 | With great power comes great responsibility. The default priorities of tasks within a job is set for a good reason; it's (usually) a sensible default. Changing these can lead to deadlock situations, so change the priorities of individual jobs at your own risk! 26 | 27 | Finally, there will never be an 'autolabour' mode where a mod sets priorities for you. Due to the way the AI is handled (e.g. pawns actively look for work, instead of there being a 'bulletin board' of jobs that need doing), it's not feasible to get the complete list of work that needs doing that would be needed to make this a reality, without extreme overhead and loads of special exception coding. 28 | 29 | ## Powered by Harmony 30 | 31 | ![Powered by Harmony](https://raw.githubusercontent.com/pardeike/Harmony/master/HarmonyLogo.png) 32 | -------------------------------------------------------------------------------- /Source/preview.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Textures/UI/Icons/LeftArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/LeftArrow.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Mood/broken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Mood/broken.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Mood/content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Mood/content.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Mood/discontent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Mood/discontent.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Mood/happy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Mood/happy.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Mood/unhappy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Mood/unhappy.png -------------------------------------------------------------------------------- /Textures/UI/Icons/RightArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/RightArrow.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/3d-hammer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/3d-hammer.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/anvil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/anvil.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/art.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/art.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/blood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/blood.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/bow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/bow.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/box.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/brickwall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/brickwall.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/briefcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/briefcase.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/bullseye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/bullseye.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/business.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/business.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/chef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/chef.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/chess-pawn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/chess-pawn.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/clean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/clean.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/cleaver-knife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/cleaver-knife.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/clock.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/cog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/cog.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/combat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/combat.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/dice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/dice.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/drop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/drop.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/eat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/eat.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/extinguish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/extinguish.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/eye.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/farming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/farming.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/fist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/fist.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/flower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/flower.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/gardening-rake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/gardening-rake.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/gun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/gun.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/ham-leg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/ham-leg.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/hammer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/hammer.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/hand.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/handcuffs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/handcuffs.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/haul.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/haul.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/health.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/health.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/hunt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/hunt.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/ingots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/ingots.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/livestock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/livestock.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/mine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/mine.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/money.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/money.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/move.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/oil-drum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/oil-drum.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/paint-brush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/paint-brush.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/paw-print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/paw-print.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/pencil.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/pray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/pray.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/research.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/research.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/reset.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/rings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/rings.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/saw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/saw.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/science.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/science.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/shepherds-crook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/shepherds-crook.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/shirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/shirt.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/shovel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/shovel.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/sick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/sick.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/sickle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/sickle.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/signs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/signs.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/social.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/spanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/spanner.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/star.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/suits-clubs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/suits-clubs.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/suits-diamonds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/suits-diamonds.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/suits-hearts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/suits-hearts.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/suits-spades.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/suits-spades.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/syringe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/syringe.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/take.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/take.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/thread-ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/thread-ball.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/undress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/undress.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/unknown.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/wear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/wear.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/wood-axe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/wood-axe.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/wrench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/wrench.png -------------------------------------------------------------------------------- /Textures/UI/Icons/Various/zzz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/Various/zzz.png -------------------------------------------------------------------------------- /Textures/UI/Icons/checks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/checks.png -------------------------------------------------------------------------------- /Textures/UI/Icons/clock-scheduler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/clock-scheduler.png -------------------------------------------------------------------------------- /Textures/UI/Icons/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/clock.png -------------------------------------------------------------------------------- /Textures/UI/Icons/collapse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/collapse.png -------------------------------------------------------------------------------- /Textures/UI/Icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/edit.png -------------------------------------------------------------------------------- /Textures/UI/Icons/expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/expand.png -------------------------------------------------------------------------------- /Textures/UI/Icons/half.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/half.png -------------------------------------------------------------------------------- /Textures/UI/Icons/now.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/now.png -------------------------------------------------------------------------------- /Textures/UI/Icons/numbers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/numbers.png -------------------------------------------------------------------------------- /Textures/UI/Icons/pin-clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/pin-clock.png -------------------------------------------------------------------------------- /Textures/UI/Icons/pin-eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/pin-eye.png -------------------------------------------------------------------------------- /Textures/UI/Icons/star-hollow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/star-hollow.png -------------------------------------------------------------------------------- /Textures/UI/Icons/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/star.png -------------------------------------------------------------------------------- /Textures/UI/Icons/whole-day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluffy-mods/WorkTab/ec609f02ef2d4ecb556b8f1df751a9c49c7da237/Textures/UI/Icons/whole-day.png --------------------------------------------------------------------------------