├── .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 | 
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 | 
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 | 
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 | 
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 | 
30 |
31 | 
32 |
33 | 
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 | 
39 |
40 | All current and past versions of this mod can be downloaded from [GitHub](https://github.com/fluffy-mods/WorkTab/releases).
41 |
42 | 
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 | 
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 | 
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 | 
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 | 
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
--------------------------------------------------------------------------------