整理
This commit is contained in:
687
MCP/mcpserver.log
Normal file
687
MCP/mcpserver.log
Normal file
@@ -0,0 +1,687 @@
|
||||
2025-08-03 15:44:02,402 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-03 15:44:02,412 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-03 15:44:02,419 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-03 15:44:02,421 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-03 15:44:02,422 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-03 15:44:27,828 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 15:44:27,828 - INFO - 收到问题: 查找 CompProperties_Explosive 的定义和用法
|
||||
2025-08-03 15:44:27,828 - INFO - 找到的潜在关键词: [('CompProperties_Explosive', 3)]
|
||||
2025-08-03 15:44:27,828 - INFO - 提取到关键词: CompProperties_Explosive
|
||||
2025-08-03 15:44:27,828 - INFO - 缓存未命中,开始实时搜索: CompProperties_Explosive
|
||||
2025-08-03 15:44:29,235 - INFO - 找到 31 个候选文件,开始向量化处理...
|
||||
2025-08-03 15:44:42,863 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 15:50:03,065 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 15:50:03,065 - INFO - 收到问题: 查找 CompProperties_Explosive 的定义和用法
|
||||
2025-08-03 15:50:03,065 - INFO - 找到的潜在关键词: [('CompProperties_Explosive', 3)]
|
||||
2025-08-03 15:50:03,065 - INFO - 提取到关键词: CompProperties_Explosive
|
||||
2025-08-03 15:50:03,065 - INFO - 缓存命中: 关键词 'CompProperties_Explosive'
|
||||
2025-08-03 15:53:04,845 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-03 15:53:04,853 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-03 15:53:51,828 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-03 15:53:51,838 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-03 15:53:51,846 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-03 15:53:51,848 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-03 15:53:51,848 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-03 15:54:10,754 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 15:54:10,755 - INFO - 收到问题: 查找 CompProperties_Explosive 的定义
|
||||
2025-08-03 15:54:10,755 - INFO - 找到的潜在关键词: [('CompProperties_Explosive', 3)]
|
||||
2025-08-03 15:54:10,755 - INFO - 提取到关键词: CompProperties_Explosive
|
||||
2025-08-03 15:54:10,755 - INFO - 缓存未命中,开始实时搜索: CompProperties_Explosive
|
||||
2025-08-03 15:54:12,401 - INFO - 找到 31 个候选文件,开始向量化处理...
|
||||
2025-08-03 15:54:28,384 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 15:54:52,951 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 15:54:52,951 - INFO - 收到问题: 查找 CompProperties_Explosive 的定义
|
||||
2025-08-03 15:54:52,951 - INFO - 找到的潜在关键词: [('CompProperties_Explosive', 3)]
|
||||
2025-08-03 15:54:52,951 - INFO - 提取到关键词: CompProperties_Explosive
|
||||
2025-08-03 15:54:52,963 - INFO - 缓存命中: 关键词 'CompProperties_Explosive'
|
||||
2025-08-03 18:58:03,910 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-03 18:58:03,919 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-03 18:58:03,927 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-03 18:58:03,929 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-03 18:58:03,930 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-03 18:58:21,536 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 18:58:21,536 - INFO - 收到问题: AspirationWorker IsCompleted
|
||||
2025-08-03 18:58:21,536 - INFO - 找到的潜在关键词: [('AspirationWorker', 2), ('IsCompleted', 2)]
|
||||
2025-08-03 18:58:21,536 - INFO - 提取到关键词: AspirationWorker
|
||||
2025-08-03 18:58:21,536 - INFO - 缓存未命中,开始实时搜索: AspirationWorker
|
||||
2025-08-03 18:58:23,022 - INFO - 未找到与 'AspirationWorker' 相关的文件。
|
||||
2025-08-03 21:00:57,503 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-03 21:00:57,518 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-03 21:00:57,531 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-03 21:00:57,533 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-03 21:00:57,535 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-03 21:12:32,710 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:12:32,713 - INFO - 收到问题: DamageDef additionalHediffsThisPart
|
||||
2025-08-03 21:12:32,713 - INFO - 找到的潜在关键词: [('DamageDef', 2), ('additionalHediffsThisPart', 2)]
|
||||
2025-08-03 21:12:32,713 - INFO - 提取到关键词: DamageDef
|
||||
2025-08-03 21:12:32,713 - INFO - 缓存未命中,开始实时搜索: DamageDef
|
||||
2025-08-03 21:12:34,071 - INFO - 找到 226 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:13:37,263 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:14:01,551 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:14:01,551 - INFO - 收到问题: DamageDef additionalHediffsThisPart
|
||||
2025-08-03 21:14:01,551 - INFO - 找到的潜在关键词: [('DamageDef', 2), ('additionalHediffsThisPart', 2)]
|
||||
2025-08-03 21:14:01,551 - INFO - 提取到关键词: DamageDef
|
||||
2025-08-03 21:14:01,561 - INFO - 缓存命中: 关键词 'DamageDef'
|
||||
2025-08-03 21:15:20,068 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:15:20,068 - INFO - 收到问题: DamageWorker Apply additionalHediffsThisPart
|
||||
2025-08-03 21:15:20,068 - INFO - 找到的潜在关键词: [('DamageWorker', 2), ('Apply', 2), ('additionalHediffsThisPart', 2)]
|
||||
2025-08-03 21:15:20,068 - INFO - 提取到关键词: DamageWorker
|
||||
2025-08-03 21:15:20,068 - INFO - 缓存未命中,开始实时搜索: DamageWorker
|
||||
2025-08-03 21:15:21,443 - INFO - 找到 37 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:15:30,428 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:16:16,210 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:16:16,210 - INFO - 收到问题: HediffDef
|
||||
2025-08-03 21:16:16,210 - INFO - 找到的潜在关键词: [('HediffDef', 2)]
|
||||
2025-08-03 21:16:16,210 - INFO - 提取到关键词: HediffDef
|
||||
2025-08-03 21:16:16,211 - INFO - 缓存未命中,开始实时搜索: HediffDef
|
||||
2025-08-03 21:16:17,587 - INFO - 找到 428 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:18:43,382 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:18:43,387 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:18:43,387 - INFO - 收到问题: HediffDef class
|
||||
2025-08-03 21:18:43,387 - INFO - 找到的潜在关键词: [('HediffDef', 2)]
|
||||
2025-08-03 21:18:43,387 - INFO - 提取到关键词: HediffDef
|
||||
2025-08-03 21:18:43,392 - INFO - 缓存命中: 关键词 'HediffDef'
|
||||
2025-08-03 21:18:55,913 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:18:55,913 - INFO - 收到问题: HediffMaker.MakeHediff
|
||||
2025-08-03 21:18:55,913 - INFO - 找到的潜在关键词: [('HediffMaker.MakeHediff', 2)]
|
||||
2025-08-03 21:18:55,913 - INFO - 提取到关键词: HediffMaker.MakeHediff
|
||||
2025-08-03 21:18:55,913 - INFO - 缓存未命中,开始实时搜索: HediffMaker.MakeHediff
|
||||
2025-08-03 21:18:57,267 - INFO - 找到 54 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:19:12,272 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:20:38,686 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:20:38,686 - INFO - 收到问题: DamageWorker Apply additionalHediffs
|
||||
2025-08-03 21:20:38,686 - INFO - 找到的潜在关键词: [('DamageWorker', 2), ('Apply', 2), ('additionalHediffs', 2)]
|
||||
2025-08-03 21:20:38,686 - INFO - 提取到关键词: DamageWorker
|
||||
2025-08-03 21:20:38,687 - INFO - 缓存命中: 关键词 'DamageWorker'
|
||||
2025-08-03 21:23:10,383 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:23:10,383 - INFO - 收到问题: DamageDefAdditionalHediff
|
||||
2025-08-03 21:23:10,383 - INFO - 找到的潜在关键词: [('DamageDefAdditionalHediff', 2)]
|
||||
2025-08-03 21:23:10,383 - INFO - 提取到关键词: DamageDefAdditionalHediff
|
||||
2025-08-03 21:23:10,383 - INFO - 缓存未命中,开始实时搜索: DamageDefAdditionalHediff
|
||||
2025-08-03 21:23:11,759 - INFO - 找到 5 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:23:13,303 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:40:06,239 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:40:06,239 - INFO - 收到问题: PsychicRitualDef
|
||||
2025-08-03 21:40:06,239 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-03 21:40:06,239 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-03 21:40:06,239 - INFO - 缓存未命中,开始实时搜索: PsychicRitualDef
|
||||
2025-08-03 21:40:07,588 - INFO - 找到 57 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:40:23,047 - WARNING - 未能从 C:\Steam\steamapps\common\RimWorld\Data\Anomaly\Languages\ChineseSimplified (简体中文)\Keyed\Misc_PsychicRituals.xml 提取到完整的代码块。
|
||||
2025-08-03 21:40:23,048 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:40:38,955 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:40:38,955 - INFO - 收到问题: CompProperties_PsychicRitualSpot
|
||||
2025-08-03 21:40:38,955 - INFO - 找到的潜在关键词: [('CompProperties_PsychicRitualSpot', 3)]
|
||||
2025-08-03 21:40:38,955 - INFO - 提取到关键词: CompProperties_PsychicRitualSpot
|
||||
2025-08-03 21:40:38,955 - INFO - 缓存未命中,开始实时搜索: CompProperties_PsychicRitualSpot
|
||||
2025-08-03 21:40:40,281 - INFO - 找到 2 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:40:41,046 - INFO - 向量搜索完成。找到了 2 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:41:38,879 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:41:38,879 - INFO - 收到问题: PsychicRitualGizmo
|
||||
2025-08-03 21:41:38,879 - INFO - 找到的潜在关键词: [('PsychicRitualGizmo', 2)]
|
||||
2025-08-03 21:41:38,879 - INFO - 提取到关键词: PsychicRitualGizmo
|
||||
2025-08-03 21:41:38,879 - INFO - 缓存未命中,开始实时搜索: PsychicRitualGizmo
|
||||
2025-08-03 21:41:40,315 - INFO - 找到 3 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:41:41,300 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 21:43:48,740 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 21:43:48,740 - INFO - 收到问题: PsychicRitualDef_InvocationCircle
|
||||
2025-08-03 21:43:48,740 - INFO - 找到的潜在关键词: [('PsychicRitualDef_InvocationCircle', 3)]
|
||||
2025-08-03 21:43:48,740 - INFO - 提取到关键词: PsychicRitualDef_InvocationCircle
|
||||
2025-08-03 21:43:48,740 - INFO - 缓存未命中,开始实时搜索: PsychicRitualDef_InvocationCircle
|
||||
2025-08-03 21:43:50,020 - INFO - 找到 26 个候选文件,开始向量化处理...
|
||||
2025-08-03 21:43:55,992 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 22:01:51,554 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 22:01:51,554 - INFO - 收到问题: Show the C# source code for the CompPsychicRitualSpot class, specifically the CompGetGizmosExtra method. I need to see how it creates the ritual selection gizmo and what it passes to the dialog window.
|
||||
2025-08-03 22:01:51,554 - INFO - 找到的潜在关键词: [('Show', 2), ('CompPsychicRitualSpot', 2), ('CompGetGizmosExtra', 2)]
|
||||
2025-08-03 22:01:51,554 - INFO - 提取到关键词: Show
|
||||
2025-08-03 22:01:51,555 - INFO - 缓存未命中,开始实时搜索: Show
|
||||
2025-08-03 22:01:52,936 - INFO - 找到 840 个候选文件,开始向量化处理...
|
||||
2025-08-03 22:06:16,237 - WARNING - 未能从 C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\RitualTargetUseReport.txt 提取到完整的代码块。
|
||||
2025-08-03 22:06:16,237 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 22:13:55,178 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 22:13:55,178 - INFO - 收到问题: Show the C# source code for the PsychicRitualDef class and the Dialog_BeginPsychicRitual class. I need to see the correct properties for Icon, cooldowns, roles, and the exact constructor signature for the dialog.
|
||||
2025-08-03 22:13:55,178 - INFO - 找到的潜在关键词: [('Dialog_BeginPsychicRitual', 3), ('Show', 2), ('PsychicRitualDef', 2), ('Icon', 2)]
|
||||
2025-08-03 22:13:55,178 - INFO - 提取到关键词: Dialog_BeginPsychicRitual
|
||||
2025-08-03 22:13:55,178 - INFO - 缓存未命中,开始实时搜索: Dialog_BeginPsychicRitual
|
||||
2025-08-03 22:13:56,380 - INFO - 找到 8 个候选文件,开始向量化处理...
|
||||
2025-08-03 22:13:58,927 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 22:30:34,550 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 22:30:34,550 - INFO - 收到问题: PsychicRitualDef_InvocationCircle class definition
|
||||
2025-08-03 22:30:34,550 - INFO - 找到的潜在关键词: [('PsychicRitualDef_InvocationCircle', 3)]
|
||||
2025-08-03 22:30:34,550 - INFO - 提取到关键词: PsychicRitualDef_InvocationCircle
|
||||
2025-08-03 22:30:34,558 - INFO - 缓存命中: 关键词 'PsychicRitualDef_InvocationCircle'
|
||||
2025-08-03 22:59:18,371 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 22:59:18,371 - INFO - 收到问题: CompPsychicRitualSpot CompGetGizmosExtra
|
||||
2025-08-03 22:59:18,371 - INFO - 找到的潜在关键词: [('CompPsychicRitualSpot', 2), ('CompGetGizmosExtra', 2)]
|
||||
2025-08-03 22:59:18,371 - INFO - 提取到关键词: CompPsychicRitualSpot
|
||||
2025-08-03 22:59:18,371 - INFO - 缓存未命中,开始实时搜索: CompPsychicRitualSpot
|
||||
2025-08-03 22:59:31,774 - INFO - 找到 4 个候选文件,开始向量化处理...
|
||||
2025-08-03 22:59:33,291 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-03 22:59:51,745 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 22:59:51,745 - INFO - 收到问题: PsychicRitualGizmo GetGizmos
|
||||
2025-08-03 22:59:51,745 - INFO - 找到的潜在关键词: [('PsychicRitualGizmo', 2), ('GetGizmos', 2)]
|
||||
2025-08-03 22:59:51,745 - INFO - 提取到关键词: PsychicRitualGizmo
|
||||
2025-08-03 22:59:51,758 - INFO - 缓存命中: 关键词 'PsychicRitualGizmo'
|
||||
2025-08-03 23:28:19,476 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 23:28:19,476 - INFO - 收到问题: PsychicRitualDef LabelCap usage
|
||||
2025-08-03 23:28:19,476 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2), ('LabelCap', 2)]
|
||||
2025-08-03 23:28:19,476 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-03 23:28:19,486 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-03 23:36:54,188 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 23:36:54,189 - INFO - 收到问题: PsychicRitualDef reward
|
||||
2025-08-03 23:36:54,189 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-03 23:36:54,189 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-03 23:36:54,189 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-03 23:43:11,852 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 23:43:11,852 - INFO - 收到问题: PsychicRitualDef create item
|
||||
2025-08-03 23:43:11,852 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-03 23:43:11,852 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-03 23:43:11,852 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-03 23:54:25,993 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 23:54:25,993 - INFO - 收到问题: CompProperties_PsychicRitualSpot PsychicRitualGizmo
|
||||
2025-08-03 23:54:25,994 - INFO - 找到的潜在关键词: [('CompProperties_PsychicRitualSpot', 3), ('PsychicRitualGizmo', 2)]
|
||||
2025-08-03 23:54:25,994 - INFO - 提取到关键词: CompProperties_PsychicRitualSpot
|
||||
2025-08-03 23:54:26,001 - INFO - 缓存命中: 关键词 'CompProperties_PsychicRitualSpot'
|
||||
2025-08-03 23:54:38,820 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 23:54:38,820 - INFO - 收到问题: CompPsychicRitualSpot CompGetGizmosExtra
|
||||
2025-08-03 23:54:38,820 - INFO - 找到的潜在关键词: [('CompPsychicRitualSpot', 2), ('CompGetGizmosExtra', 2)]
|
||||
2025-08-03 23:54:38,820 - INFO - 提取到关键词: CompPsychicRitualSpot
|
||||
2025-08-03 23:54:38,831 - INFO - 缓存命中: 关键词 'CompPsychicRitualSpot'
|
||||
2025-08-03 23:55:28,827 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-03 23:55:28,828 - INFO - 收到问题: PsychicRitualGizmo GetGizmos
|
||||
2025-08-03 23:55:28,828 - INFO - 找到的潜在关键词: [('PsychicRitualGizmo', 2), ('GetGizmos', 2)]
|
||||
2025-08-03 23:55:28,828 - INFO - 提取到关键词: PsychicRitualGizmo
|
||||
2025-08-03 23:55:28,840 - INFO - 缓存命中: 关键词 'PsychicRitualGizmo'
|
||||
2025-08-03 23:57:23,467 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-03 23:57:23,479 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-03 23:57:23,492 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-03 23:57:23,494 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-03 23:57:23,495 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-04 00:00:37,307 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 00:00:37,307 - INFO - 收到问题: PsychicRitualDef
|
||||
2025-08-04 00:00:37,307 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-04 00:00:37,307 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-04 00:00:37,317 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-04 00:00:55,095 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 00:00:55,095 - INFO - 收到问题: class PsychicRitualDef
|
||||
2025-08-04 00:00:55,095 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-04 00:00:55,095 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-04 00:00:55,095 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-04 00:09:55,831 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 00:09:55,831 - INFO - 收到问题: public class PsychicRitualDef : Def
|
||||
2025-08-04 00:09:55,832 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-04 00:09:55,832 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-04 00:09:55,832 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-04 07:20:33,529 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-04 07:20:33,539 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-04 07:20:33,547 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-04 07:20:33,549 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-04 07:20:33,551 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-04 07:20:33,559 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-04 07:20:33,560 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-04 07:20:35,996 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-04 07:20:36,004 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-04 07:20:36,011 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-04 07:20:36,013 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-04 07:20:36,013 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-04 07:24:35,273 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:24:35,273 - INFO - 收到问题: public class PsychicRitualDef : Def
|
||||
2025-08-04 07:24:35,273 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-04 07:24:35,273 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-04 07:24:35,282 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-04 07:26:21,038 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:26:21,038 - INFO - 收到问题: public class PsychicRitualDef : Def
|
||||
2025-08-04 07:26:21,038 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-04 07:26:21,038 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-04 07:26:21,038 - INFO - 缓存未命中,开始实时搜索: PsychicRitualDef
|
||||
2025-08-04 07:27:10,095 - INFO - 找到 57 个候选文件,开始向量化处理...
|
||||
2025-08-04 07:27:28,833 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-04 07:28:17,494 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:28:17,494 - INFO - 收到问题: public class PsychicRitualDef : Def
|
||||
2025-08-04 07:28:17,494 - INFO - 找到的潜在关键词: [('PsychicRitualDef', 2)]
|
||||
2025-08-04 07:28:17,494 - INFO - 提取到关键词: PsychicRitualDef
|
||||
2025-08-04 07:28:17,501 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-04 07:30:47,851 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-04 07:30:47,860 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-04 07:30:47,868 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-04 07:30:47,869 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-04 07:30:47,870 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-04 07:31:58,371 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:31:58,372 - INFO - 收到问题: PsychicRitualDef
|
||||
2025-08-04 07:31:58,372 - INFO - 找到的潜在关键词: ['PsychicRitualDef']
|
||||
2025-08-04 07:31:58,372 - INFO - 提取到关键词: ['PsychicRitualDef']
|
||||
2025-08-04 07:31:58,372 - INFO - 缓存未命中,开始实时搜索: PsychicRitualDef
|
||||
2025-08-04 07:31:59,657 - INFO - 找到 57 个候选文件,开始向量化处理...
|
||||
2025-08-04 07:31:59,658 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef.txt
|
||||
2025-08-04 07:31:59,658 - WARNING - 候选文件过多 (56),仅处理前 25 个。
|
||||
2025-08-04 07:32:06,642 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-04 07:32:54,871 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:32:54,871 - INFO - 收到问题: public class PsychicRitualDef
|
||||
2025-08-04 07:32:54,872 - INFO - 找到的潜在关键词: ['PsychicRitualDef']
|
||||
2025-08-04 07:32:54,872 - INFO - 提取到关键词: ['PsychicRitualDef']
|
||||
2025-08-04 07:32:54,878 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-04 07:35:55,326 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:35:55,326 - INFO - 收到问题: PsychicRitualToil_GatherForInvocation
|
||||
2025-08-04 07:35:55,326 - INFO - 找到的潜在关键词: ['PsychicRitualToil_GatherForInvocation']
|
||||
2025-08-04 07:35:55,326 - INFO - 提取到关键词: ['PsychicRitualToil_GatherForInvocation']
|
||||
2025-08-04 07:35:55,327 - INFO - 缓存未命中,开始实时搜索: PsychicRitualToil_GatherForInvocation
|
||||
2025-08-04 07:35:56,578 - INFO - 找到 4 个候选文件,开始向量化处理...
|
||||
2025-08-04 07:35:56,578 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI.Group\PsychicRitualToil_GatherForInvocation.txt
|
||||
2025-08-04 07:35:58,159 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-04 07:42:57,428 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:42:57,428 - INFO - 收到问题: PsychicRitualDef_InvocationCircle class
|
||||
2025-08-04 07:42:57,428 - INFO - 找到的潜在关键词: ['PsychicRitualDef_InvocationCircle']
|
||||
2025-08-04 07:42:57,428 - INFO - 提取到关键词: ['PsychicRitualDef_InvocationCircle']
|
||||
2025-08-04 07:42:57,429 - INFO - 缓存未命中,开始实时搜索: PsychicRitualDef_InvocationCircle
|
||||
2025-08-04 07:42:58,898 - INFO - 找到 26 个候选文件,开始向量化处理...
|
||||
2025-08-04 07:42:58,898 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_InvocationCircle.txt
|
||||
2025-08-04 07:43:06,851 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-04 07:43:37,198 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:43:37,198 - INFO - 收到问题: PsychicRitualDef class source
|
||||
2025-08-04 07:43:37,198 - INFO - 找到的潜在关键词: ['PsychicRitualDef']
|
||||
2025-08-04 07:43:37,198 - INFO - 提取到关键词: ['PsychicRitualDef']
|
||||
2025-08-04 07:43:37,199 - INFO - 缓存命中: 关键词 'PsychicRitualDef'
|
||||
2025-08-04 07:44:18,730 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:44:18,730 - INFO - 收到问题: PsychicRitualToil_GatherOfferings class source
|
||||
2025-08-04 07:44:18,730 - INFO - 找到的潜在关键词: ['PsychicRitualToil_GatherOfferings']
|
||||
2025-08-04 07:44:18,730 - INFO - 提取到关键词: ['PsychicRitualToil_GatherOfferings']
|
||||
2025-08-04 07:44:18,730 - INFO - 缓存未命中,开始实时搜索: PsychicRitualToil_GatherOfferings
|
||||
2025-08-04 07:44:20,107 - INFO - 找到 5 个候选文件,开始向量化处理...
|
||||
2025-08-04 07:44:20,107 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI.Group\PsychicRitualToil_GatherOfferings.txt
|
||||
2025-08-04 07:44:22,143 - INFO - 向量搜索完成。找到了 4 个匹配项并成功提取了代码。
|
||||
2025-08-04 07:53:02,419 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:53:02,419 - INFO - 收到问题: StatDef for melee attack speed
|
||||
2025-08-04 07:53:02,419 - INFO - 找到的潜在关键词: ['StatDef']
|
||||
2025-08-04 07:53:02,419 - INFO - 提取到关键词: ['StatDef']
|
||||
2025-08-04 07:53:02,419 - INFO - 缓存未命中,开始实时搜索: StatDef
|
||||
2025-08-04 07:53:03,865 - INFO - 找到 516 个候选文件,开始向量化处理...
|
||||
2025-08-04 07:53:03,867 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\StatDef.txt
|
||||
2025-08-04 07:53:03,868 - WARNING - 候选文件过多 (515),仅处理前 25 个。
|
||||
2025-08-04 07:53:12,872 - INFO - 向量搜索完成。找到了 2 个匹配项并成功提取了代码。
|
||||
2025-08-04 07:55:01,722 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:55:01,723 - INFO - 收到问题: AbilityDef for berserk pulse
|
||||
2025-08-04 07:55:01,723 - INFO - 找到的潜在关键词: ['AbilityDef']
|
||||
2025-08-04 07:55:01,723 - INFO - 提取到关键词: ['AbilityDef']
|
||||
2025-08-04 07:55:01,723 - INFO - 缓存未命中,开始实时搜索: AbilityDef
|
||||
2025-08-04 07:55:03,037 - INFO - 找到 104 个候选文件,开始向量化处理...
|
||||
2025-08-04 07:55:03,037 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\AbilityDef.txt
|
||||
2025-08-04 07:55:03,037 - WARNING - 候选文件过多 (103),仅处理前 25 个。
|
||||
2025-08-04 07:55:10,617 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-04 07:58:42,495 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:58:42,495 - INFO - 收到问题: 现在我需要找到原版“群体狂暴”灵能的 defName。
|
||||
2025-08-04 07:58:42,495 - INFO - 找到的潜在关键词: ['defName。']
|
||||
2025-08-04 07:58:42,495 - INFO - 提取到关键词: ['defName。']
|
||||
2025-08-04 07:58:42,495 - INFO - 缓存未命中,开始实时搜索: defName。
|
||||
2025-08-04 07:58:43,777 - INFO - 未找到与 '['defName。']' 相关的文件。
|
||||
2025-08-04 07:59:36,124 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 07:59:36,124 - INFO - 收到问题: 现在我需要找到原版“群体狂暴”灵能的 defName。
|
||||
2025-08-04 07:59:36,124 - INFO - 找到的潜在关键词: ['defName。']
|
||||
2025-08-04 07:59:36,124 - INFO - 提取到关键词: ['defName。']
|
||||
2025-08-04 07:59:36,124 - INFO - 缓存未命中,开始实时搜索: defName。
|
||||
2025-08-04 07:59:37,427 - INFO - 未找到与 '['defName。']' 相关的文件。
|
||||
2025-08-04 08:00:44,966 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 08:00:44,966 - INFO - 收到问题: 现在我需要找到原版“群体狂暴”灵能的 defName。
|
||||
2025-08-04 08:00:44,966 - INFO - 找到的潜在关键词: ['defName。']
|
||||
2025-08-04 08:00:44,967 - INFO - 提取到关键词: ['defName。']
|
||||
2025-08-04 08:00:44,967 - INFO - 缓存未命中,开始实时搜索: defName。
|
||||
2025-08-04 08:00:46,237 - INFO - 未找到与 '['defName。']' 相关的文件。
|
||||
2025-08-04 08:01:42,734 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-04 08:01:42,734 - INFO - 收到问题: 现在我需要找到原版“群体狂暴”灵能的 defName。
|
||||
2025-08-04 08:01:42,734 - INFO - 找到的潜在关键词: ['defName。']
|
||||
2025-08-04 08:01:42,734 - INFO - 提取到关键词: ['defName。']
|
||||
2025-08-04 08:01:42,734 - INFO - 缓存未命中,开始实时搜索: defName。
|
||||
2025-08-04 08:01:43,967 - INFO - 未找到与 '['defName。']' 相关的文件。
|
||||
2025-08-04 08:54:04,338 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-04 08:54:04,354 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-04 08:54:04,367 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-04 08:54:04,369 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-04 08:54:04,370 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-04 21:57:57,767 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-04 21:57:57,782 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-04 21:57:57,795 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-04 21:57:57,797 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-04 21:57:57,798 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-05 18:39:23,841 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-05 18:39:23,858 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-05 18:39:23,871 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-05 18:39:23,873 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-05 18:39:23,874 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-05 18:47:28,304 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-05 18:47:28,306 - INFO - 收到问题: Pawn_InventoryTracker.get_FirstUnloadableThing
|
||||
2025-08-05 18:47:28,306 - INFO - 找到的潜在关键词: ['get_FirstUnloadableThing', 'Pawn_InventoryTracker']
|
||||
2025-08-05 18:47:28,306 - INFO - 提取到关键词: ['get_FirstUnloadableThing', 'Pawn_InventoryTracker']
|
||||
2025-08-05 18:47:28,306 - INFO - 缓存未命中,开始实时搜索: Pawn_InventoryTracker-get_FirstUnloadableThing
|
||||
2025-08-05 18:48:42,219 - INFO - 使用最具体的关键词 'get_FirstUnloadableThing' 未找到文件,尝试所有关键词...
|
||||
2025-08-05 18:48:44,293 - INFO - 找到 20 个候选文件,开始向量化处理...
|
||||
2025-08-05 18:48:44,293 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\Pawn_InventoryTracker.txt
|
||||
2025-08-05 18:48:50,652 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-05 18:49:27,121 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-05 18:49:27,121 - INFO - 收到问题: Pawn_InventoryTracker.get_FirstUnloadableThing
|
||||
2025-08-05 18:49:27,122 - INFO - 找到的潜在关键词: ['get_FirstUnloadableThing', 'Pawn_InventoryTracker']
|
||||
2025-08-05 18:49:27,122 - INFO - 提取到关键词: ['get_FirstUnloadableThing', 'Pawn_InventoryTracker']
|
||||
2025-08-05 18:49:27,131 - INFO - 缓存命中: 关键词 'Pawn_InventoryTracker-get_FirstUnloadableThing'
|
||||
2025-08-05 19:04:16,910 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-05 19:04:16,910 - INFO - 收到问题: Verse.Projectile.TickInterval
|
||||
2025-08-05 19:04:16,910 - INFO - 找到的潜在关键词: ['TickInterval', 'Projectile', 'Verse']
|
||||
2025-08-05 19:04:16,910 - INFO - 提取到关键词: ['TickInterval', 'Projectile', 'Verse']
|
||||
2025-08-05 19:04:16,910 - INFO - 缓存未命中,开始实时搜索: Projectile-TickInterval-Verse
|
||||
2025-08-05 19:04:18,552 - INFO - 找到 289 个候选文件,开始向量化处理...
|
||||
2025-08-05 19:04:18,553 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\Projectile.txt
|
||||
2025-08-05 19:04:18,554 - WARNING - 候选文件过多 (288),仅处理前 25 个。
|
||||
2025-08-05 19:04:28,272 - ERROR - HTTPSConnectionPool(host='dashscope.aliyuncs.com', port=443): Max retries exceeded with url: /api/v1/services/embeddings/text-embedding/text-embedding (Caused by SSLError(SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)')))
|
||||
2025-08-05 19:04:28,272 - ERROR - 调用向量API时出错: HTTPSConnectionPool(host='dashscope.aliyuncs.com', port=443): Max retries exceeded with url: /api/v1/services/embeddings/text-embedding/text-embedding (Caused by SSLError(SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)')))
|
||||
urllib3.exceptions.SSLError: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)
|
||||
|
||||
The above exception was the direct cause of the following exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\adapters.py", line 667, in send
|
||||
resp = conn.urlopen(
|
||||
^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\urllib3\connectionpool.py", line 841, in urlopen
|
||||
retries = retries.increment(
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\urllib3\util\retry.py", line 519, in increment
|
||||
raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='dashscope.aliyuncs.com', port=443): Max retries exceeded with url: /api/v1/services/embeddings/text-embedding/text-embedding (Caused by SSLError(SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)')))
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "c:\Steam\steamapps\common\RimWorld\Mods\3516260226\Source\MCP\mcpserver_stdio.py", line 82, in get_embedding
|
||||
response = dashscope.TextEmbedding.call(
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\dashscope\embeddings\text_embedding.py", line 49, in call
|
||||
return super().call(model=model,
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\dashscope\client\base_api.py", line 148, in call
|
||||
return request.call()
|
||||
^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\dashscope\api_entities\http_request.py", line 101, in call
|
||||
output = next(response)
|
||||
^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\dashscope\api_entities\http_request.py", line 330, in _handle_request
|
||||
raise e
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\dashscope\api_entities\http_request.py", line 313, in _handle_request
|
||||
response = session.post(url=self.url,
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\sessions.py", line 637, in post
|
||||
return self.request("POST", url, data=data, json=json, **kwargs)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\sessions.py", line 589, in request
|
||||
resp = self.send(prep, **send_kwargs)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\sessions.py", line 703, in send
|
||||
r = adapter.send(request, **kwargs)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "C:\Users\Kalo\AppData\Local\Programs\Python\Python312\Lib\site-packages\requests\adapters.py", line 698, in send
|
||||
raise SSLError(e, request=request)
|
||||
requests.exceptions.SSLError: HTTPSConnectionPool(host='dashscope.aliyuncs.com', port=443): Max retries exceeded with url: /api/v1/services/embeddings/text-embedding/text-embedding (Caused by SSLError(SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)')))
|
||||
2025-08-05 19:04:32,638 - INFO - 向量搜索完成。找到了 2 个匹配项并成功提取了代码。
|
||||
2025-08-06 19:25:05,631 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-06 19:25:05,642 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-06 19:25:05,651 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-06 19:25:05,653 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-06 19:25:05,653 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-06 20:19:21,633 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-06 20:19:21,638 - INFO - 收到问题: How does RimWorld handle delayed actions or events over a specific number of ticks? I'm looking for schedulers or managers.
|
||||
2025-08-06 20:19:21,640 - INFO - 找到的潜在关键词: ['RimWorld']
|
||||
2025-08-06 20:19:21,640 - INFO - 提取到关键词: ['RimWorld']
|
||||
2025-08-06 20:19:21,640 - INFO - 缓存未命中,开始实时搜索: RimWorld
|
||||
2025-08-06 20:19:23,841 - INFO - 找到 8024 个候选文件,开始向量化处理...
|
||||
2025-08-06 20:19:23,869 - WARNING - 候选文件过多 (8024),仅处理前 25 个。
|
||||
2025-08-08 17:22:58,354 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-08 17:22:58,366 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-08 17:22:58,377 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-08 17:22:58,378 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-08 17:22:58,379 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-08 17:41:24,024 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 17:41:24,025 - INFO - 收到问题: Building_Bed
|
||||
2025-08-08 17:41:24,026 - INFO - 找到的潜在关键词: ['Building_Bed']
|
||||
2025-08-08 17:41:24,026 - INFO - 提取到关键词: ['Building_Bed']
|
||||
2025-08-08 17:41:24,026 - INFO - 缓存未命中,开始实时搜索: Building_Bed
|
||||
2025-08-08 17:42:44,193 - INFO - 找到 103 个候选文件,开始向量化处理...
|
||||
2025-08-08 17:42:44,193 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\Building_Bed.txt
|
||||
2025-08-08 17:42:44,197 - WARNING - 候选文件过多 (102),仅处理前 25 个。
|
||||
2025-08-08 17:42:51,398 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-08 17:42:51,404 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 17:42:51,404 - INFO - 收到问题: CryptosleepCasket
|
||||
2025-08-08 17:42:51,404 - INFO - 找到的潜在关键词: ['CryptosleepCasket']
|
||||
2025-08-08 17:42:51,404 - INFO - 提取到关键词: ['CryptosleepCasket']
|
||||
2025-08-08 17:42:51,404 - INFO - 缓存未命中,开始实时搜索: CryptosleepCasket
|
||||
2025-08-08 17:42:53,357 - INFO - 找到 56 个候选文件,开始向量化处理...
|
||||
2025-08-08 17:42:53,359 - WARNING - 候选文件过多 (56),仅处理前 25 个。
|
||||
2025-08-08 17:43:01,261 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-08 17:46:37,047 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 17:46:37,047 - INFO - 收到问题: BiosculpterPod
|
||||
2025-08-08 17:46:37,047 - INFO - 找到的潜在关键词: ['BiosculpterPod']
|
||||
2025-08-08 17:46:37,048 - INFO - 提取到关键词: ['BiosculpterPod']
|
||||
2025-08-08 17:46:37,048 - INFO - 缓存未命中,开始实时搜索: BiosculpterPod
|
||||
2025-08-08 17:46:39,286 - INFO - 找到 42 个候选文件,开始向量化处理...
|
||||
2025-08-08 17:46:39,286 - WARNING - 候选文件过多 (42),仅处理前 25 个。
|
||||
2025-08-08 17:46:46,223 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-08 17:47:06,637 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 17:47:06,637 - INFO - 收到问题: Building_BiosculpterPod class
|
||||
2025-08-08 17:47:06,637 - INFO - 找到的潜在关键词: ['Building_BiosculpterPod']
|
||||
2025-08-08 17:47:06,637 - INFO - 提取到关键词: ['Building_BiosculpterPod']
|
||||
2025-08-08 17:47:06,638 - INFO - 缓存未命中,开始实时搜索: Building_BiosculpterPod
|
||||
2025-08-08 17:47:08,918 - INFO - 未找到与 '['Building_BiosculpterPod']' 相关的文件。
|
||||
2025-08-08 17:56:16,922 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 17:56:16,922 - INFO - 收到问题: ThingDef of BiosculpterPod
|
||||
2025-08-08 17:56:16,922 - INFO - 找到的潜在关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-08 17:56:16,922 - INFO - 提取到关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-08 17:56:16,922 - INFO - 缓存未命中,开始实时搜索: BiosculpterPod-ThingDef
|
||||
2025-08-08 17:56:18,882 - INFO - 找到 50 个候选文件,开始向量化处理...
|
||||
2025-08-08 17:56:18,882 - WARNING - 候选文件过多 (50),仅处理前 25 个。
|
||||
2025-08-08 17:56:25,938 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-08 18:50:39,345 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 18:50:39,347 - INFO - 收到问题: Building_BiosculpterPod class definition
|
||||
2025-08-08 18:50:39,348 - INFO - 找到的潜在关键词: ['Building_BiosculpterPod']
|
||||
2025-08-08 18:50:39,348 - INFO - 提取到关键词: ['Building_BiosculpterPod']
|
||||
2025-08-08 18:50:39,348 - INFO - 缓存未命中,开始实时搜索: Building_BiosculpterPod
|
||||
2025-08-08 18:52:17,079 - INFO - 未找到与 '['Building_BiosculpterPod']' 相关的文件。
|
||||
2025-08-08 18:53:58,078 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 18:53:58,078 - INFO - 收到问题: Building_BiosculpterPod class definition
|
||||
2025-08-08 18:53:58,078 - INFO - 找到的潜在关键词: ['Building_BiosculpterPod']
|
||||
2025-08-08 18:53:58,078 - INFO - 提取到关键词: ['Building_BiosculpterPod']
|
||||
2025-08-08 18:53:58,078 - INFO - 缓存未命中,开始实时搜索: Building_BiosculpterPod
|
||||
2025-08-08 18:54:00,558 - INFO - 未找到与 '['Building_BiosculpterPod']' 相关的文件。
|
||||
2025-08-08 19:07:28,003 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 19:07:28,003 - INFO - 收到问题: CompBiosculpterPod and CompProperties_BiosculpterPod
|
||||
2025-08-08 19:07:28,003 - INFO - 找到的潜在关键词: ['CompProperties_BiosculpterPod', 'CompBiosculpterPod']
|
||||
2025-08-08 19:07:28,003 - INFO - 提取到关键词: ['CompProperties_BiosculpterPod', 'CompBiosculpterPod']
|
||||
2025-08-08 19:07:28,004 - INFO - 缓存未命中,开始实时搜索: CompBiosculpterPod-CompProperties_BiosculpterPod
|
||||
2025-08-08 19:07:29,829 - INFO - 找到 11 个候选文件,开始向量化处理...
|
||||
2025-08-08 19:07:29,829 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_BiosculpterPod.txt
|
||||
2025-08-08 19:07:29,829 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompBiosculpterPod.txt
|
||||
2025-08-08 19:07:31,777 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-08 19:35:05,891 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 19:35:05,891 - INFO - 收到问题: C# class JobDef fields
|
||||
2025-08-08 19:35:05,891 - INFO - 找到的潜在关键词: ['JobDef']
|
||||
2025-08-08 19:35:05,891 - INFO - 提取到关键词: ['JobDef']
|
||||
2025-08-08 19:35:05,891 - INFO - 缓存未命中,开始实时搜索: JobDef
|
||||
2025-08-08 19:35:08,071 - INFO - 找到 571 个候选文件,开始向量化处理...
|
||||
2025-08-08 19:35:08,072 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\JobDef.txt
|
||||
2025-08-08 19:35:08,073 - WARNING - 候选文件过多 (570),仅处理前 25 个。
|
||||
2025-08-08 19:35:13,917 - INFO - 向量搜索完成。找到了 2 个匹配项并成功提取了代码。
|
||||
2025-08-08 23:59:20,246 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-08 23:59:20,269 - INFO - 收到问题: ThingDef for BiosculpterPod
|
||||
2025-08-08 23:59:20,270 - INFO - 找到的潜在关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-08 23:59:20,270 - INFO - 提取到关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-08 23:59:20,302 - INFO - 缓存命中: 关键词 'BiosculpterPod-ThingDef'
|
||||
2025-08-09 00:32:44,309 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 00:32:44,309 - INFO - 收到问题: JobDriver_EnterCryptosleepCasket
|
||||
2025-08-09 00:32:44,310 - INFO - 找到的潜在关键词: ['JobDriver_EnterCryptosleepCasket']
|
||||
2025-08-09 00:32:44,310 - INFO - 提取到关键词: ['JobDriver_EnterCryptosleepCasket']
|
||||
2025-08-09 00:32:44,310 - INFO - 缓存未命中,开始实时搜索: JobDriver_EnterCryptosleepCasket
|
||||
2025-08-09 00:33:57,816 - INFO - 找到 2 个候选文件,开始向量化处理...
|
||||
2025-08-09 00:33:57,816 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_EnterCryptosleepCasket.txt
|
||||
2025-08-09 00:33:58,572 - INFO - 向量搜索完成。找到了 1 个匹配项并成功提取了代码。
|
||||
2025-08-09 00:42:26,054 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 00:42:26,054 - INFO - 收到问题: ThingDef for BiosculpterPod
|
||||
2025-08-09 00:42:26,054 - INFO - 找到的潜在关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-09 00:42:26,054 - INFO - 提取到关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-09 00:42:26,069 - INFO - 缓存命中: 关键词 'BiosculpterPod-ThingDef'
|
||||
2025-08-09 10:18:42,504 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-09 10:18:42,520 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-09 10:18:42,533 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-09 10:18:42,536 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-09 10:18:42,537 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-09 11:08:17,356 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-09 11:08:17,366 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-09 11:08:17,375 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-09 11:08:17,377 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-09 11:08:17,378 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-09 13:01:19,595 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 13:01:19,600 - INFO - 收到问题: HediffDef named Malnutrition
|
||||
2025-08-09 13:01:19,603 - INFO - 找到的潜在关键词: ['HediffDef', 'Malnutrition']
|
||||
2025-08-09 13:01:19,603 - INFO - 提取到关键词: ['HediffDef', 'Malnutrition']
|
||||
2025-08-09 13:01:19,604 - INFO - 缓存未命中,开始实时搜索: HediffDef-Malnutrition
|
||||
2025-08-09 13:01:21,133 - INFO - 找到 20 个候选文件,开始向量化处理...
|
||||
2025-08-09 13:01:28,002 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-09 13:02:58,802 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 13:02:58,803 - INFO - 收到问题: HediffDef named Luciferium
|
||||
2025-08-09 13:02:58,803 - INFO - 找到的潜在关键词: ['HediffDef', 'Luciferium']
|
||||
2025-08-09 13:02:58,803 - INFO - 提取到关键词: ['HediffDef', 'Luciferium']
|
||||
2025-08-09 13:02:58,803 - INFO - 缓存未命中,开始实时搜索: HediffDef-Luciferium
|
||||
2025-08-09 13:03:00,318 - INFO - 找到 29 个候选文件,开始向量化处理...
|
||||
2025-08-09 13:03:00,318 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\Core\Languages\ChineseSimplified (简体中文)\DefInjected\NeedDef\Luciferium.xml
|
||||
2025-08-09 13:03:00,318 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\Drugs\Luciferium.xml
|
||||
2025-08-09 13:03:00,318 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\Core\Languages\ChineseSimplified (简体中文)\DefInjected\ChemicalDef\Luciferium.xml
|
||||
2025-08-09 13:03:00,318 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\Core\Languages\ChineseSimplified (简体中文)\DefInjected\ThingDef\Luciferium.xml
|
||||
2025-08-09 13:03:00,318 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\Core\Languages\ChineseSimplified (简体中文)\DefInjected\HediffDef\Luciferium.xml
|
||||
2025-08-09 13:03:12,903 - INFO - 向量搜索完成。找到了 1 个匹配项并成功提取了代码。
|
||||
2025-08-09 13:33:10,729 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 13:33:10,729 - INFO - 收到问题: ThingDef for Wula race
|
||||
2025-08-09 13:33:10,729 - INFO - 找到的潜在关键词: ['Wula', 'ThingDef']
|
||||
2025-08-09 13:33:10,729 - INFO - 提取到关键词: ['Wula', 'ThingDef']
|
||||
2025-08-09 13:33:10,729 - INFO - 缓存未命中,开始实时搜索: ThingDef-Wula
|
||||
2025-08-09 13:33:12,622 - INFO - 找到 2044 个候选文件,开始向量化处理...
|
||||
2025-08-09 13:33:12,628 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\ThingDef.txt
|
||||
2025-08-09 13:33:12,629 - WARNING - 候选文件过多 (2043),仅处理前 25 个。
|
||||
2025-08-09 13:34:54,603 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 13:34:54,603 - INFO - 收到问题: LifeStageDef for HumanlikeAdult
|
||||
2025-08-09 13:34:54,603 - INFO - 找到的潜在关键词: ['LifeStageDef', 'HumanlikeAdult']
|
||||
2025-08-09 13:34:54,603 - INFO - 提取到关键词: ['LifeStageDef', 'HumanlikeAdult']
|
||||
2025-08-09 13:34:54,603 - INFO - 缓存未命中,开始实时搜索: HumanlikeAdult-LifeStageDef
|
||||
2025-08-09 13:34:56,048 - INFO - 找到 6 个候选文件,开始向量化处理...
|
||||
2025-08-09 13:34:58,422 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-09 13:35:56,165 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 13:35:56,165 - INFO - 收到问题: source code for ColonistBarColonistDrawer.DrawIcons
|
||||
2025-08-09 13:35:56,165 - INFO - 找到的潜在关键词: ['DrawIcons', 'ColonistBarColonistDrawer']
|
||||
2025-08-09 13:35:56,165 - INFO - 提取到关键词: ['DrawIcons', 'ColonistBarColonistDrawer']
|
||||
2025-08-09 13:35:56,165 - INFO - 缓存未命中,开始实时搜索: ColonistBarColonistDrawer-DrawIcons
|
||||
2025-08-09 13:35:57,819 - INFO - 找到 2 个候选文件,开始向量化处理...
|
||||
2025-08-09 13:35:57,820 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\ColonistBarColonistDrawer.txt
|
||||
2025-08-09 13:35:58,503 - INFO - 向量搜索完成。找到了 1 个匹配项并成功提取了代码。
|
||||
2025-08-09 19:13:46,499 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 19:13:46,501 - INFO - 收到问题: PawnKindDef lifeStages
|
||||
2025-08-09 19:13:46,502 - INFO - 找到的潜在关键词: ['PawnKindDef', 'lifeStages']
|
||||
2025-08-09 19:13:46,502 - INFO - 提取到关键词: ['PawnKindDef', 'lifeStages']
|
||||
2025-08-09 19:13:46,502 - INFO - 缓存未命中,开始实时搜索: PawnKindDef-lifeStages
|
||||
2025-08-09 19:14:57,492 - INFO - 找到 314 个候选文件,开始向量化处理...
|
||||
2025-08-09 19:14:57,492 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\PawnKindDef.txt
|
||||
2025-08-09 19:14:57,493 - WARNING - 候选文件过多 (313),仅处理前 25 个。
|
||||
2025-08-09 19:15:07,385 - INFO - 向量搜索完成。找到了 1 个匹配项并成功提取了代码。
|
||||
2025-08-09 19:15:07,406 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 19:15:07,407 - INFO - 收到问题: PawnKindDef lifeStages
|
||||
2025-08-09 19:15:07,407 - INFO - 找到的潜在关键词: ['PawnKindDef', 'lifeStages']
|
||||
2025-08-09 19:15:07,407 - INFO - 提取到关键词: ['PawnKindDef', 'lifeStages']
|
||||
2025-08-09 19:15:07,415 - INFO - 缓存命中: 关键词 'PawnKindDef-lifeStages'
|
||||
2025-08-09 19:22:06,405 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 19:22:06,405 - INFO - 收到问题: CompProperties_Refuelable
|
||||
2025-08-09 19:22:06,405 - INFO - 找到的潜在关键词: ['CompProperties_Refuelable']
|
||||
2025-08-09 19:22:06,405 - INFO - 提取到关键词: ['CompProperties_Refuelable']
|
||||
2025-08-09 19:22:06,405 - INFO - 缓存未命中,开始实时搜索: CompProperties_Refuelable
|
||||
2025-08-09 19:22:08,376 - INFO - 找到 18 个候选文件,开始向量化处理...
|
||||
2025-08-09 19:22:08,376 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_Refuelable.txt
|
||||
2025-08-09 19:22:17,721 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-09 19:24:09,129 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 19:24:09,129 - INFO - 收到问题: CompProperties_Refuelable
|
||||
2025-08-09 19:24:09,129 - INFO - 找到的潜在关键词: ['CompProperties_Refuelable']
|
||||
2025-08-09 19:24:09,129 - INFO - 提取到关键词: ['CompProperties_Refuelable']
|
||||
2025-08-09 19:24:09,148 - INFO - 缓存命中: 关键词 'CompProperties_Refuelable'
|
||||
2025-08-09 20:37:05,246 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 20:37:05,247 - INFO - 收到问题: WorkGiver_Scanner class definition, especially methods for float menu options
|
||||
2025-08-09 20:37:05,248 - INFO - 找到的潜在关键词: ['WorkGiver_Scanner']
|
||||
2025-08-09 20:37:05,248 - INFO - 提取到关键词: ['WorkGiver_Scanner']
|
||||
2025-08-09 20:37:05,248 - INFO - 缓存未命中,开始实时搜索: WorkGiver_Scanner
|
||||
2025-08-09 20:37:15,713 - INFO - 找到 83 个候选文件,开始向量化处理...
|
||||
2025-08-09 20:37:15,714 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_Scanner.txt
|
||||
2025-08-09 20:37:15,714 - WARNING - 候选文件过多 (82),仅处理前 25 个。
|
||||
2025-08-09 20:37:21,549 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-09 21:04:45,693 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 21:04:45,712 - INFO - 收到问题: TargetingParameters.ForRescue
|
||||
2025-08-09 21:04:45,712 - INFO - 找到的潜在关键词: ['TargetingParameters', 'ForRescue']
|
||||
2025-08-09 21:04:45,712 - INFO - 提取到关键词: ['TargetingParameters', 'ForRescue']
|
||||
2025-08-09 21:04:45,746 - INFO - 缓存未命中,开始实时搜索: ForRescue-TargetingParameters
|
||||
2025-08-09 21:05:06,716 - INFO - 找到 55 个候选文件,开始向量化处理...
|
||||
2025-08-09 21:05:06,717 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\TargetingParameters.txt
|
||||
2025-08-09 21:05:06,732 - WARNING - 候选文件过多 (54),仅处理前 25 个。
|
||||
2025-08-09 21:05:34,758 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 21:05:34,758 - INFO - 收到问题: FloatMenuMakerMap AddHumanlikeOrders
|
||||
2025-08-09 21:05:34,758 - INFO - 找到的潜在关键词: ['AddHumanlikeOrders', 'FloatMenuMakerMap']
|
||||
2025-08-09 21:05:34,758 - INFO - 提取到关键词: ['AddHumanlikeOrders', 'FloatMenuMakerMap']
|
||||
2025-08-09 21:05:34,758 - INFO - 缓存未命中,开始实时搜索: AddHumanlikeOrders-FloatMenuMakerMap
|
||||
2025-08-09 21:05:36,675 - INFO - 使用最具体的关键词 'AddHumanlikeOrders' 未找到文件,尝试所有关键词...
|
||||
2025-08-09 21:05:38,735 - INFO - 找到 9 个候选文件,开始向量化处理...
|
||||
2025-08-09 21:05:38,735 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\FloatMenuMakerMap.txt
|
||||
2025-08-09 21:05:41,806 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-09 22:01:45,270 - INFO - 成功加载 DASHSCOPE_API_KEY。
|
||||
2025-08-09 22:01:45,281 - INFO - RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...
|
||||
2025-08-09 22:01:45,293 - INFO - Processing request of type ListToolsRequest
|
||||
2025-08-09 22:01:45,294 - INFO - Processing request of type ListResourcesRequest
|
||||
2025-08-09 22:01:45,295 - INFO - Processing request of type ListResourceTemplatesRequest
|
||||
2025-08-09 22:36:40,663 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 22:36:40,664 - INFO - 收到问题: Source code for the Toil Toils_Haul.StartCarryThing
|
||||
2025-08-09 22:36:40,664 - INFO - 找到的潜在关键词: ['Source', 'Toils_Haul', 'StartCarryThing', 'Toil']
|
||||
2025-08-09 22:36:40,664 - INFO - 提取到关键词: ['Source', 'Toils_Haul', 'StartCarryThing', 'Toil']
|
||||
2025-08-09 22:36:40,664 - INFO - 缓存未命中,开始实时搜索: Source-StartCarryThing-Toil-Toils_Haul
|
||||
2025-08-09 22:36:42,122 - INFO - 找到 58 个候选文件,开始向量化处理...
|
||||
2025-08-09 22:36:42,122 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI\Toils_Haul.txt
|
||||
2025-08-09 22:36:42,123 - WARNING - 候选文件过多 (57),仅处理前 25 个。
|
||||
2025-08-09 22:36:49,931 - INFO - 向量搜索完成。找到了 5 个匹配项并成功提取了代码。
|
||||
2025-08-09 22:37:26,949 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 22:37:26,950 - INFO - 收到问题: ThingDef for the Human race
|
||||
2025-08-09 22:37:26,950 - INFO - 找到的潜在关键词: ['Human', 'ThingDef']
|
||||
2025-08-09 22:37:26,950 - INFO - 提取到关键词: ['Human', 'ThingDef']
|
||||
2025-08-09 22:37:26,950 - INFO - 缓存未命中,开始实时搜索: Human-ThingDef
|
||||
2025-08-09 22:37:28,442 - INFO - 找到 2044 个候选文件,开始向量化处理...
|
||||
2025-08-09 22:37:28,444 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\ThingDef.txt
|
||||
2025-08-09 22:37:28,449 - WARNING - 候选文件过多 (2043),仅处理前 25 个。
|
||||
2025-08-09 22:37:37,558 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-09 22:51:16,961 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 22:51:16,961 - INFO - 收到问题: WorkGiver_HaulToMaintenancePod
|
||||
2025-08-09 22:51:16,961 - INFO - 找到的潜在关键词: ['WorkGiver_HaulToMaintenancePod']
|
||||
2025-08-09 22:51:16,961 - INFO - 提取到关键词: ['WorkGiver_HaulToMaintenancePod']
|
||||
2025-08-09 22:51:16,961 - INFO - 缓存未命中,开始实时搜索: WorkGiver_HaulToMaintenancePod
|
||||
2025-08-09 22:51:18,339 - INFO - 未找到与 '['WorkGiver_HaulToMaintenancePod']' 相关的文件。
|
||||
2025-08-09 23:24:17,104 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 23:24:17,104 - INFO - 收到问题: WorkGiver_HaulToBiosculpterPod, CompBiosculpterPod
|
||||
2025-08-09 23:24:17,104 - INFO - 找到的潜在关键词: ['WorkGiver_HaulToBiosculpterPod', 'CompBiosculpterPod']
|
||||
2025-08-09 23:24:17,104 - INFO - 提取到关键词: ['WorkGiver_HaulToBiosculpterPod', 'CompBiosculpterPod']
|
||||
2025-08-09 23:24:17,104 - INFO - 缓存未命中,开始实时搜索: CompBiosculpterPod-WorkGiver_HaulToBiosculpterPod
|
||||
2025-08-09 23:24:18,974 - INFO - 找到 2 个候选文件,开始向量化处理...
|
||||
2025-08-09 23:24:18,974 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_HaulToBiosculpterPod.txt
|
||||
2025-08-09 23:24:19,422 - INFO - 向量搜索完成。找到了 1 个匹配项并成功提取了代码。
|
||||
2025-08-09 23:30:21,294 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 23:30:21,294 - INFO - 收到问题: JobDefOf.Rescue, JobDriver_TakeToBed
|
||||
2025-08-09 23:30:21,294 - INFO - 找到的潜在关键词: ['JobDriver_TakeToBed', 'Rescue', 'JobDefOf']
|
||||
2025-08-09 23:30:21,294 - INFO - 提取到关键词: ['JobDriver_TakeToBed', 'Rescue', 'JobDefOf']
|
||||
2025-08-09 23:30:21,294 - INFO - 缓存未命中,开始实时搜索: JobDefOf-JobDriver_TakeToBed-Rescue
|
||||
2025-08-09 23:30:22,675 - INFO - 找到 4 个候选文件,开始向量化处理...
|
||||
2025-08-09 23:30:22,675 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_TakeToBed.txt
|
||||
2025-08-09 23:30:24,295 - INFO - 向量搜索完成。找到了 3 个匹配项并成功提取了代码。
|
||||
2025-08-09 23:31:46,828 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 23:31:46,828 - INFO - 收到问题: ThingDef of BiosculpterPod
|
||||
2025-08-09 23:31:46,828 - INFO - 找到的潜在关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-09 23:31:46,829 - INFO - 提取到关键词: ['BiosculpterPod', 'ThingDef']
|
||||
2025-08-09 23:31:46,845 - INFO - 缓存命中: 关键词 'BiosculpterPod-ThingDef'
|
||||
2025-08-09 23:32:57,437 - INFO - Processing request of type CallToolRequest
|
||||
2025-08-09 23:32:57,437 - INFO - 收到问题: JobDefOf.CarryToBiosculpterPod, JobDriver_CarryToBiosculpterPod
|
||||
2025-08-09 23:32:57,437 - INFO - 找到的潜在关键词: ['JobDriver_CarryToBiosculpterPod', 'JobDefOf', 'CarryToBiosculpterPod']
|
||||
2025-08-09 23:32:57,437 - INFO - 提取到关键词: ['JobDriver_CarryToBiosculpterPod', 'JobDefOf', 'CarryToBiosculpterPod']
|
||||
2025-08-09 23:32:57,437 - INFO - 缓存未命中,开始实时搜索: CarryToBiosculpterPod-JobDefOf-JobDriver_CarryToBiosculpterPod
|
||||
2025-08-09 23:32:58,909 - INFO - 找到 3 个候选文件,开始向量化处理...
|
||||
2025-08-09 23:32:58,910 - INFO - 文件名精确匹配: C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_CarryToBiosculpterPod.txt
|
||||
2025-08-09 23:32:59,792 - INFO - 向量搜索完成。找到了 1 个匹配项并成功提取了代码。
|
||||
441
MCP/mcpserver_stdio.py
Normal file
441
MCP/mcpserver_stdio.py
Normal file
@@ -0,0 +1,441 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import json
|
||||
import re
|
||||
|
||||
# 1. --- 导入库 ---
|
||||
# mcp 库已通过 'pip install -e' 安装,无需修改 sys.path
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
# 新增:阿里云模型服务和向量计算库
|
||||
import dashscope
|
||||
from dashscope.api_entities.dashscope_response import Role
|
||||
from tenacity import retry, stop_after_attempt, wait_random_exponential
|
||||
from sklearn.metrics.pairwise import cosine_similarity
|
||||
import numpy as np
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 2. --- 日志、缓存和知识库配置 ---
|
||||
MCP_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
LOG_FILE_PATH = os.path.join(MCP_DIR, 'mcpserver.log')
|
||||
CACHE_DIR = os.path.join(MCP_DIR, 'vector_cache')
|
||||
CACHE_FILE_PATH = os.path.join(CACHE_DIR, 'knowledge_cache.json')
|
||||
os.makedirs(CACHE_DIR, exist_ok=True)
|
||||
|
||||
logging.basicConfig(filename=LOG_FILE_PATH, level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
encoding='utf-8')
|
||||
|
||||
# 新增: 加载 .env 文件并设置 API Key
|
||||
# 指定 .env 文件的确切路径,以确保脚本在任何工作目录下都能正确加载
|
||||
env_path = os.path.join(MCP_DIR, '.env')
|
||||
load_dotenv(dotenv_path=env_path)
|
||||
|
||||
dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")
|
||||
|
||||
if not dashscope.api_key:
|
||||
logging.error("错误:未在 .env 文件中找到或加载 DASHSCOPE_API_KEY。")
|
||||
# 如果没有Key,服务器无法工作,可以选择退出或继续运行但功能受限
|
||||
# sys.exit("错误:API Key 未配置。")
|
||||
else:
|
||||
logging.info("成功加载 DASHSCOPE_API_KEY。")
|
||||
|
||||
# 定义知识库路径
|
||||
KNOWLEDGE_BASE_PATHS = [
|
||||
r"C:\Steam\steamapps\common\RimWorld\Data"
|
||||
]
|
||||
|
||||
# 3. --- 缓存管理 (分文件存储) ---
|
||||
def load_cache_for_keyword(keyword: str):
|
||||
"""为指定关键词加载缓存文件。"""
|
||||
# 清理关键词,使其适合作为文件名
|
||||
safe_filename = "".join(c for c in keyword if c.isalnum() or c in ('_', '-')).rstrip()
|
||||
cache_file = os.path.join(CACHE_DIR, f"{safe_filename}.txt")
|
||||
|
||||
if os.path.exists(cache_file):
|
||||
try:
|
||||
with open(cache_file, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
except IOError as e:
|
||||
logging.error(f"读取缓存文件 {cache_file} 失败: {e}")
|
||||
return None
|
||||
return None
|
||||
|
||||
def save_cache_for_keyword(keyword: str, data: str):
|
||||
"""为指定关键词保存缓存到单独的文件。"""
|
||||
safe_filename = "".join(c for c in keyword if c.isalnum() or c in ('_', '-')).rstrip()
|
||||
cache_file = os.path.join(CACHE_DIR, f"{safe_filename}.txt")
|
||||
|
||||
try:
|
||||
with open(cache_file, 'w', encoding='utf-8') as f:
|
||||
f.write(data)
|
||||
except IOError as e:
|
||||
logging.error(f"写入缓存文件 {cache_file} 失败: {e}")
|
||||
|
||||
# 4. --- 向量化与相似度计算 ---
|
||||
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
|
||||
def get_embedding(text: str):
|
||||
"""获取文本的向量嵌入"""
|
||||
try:
|
||||
# 根据用户文档,选用v4模型,更适合代码和文本
|
||||
response = dashscope.TextEmbedding.call(
|
||||
model='text-embedding-v4',
|
||||
input=text
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return response.output['embeddings'][0]['embedding']
|
||||
else:
|
||||
logging.error(f"获取向量失败: {response.message}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.error(f"调用向量API时出错: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
def find_most_similar_files(question_embedding, file_embeddings, top_n=3, min_similarity=0.5):
|
||||
"""在文件向量中找到与问题向量最相似的 top_n 个文件。"""
|
||||
if not question_embedding or not file_embeddings:
|
||||
return []
|
||||
|
||||
file_vectors = np.array([emb['embedding'] for emb in file_embeddings])
|
||||
question_vector = np.array(question_embedding).reshape(1, -1)
|
||||
|
||||
similarities = cosine_similarity(question_vector, file_vectors)[0]
|
||||
|
||||
# 获取排序后的索引
|
||||
sorted_indices = np.argsort(similarities)[::-1]
|
||||
|
||||
# 筛选出最相关的结果
|
||||
results = []
|
||||
for i in sorted_indices:
|
||||
similarity_score = similarities[i]
|
||||
if similarity_score >= min_similarity and len(results) < top_n:
|
||||
results.append({
|
||||
'path': file_embeddings[i]['path'],
|
||||
'similarity': similarity_score
|
||||
})
|
||||
else:
|
||||
break
|
||||
|
||||
return results
|
||||
|
||||
def extract_relevant_code(file_path, keyword):
|
||||
"""从文件中智能提取包含关键词的完整代码块 (C#类 或 XML Def)。"""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
lines = content.split('\n')
|
||||
keyword_lower = keyword.lower()
|
||||
|
||||
found_line_index = -1
|
||||
for i, line in enumerate(lines):
|
||||
if keyword_lower in line.lower():
|
||||
found_line_index = i
|
||||
break
|
||||
|
||||
if found_line_index == -1:
|
||||
return ""
|
||||
|
||||
# 根据文件类型选择提取策略
|
||||
if file_path.endswith(('.cs', '.txt')):
|
||||
# C# 提取策略:寻找完整的类
|
||||
return extract_csharp_class(lines, found_line_index)
|
||||
elif file_path.endswith('.xml'):
|
||||
# XML 提取策略:寻找完整的 Def
|
||||
return extract_xml_def(lines, found_line_index)
|
||||
else:
|
||||
return "" # 不支持的文件类型
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"提取代码时出错 {file_path}: {e}")
|
||||
return f"# Error reading file: {e}"
|
||||
|
||||
def extract_csharp_class(lines, start_index):
|
||||
"""从C#代码行中提取完整的类定义。"""
|
||||
# 向上找到 class 声明
|
||||
class_start_index = -1
|
||||
brace_level_at_class_start = -1
|
||||
for i in range(start_index, -1, -1):
|
||||
line = lines[i]
|
||||
if 'class ' in line:
|
||||
class_start_index = i
|
||||
brace_level_at_class_start = line.count('{') - line.count('}')
|
||||
break
|
||||
|
||||
if class_start_index == -1: return "" # 没找到类
|
||||
|
||||
# 从 class 声明开始,向下找到匹配的 '}'
|
||||
brace_count = brace_level_at_class_start
|
||||
class_end_index = -1
|
||||
for i in range(class_start_index + 1, len(lines)):
|
||||
line = lines[i]
|
||||
brace_count += line.count('{')
|
||||
brace_count -= line.count('}')
|
||||
if brace_count <= 0: # 找到匹配的闭合括号
|
||||
class_end_index = i
|
||||
break
|
||||
|
||||
if class_end_index != -1:
|
||||
return "\n".join(lines[class_start_index:class_end_index+1])
|
||||
return "" # 未找到完整的类块
|
||||
|
||||
def extract_xml_def(lines, start_index):
|
||||
"""从XML行中提取完整的Def块。"""
|
||||
import re
|
||||
# 向上找到 <DefName> 或 <defName>
|
||||
def_start_index = -1
|
||||
def_tag = ""
|
||||
for i in range(start_index, -1, -1):
|
||||
line = lines[i].strip()
|
||||
match = re.match(r'<(\w+)\s+.*>', line) or re.match(r'<(\w+)>', line)
|
||||
if match and ('Def' in match.group(1) or 'def' in match.group(1)):
|
||||
# 这是一个简化的判断,实际中可能需要更复杂的逻辑
|
||||
def_start_index = i
|
||||
def_tag = match.group(1)
|
||||
break
|
||||
|
||||
if def_start_index == -1: return ""
|
||||
|
||||
# 向下找到匹配的 </DefName>
|
||||
def_end_index = -1
|
||||
for i in range(def_start_index + 1, len(lines)):
|
||||
if f'</{def_tag}>' in lines[i]:
|
||||
def_end_index = i
|
||||
break
|
||||
|
||||
if def_end_index != -1:
|
||||
return "\n".join(lines[def_start_index:def_end_index+1])
|
||||
return ""
|
||||
|
||||
# 5. --- 核心功能函数 ---
|
||||
def find_files_with_keyword(roots, keywords: list[str], extensions=['.xml', '.cs', '.txt']):
|
||||
"""在指定目录中查找包含任何一个关键字的文件。"""
|
||||
found_files = set()
|
||||
keywords_lower = [k.lower() for k in keywords]
|
||||
for root_path in roots:
|
||||
if not os.path.isdir(root_path):
|
||||
logging.warning(f"知识库路径不存在或不是一个目录: {root_path}")
|
||||
continue
|
||||
for dirpath, _, filenames in os.walk(root_path):
|
||||
for filename in filenames:
|
||||
if any(filename.lower().endswith(ext) for ext in extensions):
|
||||
file_path = os.path.join(dirpath, filename)
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content_lower = f.read().lower()
|
||||
# 如果任何一个关键词在内容中,就添加文件
|
||||
if any(kw in content_lower for kw in keywords_lower):
|
||||
found_files.add(file_path)
|
||||
except Exception as e:
|
||||
logging.error(f"读取文件时出错 {file_path}: {e}")
|
||||
return list(found_files)
|
||||
|
||||
def find_keywords_in_question(question: str) -> list[str]:
|
||||
"""从问题中提取所有可能的关键词 (类型名, defName等)。"""
|
||||
# 正则表达式优先,用于精确匹配定义
|
||||
# 匹配 C# class, struct, enum, interface 定义, 例如 "public class MyClass : Base"
|
||||
csharp_def_pattern = re.compile(r'\b(?:public|private|internal|protected|sealed|abstract|static|new)\s+(?:class|struct|enum|interface)\s+([A-Za-z_][A-Za-z0-9_]*)')
|
||||
# 匹配 XML Def, 例如 "<ThingDef Name="MyDef">" or "<MyCustomDef>"
|
||||
xml_def_pattern = re.compile(r'<([A-Za-z_][A-Za-z0-9_]*Def)\b')
|
||||
|
||||
# 启发式规则,用于匹配独立的关键词
|
||||
# 规则1: 包含下划线 (很可能是 defName)
|
||||
# 规则2: 混合大小写 (很可能是 C# 类型名)
|
||||
# 规则3: 多个大写字母(例如 CompPsychicScaling,但要排除纯大写缩写词)
|
||||
|
||||
# 排除常见但非特定的术语
|
||||
excluded_keywords = {"XML", "C#", "DEF", "CS", "CLASS", "PUBLIC"}
|
||||
|
||||
found_keywords = set()
|
||||
|
||||
# 1. 正则匹配
|
||||
csharp_matches = csharp_def_pattern.findall(question)
|
||||
xml_matches = xml_def_pattern.findall(question)
|
||||
|
||||
for match in csharp_matches:
|
||||
found_keywords.add(match)
|
||||
for match in xml_matches:
|
||||
found_keywords.add(match)
|
||||
|
||||
# 2. 启发式单词匹配
|
||||
parts = re.split(r'[\s,.:;\'"`()<>]+', question)
|
||||
|
||||
for part in parts:
|
||||
if not part or part.upper() in excluded_keywords:
|
||||
continue
|
||||
|
||||
# 规则1: 包含下划线
|
||||
if '_' in part:
|
||||
found_keywords.add(part)
|
||||
# 规则2: 驼峰命名或混合大小写
|
||||
elif any(c.islower() for c in part) and any(c.isupper() for c in part) and len(part) > 3:
|
||||
found_keywords.add(part)
|
||||
# 规则3: 多个大写字母
|
||||
elif sum(1 for c in part if c.isupper()) > 1 and not part.isupper():
|
||||
found_keywords.add(part)
|
||||
# 备用规则: 大写字母开头且较长
|
||||
elif part[0].isupper() and len(part) > 4:
|
||||
found_keywords.add(part)
|
||||
|
||||
if not found_keywords:
|
||||
logging.warning(f"在 '{question}' 中未找到合适的关键词。")
|
||||
return []
|
||||
|
||||
logging.info(f"找到的潜在关键词: {list(found_keywords)}")
|
||||
return list(found_keywords)
|
||||
|
||||
|
||||
# 5. --- 创建和配置 MCP 服务器 ---
|
||||
# 使用 FastMCP 创建服务器实例
|
||||
mcp = FastMCP(
|
||||
"rimworld-knowledge-base",
|
||||
"1.0.0-fastmcp",
|
||||
)
|
||||
|
||||
@mcp.tool()
|
||||
def get_context(question: str) -> str:
|
||||
"""
|
||||
根据问题中的关键词和向量相似度,在RimWorld知识库中搜索最相关的多个代码片段,
|
||||
并将其整合后返回。
|
||||
"""
|
||||
logging.info(f"收到问题: {question}")
|
||||
keywords = find_keywords_in_question(question)
|
||||
if not keywords:
|
||||
logging.warning("无法从问题中提取关键词。")
|
||||
return "无法从问题中提取关键词,请提供更具体的信息。"
|
||||
|
||||
logging.info(f"提取到关键词: {keywords}")
|
||||
|
||||
# 基于所有关键词创建缓存键
|
||||
cache_key = "-".join(sorted(keywords))
|
||||
|
||||
# 1. 检查缓存
|
||||
cached_result = load_cache_for_keyword(cache_key)
|
||||
if cached_result:
|
||||
logging.info(f"缓存命中: 关键词 '{cache_key}'")
|
||||
return cached_result
|
||||
|
||||
logging.info(f"缓存未命中,开始实时搜索: {cache_key}")
|
||||
|
||||
# 2. 关键词文件搜索 (分层智能筛选)
|
||||
try:
|
||||
# 优先使用最长的(通常最具体)的关键词进行搜索
|
||||
specific_keywords = sorted(keywords, key=len, reverse=True)
|
||||
candidate_files = find_files_with_keyword(KNOWLEDGE_BASE_PATHS, [specific_keywords[0]])
|
||||
|
||||
# 如果最具体的关键词找不到文件,再尝试所有关键词
|
||||
if not candidate_files and len(keywords) > 1:
|
||||
logging.info(f"使用最具体的关键词 '{specific_keywords[0]}' 未找到文件,尝试所有关键词...")
|
||||
candidate_files = find_files_with_keyword(KNOWLEDGE_BASE_PATHS, keywords)
|
||||
|
||||
if not candidate_files:
|
||||
logging.info(f"未找到与 '{keywords}' 相关的文件。")
|
||||
return f"未在知识库中找到与 '{keywords}' 相关的文件定义。"
|
||||
|
||||
logging.info(f"找到 {len(candidate_files)} 个候选文件,开始向量化处理...")
|
||||
|
||||
# 新增:文件名精确匹配优先
|
||||
priority_results = []
|
||||
remaining_files = []
|
||||
for file_path in candidate_files:
|
||||
filename_no_ext = os.path.splitext(os.path.basename(file_path))[0]
|
||||
is_priority = False
|
||||
for keyword in keywords:
|
||||
if filename_no_ext.lower() == keyword.lower():
|
||||
logging.info(f"文件名精确匹配: {file_path}")
|
||||
code_block = extract_relevant_code(file_path, keyword)
|
||||
if code_block:
|
||||
lang = "csharp" if file_path.endswith(('.cs', '.txt')) else "xml"
|
||||
priority_results.append(
|
||||
f"---\n"
|
||||
f"**文件路径 (精确匹配):** `{file_path}`\n\n"
|
||||
f"```{lang}\n"
|
||||
f"{code_block}\n"
|
||||
f"```"
|
||||
)
|
||||
is_priority = True
|
||||
break # 已处理该文件,跳出内层循环
|
||||
if not is_priority:
|
||||
remaining_files.append(file_path)
|
||||
|
||||
candidate_files = remaining_files # 更新候选文件列表,排除已优先处理的文件
|
||||
|
||||
# 3. 向量化和相似度计算 (精准筛选)
|
||||
# 增加超时保护:限制向量化的文件数量
|
||||
MAX_FILES_TO_VECTORIZE = 25
|
||||
if len(candidate_files) > MAX_FILES_TO_VECTORIZE:
|
||||
logging.warning(f"候选文件过多 ({len(candidate_files)}),仅处理前 {MAX_FILES_TO_VECTORIZE} 个。")
|
||||
candidate_files = candidate_files[:MAX_FILES_TO_VECTORIZE]
|
||||
|
||||
question_embedding = get_embedding(question)
|
||||
if not question_embedding:
|
||||
return "无法生成问题向量,请检查API连接或问题内容。"
|
||||
|
||||
file_embeddings = []
|
||||
for file_path in candidate_files:
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
file_embedding = get_embedding(content[:8000]) # 限制内容长度以提高效率
|
||||
if file_embedding:
|
||||
file_embeddings.append({'path': file_path, 'embedding': file_embedding})
|
||||
except Exception as e:
|
||||
logging.error(f"处理文件 {file_path} 时出错: {e}")
|
||||
|
||||
if not file_embeddings:
|
||||
return "无法为任何候选文件生成向量。"
|
||||
|
||||
# 找到最相似的多个文件
|
||||
best_matches = find_most_similar_files(question_embedding, file_embeddings, top_n=5) # 增加返回数量
|
||||
|
||||
if not best_matches:
|
||||
return "计算向量相似度失败或没有找到足够相似的文件。"
|
||||
|
||||
# 4. 提取代码并格式化输出
|
||||
output_parts = [f"根据向量相似度分析,与 '{', '.join(keywords)}' 最相关的代码定义如下:\n"]
|
||||
output_parts.extend(priority_results) # 将优先结果放在最前面
|
||||
|
||||
extracted_blocks = set() # 用于防止重复提取相同的代码块
|
||||
|
||||
for match in best_matches:
|
||||
file_path = match['path']
|
||||
similarity = match['similarity']
|
||||
|
||||
# 对每个关键词都尝试提取代码
|
||||
for keyword in keywords:
|
||||
code_block = extract_relevant_code(file_path, keyword)
|
||||
|
||||
if code_block and code_block not in extracted_blocks:
|
||||
extracted_blocks.add(code_block)
|
||||
lang = "csharp" if file_path.endswith(('.cs', '.txt')) else "xml"
|
||||
output_parts.append(
|
||||
f"---\n"
|
||||
f"**文件路径:** `{file_path}`\n"
|
||||
f"**相似度:** {similarity:.4f}\n\n"
|
||||
f"```{lang}\n"
|
||||
f"{code_block}\n"
|
||||
f"```"
|
||||
)
|
||||
|
||||
if len(output_parts) <= 1:
|
||||
return f"虽然找到了相似的文件,但无法在其中提取到关于 '{', '.join(keywords)}' 的完整代码块。"
|
||||
|
||||
final_output = "\n".join(output_parts)
|
||||
|
||||
# 5. 更新缓存并返回结果
|
||||
logging.info(f"向量搜索完成。找到了 {len(best_matches)} 个匹配项并成功提取了代码。")
|
||||
save_cache_for_keyword(cache_key, final_output)
|
||||
|
||||
return final_output
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"处理请求时发生意外错误: {e}", exc_info=True)
|
||||
return f"处理您的请求时发生错误: {e}"
|
||||
|
||||
# 6. --- 启动服务器 ---
|
||||
# FastMCP 实例可以直接运行
|
||||
if __name__ == "__main__":
|
||||
logging.info("RimWorld 向量知识库 (FastMCP版, v2.1-v4-model) 正在启动...")
|
||||
# 使用 'stdio' 传输协议
|
||||
mcp.run(transport="stdio")
|
||||
1
MCP/pid.txt
Normal file
1
MCP/pid.txt
Normal file
@@ -0,0 +1 @@
|
||||
86696
|
||||
621
MCP/vector_cache/AbilityDef.txt
Normal file
621
MCP/vector_cache/AbilityDef.txt
Normal file
@@ -0,0 +1,621 @@
|
||||
根据向量相似度分析,与 'AbilityDef' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\AbilityDef.txt`
|
||||
|
||||
```csharp
|
||||
public class AbilityDef : Def
|
||||
{
|
||||
public Type abilityClass = typeof(Ability);
|
||||
|
||||
public Type gizmoClass = typeof(Command_Ability);
|
||||
|
||||
public List<AbilityCompProperties> comps = new List<AbilityCompProperties>();
|
||||
|
||||
public AbilityCategoryDef category;
|
||||
|
||||
public int displayOrder;
|
||||
|
||||
public List<StatModifier> statBases;
|
||||
|
||||
public VerbProperties verbProperties;
|
||||
|
||||
public KeyBindingDef hotKey;
|
||||
|
||||
public JobDef jobDef;
|
||||
|
||||
public ThingDef warmupMote;
|
||||
|
||||
public EffecterDef warmupEffecter;
|
||||
|
||||
public FleckDef emittedFleck;
|
||||
|
||||
public int emissionInterval;
|
||||
|
||||
public string warmupMoteSocialSymbol;
|
||||
|
||||
public SoundDef warmupStartSound;
|
||||
|
||||
public SoundDef warmupSound;
|
||||
|
||||
public SoundDef warmupPreEndSound;
|
||||
|
||||
public float warmupPreEndSoundSeconds;
|
||||
|
||||
public Vector3 moteDrawOffset;
|
||||
|
||||
public float moteOffsetAmountTowardsTarget;
|
||||
|
||||
public bool canUseAoeToGetTargets = true;
|
||||
|
||||
public bool useAverageTargetPositionForWarmupEffecter;
|
||||
|
||||
public bool targetRequired = true;
|
||||
|
||||
public bool targetWorldCell;
|
||||
|
||||
public bool showGizmoOnWorldView;
|
||||
|
||||
public bool aiCanUse;
|
||||
|
||||
public bool ai_SearchAOEForTargets;
|
||||
|
||||
public bool ai_IsOffensive = true;
|
||||
|
||||
public bool ai_IsIncendiary = true;
|
||||
|
||||
public bool groupAbility;
|
||||
|
||||
public int level;
|
||||
|
||||
public IntRange cooldownTicksRange;
|
||||
|
||||
public bool cooldownPerCharge;
|
||||
|
||||
public bool hasExternallyHandledCooldown;
|
||||
|
||||
public int charges = -1;
|
||||
|
||||
public AbilityGroupDef groupDef;
|
||||
|
||||
public bool overrideGroupCooldown;
|
||||
|
||||
public List<MemeDef> requiredMemes;
|
||||
|
||||
public bool sendLetterOnCooldownComplete;
|
||||
|
||||
public bool sendMessageOnCooldownComplete;
|
||||
|
||||
public bool displayGizmoWhileUndrafted;
|
||||
|
||||
public bool disableGizmoWhileUndrafted = true;
|
||||
|
||||
public bool writeCombatLog;
|
||||
|
||||
public bool stunTargetWhileCasting;
|
||||
|
||||
public bool showPsycastEffects = true;
|
||||
|
||||
public bool showCastingProgressBar;
|
||||
|
||||
public float detectionChanceOverride = -1f;
|
||||
|
||||
public float uiOrder;
|
||||
|
||||
public bool waitForJobEnd;
|
||||
|
||||
public bool showWhenDrafted = true;
|
||||
|
||||
public bool showOnCharacterCard = true;
|
||||
|
||||
public bool hostile = true;
|
||||
|
||||
public bool casterMustBeCapableOfViolence = true;
|
||||
|
||||
[MustTranslate]
|
||||
public string confirmationDialogText;
|
||||
|
||||
[NoTranslate]
|
||||
public string iconPath;
|
||||
|
||||
public Texture2D uiIcon = BaseContent.BadTex;
|
||||
|
||||
private string cachedTooltip;
|
||||
|
||||
private Pawn cachedTooltipPawn;
|
||||
|
||||
private List<string> cachedTargets;
|
||||
|
||||
private int requiredPsyfocusBandCached = -1;
|
||||
|
||||
private bool? anyCompOverridesPsyfocusCost;
|
||||
|
||||
private FloatRange psyfocusCostRange = new FloatRange(-1f, -1f);
|
||||
|
||||
private string psyfocusCostPercent;
|
||||
|
||||
private string psyfocusCostPercentMax;
|
||||
|
||||
private Texture2D warmupMoteSocialSymbolCached;
|
||||
|
||||
public float EntropyGain => statBases.GetStatValueFromList(StatDefOf.Ability_EntropyGain, 0f);
|
||||
|
||||
public float PsyfocusCost => statBases.GetStatValueFromList(StatDefOf.Ability_PsyfocusCost, 0f);
|
||||
|
||||
public float EffectRadius => statBases.GetStatValueFromList(StatDefOf.Ability_EffectRadius, 0f);
|
||||
|
||||
public bool HasAreaOfEffect => EffectRadius > float.Epsilon;
|
||||
|
||||
public float DetectionChance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!(detectionChanceOverride >= 0f))
|
||||
{
|
||||
return this.GetStatValueAbstract(StatDefOf.Ability_DetectChancePerEntropy);
|
||||
}
|
||||
return detectionChanceOverride;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPsycast => typeof(Psycast).IsAssignableFrom(abilityClass);
|
||||
|
||||
public string PsyfocusCostPercent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (psyfocusCostPercent.NullOrEmpty())
|
||||
{
|
||||
psyfocusCostPercent = PsyfocusCost.ToStringPercent();
|
||||
}
|
||||
return psyfocusCostPercent;
|
||||
}
|
||||
}
|
||||
|
||||
public string PsyfocusCostPercentMax
|
||||
{
|
||||
get
|
||||
{
|
||||
if (psyfocusCostPercentMax.NullOrEmpty())
|
||||
{
|
||||
psyfocusCostPercentMax = PsyfocusCostRange.max.ToStringPercent();
|
||||
}
|
||||
return psyfocusCostPercentMax;
|
||||
}
|
||||
}
|
||||
|
||||
public int RequiredPsyfocusBand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (requiredPsyfocusBandCached == -1)
|
||||
{
|
||||
requiredPsyfocusBandCached = Pawn_PsychicEntropyTracker.MaxAbilityLevelPerPsyfocusBand.Count - 1;
|
||||
for (int i = 0; i < Pawn_PsychicEntropyTracker.MaxAbilityLevelPerPsyfocusBand.Count; i++)
|
||||
{
|
||||
int num = Pawn_PsychicEntropyTracker.MaxAbilityLevelPerPsyfocusBand[i];
|
||||
if (level <= num)
|
||||
{
|
||||
requiredPsyfocusBandCached = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return requiredPsyfocusBandCached;
|
||||
}
|
||||
}
|
||||
|
||||
public bool AnyCompOverridesPsyfocusCost
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!anyCompOverridesPsyfocusCost.HasValue)
|
||||
{
|
||||
anyCompOverridesPsyfocusCost = false;
|
||||
if (comps != null)
|
||||
{
|
||||
foreach (AbilityCompProperties comp in comps)
|
||||
{
|
||||
if (comp.OverridesPsyfocusCost)
|
||||
{
|
||||
anyCompOverridesPsyfocusCost = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return anyCompOverridesPsyfocusCost.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public FloatRange PsyfocusCostRange
|
||||
{
|
||||
get
|
||||
{
|
||||
if (psyfocusCostRange.min < 0f)
|
||||
{
|
||||
if (!AnyCompOverridesPsyfocusCost)
|
||||
{
|
||||
psyfocusCostRange = new FloatRange(PsyfocusCost, PsyfocusCost);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (AbilityCompProperties comp in comps)
|
||||
{
|
||||
if (comp.OverridesPsyfocusCost)
|
||||
{
|
||||
psyfocusCostRange = comp.PsyfocusCostRange;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return psyfocusCostRange;
|
||||
}
|
||||
}
|
||||
|
||||
public Texture2D WarmupMoteSocialSymbol
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!warmupMoteSocialSymbol.NullOrEmpty() && warmupMoteSocialSymbolCached == null)
|
||||
{
|
||||
warmupMoteSocialSymbolCached = ContentFinder<Texture2D>.Get(warmupMoteSocialSymbol);
|
||||
}
|
||||
return warmupMoteSocialSymbolCached;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> StatSummary(Pawn forPawn = null)
|
||||
{
|
||||
string text = null;
|
||||
foreach (AbilityCompProperties comp in comps)
|
||||
{
|
||||
if (comp.OverridesPsyfocusCost)
|
||||
{
|
||||
text = comp.PsyfocusCostExplanation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (text == null)
|
||||
{
|
||||
if (PsyfocusCost > float.Epsilon)
|
||||
{
|
||||
yield return "AbilityPsyfocusCost".Translate() + ": " + PsyfocusCost.ToStringPercent();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return text;
|
||||
}
|
||||
if (EntropyGain > float.Epsilon)
|
||||
{
|
||||
yield return string.Concat("AbilityEntropyGain".Translate() + ": ", EntropyGain.ToString());
|
||||
}
|
||||
if (verbProperties.warmupTime > float.Epsilon)
|
||||
{
|
||||
yield return string.Concat("AbilityCastingTime".Translate() + ": ", verbProperties.warmupTime.ToString()) + "LetterSecond".Translate();
|
||||
}
|
||||
if (cooldownTicksRange.min == cooldownTicksRange.max && cooldownTicksRange.min > 0)
|
||||
{
|
||||
yield return "StatsReport_Cooldown".Translate() + ": " + cooldownTicksRange.min.ToStringTicksToPeriod(allowSeconds: true, shortForm: false, canUseDecimals: true, allowYears: false);
|
||||
}
|
||||
float num = EffectDuration(forPawn);
|
||||
if (num > float.Epsilon)
|
||||
{
|
||||
int num2 = num.SecondsToTicks();
|
||||
yield return "AbilityDuration".Translate() + ": " + ((num2 >= 2500) ? num2.ToStringTicksToPeriod() : (num.ToString() + "LetterSecond".Translate()));
|
||||
}
|
||||
if (HasAreaOfEffect)
|
||||
{
|
||||
yield return string.Concat("AbilityEffectRadius".Translate() + ": ", Mathf.Ceil(EffectRadius).ToString());
|
||||
}
|
||||
if (comps == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
for (int i = 0; i < comps.Count; i++)
|
||||
{
|
||||
foreach (string item in comps[i].ExtraStatSummary())
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float EffectDuration(Pawn forPawn = null)
|
||||
{
|
||||
return this.GetStatValueAbstract(StatDefOf.Ability_Duration, forPawn);
|
||||
}
|
||||
|
||||
public override void PostLoad()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(iconPath))
|
||||
{
|
||||
LongEventHandler.ExecuteWhenFinished(delegate
|
||||
{
|
||||
uiIcon = ContentFinder<Texture2D>.Get(iconPath);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string GetTooltip(Pawn pawn = null)
|
||||
{
|
||||
if (cachedTooltip == null || cachedTooltipPawn != pawn)
|
||||
{
|
||||
cachedTooltip = LabelCap.Colorize(ColoredText.TipSectionTitleColor) + ((level > 0) ? string.Concat("\n" + "Level".Translate().CapitalizeFirst() + " ", level.ToString()) : "") + "\n\n" + description;
|
||||
cachedTooltipPawn = pawn;
|
||||
string text = StatSummary(pawn).ToLineList();
|
||||
if (!text.NullOrEmpty())
|
||||
{
|
||||
cachedTooltip = cachedTooltip + "\n\n" + text;
|
||||
}
|
||||
}
|
||||
if (pawn != null && ModsConfig.RoyaltyActive && IsPsycast && level > 0)
|
||||
{
|
||||
Faction first = Faction.GetMinTitleForImplantAllFactions(HediffDefOf.PsychicAmplifier).First;
|
||||
if (first != null)
|
||||
{
|
||||
RoyalTitleDef minTitleForImplant = first.GetMinTitleForImplant(HediffDefOf.PsychicAmplifier, level);
|
||||
RoyalTitleDef currentTitle = pawn.royalty.GetCurrentTitle(first);
|
||||
if (minTitleForImplant != null && (currentTitle == null || currentTitle.seniority < minTitleForImplant.seniority) && DetectionChance > 0f)
|
||||
{
|
||||
return cachedTooltip + "\n\n" + ((string)"PsycastIsIllegal".Translate(pawn.Named("PAWN"), minTitleForImplant.GetLabelCapFor(pawn).Named("TITLE"))).Colorize(ColoredText.WarningColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cachedTooltip;
|
||||
}
|
||||
|
||||
public override IEnumerable<StatDrawEntry> SpecialDisplayStats(StatRequest req)
|
||||
{
|
||||
if (cachedTargets == null)
|
||||
{
|
||||
cachedTargets = new List<string>();
|
||||
if (verbProperties.targetParams.canTargetPawns && verbProperties.targetParams.canTargetSelf)
|
||||
{
|
||||
cachedTargets.Add("TargetSelf".Translate());
|
||||
}
|
||||
if (verbProperties.targetParams.canTargetLocations)
|
||||
{
|
||||
cachedTargets.Add("TargetGround".Translate());
|
||||
}
|
||||
if (verbProperties.targetParams.canTargetPawns && verbProperties.targetParams.canTargetHumans)
|
||||
{
|
||||
cachedTargets.Add("TargetHuman".Translate());
|
||||
}
|
||||
if (verbProperties.targetParams.canTargetPawns && verbProperties.targetParams.canTargetAnimals)
|
||||
{
|
||||
cachedTargets.Add("TargetAnimal".Translate());
|
||||
}
|
||||
}
|
||||
int num = comps.OfType<CompProperties_AbilityEffect>().Sum((CompProperties_AbilityEffect e) => e.goodwillImpact);
|
||||
if (num != 0)
|
||||
{
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Ability, StatDefOf.Ability_GoodwillImpact, num, req);
|
||||
}
|
||||
if (IsPsycast && level != 0)
|
||||
{
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Ability, StatDefOf.Ability_RequiredPsylink, level, req);
|
||||
}
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Ability, StatDefOf.Ability_CastingTime, verbProperties.warmupTime, req);
|
||||
if (verbProperties.range > 0f)
|
||||
{
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Ability, StatDefOf.Ability_Range, verbProperties.range, req);
|
||||
}
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Ability, "Target".Translate(), cachedTargets.ToCommaList().CapitalizeFirst(), "AbilityTargetDesc".Translate(), 1001);
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Ability, "AbilityRequiresLOS".Translate(), verbProperties.requireLineOfSight ? "Yes".Translate() : "No".Translate(), "", 1000);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string item in base.ConfigErrors())
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (abilityClass == null)
|
||||
{
|
||||
yield return "abilityClass is null";
|
||||
}
|
||||
if (verbProperties == null)
|
||||
{
|
||||
yield return "verbProperties are null";
|
||||
}
|
||||
if (label.NullOrEmpty())
|
||||
{
|
||||
yield return "no label";
|
||||
}
|
||||
if (statBases != null)
|
||||
{
|
||||
foreach (StatModifier statBase in statBases)
|
||||
{
|
||||
if (statBases.Count((StatModifier st) => st.stat == statBase.stat) > 1)
|
||||
{
|
||||
yield return "defines the stat base " + statBase.stat?.ToString() + " more than once.";
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < comps.Count; i++)
|
||||
{
|
||||
foreach (string item2 in comps[i].ConfigErrors(this))
|
||||
{
|
||||
yield return item2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Royalty\Defs\AbilityDefs\Abilities.xml`
|
||||
**相似度:** 0.5815
|
||||
|
||||
```xml
|
||||
<AbilityDef Name="PsycastBaseSkip" ParentName="PsycastBase" Abstract="True">
|
||||
<category>Skip</category>
|
||||
</AbilityDef>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\AbilityStatModifiers.txt`
|
||||
**相似度:** 0.5807
|
||||
|
||||
```csharp
|
||||
public class AbilityStatModifiers
|
||||
{
|
||||
public AbilityDef ability;
|
||||
|
||||
public List<StatModifier> modifiers;
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\AbilityDefOf.txt`
|
||||
**相似度:** 0.5779
|
||||
|
||||
```csharp
|
||||
public static class AbilityDefOf
|
||||
{
|
||||
[MayRequireRoyalty]
|
||||
public static AbilityDef Speech;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static AbilityDef ReimplantXenogerm;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static AbilityDef ResurrectionMech;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static AbilityDef EntitySkip;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static AbilityDef UnnaturalCorpseSkip;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static AbilityDef ConsumeLeap_Devourer;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static AbilityDef SludgeSpew;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static AbilityDef EggSpew;
|
||||
|
||||
static AbilityDefOf()
|
||||
{
|
||||
DefOfHelper.EnsureInitializedInCtor(typeof(AbilityDefOf));
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompAbilityEffect_GiveMentalState.txt`
|
||||
**相似度:** 0.5541
|
||||
|
||||
```csharp
|
||||
public class CompAbilityEffect_GiveMentalState : CompAbilityEffect
|
||||
{
|
||||
public new CompProperties_AbilityGiveMentalState Props => (CompProperties_AbilityGiveMentalState)props;
|
||||
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
Pawn pawn = (Props.applyToSelf ? parent.pawn : (target.Thing as Pawn));
|
||||
if (pawn != null && !pawn.InMentalState)
|
||||
{
|
||||
TryGiveMentalState(pawn.RaceProps.IsMechanoid ? (Props.stateDefForMechs ?? Props.stateDef) : Props.stateDef, pawn, parent.def, Props.durationMultiplier, parent.pawn, Props.forced);
|
||||
RestUtility.WakeUp(pawn);
|
||||
if (Props.casterEffect != null)
|
||||
{
|
||||
Effecter effecter = Props.casterEffect.SpawnAttached(parent.pawn, parent.pawn.MapHeld);
|
||||
effecter.Trigger(parent.pawn, null);
|
||||
effecter.Cleanup();
|
||||
}
|
||||
if (Props.targetEffect != null)
|
||||
{
|
||||
Effecter effecter2 = Props.targetEffect.SpawnAttached(parent.pawn, parent.pawn.MapHeld);
|
||||
effecter2.Trigger(pawn, null);
|
||||
effecter2.Cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
|
||||
{
|
||||
if (!base.Valid(target, throwMessages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Pawn pawn = target.Pawn;
|
||||
if (pawn != null)
|
||||
{
|
||||
if (!AbilityUtility.ValidateNoMentalState(pawn, throwMessages, parent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Props.excludeNPCFactions && pawn.Faction != null && !pawn.Faction.IsPlayer)
|
||||
{
|
||||
if (throwMessages)
|
||||
{
|
||||
Messages.Message("CannotUseAbility".Translate(parent.def.label) + ": " + "TargetBelongsToNPCFaction".Translate(), pawn, MessageTypeDefOf.RejectInput, historical: false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void TryGiveMentalState(MentalStateDef def, Pawn p, AbilityDef ability, StatDef multiplierStat, Pawn caster, bool forced = false)
|
||||
{
|
||||
if (p.mindState.mentalStateHandler.TryStartMentalState(def, null, forced, forceWake: true, causedByMood: false, caster, transitionSilently: false, causedByDamage: false, ability.IsPsycast))
|
||||
{
|
||||
float num = ability.GetStatValueAbstract(StatDefOf.Ability_Duration, caster);
|
||||
if (multiplierStat != null)
|
||||
{
|
||||
num *= p.GetStatValue(multiplierStat);
|
||||
}
|
||||
if (num > 0f)
|
||||
{
|
||||
p.mindState.mentalStateHandler.CurState.forceRecoverAfterTicks = num.SecondsToTicks();
|
||||
}
|
||||
p.mindState.mentalStateHandler.CurState.sourceFaction = caster.Faction;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_ResurrectMech.txt`
|
||||
**相似度:** 0.5473
|
||||
|
||||
```csharp
|
||||
public class CompProperties_ResurrectMech : CompProperties_AbilityEffect
|
||||
{
|
||||
public int maxCorpseAgeTicks = int.MaxValue;
|
||||
|
||||
public List<MechChargeCosts> costs = new List<MechChargeCosts>();
|
||||
|
||||
public EffecterDef appliedEffecterDef;
|
||||
|
||||
public EffecterDef centerEffecterDef;
|
||||
|
||||
public CompProperties_ResurrectMech()
|
||||
{
|
||||
compClass = typeof(CompAbilityEffect_ResurrectMech);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(AbilityDef parentDef)
|
||||
{
|
||||
foreach (string item in base.ConfigErrors(parentDef))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (costs.NullOrEmpty())
|
||||
{
|
||||
yield return "costs list is null";
|
||||
yield break;
|
||||
}
|
||||
foreach (MechChargeCosts cost in costs)
|
||||
{
|
||||
if (cost.weightClass == null)
|
||||
{
|
||||
yield return $"costs list contains null weight class with cost {cost.cost}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
519
MCP/vector_cache/AddHumanlikeOrders-FloatMenuMakerMap.txt
Normal file
519
MCP/vector_cache/AddHumanlikeOrders-FloatMenuMakerMap.txt
Normal file
@@ -0,0 +1,519 @@
|
||||
根据向量相似度分析,与 'AddHumanlikeOrders, FloatMenuMakerMap' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\FloatMenuMakerMap.txt`
|
||||
|
||||
```csharp
|
||||
public static class FloatMenuMakerMap
|
||||
{
|
||||
private static List<FloatMenuOptionProvider> providers;
|
||||
|
||||
public static FloatMenuOptionProvider currentProvider;
|
||||
|
||||
public static Pawn makingFor;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
providers = new List<FloatMenuOptionProvider>();
|
||||
foreach (Type item in typeof(FloatMenuOptionProvider).AllSubclassesNonAbstract())
|
||||
{
|
||||
providers.Add((FloatMenuOptionProvider)Activator.CreateInstance(item));
|
||||
}
|
||||
}
|
||||
|
||||
public static List<FloatMenuOption> GetOptions(List<Pawn> selectedPawns, Vector3 clickPos, out FloatMenuContext context)
|
||||
{
|
||||
List<FloatMenuOption> list = new List<FloatMenuOption>();
|
||||
context = null;
|
||||
if (!clickPos.InBounds(Find.CurrentMap))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
context = new FloatMenuContext(selectedPawns, clickPos, Find.CurrentMap);
|
||||
if (!context.allSelectedPawns.Any())
|
||||
{
|
||||
return list;
|
||||
}
|
||||
if (!context.ClickedCell.IsValid || !context.ClickedCell.InBounds(Find.CurrentMap))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
if (!context.IsMultiselect)
|
||||
{
|
||||
AcceptanceReport acceptanceReport = ShouldGenerateFloatMenuForPawn(context.FirstSelectedPawn);
|
||||
if (!acceptanceReport.Accepted)
|
||||
{
|
||||
if (!acceptanceReport.Reason.NullOrEmpty())
|
||||
{
|
||||
Messages.Message(acceptanceReport.Reason, context.FirstSelectedPawn, MessageTypeDefOf.RejectInput, historical: false);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.allSelectedPawns.RemoveAll((Pawn selectedPawn) => !ShouldGenerateFloatMenuForPawn(selectedPawn));
|
||||
if (!context.allSelectedPawns.Any())
|
||||
{
|
||||
return list;
|
||||
}
|
||||
}
|
||||
if (!context.IsMultiselect)
|
||||
{
|
||||
makingFor = context.FirstSelectedPawn;
|
||||
}
|
||||
GetProviderOptions(context, list);
|
||||
makingFor = null;
|
||||
return list;
|
||||
}
|
||||
|
||||
private static void GetProviderOptions(FloatMenuContext context, List<FloatMenuOption> options)
|
||||
{
|
||||
foreach (FloatMenuOptionProvider provider in providers)
|
||||
{
|
||||
try
|
||||
{
|
||||
currentProvider = provider;
|
||||
if (!context.ValidSelectedPawns.Any() || !provider.Applies(context))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
options.AddRange(provider.GetOptions(context));
|
||||
foreach (Thing clickedThing in context.ClickedThings)
|
||||
{
|
||||
if (!provider.TargetThingValid(clickedThing, context))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Thing thing = clickedThing;
|
||||
if (thing.TryGetComp(out CompSelectProxy comp) && comp.thingToSelect != null)
|
||||
{
|
||||
thing = comp.thingToSelect;
|
||||
}
|
||||
foreach (FloatMenuOption item in provider.GetOptionsFor(thing, context))
|
||||
{
|
||||
FloatMenuOption floatMenuOption = item;
|
||||
if (floatMenuOption.iconThing == null)
|
||||
{
|
||||
floatMenuOption.iconThing = thing;
|
||||
}
|
||||
item.targetsDespawned = !thing.Spawned;
|
||||
options.Add(item);
|
||||
}
|
||||
}
|
||||
foreach (Pawn clickedPawn in context.ClickedPawns)
|
||||
{
|
||||
if (!provider.TargetPawnValid(clickedPawn, context))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (FloatMenuOption item2 in provider.GetOptionsFor(clickedPawn, context))
|
||||
{
|
||||
FloatMenuOption floatMenuOption = item2;
|
||||
if (floatMenuOption.iconThing == null)
|
||||
{
|
||||
floatMenuOption.iconThing = clickedPawn;
|
||||
}
|
||||
item2.targetsDespawned = !clickedPawn.Spawned;
|
||||
options.Add(item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception arg)
|
||||
{
|
||||
Log.Error($"Error in FloatMenuWorker {provider.GetType().Name}: {arg}");
|
||||
}
|
||||
}
|
||||
currentProvider = null;
|
||||
}
|
||||
|
||||
public static AcceptanceReport ShouldGenerateFloatMenuForPawn(Pawn pawn)
|
||||
{
|
||||
if (pawn.Map != Find.CurrentMap)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pawn.Downed)
|
||||
{
|
||||
return "IsIncapped".Translate(pawn.LabelCap, pawn);
|
||||
}
|
||||
if (ModsConfig.BiotechActive && pawn.Deathresting)
|
||||
{
|
||||
return "IsDeathresting".Translate(pawn.Named("PAWN"));
|
||||
}
|
||||
Lord lord = pawn.GetLord();
|
||||
if (lord != null)
|
||||
{
|
||||
AcceptanceReport result = lord.AllowsFloatMenu(pawn);
|
||||
if (!result.Accepted)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static FloatMenuOption GetAutoTakeOption(List<FloatMenuOption> options)
|
||||
{
|
||||
bool flag = true;
|
||||
FloatMenuOption floatMenuOption = null;
|
||||
foreach (FloatMenuOption option in options)
|
||||
{
|
||||
if (option.Disabled || !option.autoTakeable)
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
if (floatMenuOption == null || option.autoTakeablePriority > floatMenuOption.autoTakeablePriority)
|
||||
{
|
||||
floatMenuOption = option;
|
||||
}
|
||||
}
|
||||
if (!flag || floatMenuOption == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return floatMenuOption;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\FloatMenuContext.txt`
|
||||
**相似度:** 0.5788
|
||||
|
||||
```csharp
|
||||
public class FloatMenuContext
|
||||
{
|
||||
public List<Pawn> allSelectedPawns;
|
||||
|
||||
public Vector3 clickPosition;
|
||||
|
||||
public Map map;
|
||||
|
||||
private IntVec3 cachedClickedCell;
|
||||
|
||||
private List<Thing> cachedClickedThings;
|
||||
|
||||
private List<Pawn> cachedClickedPawns;
|
||||
|
||||
private Room cachedClickedRoom;
|
||||
|
||||
private Zone cachedClickedZone;
|
||||
|
||||
public IntVec3 ClickedCell => cachedClickedCell;
|
||||
|
||||
public Room ClickedRoom => cachedClickedRoom;
|
||||
|
||||
public Zone ClickedZone => cachedClickedZone;
|
||||
|
||||
public List<Thing> ClickedThings => cachedClickedThings;
|
||||
|
||||
public List<Pawn> ClickedPawns => cachedClickedPawns;
|
||||
|
||||
public bool IsMultiselect => allSelectedPawns.Count > 1;
|
||||
|
||||
public Pawn FirstSelectedPawn
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (Pawn allSelectedPawn in allSelectedPawns)
|
||||
{
|
||||
if (FloatMenuMakerMap.currentProvider == null || FloatMenuMakerMap.currentProvider.SelectedPawnValid(allSelectedPawn, this))
|
||||
{
|
||||
return allSelectedPawn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Pawn> ValidSelectedPawns
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (Pawn allSelectedPawn in allSelectedPawns)
|
||||
{
|
||||
if (FloatMenuMakerMap.currentProvider == null || FloatMenuMakerMap.currentProvider.SelectedPawnValid(allSelectedPawn, this))
|
||||
{
|
||||
yield return allSelectedPawn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FloatMenuContext(List<Pawn> selectedPawns, Vector3 clickPosition, Map map)
|
||||
{
|
||||
allSelectedPawns = selectedPawns;
|
||||
this.clickPosition = clickPosition;
|
||||
this.map = map;
|
||||
cachedClickedCell = IntVec3.FromVector3(clickPosition);
|
||||
cachedClickedRoom = cachedClickedCell.GetRoom(map);
|
||||
cachedClickedZone = cachedClickedCell.GetZone(map);
|
||||
cachedClickedThings = GenUI.ThingsUnderMouse(clickPosition, 0.8f, TargetingParameters.ForThing());
|
||||
cachedClickedPawns = GenUI.ThingsUnderMouse(clickPosition, 0.8f, TargetingParameters.ForPawns()).OfType<Pawn>().ToList();
|
||||
selectedPawns.RemoveAll((Pawn pawn) => !pawn.CanTakeOrder);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\FloatMenuMap.txt`
|
||||
**相似度:** 0.5739
|
||||
|
||||
```csharp
|
||||
public class FloatMenuMap : FloatMenu
|
||||
{
|
||||
private Vector3 clickPos;
|
||||
|
||||
private static Dictionary<Vector3, List<FloatMenuOption>> cachedChoices = new Dictionary<Vector3, List<FloatMenuOption>>();
|
||||
|
||||
private List<FloatMenuOption> lastOptionsForRevalidation;
|
||||
|
||||
private int nextOptionToRevalidate;
|
||||
|
||||
public const int RevalidateEveryFrame = 4;
|
||||
|
||||
public FloatMenuMap(List<FloatMenuOption> options, string title, Vector3 clickPos)
|
||||
: base(options, title)
|
||||
{
|
||||
this.clickPos = clickPos;
|
||||
}
|
||||
|
||||
public override void DoWindowContents(Rect inRect)
|
||||
{
|
||||
if (!Find.Selector.AnyPawnSelected)
|
||||
{
|
||||
Find.WindowStack.TryRemove(this);
|
||||
return;
|
||||
}
|
||||
bool flag = options.Count >= 3;
|
||||
if (Time.frameCount % 4 == 0 || lastOptionsForRevalidation == null)
|
||||
{
|
||||
lastOptionsForRevalidation = FloatMenuMakerMap.GetOptions(Find.Selector.SelectedPawns, clickPos, out var _);
|
||||
cachedChoices.Clear();
|
||||
cachedChoices.Add(clickPos, lastOptionsForRevalidation);
|
||||
if (!flag)
|
||||
{
|
||||
for (int i = 0; i < options.Count; i++)
|
||||
{
|
||||
RevalidateOption(options[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (flag)
|
||||
{
|
||||
if (nextOptionToRevalidate >= options.Count)
|
||||
{
|
||||
nextOptionToRevalidate = 0;
|
||||
}
|
||||
int num = Mathf.CeilToInt((float)options.Count / 3f);
|
||||
int num2 = nextOptionToRevalidate;
|
||||
int num3 = 0;
|
||||
while (num2 < options.Count && num3 < num)
|
||||
{
|
||||
RevalidateOption(options[num2]);
|
||||
nextOptionToRevalidate++;
|
||||
num2++;
|
||||
num3++;
|
||||
}
|
||||
}
|
||||
base.DoWindowContents(inRect);
|
||||
void RevalidateOption(FloatMenuOption option)
|
||||
{
|
||||
if (!option.Disabled && !StillValid(option, lastOptionsForRevalidation))
|
||||
{
|
||||
option.Disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool StillValid(FloatMenuOption opt, List<FloatMenuOption> curOpts)
|
||||
{
|
||||
if (opt.revalidateClickTarget == null)
|
||||
{
|
||||
for (int i = 0; i < curOpts.Count; i++)
|
||||
{
|
||||
if (OptionsMatch(opt, curOpts[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!opt.targetsDespawned && !opt.revalidateClickTarget.Spawned)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Vector3 key = opt.revalidateClickTarget.PositionHeld.ToVector3Shifted();
|
||||
if (!cachedChoices.TryGetValue(key, out var value))
|
||||
{
|
||||
FloatMenuContext context;
|
||||
List<FloatMenuOption> list = FloatMenuMakerMap.GetOptions(Find.Selector.SelectedPawns, key, out context);
|
||||
cachedChoices.Add(key, list);
|
||||
value = list;
|
||||
}
|
||||
for (int j = 0; j < value.Count; j++)
|
||||
{
|
||||
if (OptionsMatch(opt, value[j]))
|
||||
{
|
||||
return !value[j].Disabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void PreOptionChosen(FloatMenuOption opt)
|
||||
{
|
||||
base.PreOptionChosen(opt);
|
||||
if (!opt.Disabled && !StillValid(opt, FloatMenuMakerMap.GetOptions(Find.Selector.SelectedPawns, clickPos, out var _)))
|
||||
{
|
||||
opt.Disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool OptionsMatch(FloatMenuOption a, FloatMenuOption b)
|
||||
{
|
||||
if (a.Label == b.Label)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\FloatMenuOptionProvider.txt`
|
||||
**相似度:** 0.5483
|
||||
|
||||
```csharp
|
||||
public abstract class FloatMenuOptionProvider
|
||||
{
|
||||
protected abstract bool Drafted { get; }
|
||||
|
||||
protected abstract bool Undrafted { get; }
|
||||
|
||||
protected abstract bool Multiselect { get; }
|
||||
|
||||
protected virtual bool RequiresManipulation => false;
|
||||
|
||||
protected virtual bool MechanoidCanDo => false;
|
||||
|
||||
protected virtual bool CanSelfTarget => false;
|
||||
|
||||
public virtual bool CanTargetDespawned => false;
|
||||
|
||||
protected virtual bool IgnoreFogged => true;
|
||||
|
||||
public virtual bool SelectedPawnValid(Pawn pawn, FloatMenuContext context)
|
||||
{
|
||||
if (pawn.IsMutant && pawn.mutant.Def.whitelistedFloatMenuProviders != null && !pawn.mutant.Def.whitelistedFloatMenuProviders.Contains(FloatMenuMakerMap.currentProvider.GetType()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Drafted && pawn.Drafted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Undrafted && !pawn.Drafted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!MechanoidCanDo && pawn.RaceProps.IsMechanoid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (RequiresManipulation && !pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool TargetThingValid(Thing thing, FloatMenuContext context)
|
||||
{
|
||||
if (!CanTargetDespawned && !thing.Spawned)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (thing is Pawn pawn && !TargetPawnValid(pawn, context))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool TargetPawnValid(Pawn pawn, FloatMenuContext context)
|
||||
{
|
||||
if (!CanSelfTarget && pawn == context.FirstSelectedPawn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool Applies(FloatMenuContext context)
|
||||
{
|
||||
if (!Multiselect && context.IsMultiselect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (IgnoreFogged && context.ClickedCell.Fogged(context.map))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!AppliesInt(context))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool AppliesInt(FloatMenuContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<FloatMenuOption> GetOptions(FloatMenuContext context)
|
||||
{
|
||||
FloatMenuOption singleOption = GetSingleOption(context);
|
||||
if (singleOption != null)
|
||||
{
|
||||
yield return singleOption;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<FloatMenuOption> GetOptionsFor(Thing clickedThing, FloatMenuContext context)
|
||||
{
|
||||
FloatMenuOption singleOptionFor = GetSingleOptionFor(clickedThing, context);
|
||||
if (singleOptionFor != null)
|
||||
{
|
||||
yield return singleOptionFor;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<FloatMenuOption> GetOptionsFor(Pawn clickedPawn, FloatMenuContext context)
|
||||
{
|
||||
FloatMenuOption singleOptionFor = GetSingleOptionFor(clickedPawn, context);
|
||||
if (singleOptionFor != null)
|
||||
{
|
||||
yield return singleOptionFor;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual FloatMenuOption GetSingleOption(FloatMenuContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual FloatMenuOption GetSingleOptionFor(Thing clickedThing, FloatMenuContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual FloatMenuOption GetSingleOptionFor(Pawn clickedPawn, FloatMenuContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
1502
MCP/vector_cache/BiosculpterPod-ThingDef.txt
Normal file
1502
MCP/vector_cache/BiosculpterPod-ThingDef.txt
Normal file
File diff suppressed because it is too large
Load Diff
74
MCP/vector_cache/BiosculpterPod.txt
Normal file
74
MCP/vector_cache/BiosculpterPod.txt
Normal file
@@ -0,0 +1,74 @@
|
||||
根据向量相似度分析,与 'BiosculpterPod' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_BiosculpterPod_BaseCycle.txt`
|
||||
**相似度:** 0.6754
|
||||
|
||||
```csharp
|
||||
public abstract class CompProperties_BiosculpterPod_BaseCycle : CompProperties
|
||||
{
|
||||
[NoTranslate]
|
||||
public string key;
|
||||
|
||||
[MustTranslate]
|
||||
public string label;
|
||||
|
||||
[MustTranslate]
|
||||
public string description;
|
||||
|
||||
[NoTranslate]
|
||||
public string iconPath;
|
||||
|
||||
public float durationDays;
|
||||
|
||||
public Color operatingColor = new Color(0.5f, 0.7f, 0.5f);
|
||||
|
||||
public ThoughtDef gainThoughtOnCompletion;
|
||||
|
||||
public List<ResearchProjectDef> requiredResearch;
|
||||
|
||||
public List<ThingDefCountClass> extraRequiredIngredients;
|
||||
|
||||
private Texture2D icon;
|
||||
|
||||
public Texture2D Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
icon = ContentFinder<Texture2D>.Get(iconPath);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
public string LabelCap => label.CapitalizeFirst();
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_BiosculpterPod_PleasureCycle.txt`
|
||||
**相似度:** 0.6624
|
||||
|
||||
```csharp
|
||||
public class CompProperties_BiosculpterPod_PleasureCycle : CompProperties_BiosculpterPod_BaseCycle
|
||||
{
|
||||
public CompProperties_BiosculpterPod_PleasureCycle()
|
||||
{
|
||||
compClass = typeof(CompBiosculpterPod_PleasureCycle);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_BiosculpterPod_AgeReversalCycle.txt`
|
||||
**相似度:** 0.6461
|
||||
|
||||
```csharp
|
||||
public class CompProperties_BiosculpterPod_AgeReversalCycle : CompProperties_BiosculpterPod_BaseCycle
|
||||
{
|
||||
public CompProperties_BiosculpterPod_AgeReversalCycle()
|
||||
{
|
||||
compClass = typeof(CompBiosculpterPod_AgeReversalCycle);
|
||||
}
|
||||
}
|
||||
```
|
||||
1122
MCP/vector_cache/Building_Bed.txt
Normal file
1122
MCP/vector_cache/Building_Bed.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,198 @@
|
||||
根据向量相似度分析,与 'JobDriver_CarryToBiosculpterPod, JobDefOf, CarryToBiosculpterPod' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_CarryToBiosculpterPod.txt`
|
||||
|
||||
```csharp
|
||||
public class JobDriver_CarryToBiosculpterPod : JobDriver
|
||||
{
|
||||
private const TargetIndex TakeeInd = TargetIndex.A;
|
||||
|
||||
private const TargetIndex IngredientInd = TargetIndex.B;
|
||||
|
||||
private const TargetIndex PodInd = TargetIndex.C;
|
||||
|
||||
private List<Thing> pickedUpIngredients = new List<Thing>();
|
||||
|
||||
private List<ThingCount> thingsToTransfer = new List<ThingCount>();
|
||||
|
||||
private Pawn Takee => (Pawn)job.GetTarget(TargetIndex.A).Thing;
|
||||
|
||||
private CompBiosculpterPod Pod => job.GetTarget(TargetIndex.C).Thing.TryGetComp<CompBiosculpterPod>();
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
if (!pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed) || !pawn.Reserve(Pod.parent, job, 1, -1, null, errorOnFailed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
List<LocalTargetInfo> targetQueue = job.GetTargetQueue(TargetIndex.B);
|
||||
for (int i = 0; i < targetQueue.Count; i++)
|
||||
{
|
||||
if (!pawn.Reserve(targetQueue[i], job, 1, -1, null, errorOnFailed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
if (!ModLister.CheckIdeology("Biosculpting"))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
AddFinishAction(delegate
|
||||
{
|
||||
if (Pod != null)
|
||||
{
|
||||
if (Pod.queuedEnterJob == job)
|
||||
{
|
||||
Pod.ClearQueuedInformation();
|
||||
}
|
||||
if (Pod.Occupant != Takee)
|
||||
{
|
||||
foreach (Thing pickedUpIngredient in pickedUpIngredients)
|
||||
{
|
||||
Thing lastResultingThing;
|
||||
if (pawn.inventory.Contains(pickedUpIngredient))
|
||||
{
|
||||
pawn.inventory.innerContainer.TryDrop(pickedUpIngredient, ThingPlaceMode.Near, out lastResultingThing);
|
||||
}
|
||||
else if (Takee.inventory.Contains(pickedUpIngredient))
|
||||
{
|
||||
Takee.inventory.innerContainer.TryDrop(pickedUpIngredient, ThingPlaceMode.Near, out lastResultingThing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.FailOnDestroyedOrNull(TargetIndex.A);
|
||||
this.FailOnDestroyedOrNull(TargetIndex.C);
|
||||
this.FailOnAggroMentalState(TargetIndex.A);
|
||||
this.FailOn(() => job.biosculpterCycleKey == null || !Pod.CanAcceptOnceCycleChosen(Takee));
|
||||
Toil goToTakee = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.OnCell).FailOnDestroyedNullOrForbidden(TargetIndex.A).FailOnDespawnedNullOrForbidden(TargetIndex.C)
|
||||
.FailOn(() => Takee.IsFreeColonist && !Takee.Downed)
|
||||
.FailOnSomeonePhysicallyInteracting(TargetIndex.A);
|
||||
Toil startCarryingTakee = Toils_Haul.StartCarryThing(TargetIndex.A);
|
||||
Toil goToThing = Toils_Goto.GotoThing(TargetIndex.C, PathEndMode.InteractionCell);
|
||||
Toil toil = Toils_Jump.JumpIf(goToThing, () => pawn.IsCarryingPawn(Takee) && job.GetTargetQueue(TargetIndex.B).NullOrEmpty());
|
||||
Toil jumpIfGoToTakee = Toils_Jump.JumpIf(goToTakee, () => job.GetTargetQueue(TargetIndex.B).NullOrEmpty());
|
||||
yield return toil;
|
||||
yield return jumpIfGoToTakee;
|
||||
yield return DropCarryToGrabIngredients();
|
||||
foreach (Toil item in JobDriver_EnterBiosculpterPod.CollectIngredientsToilsHelper(TargetIndex.B, pawn, pickedUpIngredients))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
yield return goToTakee;
|
||||
yield return TransferIngredientsAndPrepareCarryDownedPawn();
|
||||
yield return startCarryingTakee;
|
||||
yield return goToThing.FailOn(() => !Pod.PawnCarryingExtraCycleIngredients(Takee, job.biosculpterCycleKey));
|
||||
yield return JobDriver_EnterBiosculpterPod.PrepareToEnterToil(TargetIndex.C);
|
||||
Toil toil2 = ToilMaker.MakeToil("MakeNewToils");
|
||||
toil2.initAction = delegate
|
||||
{
|
||||
Pod.TryAcceptPawn(Takee, job.biosculpterCycleKey);
|
||||
};
|
||||
toil2.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||
yield return toil2;
|
||||
}
|
||||
|
||||
private Toil TransferIngredientsAndPrepareCarryDownedPawn()
|
||||
{
|
||||
Toil toil = ToilMaker.MakeToil("TransferIngredientsAndPrepareCarryDownedPawn");
|
||||
toil.initAction = delegate
|
||||
{
|
||||
List<ThingDefCountClass> extraRequiredIngredients = Pod.GetCycle(job.biosculpterCycleKey).Props.extraRequiredIngredients;
|
||||
if (extraRequiredIngredients != null && !Pod.devFillPodLatch)
|
||||
{
|
||||
ThingOwner<Thing> innerContainer = pawn.inventory.innerContainer;
|
||||
foreach (ThingDefCountClass item in extraRequiredIngredients)
|
||||
{
|
||||
if (Takee.inventory.Count(item.thingDef) < item.count)
|
||||
{
|
||||
if (pawn.inventory.Count(item.thingDef) < item.count)
|
||||
{
|
||||
EndJobWith(JobCondition.Incompletable);
|
||||
return;
|
||||
}
|
||||
thingsToTransfer.Clear();
|
||||
int num = 0;
|
||||
foreach (Thing item2 in innerContainer)
|
||||
{
|
||||
if (num >= item.count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (item2.def == item.thingDef)
|
||||
{
|
||||
int num2 = Mathf.Min(item.count - num, item2.stackCount);
|
||||
thingsToTransfer.Add(new ThingCount(item2, Mathf.Min(item.count - num, item2.stackCount)));
|
||||
num += num2;
|
||||
}
|
||||
}
|
||||
foreach (ThingCount item3 in thingsToTransfer)
|
||||
{
|
||||
int num3 = Takee.inventory.innerContainer.TryAddOrTransfer(item3.Thing, item3.Count);
|
||||
if (num3 != item3.Count)
|
||||
{
|
||||
Log.Warning($"Only able to transfer x{num3} of the expected x{item3.Count} of {item3.Thing.Label} while CarryToBiosculpter");
|
||||
EndJobWith(JobCondition.Incompletable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
job.count = 1;
|
||||
};
|
||||
toil.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||
return toil;
|
||||
}
|
||||
|
||||
private Toil DropCarryToGrabIngredients()
|
||||
{
|
||||
Toil toil = ToilMaker.MakeToil("DropCarryToGrabIngredients");
|
||||
toil.initAction = delegate
|
||||
{
|
||||
if (pawn.carryTracker.CarriedThing != null)
|
||||
{
|
||||
pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out var _);
|
||||
}
|
||||
};
|
||||
toil.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||
return toil;
|
||||
}
|
||||
|
||||
public override string GetReport()
|
||||
{
|
||||
if (!Pod.PawnCarryingExtraCycleIngredients(Takee, job.biosculpterCycleKey) && !Pod.PawnCarryingExtraCycleIngredients(pawn, job.biosculpterCycleKey))
|
||||
{
|
||||
return "BiosculpterJobReportCollectIngredients".Translate();
|
||||
}
|
||||
return base.GetReport();
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Collections.Look(ref pickedUpIngredients, "pickedUpIngredients", LookMode.Reference);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Ideology\Defs\JobDefs\Jobs_Misc.xml`
|
||||
**相似度:** 0.5483
|
||||
|
||||
```xml
|
||||
<defName>CarryToBiosculpterPod</defName>
|
||||
<driverClass>JobDriver_CarryToBiosculpterPod</driverClass>
|
||||
<reportString>carrying TargetA to biosculpter pod.</reportString>
|
||||
<casualInterruptible>false</casualInterruptible>
|
||||
</JobDef>
|
||||
|
||||
<JobDef>
|
||||
<defName>RecolorApparel</defName>
|
||||
```
|
||||
985
MCP/vector_cache/ColonistBarColonistDrawer-DrawIcons.txt
Normal file
985
MCP/vector_cache/ColonistBarColonistDrawer-DrawIcons.txt
Normal file
@@ -0,0 +1,985 @@
|
||||
根据向量相似度分析,与 'DrawIcons, ColonistBarColonistDrawer' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\ColonistBarColonistDrawer.txt`
|
||||
|
||||
```csharp
|
||||
public class ColonistBarColonistDrawer
|
||||
{
|
||||
private struct IconDrawCall
|
||||
{
|
||||
public Texture2D texture;
|
||||
|
||||
public string tooltip;
|
||||
|
||||
public Color? color;
|
||||
|
||||
public IconDrawCall(Texture2D texture, string tooltip = null, Color? color = null)
|
||||
{
|
||||
this.texture = texture;
|
||||
this.tooltip = tooltip;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, string> pawnLabelsCache = new Dictionary<string, string>();
|
||||
|
||||
private static readonly Texture2D MoodBGTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.4f, 0.47f, 0.53f, 0.44f));
|
||||
|
||||
private static readonly Texture2D MoodAtlas = ContentFinder<Texture2D>.Get("UI/Widgets/SubtleGradient");
|
||||
|
||||
private static readonly Texture2D DeadColonistTex = ContentFinder<Texture2D>.Get("UI/Misc/DeadColonist");
|
||||
|
||||
private static readonly Texture2D Icon_FormingCaravan = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/FormingCaravan");
|
||||
|
||||
private static readonly Texture2D Icon_MentalStateNonAggro = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/MentalStateNonAggro");
|
||||
|
||||
private static readonly Texture2D Icon_MentalStateAggro = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/MentalStateAggro");
|
||||
|
||||
private static readonly Texture2D Icon_MedicalRest = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/MedicalRest");
|
||||
|
||||
private static readonly Texture2D Icon_Sleeping = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/Sleeping");
|
||||
|
||||
private static readonly Texture2D Icon_Fleeing = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/Fleeing");
|
||||
|
||||
private static readonly Texture2D Icon_Attacking = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/Attacking");
|
||||
|
||||
private static readonly Texture2D Icon_Idle = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/Idle");
|
||||
|
||||
private static readonly Texture2D Icon_Burning = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/Burning");
|
||||
|
||||
private static readonly Texture2D Icon_Inspired = ContentFinder<Texture2D>.Get("UI/Icons/ColonistBar/Inspired");
|
||||
|
||||
private static readonly Texture2D MoodGradient = ContentFinder<Texture2D>.Get("UI/Widgets/MoodGradient");
|
||||
|
||||
public static readonly Vector2 PawnTextureSize = new Vector2(ColonistBar.BaseSize.x - 2f, 75f);
|
||||
|
||||
public static readonly Vector3 PawnTextureCameraOffset = new Vector3(0f, 0f, 0.3f);
|
||||
|
||||
public const float PawnTextureCameraZoom = 1.28205f;
|
||||
|
||||
private const float PawnTextureHorizontalPadding = 1f;
|
||||
|
||||
private static readonly float BaseIconAreaWidth = PawnTextureSize.x;
|
||||
|
||||
private static readonly float BaseIconMaxSize = 20f;
|
||||
|
||||
private const float BaseGroupFrameMargin = 12f;
|
||||
|
||||
public const float DoubleClickTime = 0.5f;
|
||||
|
||||
public const float FactionIconSpacing = 2f;
|
||||
|
||||
public const float IdeoRoleIconSpacing = 2f;
|
||||
|
||||
public const float SlaveIconSpacing = 2f;
|
||||
|
||||
private const float MoodGradientHeight = 35f;
|
||||
|
||||
private static List<IconDrawCall> tmpIconsToDraw = new List<IconDrawCall>();
|
||||
|
||||
private ColonistBar ColonistBar => Find.ColonistBar;
|
||||
|
||||
public void DrawColonist(Rect rect, Pawn colonist, Map pawnMap, bool highlight, bool reordering)
|
||||
{
|
||||
float alpha = ColonistBar.GetEntryRectAlpha(rect);
|
||||
bool num = Prefs.VisibleMood && colonist.needs?.mood != null && colonist.mindState.mentalBreaker.CanDoRandomMentalBreaks && !colonist.Dead && !colonist.Downed;
|
||||
MoodThreshold moodThreshold = MoodThresholdExtensions.CurrentMoodThresholdFor(colonist);
|
||||
Color color = moodThreshold.GetColor();
|
||||
color.a *= alpha;
|
||||
ApplyEntryInAnotherMapAlphaFactor(pawnMap, ref alpha);
|
||||
if (reordering)
|
||||
{
|
||||
alpha *= 0.5f;
|
||||
}
|
||||
Color color3 = (GUI.color = new Color(1f, 1f, 1f, alpha));
|
||||
if (num && alpha >= 1f)
|
||||
{
|
||||
float num2 = moodThreshold.EdgeExpansion();
|
||||
if (num2 > 0f)
|
||||
{
|
||||
GUI.color = color;
|
||||
Widgets.DrawAtlas(rect.ExpandedBy(num2), MoodAtlas);
|
||||
GUI.color = color3;
|
||||
}
|
||||
}
|
||||
GUI.DrawTexture(rect, ColonistBar.BGTex);
|
||||
if (colonist.needs != null && colonist.needs.mood != null)
|
||||
{
|
||||
Rect position = rect.ContractedBy(2f);
|
||||
float num3 = position.height * colonist.needs.mood.CurLevelPercentage;
|
||||
position.yMin = position.yMax - num3;
|
||||
position.height = num3;
|
||||
GUI.DrawTexture(position, MoodBGTex);
|
||||
}
|
||||
if (num && alpha >= 1f)
|
||||
{
|
||||
float transparency = ((moodThreshold < MoodThreshold.Major) ? 0.1f : 0.15f);
|
||||
Widgets.DrawBoxSolid(rect, moodThreshold.GetColor().ToTransparent(transparency));
|
||||
}
|
||||
if (highlight)
|
||||
{
|
||||
int thickness = ((rect.width <= 22f) ? 2 : 3);
|
||||
GUI.color = Color.white;
|
||||
Widgets.DrawBox(rect, thickness);
|
||||
GUI.color = color3;
|
||||
}
|
||||
Rect rect2 = rect.ContractedBy(-2f * ColonistBar.Scale);
|
||||
if ((colonist.Dead ? Find.Selector.SelectedObjects.Contains(colonist.Corpse) : Find.Selector.SelectedObjects.Contains(colonist)) && !WorldRendererUtility.WorldSelected)
|
||||
{
|
||||
DrawSelectionOverlayOnGUI(colonist, rect2);
|
||||
}
|
||||
else if (WorldRendererUtility.WorldSelected && colonist.IsCaravanMember() && Find.WorldSelector.IsSelected(colonist.GetCaravan()))
|
||||
{
|
||||
DrawCaravanSelectionOverlayOnGUI(colonist.GetCaravan(), rect2);
|
||||
}
|
||||
GUI.DrawTexture(GetPawnTextureRect(rect.position), PortraitsCache.Get(colonist, PawnTextureSize, Rot4.South, PawnTextureCameraOffset, 1.28205f));
|
||||
if (num)
|
||||
{
|
||||
Rect rect3 = rect.ContractedBy(1f);
|
||||
Widgets.BeginGroup(rect3);
|
||||
Rect position2 = rect3.AtZero();
|
||||
position2.yMin = position2.yMax - 35f;
|
||||
GUI.color = color;
|
||||
GUI.DrawTexture(position2, MoodGradient);
|
||||
GUI.color = color3;
|
||||
Widgets.EndGroup();
|
||||
}
|
||||
GUI.color = new Color(1f, 1f, 1f, alpha * 0.8f);
|
||||
DrawIcons(rect, colonist);
|
||||
GUI.color = color3;
|
||||
if (colonist.Dead)
|
||||
{
|
||||
GUI.DrawTexture(rect, DeadColonistTex);
|
||||
}
|
||||
float num4 = 4f * ColonistBar.Scale;
|
||||
Vector2 pos = new Vector2(rect.center.x, rect.yMax - num4);
|
||||
GenMapUI.DrawPawnLabel(colonist, pos, alpha, rect.width + ColonistBar.SpaceBetweenColonistsHorizontal - 2f, pawnLabelsCache);
|
||||
Text.Font = GameFont.Small;
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
private Rect GroupFrameRect(int group)
|
||||
{
|
||||
float num = 99999f;
|
||||
float num2 = 0f;
|
||||
float num3 = 0f;
|
||||
List<ColonistBar.Entry> entries = ColonistBar.Entries;
|
||||
List<Vector2> drawLocs = ColonistBar.DrawLocs;
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
if (entries[i].group == group)
|
||||
{
|
||||
num = Mathf.Min(num, drawLocs[i].x);
|
||||
num2 = Mathf.Max(num2, drawLocs[i].x + ColonistBar.Size.x);
|
||||
num3 = Mathf.Max(num3, drawLocs[i].y + ColonistBar.Size.y);
|
||||
}
|
||||
}
|
||||
return new Rect(num, 0f, num2 - num, num3 - 0f).ContractedBy(-12f * ColonistBar.Scale);
|
||||
}
|
||||
|
||||
public void DrawGroupFrame(int group)
|
||||
{
|
||||
Rect position = GroupFrameRect(group);
|
||||
Map map = ColonistBar.Entries.Find((ColonistBar.Entry x) => x.group == group).map;
|
||||
float num = ((map == null) ? ((!WorldRendererUtility.WorldSelected) ? 0.75f : 1f) : ((map == Find.CurrentMap && !WorldRendererUtility.WorldSelected) ? 1f : 0.75f));
|
||||
Widgets.DrawRectFast(position, new Color(0.5f, 0.5f, 0.5f, 0.4f * num));
|
||||
}
|
||||
|
||||
private void ApplyEntryInAnotherMapAlphaFactor(Map map, ref float alpha)
|
||||
{
|
||||
if (map == null)
|
||||
{
|
||||
if (!WorldRendererUtility.WorldSelected)
|
||||
{
|
||||
alpha = Mathf.Min(alpha, 0.4f);
|
||||
}
|
||||
}
|
||||
else if (map != Find.CurrentMap || WorldRendererUtility.WorldSelected)
|
||||
{
|
||||
alpha = Mathf.Min(alpha, 0.4f);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleClicks(Rect rect, Pawn colonist, int reorderableGroup, out bool reordering)
|
||||
{
|
||||
if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && Event.current.clickCount == 2 && Mouse.IsOver(rect))
|
||||
{
|
||||
Event.current.Use();
|
||||
CameraJumper.TryJump(colonist);
|
||||
}
|
||||
reordering = ReorderableWidget.Reorderable(reorderableGroup, rect, useRightButton: true);
|
||||
if (Event.current.type == EventType.MouseDown && Event.current.button == 1 && Mouse.IsOver(rect))
|
||||
{
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleGroupFrameClicks(int group)
|
||||
{
|
||||
Rect rect = GroupFrameRect(group);
|
||||
if (Event.current.type == EventType.MouseUp && Event.current.button == 0 && Mouse.IsOver(rect) && !ColonistBar.AnyColonistOrCorpseAt(UI.MousePositionOnUIInverted))
|
||||
{
|
||||
bool worldSelected = WorldRendererUtility.WorldSelected;
|
||||
if ((!worldSelected && !Find.Selector.dragBox.IsValidAndActive) || (worldSelected && !Find.WorldSelector.dragBox.IsValidAndActive))
|
||||
{
|
||||
Find.Selector.dragBox.active = false;
|
||||
Find.WorldSelector.dragBox.active = false;
|
||||
ColonistBar.Entry entry = ColonistBar.Entries.Find((ColonistBar.Entry x) => x.group == group);
|
||||
Map map = entry.map;
|
||||
if (map == null)
|
||||
{
|
||||
if (WorldRendererUtility.WorldSelected)
|
||||
{
|
||||
CameraJumper.TrySelect(entry.pawn);
|
||||
}
|
||||
else
|
||||
{
|
||||
CameraJumper.TryJumpAndSelect(entry.pawn);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CameraJumper.TryHideWorld() && Find.CurrentMap != map)
|
||||
{
|
||||
SoundDefOf.MapSelected.PlayOneShotOnCamera();
|
||||
}
|
||||
Current.Game.CurrentMap = map;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Event.current.type == EventType.MouseDown && Event.current.button == 1 && Mouse.IsOver(rect))
|
||||
{
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
|
||||
public void Notify_RecachedEntries()
|
||||
{
|
||||
pawnLabelsCache.Clear();
|
||||
}
|
||||
|
||||
public void ClearLabelCache()
|
||||
{
|
||||
pawnLabelsCache.Clear();
|
||||
}
|
||||
|
||||
public Rect GetPawnTextureRect(Vector2 pos)
|
||||
{
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
Vector2 vector = PawnTextureSize * ColonistBar.Scale;
|
||||
return new Rect(x + 1f, y - (vector.y - ColonistBar.Size.y) - 1f, vector.x, vector.y).ContractedBy(1f);
|
||||
}
|
||||
|
||||
private void DrawIcons(Rect rect, Pawn colonist)
|
||||
{
|
||||
if (colonist.Dead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
tmpIconsToDraw.Clear();
|
||||
bool flag = false;
|
||||
if (colonist.CurJob != null)
|
||||
{
|
||||
JobDef def = colonist.CurJob.def;
|
||||
if (def == JobDefOf.AttackMelee || def == JobDefOf.AttackStatic)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
else if (def == JobDefOf.Wait_Combat && colonist.stances.curStance is Stance_Busy stance_Busy && stance_Busy.focusTarg.IsValid)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
if (colonist.IsFormingCaravan())
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_FormingCaravan, "ActivityIconFormingCaravan".Translate()));
|
||||
}
|
||||
if (colonist.InAggroMentalState)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_MentalStateAggro, colonist.MentalStateDef.LabelCap));
|
||||
}
|
||||
else if (colonist.InMentalState)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_MentalStateNonAggro, colonist.MentalStateDef.LabelCap));
|
||||
}
|
||||
else if (colonist.InBed() && colonist.CurrentBed().Medical)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_MedicalRest, "ActivityIconMedicalRest".Translate()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (colonist.CurJob != null && colonist.jobs.curDriver.asleep)
|
||||
{
|
||||
goto IL_01c5;
|
||||
}
|
||||
if (colonist.GetCaravan() != null)
|
||||
{
|
||||
Pawn_NeedsTracker needs = colonist.needs;
|
||||
if (needs != null && needs.rest?.Resting == true)
|
||||
{
|
||||
goto IL_01c5;
|
||||
}
|
||||
}
|
||||
if (colonist.CurJob != null && colonist.CurJob.def == JobDefOf.FleeAndCower)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_Fleeing, "ActivityIconFleeing".Translate()));
|
||||
}
|
||||
else if (flag)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_Attacking, "ActivityIconAttacking".Translate()));
|
||||
}
|
||||
else if (colonist.mindState.IsIdle && GenDate.DaysPassed >= 1)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_Idle, "ActivityIconIdle".Translate()));
|
||||
}
|
||||
}
|
||||
goto IL_02b4;
|
||||
IL_01c5:
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_Sleeping, "ActivityIconSleeping".Translate()));
|
||||
goto IL_02b4;
|
||||
IL_02b4:
|
||||
if (colonist.IsBurning())
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_Burning, "ActivityIconBurning".Translate()));
|
||||
}
|
||||
if (colonist.Inspired)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(Icon_Inspired, colonist.InspirationDef.LabelCap));
|
||||
}
|
||||
if (colonist.IsSlaveOfColony)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(colonist.guest.GetIcon()));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool flag2 = false;
|
||||
if (colonist.Ideo != null)
|
||||
{
|
||||
Ideo ideo = colonist.Ideo;
|
||||
Precept_Role role = ideo.GetRole(colonist);
|
||||
if (role != null)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(role.Icon, null, ideo.Color));
|
||||
flag2 = true;
|
||||
}
|
||||
}
|
||||
if (!flag2)
|
||||
{
|
||||
Faction faction = null;
|
||||
if (colonist.HasExtraMiniFaction())
|
||||
{
|
||||
faction = colonist.GetExtraMiniFaction();
|
||||
}
|
||||
else if (colonist.HasExtraHomeFaction())
|
||||
{
|
||||
faction = colonist.GetExtraHomeFaction();
|
||||
}
|
||||
if (faction != null)
|
||||
{
|
||||
tmpIconsToDraw.Add(new IconDrawCall(faction.def.FactionIcon, null, faction.Color));
|
||||
}
|
||||
}
|
||||
}
|
||||
float num = Mathf.Min(BaseIconAreaWidth / (float)tmpIconsToDraw.Count, BaseIconMaxSize) * ColonistBar.Scale;
|
||||
Vector2 pos = new Vector2(rect.x + 1f, rect.yMax - num - 1f);
|
||||
foreach (IconDrawCall item in tmpIconsToDraw)
|
||||
{
|
||||
GUI.color = item.color ?? Color.white;
|
||||
DrawIcon(item.texture, ref pos, num, item.tooltip);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawIcon(Texture2D icon, ref Vector2 pos, float iconSize, string tooltip = null)
|
||||
{
|
||||
Rect rect = new Rect(pos.x, pos.y, iconSize, iconSize);
|
||||
GUI.DrawTexture(rect, icon);
|
||||
if (tooltip != null)
|
||||
{
|
||||
TooltipHandler.TipRegion(rect, tooltip);
|
||||
}
|
||||
pos.x += iconSize;
|
||||
}
|
||||
|
||||
private void DrawSelectionOverlayOnGUI(Pawn colonist, Rect rect)
|
||||
{
|
||||
Thing target = colonist;
|
||||
if (colonist.Dead)
|
||||
{
|
||||
target = colonist.Corpse;
|
||||
}
|
||||
SelectionDrawerUtility.DrawSelectionOverlayOnGUI(target, rect, 0.4f * ColonistBar.Scale, 20f * ColonistBar.Scale);
|
||||
}
|
||||
|
||||
private void DrawCaravanSelectionOverlayOnGUI(Caravan caravan, Rect rect)
|
||||
{
|
||||
SelectionDrawerUtility.DrawSelectionOverlayOnGUI(caravan, rect, 0.4f * ColonistBar.Scale, 20f * ColonistBar.Scale);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\ColonistBar.txt`
|
||||
**相似度:** 0.7704
|
||||
|
||||
```csharp
|
||||
public class ColonistBar
|
||||
{
|
||||
public struct Entry
|
||||
{
|
||||
public Pawn pawn;
|
||||
|
||||
public Map map;
|
||||
|
||||
public int group;
|
||||
|
||||
public Action<int, int> reorderAction;
|
||||
|
||||
public Action<int, Vector2> extraDraggedItemOnGUI;
|
||||
|
||||
public Entry(Pawn pawn, Map map, int group)
|
||||
{
|
||||
this.pawn = pawn;
|
||||
this.map = map;
|
||||
this.group = group;
|
||||
reorderAction = delegate(int from, int to)
|
||||
{
|
||||
Find.ColonistBar.Reorder(from, to, group);
|
||||
};
|
||||
extraDraggedItemOnGUI = delegate(int index, Vector2 dragStartPos)
|
||||
{
|
||||
Find.ColonistBar.DrawColonistMouseAttachment(index, dragStartPos, group);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public ColonistBarColonistDrawer drawer = new ColonistBarColonistDrawer();
|
||||
|
||||
private ColonistBarDrawLocsFinder drawLocsFinder = new ColonistBarDrawLocsFinder();
|
||||
|
||||
private List<Entry> cachedEntries = new List<Entry>();
|
||||
|
||||
private List<Vector2> cachedDrawLocs = new List<Vector2>();
|
||||
|
||||
private List<int> cachedReorderableGroups = new List<int>();
|
||||
|
||||
private float cachedScale = 1f;
|
||||
|
||||
private bool entriesDirty = true;
|
||||
|
||||
private List<Pawn> colonistsToHighlight = new List<Pawn>();
|
||||
|
||||
public static readonly Texture2D BGTex = Command.BGTex;
|
||||
|
||||
public static readonly Vector2 BaseSize = new Vector2(48f, 48f);
|
||||
|
||||
public const float BaseSelectedTexJump = 20f;
|
||||
|
||||
public const float BaseSelectedTexScale = 0.4f;
|
||||
|
||||
public const float EntryInAnotherMapAlpha = 0.4f;
|
||||
|
||||
public const float BaseSpaceBetweenGroups = 25f;
|
||||
|
||||
public const float BaseSpaceBetweenColonistsHorizontal = 24f;
|
||||
|
||||
public const float BaseSpaceBetweenColonistsVertical = 32f;
|
||||
|
||||
private const float WeaponIconOffsetScaleFactor = 1.05f;
|
||||
|
||||
private const float WeaponIconScaleFactor = 0.75f;
|
||||
|
||||
private static List<Pawn> tmpPawns = new List<Pawn>();
|
||||
|
||||
private static List<Map> tmpMaps = new List<Map>();
|
||||
|
||||
private static List<Caravan> tmpCaravans = new List<Caravan>();
|
||||
|
||||
private static List<Pawn> tmpColonistsInOrder = new List<Pawn>();
|
||||
|
||||
private static List<Pair<Thing, Map>> tmpColonistsWithMap = new List<Pair<Thing, Map>>();
|
||||
|
||||
private static List<Thing> tmpColonists = new List<Thing>();
|
||||
|
||||
private static List<Thing> tmpMapColonistsOrCorpsesInScreenRect = new List<Thing>();
|
||||
|
||||
private static List<Pawn> tmpCaravanPawns = new List<Pawn>();
|
||||
|
||||
public List<Entry> Entries
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckRecacheEntries();
|
||||
return cachedEntries;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShowGroupFrames
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Entry> entries = Entries;
|
||||
int num = -1;
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
num = Mathf.Max(num, entries[i].group);
|
||||
}
|
||||
return num >= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public float Scale => cachedScale;
|
||||
|
||||
public List<Vector2> DrawLocs => cachedDrawLocs;
|
||||
|
||||
public Vector2 Size => BaseSize * Scale;
|
||||
|
||||
public float SpaceBetweenColonistsHorizontal => 24f * Scale;
|
||||
|
||||
private bool Visible
|
||||
{
|
||||
get
|
||||
{
|
||||
if (UI.screenWidth < 800 || UI.screenHeight < 500)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Find.TilePicker.Active)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkColonistsDirty()
|
||||
{
|
||||
entriesDirty = true;
|
||||
}
|
||||
|
||||
public void ColonistBarOnGUI()
|
||||
{
|
||||
if (!Visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Event.current.type != EventType.Layout)
|
||||
{
|
||||
List<Entry> entries = Entries;
|
||||
int num = -1;
|
||||
bool showGroupFrames = ShowGroupFrames;
|
||||
int value = -1;
|
||||
for (int i = 0; i < cachedDrawLocs.Count; i++)
|
||||
{
|
||||
Rect rect = new Rect(cachedDrawLocs[i].x, cachedDrawLocs[i].y, Size.x, Size.y);
|
||||
Entry entry = entries[i];
|
||||
bool flag = num != entry.group;
|
||||
num = entry.group;
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
value = ReorderableWidget.NewGroup(entry.reorderAction, ReorderableDirection.Horizontal, new Rect(0f, 0f, UI.screenWidth, UI.screenHeight), SpaceBetweenColonistsHorizontal, entry.extraDraggedItemOnGUI);
|
||||
}
|
||||
cachedReorderableGroups[i] = value;
|
||||
}
|
||||
bool reordering;
|
||||
if (entry.pawn != null)
|
||||
{
|
||||
drawer.HandleClicks(rect, entry.pawn, cachedReorderableGroups[i], out reordering);
|
||||
}
|
||||
else
|
||||
{
|
||||
reordering = false;
|
||||
}
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (flag && showGroupFrames)
|
||||
{
|
||||
drawer.DrawGroupFrame(entry.group);
|
||||
}
|
||||
if (entry.pawn != null)
|
||||
{
|
||||
drawer.DrawColonist(rect, entry.pawn, entry.map, colonistsToHighlight.Contains(entry.pawn), reordering);
|
||||
ThingWithComps thingWithComps = entry.pawn.equipment?.Primary;
|
||||
if ((Prefs.ShowWeaponsUnderPortraitMode == ShowWeaponsUnderPortraitMode.Always || (Prefs.ShowWeaponsUnderPortraitMode == ShowWeaponsUnderPortraitMode.WhileDrafted && entry.pawn.Drafted)) && thingWithComps != null && thingWithComps.def.IsWeapon)
|
||||
{
|
||||
Widgets.ThingIcon(new Rect(rect.x, rect.y + rect.height * 1.05f, rect.width, rect.height).ScaledBy(0.75f), thingWithComps, 1f, null, stackOfOne: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
num = -1;
|
||||
if (showGroupFrames)
|
||||
{
|
||||
for (int j = 0; j < cachedDrawLocs.Count; j++)
|
||||
{
|
||||
Entry entry2 = entries[j];
|
||||
bool num2 = num != entry2.group;
|
||||
num = entry2.group;
|
||||
if (num2)
|
||||
{
|
||||
drawer.HandleGroupFrameClicks(entry2.group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
colonistsToHighlight.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckRecacheEntries()
|
||||
{
|
||||
if (!entriesDirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
entriesDirty = false;
|
||||
cachedEntries.Clear();
|
||||
int num = 0;
|
||||
if (Find.PlaySettings.showColonistBar)
|
||||
{
|
||||
tmpMaps.Clear();
|
||||
tmpMaps.AddRange(Find.Maps);
|
||||
tmpMaps.SortBy((Map x) => !x.IsPlayerHome, (Map x) => x.uniqueID);
|
||||
for (int i = 0; i < tmpMaps.Count; i++)
|
||||
{
|
||||
tmpPawns.Clear();
|
||||
tmpPawns.AddRange(tmpMaps[i].mapPawns.FreeColonists);
|
||||
tmpPawns.AddRange(tmpMaps[i].mapPawns.ColonySubhumansControllable);
|
||||
List<Thing> list = tmpMaps[i].listerThings.ThingsInGroup(ThingRequestGroup.Corpse);
|
||||
for (int j = 0; j < list.Count; j++)
|
||||
{
|
||||
if (!list[j].IsDessicated())
|
||||
{
|
||||
Pawn innerPawn = ((Corpse)list[j]).InnerPawn;
|
||||
if (innerPawn != null && innerPawn.IsColonist)
|
||||
{
|
||||
tmpPawns.Add(innerPawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
IReadOnlyList<Pawn> allPawnsSpawned = tmpMaps[i].mapPawns.AllPawnsSpawned;
|
||||
for (int k = 0; k < allPawnsSpawned.Count; k++)
|
||||
{
|
||||
if (allPawnsSpawned[k].carryTracker.CarriedThing is Corpse corpse && !corpse.IsDessicated() && corpse.InnerPawn.IsColonist)
|
||||
{
|
||||
tmpPawns.Add(corpse.InnerPawn);
|
||||
}
|
||||
}
|
||||
foreach (Pawn tmpPawn in tmpPawns)
|
||||
{
|
||||
if (tmpPawn.playerSettings.displayOrder == -9999999)
|
||||
{
|
||||
tmpPawn.playerSettings.displayOrder = Mathf.Max(tmpPawns.MaxBy((Pawn p) => p.playerSettings.displayOrder).playerSettings.displayOrder, 0) + 1;
|
||||
}
|
||||
}
|
||||
PlayerPawnsDisplayOrderUtility.Sort(tmpPawns);
|
||||
foreach (Pawn tmpPawn2 in tmpPawns)
|
||||
{
|
||||
cachedEntries.Add(new Entry(tmpPawn2, tmpMaps[i], num));
|
||||
}
|
||||
if (!tmpPawns.Any())
|
||||
{
|
||||
cachedEntries.Add(new Entry(null, tmpMaps[i], num));
|
||||
}
|
||||
num++;
|
||||
}
|
||||
tmpCaravans.Clear();
|
||||
tmpCaravans.AddRange(Find.WorldObjects.Caravans);
|
||||
tmpCaravans.SortBy((Caravan x) => x.ID);
|
||||
for (int l = 0; l < tmpCaravans.Count; l++)
|
||||
{
|
||||
if (!tmpCaravans[l].IsPlayerControlled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
tmpPawns.Clear();
|
||||
tmpPawns.AddRange(tmpCaravans[l].PawnsListForReading);
|
||||
PlayerPawnsDisplayOrderUtility.Sort(tmpPawns);
|
||||
for (int m = 0; m < tmpPawns.Count; m++)
|
||||
{
|
||||
if (tmpPawns[m].IsColonist || tmpPawns[m].IsColonySubhumanPlayerControlled)
|
||||
{
|
||||
cachedEntries.Add(new Entry(tmpPawns[m], null, num));
|
||||
}
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
cachedReorderableGroups.Clear();
|
||||
foreach (Entry cachedEntry in cachedEntries)
|
||||
{
|
||||
_ = cachedEntry;
|
||||
cachedReorderableGroups.Add(-1);
|
||||
}
|
||||
drawer.Notify_RecachedEntries();
|
||||
tmpPawns.Clear();
|
||||
tmpMaps.Clear();
|
||||
tmpCaravans.Clear();
|
||||
drawLocsFinder.CalculateDrawLocs(cachedDrawLocs, out cachedScale, num);
|
||||
}
|
||||
|
||||
public float GetEntryRectAlpha(Rect rect)
|
||||
{
|
||||
if (Messages.CollidesWithAnyMessage(rect, out var messageAlpha))
|
||||
{
|
||||
return Mathf.Lerp(1f, 0.2f, messageAlpha);
|
||||
}
|
||||
return 1f;
|
||||
}
|
||||
|
||||
public void Highlight(Pawn pawn)
|
||||
{
|
||||
if (Visible && !colonistsToHighlight.Contains(pawn))
|
||||
{
|
||||
colonistsToHighlight.Add(pawn);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reorder(int from, int to, int entryGroup)
|
||||
{
|
||||
int num = 0;
|
||||
Pawn pawn = null;
|
||||
Pawn pawn2 = null;
|
||||
Pawn pawn3 = null;
|
||||
for (int i = 0; i < cachedEntries.Count; i++)
|
||||
{
|
||||
if (cachedEntries[i].group == entryGroup && cachedEntries[i].pawn != null)
|
||||
{
|
||||
if (num == from)
|
||||
{
|
||||
pawn = cachedEntries[i].pawn;
|
||||
}
|
||||
if (num == to)
|
||||
{
|
||||
pawn2 = cachedEntries[i].pawn;
|
||||
}
|
||||
pawn3 = cachedEntries[i].pawn;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if (pawn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int num2 = pawn2?.playerSettings.displayOrder ?? (pawn3.playerSettings.displayOrder + 1);
|
||||
for (int j = 0; j < cachedEntries.Count; j++)
|
||||
{
|
||||
Pawn pawn4 = cachedEntries[j].pawn;
|
||||
if (pawn4 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pawn4.playerSettings.displayOrder == num2)
|
||||
{
|
||||
if (pawn2 != null && cachedEntries[j].group == entryGroup)
|
||||
{
|
||||
pawn4.playerSettings.displayOrder++;
|
||||
}
|
||||
}
|
||||
else if (pawn4.playerSettings.displayOrder > num2)
|
||||
{
|
||||
pawn4.playerSettings.displayOrder++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pawn4.playerSettings.displayOrder--;
|
||||
}
|
||||
}
|
||||
pawn.playerSettings.displayOrder = num2;
|
||||
MarkColonistsDirty();
|
||||
MainTabWindowUtility.NotifyAllPawnTables_PawnsChanged();
|
||||
}
|
||||
|
||||
public void DrawColonistMouseAttachment(int index, Vector2 dragStartPos, int entryGroup)
|
||||
{
|
||||
Pawn pawn = null;
|
||||
Vector2 vector = default(Vector2);
|
||||
int num = 0;
|
||||
for (int i = 0; i < cachedEntries.Count; i++)
|
||||
{
|
||||
if (cachedEntries[i].group == entryGroup && cachedEntries[i].pawn != null)
|
||||
{
|
||||
if (num == index)
|
||||
{
|
||||
pawn = cachedEntries[i].pawn;
|
||||
vector = cachedDrawLocs[i];
|
||||
break;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if (pawn != null)
|
||||
{
|
||||
RenderTexture iconTex = PortraitsCache.Get(pawn, ColonistBarColonistDrawer.PawnTextureSize, Rot4.South, ColonistBarColonistDrawer.PawnTextureCameraOffset, 1.28205f);
|
||||
Rect rect = new Rect(vector.x, vector.y, Size.x, Size.y);
|
||||
Rect pawnTextureRect = drawer.GetPawnTextureRect(rect.position);
|
||||
pawnTextureRect.position += Event.current.mousePosition - dragStartPos;
|
||||
Rect? customRect = pawnTextureRect;
|
||||
GenUI.DrawMouseAttachment(iconTex, "", 0f, default(Vector2), customRect);
|
||||
}
|
||||
}
|
||||
|
||||
public bool AnyColonistOrCorpseAt(Vector2 pos)
|
||||
{
|
||||
if (!TryGetEntryAt(pos, out var entry))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return entry.pawn != null;
|
||||
}
|
||||
|
||||
public bool TryGetEntryAt(Vector2 pos, out Entry entry)
|
||||
{
|
||||
List<Vector2> drawLocs = DrawLocs;
|
||||
List<Entry> entries = Entries;
|
||||
Vector2 size = Size;
|
||||
for (int i = 0; i < drawLocs.Count; i++)
|
||||
{
|
||||
if (new Rect(drawLocs[i].x, drawLocs[i].y, size.x, size.y).Contains(pos))
|
||||
{
|
||||
entry = entries[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
entry = default(Entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Pawn> GetColonistsInOrder()
|
||||
{
|
||||
List<Entry> entries = Entries;
|
||||
tmpColonistsInOrder.Clear();
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
if (entries[i].pawn != null)
|
||||
{
|
||||
tmpColonistsInOrder.Add(entries[i].pawn);
|
||||
}
|
||||
}
|
||||
return tmpColonistsInOrder;
|
||||
}
|
||||
|
||||
public List<Thing> ColonistsOrCorpsesInScreenRect(Rect rect)
|
||||
{
|
||||
List<Vector2> drawLocs = DrawLocs;
|
||||
List<Entry> entries = Entries;
|
||||
Vector2 size = Size;
|
||||
tmpColonistsWithMap.Clear();
|
||||
for (int i = 0; i < drawLocs.Count; i++)
|
||||
{
|
||||
if (rect.Overlaps(new Rect(drawLocs[i].x, drawLocs[i].y, size.x, size.y)))
|
||||
{
|
||||
Pawn pawn = entries[i].pawn;
|
||||
if (pawn != null)
|
||||
{
|
||||
Thing first = ((!pawn.Dead || pawn.Corpse == null || !pawn.Corpse.SpawnedOrAnyParentSpawned) ? ((Thing)pawn) : ((Thing)pawn.Corpse));
|
||||
tmpColonistsWithMap.Add(new Pair<Thing, Map>(first, entries[i].map));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (WorldRendererUtility.WorldSelected && tmpColonistsWithMap.Any((Pair<Thing, Map> x) => x.Second == null))
|
||||
{
|
||||
tmpColonistsWithMap.RemoveAll((Pair<Thing, Map> x) => x.Second != null);
|
||||
}
|
||||
else if (tmpColonistsWithMap.Any((Pair<Thing, Map> x) => x.Second == Find.CurrentMap))
|
||||
{
|
||||
tmpColonistsWithMap.RemoveAll((Pair<Thing, Map> x) => x.Second != Find.CurrentMap);
|
||||
}
|
||||
tmpColonists.Clear();
|
||||
for (int j = 0; j < tmpColonistsWithMap.Count; j++)
|
||||
{
|
||||
tmpColonists.Add(tmpColonistsWithMap[j].First);
|
||||
}
|
||||
tmpColonistsWithMap.Clear();
|
||||
return tmpColonists;
|
||||
}
|
||||
|
||||
public List<Thing> MapColonistsOrCorpsesInScreenRect(Rect rect)
|
||||
{
|
||||
tmpMapColonistsOrCorpsesInScreenRect.Clear();
|
||||
if (!Visible)
|
||||
{
|
||||
return tmpMapColonistsOrCorpsesInScreenRect;
|
||||
}
|
||||
List<Thing> list = ColonistsOrCorpsesInScreenRect(rect);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (list[i].Spawned)
|
||||
{
|
||||
tmpMapColonistsOrCorpsesInScreenRect.Add(list[i]);
|
||||
}
|
||||
}
|
||||
return tmpMapColonistsOrCorpsesInScreenRect;
|
||||
}
|
||||
|
||||
public List<Pawn> CaravanMembersInScreenRect(Rect rect)
|
||||
{
|
||||
tmpCaravanPawns.Clear();
|
||||
if (!Visible)
|
||||
{
|
||||
return tmpCaravanPawns;
|
||||
}
|
||||
List<Thing> list = ColonistsOrCorpsesInScreenRect(rect);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (list[i] is Pawn pawn && pawn.IsCaravanMember())
|
||||
{
|
||||
tmpCaravanPawns.Add(pawn);
|
||||
}
|
||||
}
|
||||
return tmpCaravanPawns;
|
||||
}
|
||||
|
||||
public List<Caravan> CaravanMembersCaravansInScreenRect(Rect rect)
|
||||
{
|
||||
tmpCaravans.Clear();
|
||||
if (!Visible)
|
||||
{
|
||||
return tmpCaravans;
|
||||
}
|
||||
List<Pawn> list = CaravanMembersInScreenRect(rect);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
tmpCaravans.Add(list[i].GetCaravan());
|
||||
}
|
||||
return tmpCaravans;
|
||||
}
|
||||
|
||||
public Caravan CaravanMemberCaravanAt(Vector2 at)
|
||||
{
|
||||
if (!Visible)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (ColonistOrCorpseAt(at) is Pawn pawn && pawn.IsCaravanMember())
|
||||
{
|
||||
return pawn.GetCaravan();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Thing ColonistOrCorpseAt(Vector2 pos)
|
||||
{
|
||||
if (!Visible)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!TryGetEntryAt(pos, out var entry))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Pawn pawn = entry.pawn;
|
||||
if (pawn != null && pawn.Dead && pawn.Corpse != null && pawn.Corpse.SpawnedOrAnyParentSpawned)
|
||||
{
|
||||
return pawn.Corpse;
|
||||
}
|
||||
return pawn;
|
||||
}
|
||||
}
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
根据向量相似度分析,与 'WorkGiver_HaulToBiosculpterPod, CompBiosculpterPod' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_HaulToBiosculpterPod.txt`
|
||||
|
||||
```csharp
|
||||
public class WorkGiver_HaulToBiosculpterPod : WorkGiver_Scanner
|
||||
{
|
||||
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDefOf.BiosculpterPod);
|
||||
|
||||
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||
|
||||
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
if (!ModLister.CheckIdeology("Biosculpting"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!pawn.CanReserve(t, 1, -1, null, forced))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pawn.Map.designationManager.DesignationOn(t, DesignationDefOf.Deconstruct) != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
CompBiosculpterPod compBiosculpterPod = t.TryGetComp<CompBiosculpterPod>();
|
||||
if (compBiosculpterPod == null || !compBiosculpterPod.PowerOn || compBiosculpterPod.State != 0 || (!forced && !compBiosculpterPod.autoLoadNutrition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (t.IsBurning())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (compBiosculpterPod.RequiredNutritionRemaining > 0f)
|
||||
{
|
||||
if (FindNutrition(pawn, compBiosculpterPod).Thing == null)
|
||||
{
|
||||
JobFailReason.Is("NoFood".Translate());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
CompBiosculpterPod compBiosculpterPod = t.TryGetComp<CompBiosculpterPod>();
|
||||
if (compBiosculpterPod == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (compBiosculpterPod.RequiredNutritionRemaining > 0f)
|
||||
{
|
||||
ThingCount thingCount = FindNutrition(pawn, compBiosculpterPod);
|
||||
if (thingCount.Thing != null)
|
||||
{
|
||||
Job job = HaulAIUtility.HaulToContainerJob(pawn, thingCount.Thing, t);
|
||||
job.count = Mathf.Min(job.count, thingCount.Count);
|
||||
return job;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ThingCount FindNutrition(Pawn pawn, CompBiosculpterPod pod)
|
||||
{
|
||||
Thing thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.FoodSourceNotPlantOrTree), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 9999f, Validator);
|
||||
if (thing == null)
|
||||
{
|
||||
return default(ThingCount);
|
||||
}
|
||||
int b = Mathf.CeilToInt(pod.RequiredNutritionRemaining / thing.GetStatValue(StatDefOf.Nutrition));
|
||||
return new ThingCount(thing, Mathf.Min(thing.stackCount, b));
|
||||
bool Validator(Thing x)
|
||||
{
|
||||
if (x.IsForbidden(pawn) || !pawn.CanReserve(x))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!pod.CanAcceptNutrition(x))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
881
MCP/vector_cache/CompProperties_Refuelable.txt
Normal file
881
MCP/vector_cache/CompProperties_Refuelable.txt
Normal file
@@ -0,0 +1,881 @@
|
||||
根据向量相似度分析,与 'CompProperties_Refuelable' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompProperties_Refuelable.txt`
|
||||
|
||||
```csharp
|
||||
public class CompProperties_Refuelable : CompProperties
|
||||
{
|
||||
public float fuelConsumptionRate = 1f;
|
||||
|
||||
public float fuelCapacity = 2f;
|
||||
|
||||
public float initialFuelPercent;
|
||||
|
||||
public float autoRefuelPercent = 0.3f;
|
||||
|
||||
public float fuelConsumptionPerTickInRain;
|
||||
|
||||
public ThingFilter fuelFilter;
|
||||
|
||||
public bool destroyOnNoFuel;
|
||||
|
||||
public bool consumeFuelOnlyWhenUsed;
|
||||
|
||||
public bool consumeFuelOnlyWhenPowered;
|
||||
|
||||
public bool showFuelGizmo;
|
||||
|
||||
public bool initialAllowAutoRefuel = true;
|
||||
|
||||
public bool showAllowAutoRefuelToggle;
|
||||
|
||||
public bool allowRefuelIfNotEmpty = true;
|
||||
|
||||
public bool fuelIsMortarBarrel;
|
||||
|
||||
public bool targetFuelLevelConfigurable;
|
||||
|
||||
public float initialConfigurableTargetFuelLevel;
|
||||
|
||||
public bool drawOutOfFuelOverlay = true;
|
||||
|
||||
public float minimumFueledThreshold;
|
||||
|
||||
public bool drawFuelGaugeInMap;
|
||||
|
||||
public bool atomicFueling;
|
||||
|
||||
private float fuelMultiplier = 1f;
|
||||
|
||||
public bool factorByDifficulty;
|
||||
|
||||
[MustTranslate]
|
||||
public string fuelLabel;
|
||||
|
||||
[MustTranslate]
|
||||
public string fuelGizmoLabel;
|
||||
|
||||
[MustTranslate]
|
||||
public string outOfFuelMessage;
|
||||
|
||||
[NoTranslate]
|
||||
public string fuelIconPath;
|
||||
|
||||
public bool externalTicking;
|
||||
|
||||
public bool hideGizmosIfNotPlayerFaction;
|
||||
|
||||
public bool functionsInVacuum = true;
|
||||
|
||||
private Texture2D fuelIcon;
|
||||
|
||||
public string FuelLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fuelLabel.NullOrEmpty())
|
||||
{
|
||||
return "Fuel".TranslateSimple();
|
||||
}
|
||||
return fuelLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public string FuelGizmoLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fuelGizmoLabel.NullOrEmpty())
|
||||
{
|
||||
return "Fuel".TranslateSimple();
|
||||
}
|
||||
return fuelGizmoLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public Texture2D FuelIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fuelIcon == null)
|
||||
{
|
||||
if (!fuelIconPath.NullOrEmpty())
|
||||
{
|
||||
fuelIcon = ContentFinder<Texture2D>.Get(fuelIconPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThingDef thingDef = ((fuelFilter.AnyAllowedDef == null) ? ThingDefOf.Chemfuel : fuelFilter.AnyAllowedDef);
|
||||
fuelIcon = thingDef.uiIcon;
|
||||
}
|
||||
}
|
||||
return fuelIcon;
|
||||
}
|
||||
}
|
||||
|
||||
public float FuelMultiplierCurrentDifficulty
|
||||
{
|
||||
get
|
||||
{
|
||||
if (factorByDifficulty && Find.Storyteller?.difficulty != null)
|
||||
{
|
||||
return fuelMultiplier / Find.Storyteller.difficulty.maintenanceCostFactor;
|
||||
}
|
||||
return fuelMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
public CompProperties_Refuelable()
|
||||
{
|
||||
compClass = typeof(CompRefuelable);
|
||||
}
|
||||
|
||||
public override void ResolveReferences(ThingDef parentDef)
|
||||
{
|
||||
base.ResolveReferences(parentDef);
|
||||
fuelFilter.ResolveReferences();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(ThingDef parentDef)
|
||||
{
|
||||
foreach (string item in base.ConfigErrors(parentDef))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (destroyOnNoFuel && initialFuelPercent <= 0f)
|
||||
{
|
||||
yield return "Refuelable component has destroyOnNoFuel, but initialFuelPercent <= 0";
|
||||
}
|
||||
if ((!consumeFuelOnlyWhenUsed || fuelConsumptionPerTickInRain > 0f) && parentDef.tickerType != TickerType.Normal)
|
||||
{
|
||||
yield return $"Refuelable component set to consume fuel per tick, but parent tickertype is {parentDef.tickerType} instead of {TickerType.Normal}";
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<StatDrawEntry> SpecialDisplayStats(StatRequest req)
|
||||
{
|
||||
foreach (StatDrawEntry item in base.SpecialDisplayStats(req))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (((ThingDef)req.Def).building.IsTurret)
|
||||
{
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Building, "ShotsBeforeRearm".Translate(), ((int)fuelCapacity).ToString(), "ShotsBeforeRearmExplanation".Translate(), 3171);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompRefuelable.txt`
|
||||
**相似度:** 0.7548
|
||||
|
||||
```csharp
|
||||
public class CompRefuelable : ThingComp_VacuumAware, IThingGlower
|
||||
{
|
||||
private float fuel;
|
||||
|
||||
private float configuredTargetFuelLevel = -1f;
|
||||
|
||||
public bool allowAutoRefuel = true;
|
||||
|
||||
private CompFlickable flickComp;
|
||||
|
||||
private CompExplosive explosiveComp;
|
||||
|
||||
public const string RefueledSignal = "Refueled";
|
||||
|
||||
public const string RanOutOfFuelSignal = "RanOutOfFuel";
|
||||
|
||||
private static readonly Texture2D SetTargetFuelLevelCommand = ContentFinder<Texture2D>.Get("UI/Commands/SetTargetFuelLevel");
|
||||
|
||||
private static readonly Vector2 FuelBarSize = new Vector2(1f, 0.2f);
|
||||
|
||||
private static readonly Material FuelBarFilledMat = SolidColorMaterials.SimpleSolidColorMaterial(new Color(0.6f, 0.56f, 0.13f));
|
||||
|
||||
private static readonly Material FuelBarUnfilledMat = SolidColorMaterials.SimpleSolidColorMaterial(new Color(0.3f, 0.3f, 0.3f));
|
||||
|
||||
protected override bool FunctionsInVacuum => Props.functionsInVacuum;
|
||||
|
||||
public float TargetFuelLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (configuredTargetFuelLevel >= 0f)
|
||||
{
|
||||
return configuredTargetFuelLevel;
|
||||
}
|
||||
if (Props.targetFuelLevelConfigurable)
|
||||
{
|
||||
return Props.initialConfigurableTargetFuelLevel;
|
||||
}
|
||||
return Props.fuelCapacity;
|
||||
}
|
||||
set
|
||||
{
|
||||
configuredTargetFuelLevel = Mathf.Clamp(value, 0f, Props.fuelCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
public CompProperties_Refuelable Props => (CompProperties_Refuelable)props;
|
||||
|
||||
public float Fuel => fuel;
|
||||
|
||||
public float FuelPercentOfTarget => fuel / TargetFuelLevel;
|
||||
|
||||
public float FuelPercentOfMax => fuel / Props.fuelCapacity;
|
||||
|
||||
public bool IsFull => TargetFuelLevel - fuel < 1f;
|
||||
|
||||
public bool HasFuel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fuel > 0f && fuel >= Props.minimumFueledThreshold)
|
||||
{
|
||||
if (!FunctionsInVacuum)
|
||||
{
|
||||
return !base.InVacuum;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private float ConsumptionRatePerTick => Props.fuelConsumptionRate / 60000f;
|
||||
|
||||
public bool ShouldAutoRefuelNow
|
||||
{
|
||||
get
|
||||
{
|
||||
if (FuelPercentOfTarget <= Props.autoRefuelPercent && !IsFull && TargetFuelLevel > 0f)
|
||||
{
|
||||
return ShouldAutoRefuelNowIgnoringFuelPct;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldAutoRefuelNowIgnoringFuelPct
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!parent.IsBurning() && (flickComp == null || flickComp.SwitchIsOn) && parent.Map.designationManager.DesignationOn(parent, DesignationDefOf.Flick) == null)
|
||||
{
|
||||
return parent.Map.designationManager.DesignationOn(parent, DesignationDefOf.Deconstruct) == null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldBeLitNow()
|
||||
{
|
||||
return HasFuel;
|
||||
}
|
||||
|
||||
public override void Initialize(CompProperties props)
|
||||
{
|
||||
base.Initialize(props);
|
||||
allowAutoRefuel = Props.initialAllowAutoRefuel;
|
||||
fuel = Props.fuelCapacity * Props.initialFuelPercent;
|
||||
}
|
||||
|
||||
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||
{
|
||||
flickComp = parent.GetComp<CompFlickable>();
|
||||
explosiveComp = parent.GetComp<CompExplosive>();
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
Scribe_Values.Look(ref fuel, "fuel", 0f);
|
||||
Scribe_Values.Look(ref configuredTargetFuelLevel, "configuredTargetFuelLevel", -1f);
|
||||
Scribe_Values.Look(ref allowAutoRefuel, "allowAutoRefuel", defaultValue: false);
|
||||
if (Scribe.mode == LoadSaveMode.PostLoadInit && !Props.showAllowAutoRefuelToggle)
|
||||
{
|
||||
allowAutoRefuel = Props.initialAllowAutoRefuel;
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostDraw()
|
||||
{
|
||||
base.PostDraw();
|
||||
if (!allowAutoRefuel)
|
||||
{
|
||||
parent.Map.overlayDrawer.DrawOverlay(parent, OverlayTypes.ForbiddenRefuel);
|
||||
}
|
||||
else if (!HasFuel && Props.drawOutOfFuelOverlay)
|
||||
{
|
||||
parent.Map.overlayDrawer.DrawOverlay(parent, OverlayTypes.OutOfFuel);
|
||||
}
|
||||
if (Props.drawFuelGaugeInMap)
|
||||
{
|
||||
GenDraw.FillableBarRequest r = default(GenDraw.FillableBarRequest);
|
||||
r.center = parent.DrawPos + Vector3.up * 0.1f;
|
||||
r.size = FuelBarSize;
|
||||
r.fillPercent = FuelPercentOfMax;
|
||||
r.filledMat = FuelBarFilledMat;
|
||||
r.unfilledMat = FuelBarUnfilledMat;
|
||||
r.margin = 0.15f;
|
||||
Rot4 rotation = parent.Rotation;
|
||||
rotation.Rotate(RotationDirection.Clockwise);
|
||||
r.rotation = rotation;
|
||||
GenDraw.DrawFillableBar(r);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostDestroy(DestroyMode mode, Map previousMap)
|
||||
{
|
||||
base.PostDestroy(mode, previousMap);
|
||||
if ((!Props.fuelIsMortarBarrel || !Find.Storyteller.difficulty.classicMortars) && mode != 0 && previousMap != null && Props.fuelFilter.AllowedDefCount == 1 && Props.initialFuelPercent == 0f)
|
||||
{
|
||||
ThingDef thingDef = Props.fuelFilter.AllowedThingDefs.First();
|
||||
int num = Mathf.FloorToInt(1f * fuel);
|
||||
while (num > 0)
|
||||
{
|
||||
Thing thing = ThingMaker.MakeThing(thingDef);
|
||||
thing.stackCount = Mathf.Min(num, thingDef.stackLimit);
|
||||
num -= thing.stackCount;
|
||||
GenPlace.TryPlaceThing(thing, parent.Position, previousMap, ThingPlaceMode.Near);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string CompInspectStringExtra()
|
||||
{
|
||||
if (Props.fuelIsMortarBarrel && Find.Storyteller.difficulty.classicMortars)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
string text = base.CompInspectStringExtra();
|
||||
text = ((text != null) ? (text + "\n") : string.Empty);
|
||||
text = text + Props.FuelLabel + ": " + fuel.ToStringDecimalIfSmall() + " / " + Props.fuelCapacity.ToStringDecimalIfSmall();
|
||||
if (!Props.consumeFuelOnlyWhenUsed && HasFuel)
|
||||
{
|
||||
int numTicks = (int)(fuel / Props.fuelConsumptionRate * 60000f);
|
||||
text = text + " (" + numTicks.ToStringTicksToPeriod() + ")";
|
||||
}
|
||||
if (!HasFuel && !Props.outOfFuelMessage.NullOrEmpty())
|
||||
{
|
||||
string arg = ((parent.def.building != null && parent.def.building.IsTurret) ? ("CannotShoot".Translate() + ": " + Props.outOfFuelMessage).Resolve() : Props.outOfFuelMessage);
|
||||
text += $"\n{arg} ({GetFuelCountToFullyRefuel()}x {Props.fuelFilter.AnyAllowedDef.label})";
|
||||
}
|
||||
if (Props.targetFuelLevelConfigurable)
|
||||
{
|
||||
text += "\n" + "ConfiguredTargetFuelLevel".Translate(TargetFuelLevel.ToStringDecimalIfSmall());
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public override IEnumerable<StatDrawEntry> SpecialDisplayStats()
|
||||
{
|
||||
if (parent.def.building != null && parent.def.building.IsTurret)
|
||||
{
|
||||
TaggedString taggedString = "RearmCostExplanation".Translate();
|
||||
if (Props.factorByDifficulty)
|
||||
{
|
||||
taggedString += " (" + "RearmCostExplanationDifficulty".Translate() + ")";
|
||||
}
|
||||
taggedString += ".";
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.Building, "RearmCost".Translate(), GenLabel.ThingLabel(Props.fuelFilter.AnyAllowedDef, null, GetFuelCountToFullyRefuel()).CapitalizeFirst(), taggedString, 3171);
|
||||
}
|
||||
}
|
||||
|
||||
public override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
CompPowerTrader comp = parent.GetComp<CompPowerTrader>();
|
||||
if (!Props.consumeFuelOnlyWhenUsed && (flickComp == null || flickComp.SwitchIsOn) && (!Props.consumeFuelOnlyWhenPowered || (comp != null && comp.PowerOn)) && !Props.externalTicking)
|
||||
{
|
||||
ConsumeFuel(ConsumptionRatePerTick);
|
||||
}
|
||||
if (Props.fuelConsumptionPerTickInRain > 0f && parent.Spawned && parent.Map.weatherManager.RainRate > 0.4f && !parent.Map.roofGrid.Roofed(parent.Position) && !Props.externalTicking)
|
||||
{
|
||||
ConsumeFuel(Props.fuelConsumptionPerTickInRain);
|
||||
}
|
||||
}
|
||||
|
||||
public void ConsumeFuel(float amount)
|
||||
{
|
||||
if ((!Props.fuelIsMortarBarrel || !Find.Storyteller.difficulty.classicMortars) && !(fuel <= 0f))
|
||||
{
|
||||
fuel -= amount;
|
||||
if (fuel <= 0f)
|
||||
{
|
||||
fuel = 0f;
|
||||
Notify_RanOutOfFuel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Notify_RanOutOfFuel()
|
||||
{
|
||||
if (Props.destroyOnNoFuel)
|
||||
{
|
||||
parent.Destroy();
|
||||
}
|
||||
parent.BroadcastCompSignal("RanOutOfFuel");
|
||||
}
|
||||
|
||||
public void Refuel(List<Thing> fuelThings)
|
||||
{
|
||||
if (Props.atomicFueling && fuelThings.Sum((Thing t) => t.stackCount) < GetFuelCountToFullyRefuel())
|
||||
{
|
||||
Log.ErrorOnce("Error refueling; not enough fuel available for proper atomic refuel", 19586442);
|
||||
return;
|
||||
}
|
||||
int num = GetFuelCountToFullyRefuel();
|
||||
while (num > 0 && fuelThings.Count > 0)
|
||||
{
|
||||
Thing thing = fuelThings.Pop();
|
||||
int num2 = Mathf.Min(num, thing.stackCount);
|
||||
Refuel(num2);
|
||||
thing.SplitOff(num2).Destroy();
|
||||
num -= num2;
|
||||
}
|
||||
}
|
||||
|
||||
public void Refuel(float amount)
|
||||
{
|
||||
fuel += amount * Props.FuelMultiplierCurrentDifficulty;
|
||||
if (fuel > Props.fuelCapacity)
|
||||
{
|
||||
fuel = Props.fuelCapacity;
|
||||
}
|
||||
parent.BroadcastCompSignal("Refueled");
|
||||
}
|
||||
|
||||
public AcceptanceReport CanEjectFuel()
|
||||
{
|
||||
CompExplosive compExplosive = explosiveComp;
|
||||
if (compExplosive != null && compExplosive.wickStarted)
|
||||
{
|
||||
return "AboutToExplode".Translate();
|
||||
}
|
||||
if (Fuel == 0f)
|
||||
{
|
||||
return "RefuelableNoFuelToEject".Translate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void EjectFuel()
|
||||
{
|
||||
ThingDef thingDef = Props.fuelFilter.AllowedThingDefs.First();
|
||||
int num = Mathf.FloorToInt(fuel);
|
||||
while (num > 0)
|
||||
{
|
||||
Thing thing = ThingMaker.MakeThing(thingDef);
|
||||
thing.stackCount = Mathf.Min(num, thingDef.stackLimit);
|
||||
num -= thing.stackCount;
|
||||
GenPlace.TryPlaceThing(thing, parent.Position, parent.Map, ThingPlaceMode.Near);
|
||||
thing.SetForbidden(value: true);
|
||||
}
|
||||
fuel = 0f;
|
||||
Notify_RanOutOfFuel();
|
||||
}
|
||||
|
||||
public void Notify_UsedThisTick()
|
||||
{
|
||||
ConsumeFuel(ConsumptionRatePerTick);
|
||||
}
|
||||
|
||||
public int GetFuelCountToFullyRefuel()
|
||||
{
|
||||
if (Props.atomicFueling)
|
||||
{
|
||||
return Mathf.CeilToInt(Props.fuelCapacity / Props.FuelMultiplierCurrentDifficulty);
|
||||
}
|
||||
return Mathf.Max(Mathf.CeilToInt((TargetFuelLevel - fuel) / Props.FuelMultiplierCurrentDifficulty), 1);
|
||||
}
|
||||
|
||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||
{
|
||||
if (Props.fuelIsMortarBarrel && Find.Storyteller.difficulty.classicMortars)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
if (!Props.hideGizmosIfNotPlayerFaction || parent.Faction == Faction.OfPlayer)
|
||||
{
|
||||
if (Find.Selector.SelectedObjects.Count == 1)
|
||||
{
|
||||
yield return new Gizmo_SetFuelLevel(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Props.targetFuelLevelConfigurable)
|
||||
{
|
||||
Command_SetTargetFuelLevel command_SetTargetFuelLevel = new Command_SetTargetFuelLevel();
|
||||
command_SetTargetFuelLevel.refuelable = this;
|
||||
command_SetTargetFuelLevel.defaultLabel = "CommandSetTargetFuelLevel".Translate();
|
||||
command_SetTargetFuelLevel.defaultDesc = "CommandSetTargetFuelLevelDesc".Translate();
|
||||
command_SetTargetFuelLevel.icon = SetTargetFuelLevelCommand;
|
||||
yield return command_SetTargetFuelLevel;
|
||||
}
|
||||
if (Props.showAllowAutoRefuelToggle)
|
||||
{
|
||||
string str = (allowAutoRefuel ? "On".Translate() : "Off".Translate());
|
||||
Command_Toggle command_Toggle = new Command_Toggle();
|
||||
command_Toggle.isActive = () => allowAutoRefuel;
|
||||
command_Toggle.toggleAction = delegate
|
||||
{
|
||||
allowAutoRefuel = !allowAutoRefuel;
|
||||
};
|
||||
command_Toggle.defaultLabel = "CommandToggleAllowAutoRefuel".Translate();
|
||||
command_Toggle.defaultDesc = "CommandToggleAllowAutoRefuelDescMult".Translate(str.UncapitalizeFirst().Named("ONOFF"));
|
||||
command_Toggle.icon = (allowAutoRefuel ? TexCommand.ForbidOn : TexCommand.ForbidOff);
|
||||
command_Toggle.Order = 20f;
|
||||
command_Toggle.hotKey = KeyBindingDefOf.Command_ItemForbid;
|
||||
yield return command_Toggle;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DebugSettings.ShowDevGizmos)
|
||||
{
|
||||
Command_Action command_Action = new Command_Action();
|
||||
command_Action.defaultLabel = "DEV: Set fuel to 0";
|
||||
command_Action.action = delegate
|
||||
{
|
||||
fuel = 0f;
|
||||
parent.BroadcastCompSignal("Refueled");
|
||||
};
|
||||
yield return command_Action;
|
||||
Command_Action command_Action2 = new Command_Action();
|
||||
command_Action2.defaultLabel = "DEV: Set fuel to 0.1";
|
||||
command_Action2.action = delegate
|
||||
{
|
||||
fuel = 0.1f;
|
||||
parent.BroadcastCompSignal("Refueled");
|
||||
};
|
||||
yield return command_Action2;
|
||||
Command_Action command_Action3 = new Command_Action();
|
||||
command_Action3.defaultLabel = "DEV: Fuel -20%";
|
||||
command_Action3.action = delegate
|
||||
{
|
||||
ConsumeFuel(Props.fuelCapacity * 0.2f);
|
||||
};
|
||||
yield return command_Action3;
|
||||
Command_Action command_Action4 = new Command_Action();
|
||||
command_Action4.defaultLabel = "DEV: Set fuel to max";
|
||||
command_Action4.action = delegate
|
||||
{
|
||||
fuel = Props.fuelCapacity;
|
||||
parent.BroadcastCompSignal("Refueled");
|
||||
};
|
||||
yield return command_Action4;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Odyssey\Defs\ThingDefs_Buildings\Buildings_Gravship.xml`
|
||||
**相似度:** 0.5864
|
||||
|
||||
```xml
|
||||
<defName>ChemfuelTank</defName>
|
||||
<label>small chemfuel tank</label>
|
||||
<description>A chemfuel storage tank that supplies fuel for thrusters on a gravship.</description>
|
||||
<graphicData>
|
||||
<graphicClass>Graphic_Multi</graphicClass>
|
||||
<texPath>Things/Building/ChemfuelTank/ChemfuelTank</texPath>
|
||||
<drawSize>(2, 2)</drawSize>
|
||||
</graphicData>
|
||||
<statBases>
|
||||
<MaxHitPoints>200</MaxHitPoints>
|
||||
<Mass>30</Mass>
|
||||
<Flammability>1</Flammability>
|
||||
<Beauty>-10</Beauty>
|
||||
<WorkToBuild>2000</WorkToBuild>
|
||||
</statBases>
|
||||
<size>(2, 2)</size>
|
||||
<costList>
|
||||
<Steel>120</Steel>
|
||||
</costList>
|
||||
<researchPrerequisites>
|
||||
<li>BasicGravtech</li>
|
||||
</researchPrerequisites>
|
||||
<comps>
|
||||
<li Class="CompProperties_Refuelable">
|
||||
<fuelCapacity>250</fuelCapacity>
|
||||
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
|
||||
<initialConfigurableTargetFuelLevel>250</initialConfigurableTargetFuelLevel>
|
||||
<fuelFilter>
|
||||
<thingDefs>
|
||||
<li>Chemfuel</li>
|
||||
</thingDefs>
|
||||
</fuelFilter>
|
||||
<fuelLabel>Chemfuel</fuelLabel>
|
||||
<fuelGizmoLabel>Chemfuel</fuelGizmoLabel>
|
||||
<consumeFuelOnlyWhenUsed>true</consumeFuelOnlyWhenUsed>
|
||||
<autoRefuelPercent>1</autoRefuelPercent>
|
||||
<showFuelGizmo>true</showFuelGizmo>
|
||||
<drawOutOfFuelOverlay>false</drawOutOfFuelOverlay>
|
||||
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
|
||||
<canEjectFuel>true</canEjectFuel>
|
||||
<drawFuelGaugeInMap>false</drawFuelGaugeInMap>
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
|
||||
<ThingDef ParentName="FuelTankBase">
|
||||
<defName>LargeChemfuelTank</defName>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\ThingDefs_Buildings\Buildings_Power.xml`
|
||||
**相似度:** 0.5793
|
||||
|
||||
```xml
|
||||
<defName>WoodFiredGenerator</defName>
|
||||
<label>wood-fired generator</label>
|
||||
<description>Produces power by consuming wood. Must be periodically loaded with wood fuel by hand.</description>
|
||||
<thingClass>Building</thingClass>
|
||||
<drawerType>MapMeshAndRealTime</drawerType>
|
||||
<graphicData>
|
||||
<texPath>Things/Building/Power/WoodFiredGenerator</texPath>
|
||||
<graphicClass>Graphic_Single</graphicClass>
|
||||
<drawSize>(2,2)</drawSize>
|
||||
<shadowData>
|
||||
<volume>(1.93,1,1.69)</volume>
|
||||
<offset>(-0.03,0,-0.1)</offset>
|
||||
</shadowData>
|
||||
</graphicData>
|
||||
<altitudeLayer>Building</altitudeLayer>
|
||||
<passability>PassThroughOnly</passability>
|
||||
<fillPercent>0.9</fillPercent>
|
||||
<pathCost>50</pathCost>
|
||||
<rotatable>false</rotatable>
|
||||
<blockWind>true</blockWind>
|
||||
<castEdgeShadows>false</castEdgeShadows>
|
||||
<statBases>
|
||||
<MaxHitPoints>300</MaxHitPoints>
|
||||
<WorkToBuild>2500</WorkToBuild>
|
||||
<Flammability>1.0</Flammability>
|
||||
<Beauty>-20</Beauty>
|
||||
</statBases>
|
||||
<tickerType>Normal</tickerType>
|
||||
<canOverlapZones>false</canOverlapZones>
|
||||
<size>(2,2)</size>
|
||||
<building>
|
||||
<destroySound>BuildingDestroyed_Metal_Medium</destroySound>
|
||||
</building>
|
||||
<costList>
|
||||
<Steel>100</Steel>
|
||||
<ComponentIndustrial>2</ComponentIndustrial>
|
||||
</costList>
|
||||
<comps>
|
||||
<li Class="CompProperties_Power">
|
||||
<compClass>CompPowerPlant</compClass>
|
||||
<basePowerConsumption>-1000</basePowerConsumption>
|
||||
<transmitsPower>true</transmitsPower>
|
||||
<soundAmbientProducingPower>WoodFiredGenerator_Ambience</soundAmbientProducingPower>
|
||||
</li>
|
||||
<li Class="CompProperties_Flickable"/>
|
||||
<li Class="CompProperties_Refuelable">
|
||||
<fuelConsumptionRate>22.0</fuelConsumptionRate>
|
||||
<fuelCapacity>75.0</fuelCapacity>
|
||||
<fuelFilter>
|
||||
<thingDefs>
|
||||
<li>WoodLog</li>
|
||||
</thingDefs>
|
||||
</fuelFilter>
|
||||
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
|
||||
<canEjectFuel>true</canEjectFuel>
|
||||
</li>
|
||||
<li Class="CompProperties_Glower">
|
||||
<glowRadius>6</glowRadius>
|
||||
<glowColor>(217,112,33,0)</glowColor>
|
||||
</li>
|
||||
<li Class="CompProperties_HeatPusher">
|
||||
<compClass>CompHeatPusherPowered</compClass>
|
||||
<heatPerSecond>6</heatPerSecond>
|
||||
</li>
|
||||
<li Class="CompProperties_Breakdownable"/>
|
||||
<li Class="CompProperties_Stunnable">
|
||||
<useLargeEMPEffecter>true</useLargeEMPEffecter>
|
||||
<affectedDamageDefs>
|
||||
<li>EMP</li>
|
||||
</affectedDamageDefs>
|
||||
</li>
|
||||
</comps>
|
||||
<terrainAffordanceNeeded>Medium</terrainAffordanceNeeded>
|
||||
<designationCategory>Power</designationCategory>
|
||||
<uiOrder>2100</uiOrder>
|
||||
<designationHotKey>Misc3</designationHotKey>
|
||||
<constructEffect>ConstructMetal</constructEffect>
|
||||
<researchPrerequisites>
|
||||
<li>Electricity</li>
|
||||
</researchPrerequisites>
|
||||
<constructionSkillPrerequisite>4</constructionSkillPrerequisite>
|
||||
</ThingDef>
|
||||
|
||||
<ThingDef ParentName="BuildingBase">
|
||||
<defName>ChemfuelPoweredGenerator</defName>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Biotech\Defs\ThingDefs_Buildings\Buildings_Deathrest.xml`
|
||||
**相似度:** 0.5764
|
||||
|
||||
```xml
|
||||
<ThingDef ParentName="DeathrestBuildingBase" Name="DeathrestBuildingHemogenFueled" Abstract="True">
|
||||
<comps>
|
||||
<li Class="CompProperties_Power">
|
||||
<compClass>CompPowerTrader</compClass>
|
||||
<basePowerConsumption>100</basePowerConsumption>
|
||||
<idlePowerDraw>0</idlePowerDraw>
|
||||
<alwaysDisplayAsUsingPower>true</alwaysDisplayAsUsingPower>
|
||||
</li>
|
||||
<li Class="CompProperties_Flickable"/>
|
||||
<li Class="CompProperties_Refuelable">
|
||||
<fuelConsumptionRate>0.5</fuelConsumptionRate> <!-- Empty in one year -->
|
||||
<fuelCapacity>5</fuelCapacity>
|
||||
<fuelLabel>Hemogen</fuelLabel>
|
||||
<fuelFilter>
|
||||
<thingDefs>
|
||||
<li>HemogenPack</li>
|
||||
</thingDefs>
|
||||
</fuelFilter>
|
||||
<initialFuelPercent>1</initialFuelPercent>
|
||||
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
|
||||
<externalTicking>true</externalTicking>
|
||||
<autoRefuelPercent>0.05</autoRefuelPercent>
|
||||
<canEjectFuel>true</canEjectFuel>
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\ThingDefs_Buildings\Buildings_Temperature.xml`
|
||||
**相似度:** 0.5668
|
||||
|
||||
```xml
|
||||
<soundImpactDefault>BulletImpact_Ground</soundImpactDefault>
|
||||
<leaveResourcesWhenKilled>false</leaveResourcesWhenKilled>
|
||||
<resourcesFractionWhenDeconstructed>0</resourcesFractionWhenDeconstructed>
|
||||
<placeWorkers>
|
||||
<li>PlaceWorker_PreventInteractionSpotOverlap</li>
|
||||
<li>PlaceWorker_Heater</li>
|
||||
<li>PlaceWorker_GlowRadius</li>
|
||||
</placeWorkers>
|
||||
<drawPlaceWorkersWhileSelected>true</drawPlaceWorkersWhileSelected>
|
||||
<comps>
|
||||
<li Class="CompProperties_Refuelable">
|
||||
<fuelConsumptionRate>10.0</fuelConsumptionRate>
|
||||
<fuelCapacity>20.0</fuelCapacity>
|
||||
<fuelConsumptionPerTickInRain>0.0006</fuelConsumptionPerTickInRain>
|
||||
<fuelFilter>
|
||||
<thingDefs>
|
||||
<li>WoodLog</li>
|
||||
</thingDefs>
|
||||
</fuelFilter>
|
||||
<initialFuelPercent>1</initialFuelPercent>
|
||||
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
|
||||
<functionsInVacuum>false</functionsInVacuum>
|
||||
</li>
|
||||
<li Class="CompProperties_Glower">
|
||||
<glowRadius>10</glowRadius>
|
||||
<glowColor>(252,187,113,0)</glowColor>
|
||||
</li>
|
||||
<li Class="CompProperties_HeatPusher">
|
||||
<compClass>CompHeatPusherPowered</compClass>
|
||||
<heatPerSecond>21</heatPerSecond>
|
||||
<heatPushMaxTemperature>28</heatPushMaxTemperature>
|
||||
</li>
|
||||
<li Class="CompProperties_FireOverlay">
|
||||
<fireSize>1</fireSize>
|
||||
</li>
|
||||
<li>
|
||||
<compClass>CompGatherSpot</compClass>
|
||||
</li>
|
||||
<li Class="CompProperties_MeditationFocus">
|
||||
<statDef>MeditationFocusStrength</statDef>
|
||||
<focusTypes><li>Flame</li></focusTypes>
|
||||
<offsets>
|
||||
<li Class="FocusStrengthOffset_Lit">
|
||||
<offset>0.12</offset>
|
||||
</li>
|
||||
<li Class="FocusStrengthOffset_BuildingDefsLit">
|
||||
<defs>
|
||||
<li>Campfire</li>
|
||||
<li>TorchLamp</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Royalty">Brazier</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Royalty,Ludeon.RimWorld.Ideology">DarklightBrazier</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Ideology">Darktorch</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Ideology">DarktorchFungus</li>
|
||||
</defs>
|
||||
<offsetPerBuilding>0.02</offsetPerBuilding>
|
||||
<radius>9.9</radius>
|
||||
<maxBuildings>8</maxBuildings>
|
||||
<explanationKey>MeditationFocusPerFlame</explanationKey>
|
||||
<explanationKeyAbstract>MeditationFocusPerFlameAbstract</explanationKeyAbstract>
|
||||
</li>
|
||||
</offsets>
|
||||
</li>
|
||||
</comps>
|
||||
<designationCategory>Temperature</designationCategory>
|
||||
<designationHotKey>Misc1</designationHotKey>
|
||||
<hasInteractionCell>True</hasInteractionCell>
|
||||
<interactionCellOffset>(0,0,-1)</interactionCellOffset>
|
||||
<recipes>
|
||||
<li>CookMealSimple</li>
|
||||
<li>CookMealSimpleBulk</li>
|
||||
<li>Make_Pemmican</li>
|
||||
<li>Make_PemmicanBulk</li>
|
||||
<li>BurnApparel</li>
|
||||
<li>BurnWeapon</li>
|
||||
<li>BurnDrugs</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">Make_BabyFood</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">Make_BabyFoodBulk</li>
|
||||
</recipes>
|
||||
<inspectorTabs>
|
||||
<li>ITab_Bills</li>
|
||||
</inspectorTabs>
|
||||
<building>
|
||||
<isMealSource>true</isMealSource>
|
||||
<spawnedConceptLearnOpportunity>BillsTab</spawnedConceptLearnOpportunity>
|
||||
<artificialForMeditationPurposes>false</artificialForMeditationPurposes>
|
||||
<destroySound>BuildingDestroyed_Wood_Small</destroySound>
|
||||
</building>
|
||||
</ThingDef>
|
||||
|
||||
<ThingDef ParentName="BuildingBase">
|
||||
<defName>PassiveCooler</defName>
|
||||
<label>passive cooler</label>
|
||||
<description>A traditional unpowered cooler that works by water evaporation. Must be regularly replenished with wood. Not efficient enough to refrigerate food.</description>
|
||||
<category>Building</category>
|
||||
<graphicData>
|
||||
<texPath>Things/Building/Misc/PassiveCooler</texPath>
|
||||
<graphicClass>Graphic_Single</graphicClass>
|
||||
<drawRotated>false</drawRotated>
|
||||
<allowFlip>false</allowFlip>
|
||||
<addTopAltitudeBias>true</addTopAltitudeBias>
|
||||
<shadowData>
|
||||
<volume>(0.9,0.3,0.9)</volume>
|
||||
</shadowData>
|
||||
<damageData>
|
||||
<rect>(0.2,0,0.6,0.1)</rect>
|
||||
</damageData>
|
||||
</graphicData>
|
||||
<rotatable>false</rotatable>
|
||||
<altitudeLayer>Building</altitudeLayer>
|
||||
<passability>PassThroughOnly</passability>
|
||||
<pathCost>30</pathCost>
|
||||
<constructEffect>ConstructDirt</constructEffect>
|
||||
<tickerType>Normal</tickerType>
|
||||
<drawerType>RealtimeOnly</drawerType>
|
||||
<fillPercent>0.40</fillPercent>
|
||||
<statBases>
|
||||
<MaxHitPoints>80</MaxHitPoints>
|
||||
<WorkToBuild>200</WorkToBuild>
|
||||
<Flammability>1</Flammability>
|
||||
</statBases>
|
||||
<selectable>true</selectable>
|
||||
<costList>
|
||||
<WoodLog>50</WoodLog>
|
||||
</costList>
|
||||
<building>
|
||||
<destroySound>BuildingDestroyed_Metal_Small</destroySound>
|
||||
</building>
|
||||
<soundImpactDefault>BulletImpact_Ground</soundImpactDefault>
|
||||
```
|
||||
267
MCP/vector_cache/CryptosleepCasket.txt
Normal file
267
MCP/vector_cache/CryptosleepCasket.txt
Normal file
@@ -0,0 +1,267 @@
|
||||
根据向量相似度分析,与 'CryptosleepCasket' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\RoomContents_CryptosleepCasket.txt`
|
||||
**相似度:** 0.7176
|
||||
|
||||
```csharp
|
||||
public class RoomContents_CryptosleepCasket : RoomContentsWorker
|
||||
{
|
||||
private const string OpenedSignal = "OpenedSignal";
|
||||
|
||||
public override void FillRoom(Map map, LayoutRoom room, Faction faction, float? threatPoints = null)
|
||||
{
|
||||
if (!room.TryGetRandomCellInRoom(map, out var cell, 3))
|
||||
{
|
||||
cell = room.rects[0].CenterCell;
|
||||
}
|
||||
int nextAncientCryptosleepCasketGroupID = Find.UniqueIDsManager.GetNextAncientCryptosleepCasketGroupID();
|
||||
PodContentsType type = Gen.RandomEnumValue<PodContentsType>(disallowFirstValue: true);
|
||||
Building_AncientCryptosleepCasket pod = RoomGenUtility.SpawnCryptoCasket(cell, map, Rot4.Random, nextAncientCryptosleepCasketGroupID, type, ThingSetMakerDefOf.MapGen_ScarlandsAncientPodContents);
|
||||
ThreatSignal = "OpenedSignal" + Find.UniqueIDsManager.GetNextSignalTagID();
|
||||
RoomGenUtility.SpawnOpenCryptoCasketSignal(pod, map, ThreatSignal);
|
||||
base.FillRoom(map, room, faction, threatPoints);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\Building_AncientCryptosleepPod.txt`
|
||||
**相似度:** 0.7115
|
||||
|
||||
```csharp
|
||||
public class Building_AncientCryptosleepPod : Building_AncientCryptosleepCasket
|
||||
{
|
||||
public override IEnumerable<FloatMenuOption> GetFloatMenuOptions(Pawn myPawn)
|
||||
{
|
||||
return Enumerable.Empty<FloatMenuOption>();
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\Building_AncientCryptosleepCasket.txt`
|
||||
**相似度:** 0.7023
|
||||
|
||||
```csharp
|
||||
public class Building_AncientCryptosleepCasket : Building_CryptosleepCasket
|
||||
{
|
||||
public int groupID = -1;
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref groupID, "groupID", 0);
|
||||
}
|
||||
|
||||
public override void PreApplyDamage(ref DamageInfo dinfo, out bool absorbed)
|
||||
{
|
||||
base.PreApplyDamage(ref dinfo, out absorbed);
|
||||
if (absorbed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!contentsKnown && innerContainer.Count > 0 && dinfo.Def.harmsHealth && dinfo.Instigator != null && dinfo.Instigator.Faction != null)
|
||||
{
|
||||
bool flag = false;
|
||||
foreach (Thing item in (IEnumerable<Thing>)innerContainer)
|
||||
{
|
||||
if (item is Pawn)
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
EjectContents();
|
||||
}
|
||||
}
|
||||
absorbed = false;
|
||||
}
|
||||
|
||||
public override void EjectContents()
|
||||
{
|
||||
bool num = contentsKnown;
|
||||
List<Thing> list = null;
|
||||
if (!num)
|
||||
{
|
||||
list = new List<Thing>();
|
||||
list.AddRange(innerContainer);
|
||||
list.AddRange(UnopenedCasketsInGroup().SelectMany((Building_AncientCryptosleepCasket c) => c.innerContainer));
|
||||
list.RemoveDuplicates();
|
||||
}
|
||||
base.EjectContents();
|
||||
if ((bool)ClaimableBy(Faction.OfPlayer))
|
||||
{
|
||||
SetFaction(null);
|
||||
}
|
||||
if (num)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ThingDef filth_Slime = ThingDefOf.Filth_Slime;
|
||||
FilthMaker.TryMakeFilth(base.Position, base.Map, filth_Slime, Rand.Range(8, 12));
|
||||
foreach (Building_AncientCryptosleepCasket item in UnopenedCasketsInGroup())
|
||||
{
|
||||
item.contentsKnown = true;
|
||||
item.EjectContents();
|
||||
}
|
||||
IEnumerable<Pawn> enumerable = from p in list.OfType<Pawn>().ToList()
|
||||
where p.RaceProps.Humanlike && p.GetLord() == null && p.Faction == Faction.OfAncientsHostile
|
||||
select p;
|
||||
if (enumerable.Any())
|
||||
{
|
||||
LordMaker.MakeNewLord(Faction.OfAncientsHostile, new LordJob_AssaultColony(Faction.OfAncientsHostile, canKidnap: false, canTimeoutOrFlee: true, sappers: false, useAvoidGridSmart: false, canSteal: false), base.Map, enumerable);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Building_AncientCryptosleepCasket> UnopenedCasketsInGroup()
|
||||
{
|
||||
yield return this;
|
||||
if (groupID == -1)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (Thing item in base.Map.listerThings.ThingsOfDef(ThingDefOf.AncientCryptosleepCasket))
|
||||
{
|
||||
Building_AncientCryptosleepCasket building_AncientCryptosleepCasket = item as Building_AncientCryptosleepCasket;
|
||||
if (building_AncientCryptosleepCasket.groupID == groupID && !building_AncientCryptosleepCasket.contentsKnown)
|
||||
{
|
||||
yield return building_AncientCryptosleepCasket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\ComplexThreatWorker_CryptosleepPods.txt`
|
||||
**相似度:** 0.6424
|
||||
|
||||
```csharp
|
||||
public class ComplexThreatWorker_CryptosleepPods : ComplexThreatWorker
|
||||
{
|
||||
private const string TriggerOpenAction = "TriggerOpenAction";
|
||||
|
||||
private const string CompletedOpenAction = "CompletedOpenAction";
|
||||
|
||||
private const float RoomEntryTriggerChance = 0.25f;
|
||||
|
||||
protected override bool CanResolveInt(ComplexResolveParams parms)
|
||||
{
|
||||
if (base.CanResolveInt(parms) && ComplexUtility.TryFindRandomSpawnCell(ThingDefOf.AncientCryptosleepPod, parms.room, parms.map, out var _) && parms.points >= PawnKindDefOf.AncientSoldier.combatPower)
|
||||
{
|
||||
if (parms.hostileFaction != null)
|
||||
{
|
||||
return parms.hostileFaction == Faction.OfAncientsHostile;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void ResolveInt(ComplexResolveParams parms, ref float threatPointsUsed, List<Thing> outSpawnedThings)
|
||||
{
|
||||
List<Thing> list = SpawnCasketsWithHostiles(parms.room, parms.points, parms.triggerSignal, parms.map);
|
||||
SignalAction_OpenCasket signalAction_OpenCasket = (SignalAction_OpenCasket)ThingMaker.MakeThing(ThingDefOf.SignalAction_OpenCasket);
|
||||
signalAction_OpenCasket.signalTag = parms.triggerSignal;
|
||||
signalAction_OpenCasket.caskets.AddRange(list);
|
||||
signalAction_OpenCasket.completedSignalTag = "CompletedOpenAction" + Find.UniqueIDsManager.GetNextSignalTagID();
|
||||
if (parms.delayTicks.HasValue)
|
||||
{
|
||||
signalAction_OpenCasket.delayTicks = parms.delayTicks.Value;
|
||||
SignalAction_Message obj = (SignalAction_Message)ThingMaker.MakeThing(ThingDefOf.SignalAction_Message);
|
||||
obj.signalTag = parms.triggerSignal;
|
||||
obj.lookTargets = list;
|
||||
obj.messageType = MessageTypeDefOf.ThreatBig;
|
||||
obj.message = "MessageSleepingThreatDelayActivated".Translate(Faction.OfAncientsHostile, signalAction_OpenCasket.delayTicks.ToStringTicksToPeriod());
|
||||
GenSpawn.Spawn(obj, parms.room.rects[0].CenterCell, parms.map);
|
||||
}
|
||||
GenSpawn.Spawn(signalAction_OpenCasket, parms.map.Center, parms.map);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (!(list[i] is Building_Casket building_Casket))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (Thing item in (IEnumerable<Thing>)building_Casket.GetDirectlyHeldThings())
|
||||
{
|
||||
if (item is Pawn pawn)
|
||||
{
|
||||
threatPointsUsed += pawn.kindDef.combatPower;
|
||||
}
|
||||
}
|
||||
}
|
||||
SignalAction_Message obj2 = (SignalAction_Message)ThingMaker.MakeThing(ThingDefOf.SignalAction_Message);
|
||||
obj2.signalTag = signalAction_OpenCasket.completedSignalTag;
|
||||
obj2.lookTargets = list;
|
||||
obj2.messageType = MessageTypeDefOf.ThreatBig;
|
||||
obj2.message = "MessageSleepingPawnsWokenUp".Translate(Faction.OfAncientsHostile.def.pawnsPlural.CapitalizeFirst());
|
||||
GenSpawn.Spawn(obj2, parms.room.rects[0].CenterCell, parms.map);
|
||||
}
|
||||
|
||||
private List<Thing> SpawnCasketsWithHostiles(LayoutRoom room, float threatPoints, string openSignal, Map map)
|
||||
{
|
||||
int num = Mathf.FloorToInt(threatPoints / PawnKindDefOf.AncientSoldier.combatPower);
|
||||
List<Thing> list = new List<Thing>();
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!ComplexUtility.TryFindRandomSpawnCell(ThingDefOf.AncientCryptosleepPod, room, map, out var spawnPosition))
|
||||
{
|
||||
break;
|
||||
}
|
||||
Building_AncientCryptosleepPod building_AncientCryptosleepPod = (Building_AncientCryptosleepPod)GenSpawn.Spawn(ThingDefOf.AncientCryptosleepPod, spawnPosition, map);
|
||||
building_AncientCryptosleepPod.groupID = Find.UniqueIDsManager.GetNextAncientCryptosleepCasketGroupID();
|
||||
building_AncientCryptosleepPod.openedSignal = openSignal;
|
||||
ThingSetMakerParams parms = default(ThingSetMakerParams);
|
||||
parms.podContentsType = PodContentsType.AncientHostile;
|
||||
List<Thing> list2 = ThingSetMakerDefOf.MapGen_AncientPodContents.root.Generate(parms);
|
||||
for (int j = 0; j < list2.Count; j++)
|
||||
{
|
||||
Pawn pawn = list2[j] as Pawn;
|
||||
if (!building_AncientCryptosleepPod.TryAcceptThing(list2[j], allowSpecialEffects: false))
|
||||
{
|
||||
if (pawn != null)
|
||||
{
|
||||
Find.WorldPawns.PassToWorld(pawn, PawnDiscardDecideMode.Discard);
|
||||
}
|
||||
else
|
||||
{
|
||||
list2[i].Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
list.Add(building_AncientCryptosleepPod);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\ThingDefs_Buildings\Buildings_Ancient_Active.xml`
|
||||
**相似度:** 0.6040
|
||||
|
||||
```xml
|
||||
<ThingDef ParentName="AncientCryptosleepCasket">
|
||||
<defName>AncientCryptosleepPod</defName>
|
||||
<label>ancient cryptosleep pod</label>
|
||||
<thingClass>Building_AncientCryptosleepPod</thingClass>
|
||||
<containedPawnsSelectable>true</containedPawnsSelectable>
|
||||
<description>A single-use pod for preserving one person in a state of suspended animation. Unlike cryptosleep caskets, cryptosleep pods can only be used once.</description>
|
||||
<graphicData>
|
||||
<texPath>Things/Building/Ruins/AncientCryptosleepPod</texPath>
|
||||
<graphicClass>Graphic_Multi</graphicClass>
|
||||
</graphicData>
|
||||
<building>
|
||||
<deconstructible>false</deconstructible>
|
||||
<claimable>false</claimable>
|
||||
</building>
|
||||
<researchPrerequisites Inherit="False" />
|
||||
<hasInteractionCell>false</hasInteractionCell>
|
||||
<statBases>
|
||||
<WorkToBuild>2000</WorkToBuild>
|
||||
<MaxHitPoints>200</MaxHitPoints>
|
||||
</statBases>
|
||||
<designationCategory Inherit="False" />
|
||||
<costList Inherit="False" />
|
||||
<comps Inherit="False" />
|
||||
</ThingDef>
|
||||
```
|
||||
118
MCP/vector_cache/HediffDef-Luciferium.txt
Normal file
118
MCP/vector_cache/HediffDef-Luciferium.txt
Normal file
@@ -0,0 +1,118 @@
|
||||
根据向量相似度分析,与 'HediffDef, Luciferium' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\Drugs\Luciferium.xml`
|
||||
|
||||
```xml
|
||||
<defName>Luciferium</defName>
|
||||
<label>luciferium</label>
|
||||
<description>A concoction of mechanites that dramatically improve the body's functioning in all respects. Over time, it can even heal old scarred-over wounds or brain damage, though it cannot regenerate lost limbs. Unfortunately, without the moderating effects of regular doses every five or six days, the mechanites lose cohesion, causing continuous berserk rages and, eventually, death.\n\nAfter the first dose, there is no way to get the mechanites out, ever.\n\nOn the urbworlds, they call Luciferium the 'Devil's Bargain'. Many have been forced to kill friends when no more of the seductive red pills could be found.</description>
|
||||
<descriptionHyperlinks>
|
||||
<HediffDef>LuciferiumHigh</HediffDef>
|
||||
<HediffDef>LuciferiumAddiction</HediffDef>
|
||||
</descriptionHyperlinks>
|
||||
<graphicData>
|
||||
<texPath>Things/Item/Drug/Luciferium</texPath>
|
||||
<graphicClass>Graphic_StackCount</graphicClass>
|
||||
</graphicData>
|
||||
<rotatable>false</rotatable>
|
||||
<statBases>
|
||||
<MarketValue>70</MarketValue>
|
||||
<Mass>0.01</Mass>
|
||||
</statBases>
|
||||
<techLevel>Ultra</techLevel>
|
||||
<minRewardCount>10</minRewardCount>
|
||||
<ingestible>
|
||||
<drugCategory>Medical</drugCategory>
|
||||
<outcomeDoers>
|
||||
<li Class="IngestionOutcomeDoer_GiveHediff">
|
||||
<hediffDef>LuciferiumHigh</hediffDef>
|
||||
<severity>1.00</severity>
|
||||
<doToGeneratedPawnIfAddicted>true</doToGeneratedPawnIfAddicted>
|
||||
</li>
|
||||
</outcomeDoers>
|
||||
</ingestible>
|
||||
<comps>
|
||||
<li Class="CompProperties_Drug">
|
||||
<chemical>Luciferium</chemical>
|
||||
<addictiveness>1.00</addictiveness>
|
||||
<needLevelOffset>0.9</needLevelOffset>
|
||||
<listOrder>1010</listOrder>
|
||||
</li>
|
||||
</comps>
|
||||
<tradeTags>
|
||||
<li>ExoticMisc</li>
|
||||
</tradeTags>
|
||||
<thingSetMakerTags><li>RewardStandardCore</li></thingSetMakerTags>
|
||||
<allowedArchonexusCount>50</allowedArchonexusCount>
|
||||
</ThingDef>
|
||||
|
||||
<HediffDef>
|
||||
<defName>LuciferiumHigh</defName>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Anomaly\Defs\Misc\Mutants.xml`
|
||||
**相似度:** 0.5154
|
||||
|
||||
```xml
|
||||
<MutantDef Abstract="True" Name="BaseMutantEntity">
|
||||
<workDisables>
|
||||
<li>AllWork</li>
|
||||
<li>Shooting</li>
|
||||
</workDisables>
|
||||
<consideredSubhuman>true</consideredSubhuman>
|
||||
<canCarryPawns>false</canCarryPawns>
|
||||
<canTend>false</canTend>
|
||||
<whitelistedFloatMenuProviders />
|
||||
<preventsMentalBreaks>true</preventsMentalBreaks>
|
||||
<disablesIdeo>true</disablesIdeo>
|
||||
<disableOwnership>true</disableOwnership>
|
||||
<disablePolicies>true</disablePolicies>
|
||||
<disableTitles>true</disableTitles>
|
||||
<disableNeeds>true</disableNeeds>
|
||||
<disableEatingAtTable>true</disableEatingAtTable>
|
||||
<incapableOfSocialInteractions>true</incapableOfSocialInteractions>
|
||||
<canBeCapturedToHoldingPlatform>true</canBeCapturedToHoldingPlatform>
|
||||
<producesBioferrite>true</producesBioferrite>
|
||||
<overrideLabel>true</overrideLabel>
|
||||
<overrideInspectString>true</overrideInspectString>
|
||||
<canBleed>false</canBleed>
|
||||
<terminatePregnancy>true</terminatePregnancy>
|
||||
<isImmuneToInfections>true</isImmuneToInfections>
|
||||
<removeChronicIllnesses>true</removeChronicIllnesses>
|
||||
<removeAddictions>true</removeAddictions>
|
||||
<disableAging>true</disableAging>
|
||||
<clearsEgo>true</clearsEgo>
|
||||
<partsCleanAndDroppable>false</partsCleanAndDroppable>
|
||||
<breathesAir>false</breathesAir>
|
||||
<removesHediffs>
|
||||
<li>CryptosleepSickness</li>
|
||||
<li>LuciferiumHigh</li>
|
||||
<li>LuciferiumAddiction</li>
|
||||
<li>Scaria</li>
|
||||
<li>CorpseTorment</li>
|
||||
<li>CubeInterest</li>
|
||||
<li>CubeWithdrawal</li>
|
||||
<li>CubeComa</li>
|
||||
<li>CubeRage</li>
|
||||
<li>HeartAttack</li>
|
||||
<li>Scaria</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Royalty">PsychicAmplifier</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">MechlinkImplant</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">PregnantHuman</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">PregnancyLabor</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">HemogenAmplified</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">DeathrestExhaustion</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">InterruptedDeathrest</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">HemogenCraving</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">Deathrest</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">RegenerationComa</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">PostpartumExhaustion</li>
|
||||
<li>Inhumanized</li>
|
||||
</removesHediffs>
|
||||
<disablesGenes>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">Hemogenic</li>
|
||||
<li MayRequire="Ludeon.RimWorld.Biotech">Deathrest</li>
|
||||
</disablesGenes>
|
||||
</MutantDef>
|
||||
```
|
||||
750
MCP/vector_cache/HediffDef-Malnutrition.txt
Normal file
750
MCP/vector_cache/HediffDef-Malnutrition.txt
Normal file
@@ -0,0 +1,750 @@
|
||||
根据向量相似度分析,与 'HediffDef, Malnutrition' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\HediffDefs\Hediffs_Global_Needs.xml`
|
||||
**相似度:** 0.8237
|
||||
|
||||
```xml
|
||||
<HediffDef>
|
||||
<defName>Malnutrition</defName>
|
||||
<label>malnutrition</label>
|
||||
<description>Abnormally low body fat and weight, typically caused by lack of food. Malnutrition is always very unpleasant, but its initial effects are mild. Without food, though, a malnourished creature will waste away, losing muscle mass and capacities. Malnutrition ends with death. Upon re-feeding malnutrition naturally recovers over time. Malnourished creatures have larger appetites than normal.</description>
|
||||
<lethalSeverity>1</lethalSeverity>
|
||||
<scenarioCanAdd>true</scenarioCanAdd>
|
||||
<stages>
|
||||
<li>
|
||||
<label>trivial</label>
|
||||
<socialFightChanceFactor>1.5</socialFightChanceFactor>
|
||||
<hungerRateFactorOffset>0.5</hungerRateFactorOffset>
|
||||
<capMods>
|
||||
<li>
|
||||
<capacity>Consciousness</capacity>
|
||||
<offset>-0.05</offset>
|
||||
</li>
|
||||
</capMods>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>0.2</minSeverity>
|
||||
<label>minor</label>
|
||||
<socialFightChanceFactor>2</socialFightChanceFactor>
|
||||
<hungerRateFactorOffset>0.6</hungerRateFactorOffset>
|
||||
<capMods>
|
||||
<li>
|
||||
<capacity>Consciousness</capacity>
|
||||
<offset>-0.10</offset>
|
||||
</li>
|
||||
</capMods>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>0.4</minSeverity>
|
||||
<label>moderate</label>
|
||||
<socialFightChanceFactor>2.5</socialFightChanceFactor>
|
||||
<hungerRateFactorOffset>0.6</hungerRateFactorOffset>
|
||||
<capMods>
|
||||
<li>
|
||||
<capacity>Consciousness</capacity>
|
||||
<offset>-0.20</offset>
|
||||
</li>
|
||||
</capMods>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>0.6</minSeverity>
|
||||
<label>severe</label>
|
||||
<socialFightChanceFactor>3</socialFightChanceFactor>
|
||||
<hungerRateFactorOffset>0.6</hungerRateFactorOffset>
|
||||
<capMods>
|
||||
<li>
|
||||
<capacity>Consciousness</capacity>
|
||||
<offset>-0.30</offset>
|
||||
</li>
|
||||
</capMods>
|
||||
</li>
|
||||
<li>
|
||||
<minSeverity>0.8</minSeverity>
|
||||
<label>extreme</label>
|
||||
<lifeThreatening>true</lifeThreatening>
|
||||
<hungerRateFactorOffset>0.6</hungerRateFactorOffset>
|
||||
<capMods>
|
||||
<li>
|
||||
<capacity>Consciousness</capacity>
|
||||
<setMax>0.1</setMax>
|
||||
</li>
|
||||
</capMods>
|
||||
</li>
|
||||
</stages>
|
||||
</HediffDef>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\StatPart_Malnutrition.txt`
|
||||
**相似度:** 0.7310
|
||||
|
||||
```csharp
|
||||
public class StatPart_Malnutrition : StatPart
|
||||
{
|
||||
private SimpleCurve curve;
|
||||
|
||||
public override void TransformValue(StatRequest req, ref float val)
|
||||
{
|
||||
if (TryGetMalnutritionFactor(req, out var _, out var factor))
|
||||
{
|
||||
val *= factor;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ExplanationPart(StatRequest req)
|
||||
{
|
||||
if (TryGetMalnutritionFactor(req, out var malnutritionSeverity, out var factor))
|
||||
{
|
||||
return "StatsReport_Malnutrition".Translate(malnutritionSeverity.ToStringPercent()) + ": x" + factor.ToStringPercent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool TryGetMalnutritionFactor(StatRequest req, out float malnutritionSeverity, out float factor)
|
||||
{
|
||||
factor = 0f;
|
||||
malnutritionSeverity = 0f;
|
||||
if (!req.HasThing || !(req.Thing is Pawn pawn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Hediff firstHediffOfDef = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Malnutrition);
|
||||
if (firstHediffOfDef == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
malnutritionSeverity = firstHediffOfDef.Severity;
|
||||
factor = curve.Evaluate(malnutritionSeverity);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\Need_Food.txt`
|
||||
**相似度:** 0.6580
|
||||
|
||||
```csharp
|
||||
public class Need_Food : Need
|
||||
{
|
||||
public int lastNonStarvingTick = -99999;
|
||||
|
||||
public const float BaseFoodFallPerTick = 2.6666667E-05f;
|
||||
|
||||
private const float BaseMalnutritionSeverityPerDay = 0.453f;
|
||||
|
||||
private const float BaseMalnutritionSeverityPerInterval = 0.0011325f;
|
||||
|
||||
private CompHoldingPlatformTarget platformComp;
|
||||
|
||||
public bool Starving => CurCategory == HungerCategory.Starving;
|
||||
|
||||
public float PercentageThreshUrgentlyHungry => pawn.RaceProps.FoodLevelPercentageWantEat * 0.4f;
|
||||
|
||||
public float PercentageThreshHungry => pawn.RaceProps.FoodLevelPercentageWantEat * 0.8f;
|
||||
|
||||
public float NutritionBetweenHungryAndFed => (1f - PercentageThreshHungry) * MaxLevel;
|
||||
|
||||
private CompHoldingPlatformTarget PlatformTarget => platformComp ?? (platformComp = pawn.TryGetComp<CompHoldingPlatformTarget>());
|
||||
|
||||
public HungerCategory CurCategory
|
||||
{
|
||||
get
|
||||
{
|
||||
if (base.CurLevelPercentage <= 0f)
|
||||
{
|
||||
return HungerCategory.Starving;
|
||||
}
|
||||
if (base.CurLevelPercentage < PercentageThreshUrgentlyHungry)
|
||||
{
|
||||
return HungerCategory.UrgentlyHungry;
|
||||
}
|
||||
if (base.CurLevelPercentage < PercentageThreshHungry)
|
||||
{
|
||||
return HungerCategory.Hungry;
|
||||
}
|
||||
return HungerCategory.Fed;
|
||||
}
|
||||
}
|
||||
|
||||
public float FoodFallPerTick => FoodFallPerTickAssumingCategory(CurCategory);
|
||||
|
||||
public int TicksUntilHungryWhenFed => Mathf.CeilToInt(NutritionBetweenHungryAndFed / FoodFallPerTickAssumingCategory(HungerCategory.Fed));
|
||||
|
||||
public int TicksUntilHungryWhenFedIgnoringMalnutrition => Mathf.CeilToInt(NutritionBetweenHungryAndFed / FoodFallPerTickAssumingCategory(HungerCategory.Fed, ignoreMalnutrition: true));
|
||||
|
||||
public override int GUIChangeArrow
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GainingFood())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (!(FoodFallPerTickAssumingCategory(HungerCategory.Hungry) > 0f))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override float MaxLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Current.ProgramState != ProgramState.Playing)
|
||||
{
|
||||
return pawn.BodySize * pawn.ageTracker.CurLifeStage.foodMaxFactor;
|
||||
}
|
||||
return pawn.GetStatValue(StatDefOf.MaxNutrition, applyPostProcess: true, 15);
|
||||
}
|
||||
}
|
||||
|
||||
public float NutritionWanted => MaxLevel - CurLevel;
|
||||
|
||||
public int TicksStarving => Mathf.Max(0, Find.TickManager.TicksGame - lastNonStarvingTick);
|
||||
|
||||
private float MalnutritionSeverityPerInterval => 0.0011325f * Mathf.Lerp(0.8f, 1.2f, Rand.ValueSeeded(pawn.thingIDNumber ^ 0x26EF7A));
|
||||
|
||||
protected override bool IsFrozen
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!base.IsFrozen && !pawn.Deathresting)
|
||||
{
|
||||
return PlatformTarget?.CurrentlyHeldOnPlatform ?? false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public Need_Food(Pawn pawn)
|
||||
: base(pawn)
|
||||
{
|
||||
}
|
||||
|
||||
public bool GainingFood()
|
||||
{
|
||||
if (pawn.jobs?.curDriver is IEatingDriver { GainingNutritionNow: not false })
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (ModsConfig.BiotechActive && ChildcareUtility.CanSuckle(pawn, out var _) && pawn.CarriedBy?.jobs.curDriver is JobDriver_FeedBaby { Feeding: not false })
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public float FoodFallPerTickAssumingCategory(HungerCategory hunger, bool ignoreMalnutrition = false)
|
||||
{
|
||||
Building_Bed building_Bed = pawn.CurrentBed();
|
||||
float num = BaseHungerRate(pawn.ageTracker.CurLifeStage, pawn.def) * hunger.HungerMultiplier() * pawn.health.hediffSet.GetHungerRateFactor(ignoreMalnutrition ? HediffDefOf.Malnutrition : null) * (pawn.story?.traits?.HungerRateFactor ?? 1f) * (building_Bed?.GetStatValue(StatDefOf.BedHungerRateFactor) ?? 1f);
|
||||
if (ModsConfig.BiotechActive)
|
||||
{
|
||||
Hediff firstHediffOfDef = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Lactating);
|
||||
if (firstHediffOfDef != null)
|
||||
{
|
||||
HediffComp_Lactating hediffComp_Lactating = firstHediffOfDef.TryGetComp<HediffComp_Lactating>();
|
||||
if (hediffComp_Lactating != null)
|
||||
{
|
||||
num += hediffComp_Lactating.AddedNutritionPerDay() / 60000f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ModsConfig.BiotechActive && pawn.genes != null)
|
||||
{
|
||||
int num2 = 0;
|
||||
foreach (Gene item in pawn.genes.GenesListForReading)
|
||||
{
|
||||
if (!item.Overridden)
|
||||
{
|
||||
num2 += item.def.biostatMet;
|
||||
}
|
||||
}
|
||||
num *= GeneTuning.MetabolismToFoodConsumptionFactorCurve.Evaluate(num2);
|
||||
}
|
||||
if (ModsConfig.AnomalyActive)
|
||||
{
|
||||
CompHoldingPlatformTarget platformTarget = PlatformTarget;
|
||||
if (platformTarget != null && platformTarget.CurrentlyHeldOnPlatform)
|
||||
{
|
||||
num = 0f;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public override void NeedInterval()
|
||||
{
|
||||
if (!IsFrozen)
|
||||
{
|
||||
CurLevel -= FoodFallPerTick * 150f;
|
||||
}
|
||||
if (!Starving)
|
||||
{
|
||||
lastNonStarvingTick = Find.TickManager.TicksGame;
|
||||
}
|
||||
if (!IsFrozen || pawn.Deathresting)
|
||||
{
|
||||
if (Starving)
|
||||
{
|
||||
HealthUtility.AdjustSeverity(pawn, HediffDefOf.Malnutrition, MalnutritionSeverityPerInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
HealthUtility.AdjustSeverity(pawn, HediffDefOf.Malnutrition, 0f - MalnutritionSeverityPerInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetInitialLevel()
|
||||
{
|
||||
StatDefOf.MaxNutrition.Worker.ClearCacheForThing(pawn);
|
||||
base.CurLevelPercentage = (pawn.RaceProps.Humanlike ? 0.8f : Rand.Range(0.5f, 0.9f));
|
||||
if (Current.ProgramState == ProgramState.Playing)
|
||||
{
|
||||
lastNonStarvingTick = Find.TickManager.TicksGame;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnNeedRemoved()
|
||||
{
|
||||
if (pawn.health.hediffSet.TryGetHediff(HediffDefOf.Malnutrition, out var hediff))
|
||||
{
|
||||
pawn.health.RemoveHediff(hediff);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetTipString()
|
||||
{
|
||||
return (base.LabelCap + ": " + base.CurLevelPercentage.ToStringPercent()).Colorize(ColoredText.TipSectionTitleColor) + " (" + CurLevel.ToString("0.##") + " / " + MaxLevel.ToString("0.##") + ")\n" + def.description;
|
||||
}
|
||||
|
||||
public override void DrawOnGUI(Rect rect, int maxThresholdMarkers = int.MaxValue, float customMargin = -1f, bool drawArrows = true, bool doTooltip = true, Rect? rectForTooltip = null, bool drawLabel = true)
|
||||
{
|
||||
if (threshPercents == null)
|
||||
{
|
||||
threshPercents = new List<float>();
|
||||
}
|
||||
threshPercents.Clear();
|
||||
threshPercents.Add(PercentageThreshHungry);
|
||||
threshPercents.Add(PercentageThreshUrgentlyHungry);
|
||||
base.DrawOnGUI(rect, maxThresholdMarkers, customMargin, drawArrows, doTooltip, rectForTooltip, drawLabel);
|
||||
}
|
||||
|
||||
public static float BaseHungerRate(LifeStageDef lifeStage, ThingDef pawnDef)
|
||||
{
|
||||
return lifeStage.hungerRateFactor * pawnDef.race.baseHungerRate * 2.6666667E-05f;
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref lastNonStarvingTick, "lastNonStarvingTick", -99999);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\HediffDefOf.txt`
|
||||
**相似度:** 0.6514
|
||||
|
||||
```csharp
|
||||
public static class HediffDefOf
|
||||
{
|
||||
public static HediffDef Cut;
|
||||
|
||||
public static HediffDef SurgicalCut;
|
||||
|
||||
public static HediffDef ExecutionCut;
|
||||
|
||||
public static HediffDef Bite;
|
||||
|
||||
public static HediffDef MissingBodyPart;
|
||||
|
||||
public static HediffDef Misc;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef BloodfeederMark;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Decayed;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Digested;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static HediffDef PorcupineQuill;
|
||||
|
||||
public static HediffDef BloodLoss;
|
||||
|
||||
public static HediffDef Hypothermia;
|
||||
|
||||
public static HediffDef Heatstroke;
|
||||
|
||||
public static HediffDef Malnutrition;
|
||||
|
||||
public static HediffDef ToxicBuildup;
|
||||
|
||||
public static HediffDef PsychicShock;
|
||||
|
||||
public static HediffDef ResurrectionSickness;
|
||||
|
||||
public static HediffDef ResurrectionPsychosis;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PollutionStimulus;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef ToxGasExposure;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Shambler;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef ShamblerCorpse;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Rising;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef DeathRefusal;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef DeathRefusalSickness;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef MetalhorrorImplant;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef MetalhorrorSpeedBoost;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef PsychicTrance;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef DuplicateSickness;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef VoidTouched;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef MeatHunger;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef ShardHolder;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Inhumanized;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef DarknessExposure;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef LightExposure;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef DisruptorFlash;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static HediffDef VacuumExposure;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static HediffDef PsilocapHigh;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static HediffDef GravNausea;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static HediffDef VolcanicAsh;
|
||||
|
||||
public static HediffDef Anesthetic;
|
||||
|
||||
public static HediffDef CryptosleepSickness;
|
||||
|
||||
public static HediffDef FoodPoisoning;
|
||||
|
||||
public static HediffDef Pregnant;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PregnantHuman;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef MorningSickness;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PregnancyMood;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PregnancyLabor;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PregnancyLaborPushing;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef OvumExtracted;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef VatLearning;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef VatGrowing;
|
||||
|
||||
public static HediffDef CatatonicBreakdown;
|
||||
|
||||
public static HediffDef Scaria;
|
||||
|
||||
[MayRequireIdeology]
|
||||
public static HediffDef Scarification;
|
||||
|
||||
[MayRequireIdeology]
|
||||
public static HediffDef NeuralSupercharge;
|
||||
|
||||
[MayRequireIdeology]
|
||||
public static HediffDef BiosculptingSickness;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef PsychicEntropy;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef PsychicHangover;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef PsychicSuppression;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef Abasia;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef PsychicLove;
|
||||
|
||||
public static HediffDef Sterilized;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef Vasectomy;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef ImplantedIUD;
|
||||
|
||||
[MayRequireIdeology]
|
||||
public static HediffDef WorkFocus;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef ScanningSickness;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PsychicBond;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PsychicBondTorn;
|
||||
|
||||
public static HediffDef LungRot;
|
||||
|
||||
public static HediffDef LungRotExposure;
|
||||
|
||||
public static HediffDef CoveredInFirefoam;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef BioferriteExtracted;
|
||||
|
||||
public static HediffDef Plague;
|
||||
|
||||
public static HediffDef WoundInfection;
|
||||
|
||||
public static HediffDef ScariaInfection;
|
||||
|
||||
public static HediffDef AlcoholHigh;
|
||||
|
||||
public static HediffDef Hangover;
|
||||
|
||||
public static HediffDef DrugOverdose;
|
||||
|
||||
public static HediffDef WakeUpTolerance;
|
||||
|
||||
public static HediffDef GoJuiceTolerance;
|
||||
|
||||
public static HediffDef Blindness;
|
||||
|
||||
public static HediffDef Carcinoma;
|
||||
|
||||
public static HediffDef Dementia;
|
||||
|
||||
public static HediffDef OrganDecay;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef DetoxifierLung;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef LoveEnhancer;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef PsychicAmplifier;
|
||||
|
||||
[MayRequireRoyalty]
|
||||
public static HediffDef PsychicHarmonizer;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef MechlinkImplant;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef SelfShutdown;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef InterruptedDeathrest;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef InfantIllness;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef Stillborn;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef PostpartumExhaustion;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef Lactating;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef RegenerationComa;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef XenogermLossShock;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef XenogermReplicating;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef GeneticDrugNeed;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef BioStarvation;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef XenogerminationComa;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef Deathrest;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef DeathrestExhaustion;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef BandNode;
|
||||
|
||||
[MayRequireBiotech]
|
||||
public static HediffDef HemogenCraving;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef HoraxianInvisibility;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef RevenantHypnosis;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef AwokenHypnosis;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef DarkPsychicShock;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Tentacle;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef FleshWhip;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef OrganDecayUndiagnosedDuplicaton;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CrumblingMindUndiagnosedDuplication;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef OrganDecayCreepjoiner;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CrumblingMind;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CrumbledMind;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef BlissLobotomy;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef PleasurePulse;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef NeurosisPulse;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef BloodRage;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef FrenzyField;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef AgonyPulse;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CubeInterest;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CubeWithdrawal;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CubeRage;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CubeComa;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef BrainwipeComa;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef CorpseTorment;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef PsychicallyDead;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Psychophage;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef SleepSuppression;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef RageSpeed;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef AwokenCorpse;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef RapidRegeneration;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef GhoulBarbs;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef GhoulPlating;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef AdrenalHeart;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef FleshmassStomach;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef FleshmassLung;
|
||||
|
||||
[MayRequireAnomaly]
|
||||
public static HediffDef Metalblood;
|
||||
|
||||
[MayRequireOdyssey]
|
||||
public static HediffDef SentienceCatalyst;
|
||||
|
||||
static HediffDefOf()
|
||||
{
|
||||
DefOfHelper.EnsureInitializedInCtor(typeof(HediffDefOf));
|
||||
}
|
||||
}
|
||||
```
|
||||
2691
MCP/vector_cache/Human-ThingDef.txt
Normal file
2691
MCP/vector_cache/Human-ThingDef.txt
Normal file
File diff suppressed because it is too large
Load Diff
134
MCP/vector_cache/HumanlikeAdult-LifeStageDef.txt
Normal file
134
MCP/vector_cache/HumanlikeAdult-LifeStageDef.txt
Normal file
@@ -0,0 +1,134 @@
|
||||
根据向量相似度分析,与 'LifeStageDef, HumanlikeAdult' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\LifeStageDefOf.txt`
|
||||
**相似度:** 0.7850
|
||||
|
||||
```csharp
|
||||
public static class LifeStageDefOf
|
||||
{
|
||||
public static LifeStageDef HumanlikeBaby;
|
||||
|
||||
public static LifeStageDef HumanlikeChild;
|
||||
|
||||
public static LifeStageDef HumanlikeAdult;
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\Misc\LifeStageDefs\LifeStages.xml`
|
||||
**相似度:** 0.7399
|
||||
|
||||
```xml
|
||||
<LifeStageDef>
|
||||
<defName>MechanoidFullyFormed</defName>
|
||||
<label>fully-formed</label>
|
||||
<visible>false</visible>
|
||||
</LifeStageDef>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\Misc\LifeStageDefs\LifeStages.xml`
|
||||
**相似度:** 0.7399
|
||||
|
||||
```xml
|
||||
<defName>HumanlikeTeenager</defName>
|
||||
<label>teenager</label>
|
||||
<workerClass MayRequire="Ludeon.RimWorld.Biotech">LifeStageWorker_HumanlikeAdult</workerClass>
|
||||
<adjective>teenage</adjective>
|
||||
<reproductive>true</reproductive>
|
||||
<bodySizeFactor>0.8</bodySizeFactor>
|
||||
<healthScaleFactor>0.90</healthScaleFactor>
|
||||
<foodMaxFactor>1.25</foodMaxFactor> <!-- bodySizeFactor * foodMaxFactor = maxFood = 1.0 -->
|
||||
<meleeDamageFactor>0.75</meleeDamageFactor>
|
||||
<equipmentDrawDistanceFactor>0.65</equipmentDrawDistanceFactor>
|
||||
<sittingOffset>0.23</sittingOffset>
|
||||
<silhouetteGraphicData>
|
||||
<texPath>Things/Pawn/Humanlike/Silhouettes/Silhouette_HumanChild</texPath>
|
||||
<graphicClass>Graphic_Single</graphicClass>
|
||||
<drawSize>1</drawSize>
|
||||
</silhouetteGraphicData>
|
||||
<statFactors>
|
||||
<MoveSpeed>0.95</MoveSpeed>
|
||||
</statFactors>
|
||||
</LifeStageDef>
|
||||
|
||||
<LifeStageDef>
|
||||
<defName>HumanlikeAdult</defName>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\LifeStageWorker_HumanlikeAdult.txt`
|
||||
**相似度:** 0.7169
|
||||
|
||||
```csharp
|
||||
public class LifeStageWorker_HumanlikeAdult : LifeStageWorker
|
||||
{
|
||||
public const int VatGrowBackstoryTicks = 1200000;
|
||||
|
||||
private static readonly List<BackstoryCategoryFilter> VatgrowBackstoryFilter = new List<BackstoryCategoryFilter>
|
||||
{
|
||||
new BackstoryCategoryFilter
|
||||
{
|
||||
categories = new List<string> { "VatGrown" }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly List<BackstoryCategoryFilter> BackstoryFiltersTribal = new List<BackstoryCategoryFilter>
|
||||
{
|
||||
new BackstoryCategoryFilter
|
||||
{
|
||||
categories = new List<string> { "AdultTribal" }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly List<BackstoryCategoryFilter> BackstoryFiltersColonist = new List<BackstoryCategoryFilter>
|
||||
{
|
||||
new BackstoryCategoryFilter
|
||||
{
|
||||
categories = new List<string> { "AdultColonist" }
|
||||
}
|
||||
};
|
||||
|
||||
public override void Notify_LifeStageStarted(Pawn pawn, LifeStageDef previousLifeStage)
|
||||
{
|
||||
base.Notify_LifeStageStarted(pawn, previousLifeStage);
|
||||
if (Current.ProgramState != ProgramState.Playing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (pawn.Spawned && previousLifeStage != null && previousLifeStage.developmentalStage.Juvenile())
|
||||
{
|
||||
EffecterDefOf.Birthday.SpawnAttached(pawn, pawn.Map);
|
||||
}
|
||||
if (pawn.story.bodyType == BodyTypeDefOf.Child || pawn.story.bodyType == BodyTypeDefOf.Baby)
|
||||
{
|
||||
pawn.apparel?.DropAllOrMoveAllToInventory((Apparel apparel) => !apparel.def.apparel.developmentalStageFilter.Has(DevelopmentalStage.Adult));
|
||||
BodyTypeDef bodyTypeFor = PawnGenerator.GetBodyTypeFor(pawn);
|
||||
pawn.story.bodyType = bodyTypeFor;
|
||||
pawn.Drawer.renderer.SetAllGraphicsDirty();
|
||||
}
|
||||
if (!pawn.IsColonist)
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<BackstoryCategoryFilter> backstoryCategories = ((Faction.OfPlayer.def == FactionDefOf.PlayerTribe) ? BackstoryFiltersTribal : BackstoryFiltersColonist);
|
||||
if (previousLifeStage.developmentalStage.Juvenile())
|
||||
{
|
||||
if (pawn.ageTracker.vatGrowTicks >= 1200000)
|
||||
{
|
||||
PawnBioAndNameGenerator.FillBackstorySlotShuffled(pawn, BackstorySlot.Childhood, VatgrowBackstoryFilter, pawn.Faction?.def);
|
||||
}
|
||||
else
|
||||
{
|
||||
BackstoryDef backstory = pawn.story.GetBackstory(BackstorySlot.Childhood);
|
||||
if (backstory != null && backstory.IsPlayerColonyChildBackstory)
|
||||
{
|
||||
PawnBioAndNameGenerator.FillBackstorySlotShuffled(pawn, BackstorySlot.Childhood, backstoryCategories, pawn.Faction?.def);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pawn.story.GetBackstory(BackstorySlot.Adulthood) == null)
|
||||
{
|
||||
PawnBioAndNameGenerator.FillBackstorySlotShuffled(pawn, BackstorySlot.Adulthood, backstoryCategories, pawn.Faction?.def);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
115
MCP/vector_cache/JobDef.txt
Normal file
115
MCP/vector_cache/JobDef.txt
Normal file
@@ -0,0 +1,115 @@
|
||||
根据向量相似度分析,与 'JobDef' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\JobDef.txt`
|
||||
|
||||
```csharp
|
||||
public class JobDef : Def
|
||||
{
|
||||
public Type driverClass;
|
||||
|
||||
[MustTranslate]
|
||||
public string reportString = "Doing something.";
|
||||
|
||||
public bool playerInterruptible = true;
|
||||
|
||||
public bool forceCompleteBeforeNextJob;
|
||||
|
||||
public CheckJobOverrideOnDamageMode checkOverrideOnDamage = CheckJobOverrideOnDamageMode.Always;
|
||||
|
||||
public bool alwaysShowWeapon;
|
||||
|
||||
public bool neverShowWeapon;
|
||||
|
||||
public bool suspendable = true;
|
||||
|
||||
public bool casualInterruptible = true;
|
||||
|
||||
public bool allowOpportunisticPrefix;
|
||||
|
||||
public bool collideWithPawns;
|
||||
|
||||
public bool isIdle;
|
||||
|
||||
public TaleDef taleOnCompletion;
|
||||
|
||||
public bool neverFleeFromEnemies;
|
||||
|
||||
public bool sleepCanInterrupt = true;
|
||||
|
||||
public bool makeTargetPrisoner;
|
||||
|
||||
public int waitAfterArriving;
|
||||
|
||||
public bool carryThingAfterJob;
|
||||
|
||||
public bool dropThingBeforeJob = true;
|
||||
|
||||
public bool isCrawlingIfDowned = true;
|
||||
|
||||
public bool alwaysShowReport;
|
||||
|
||||
public bool abilityCasting;
|
||||
|
||||
public bool tryStartFlying;
|
||||
|
||||
public bool ifFlyingKeepFlying;
|
||||
|
||||
public float overrideFlyChance = -1f;
|
||||
|
||||
public bool displayAsAreaInFloatMenu = true;
|
||||
|
||||
public int joyDuration = 4000;
|
||||
|
||||
public int joyMaxParticipants = 1;
|
||||
|
||||
public float joyGainRate = 1f;
|
||||
|
||||
public SkillDef joySkill;
|
||||
|
||||
public float joyXpPerTick;
|
||||
|
||||
public JoyKindDef joyKind;
|
||||
|
||||
public Rot4 faceDir = Rot4.Invalid;
|
||||
|
||||
public int learningDuration = 20000;
|
||||
|
||||
public ReservationLayerDef containerReservationLayer;
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string item in base.ConfigErrors())
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (joySkill != null && joyXpPerTick == 0f)
|
||||
{
|
||||
yield return "funSkill is not null but funXpPerTick is zero";
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\JobDefs\Jobs_Animal.xml`
|
||||
**相似度:** 0.5912
|
||||
|
||||
```xml
|
||||
<JobDef>
|
||||
<defName>Nuzzle</defName>
|
||||
<driverClass>JobDriver_Nuzzle</driverClass>
|
||||
<reportString>nuzzling TargetA.</reportString>
|
||||
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
||||
</JobDef>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Ideology\Defs\JobDefs\Jobs_Gatherings.xml`
|
||||
**相似度:** 0.5788
|
||||
|
||||
```xml
|
||||
<JobDef>
|
||||
<defName>Dance</defName>
|
||||
<driverClass>JobDriver_Dance</driverClass>
|
||||
<reportString>dancing.</reportString>
|
||||
</JobDef>
|
||||
```
|
||||
827
MCP/vector_cache/JobDefOf-JobDriver_TakeToBed-Rescue.txt
Normal file
827
MCP/vector_cache/JobDefOf-JobDriver_TakeToBed-Rescue.txt
Normal file
@@ -0,0 +1,827 @@
|
||||
根据向量相似度分析,与 'JobDriver_TakeToBed, Rescue, JobDefOf' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_TakeToBed.txt`
|
||||
|
||||
```csharp
|
||||
public class JobDriver_TakeToBed : JobDriver
|
||||
{
|
||||
private const TargetIndex TakeeIndex = TargetIndex.A;
|
||||
|
||||
private const TargetIndex BedIndex = TargetIndex.B;
|
||||
|
||||
protected Pawn Takee => (Pawn)job.GetTarget(TargetIndex.A).Thing;
|
||||
|
||||
protected Building_Bed DropBed => (Building_Bed)job.GetTarget(TargetIndex.B).Thing;
|
||||
|
||||
private bool TakeeRescued
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Takee.RaceProps.Humanlike && job.def != JobDefOf.Arrest && !Takee.IsPrisonerOfColony)
|
||||
{
|
||||
if (Takee.ageTracker.CurLifeStage.alwaysDowned)
|
||||
{
|
||||
return HealthAIUtility.ShouldSeekMedicalRest(Takee);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetReport()
|
||||
{
|
||||
if (job.def == JobDefOf.Rescue && !TakeeRescued)
|
||||
{
|
||||
return "TakingToBed".Translate(Takee);
|
||||
}
|
||||
return base.GetReport();
|
||||
}
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
Takee.ClearAllReservations();
|
||||
if (pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed))
|
||||
{
|
||||
return pawn.Reserve(DropBed, job, DropBed.SleepingSlotsCount, 0, null, errorOnFailed);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
this.FailOnDestroyedOrNull(TargetIndex.A);
|
||||
this.FailOnDestroyedOrNull(TargetIndex.B);
|
||||
this.FailOnAggroMentalStateAndHostile(TargetIndex.A);
|
||||
this.FailOn(delegate
|
||||
{
|
||||
if (job.def.makeTargetPrisoner)
|
||||
{
|
||||
if (!DropBed.ForPrisoners)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (DropBed.ForPrisoners != Takee.IsPrisoner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
yield return Toils_Bed.ClaimBedIfNonMedical(TargetIndex.B, TargetIndex.A);
|
||||
AddFinishAction(delegate
|
||||
{
|
||||
if (job.def.makeTargetPrisoner && Takee.ownership.OwnedBed == DropBed && Takee.Position != RestUtility.GetBedSleepingSlotPosFor(Takee, DropBed))
|
||||
{
|
||||
Takee.ownership.UnclaimBed();
|
||||
}
|
||||
if (pawn.carryTracker.CarriedThing != null)
|
||||
{
|
||||
pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Direct, out var _);
|
||||
}
|
||||
});
|
||||
Toil goToTakee = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A).FailOnDespawnedNullOrForbidden(TargetIndex.B)
|
||||
.FailOn(() => job.def == JobDefOf.Arrest && !Takee.CanBeArrestedBy(pawn))
|
||||
.FailOn(() => !pawn.CanReach(DropBed, PathEndMode.OnCell, Danger.Deadly))
|
||||
.FailOn(() => (job.def == JobDefOf.Rescue || job.def == JobDefOf.Capture) && !Takee.Downed)
|
||||
.FailOnSomeonePhysicallyInteracting(TargetIndex.A);
|
||||
Toil checkArrestResistance = ToilMaker.MakeToil("MakeNewToils");
|
||||
checkArrestResistance.initAction = delegate
|
||||
{
|
||||
if (job.def.makeTargetPrisoner)
|
||||
{
|
||||
Pawn pawn = (Pawn)job.targetA.Thing;
|
||||
pawn.GetLord()?.Notify_PawnAttemptArrested(pawn);
|
||||
GenClamor.DoClamor(pawn, 10f, ClamorDefOf.Harm);
|
||||
if (!pawn.IsPrisoner && !pawn.IsSlave)
|
||||
{
|
||||
QuestUtility.SendQuestTargetSignals(pawn.questTags, "Arrested", pawn.Named("SUBJECT"));
|
||||
if (pawn.Faction != null)
|
||||
{
|
||||
QuestUtility.SendQuestTargetSignals(pawn.Faction.questTags, "FactionMemberArrested", pawn.Faction.Named("FACTION"));
|
||||
}
|
||||
}
|
||||
if (job.def == JobDefOf.Arrest && !pawn.CheckAcceptArrest(base.pawn))
|
||||
{
|
||||
base.pawn.jobs.EndCurrentJob(JobCondition.Incompletable);
|
||||
}
|
||||
}
|
||||
};
|
||||
yield return Toils_Jump.JumpIf(checkArrestResistance, () => pawn.IsCarryingPawn(Takee));
|
||||
yield return goToTakee;
|
||||
yield return checkArrestResistance;
|
||||
Toil startCarrying = Toils_Haul.StartCarryThing(TargetIndex.A);
|
||||
startCarrying.FailOnBedNoLongerUsable(TargetIndex.B, TargetIndex.A);
|
||||
startCarrying.AddPreInitAction(CheckMakeTakeeGuest);
|
||||
startCarrying.AddFinishAction(delegate
|
||||
{
|
||||
if (pawn.Faction == Takee.Faction)
|
||||
{
|
||||
CheckMakeTakeePrisoner();
|
||||
}
|
||||
});
|
||||
Toil goToBed = Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.Touch).FailOn(() => !pawn.IsCarryingPawn(Takee));
|
||||
goToBed.FailOnBedNoLongerUsable(TargetIndex.B, TargetIndex.A);
|
||||
yield return Toils_Jump.JumpIf(goToBed, () => pawn.IsCarryingPawn(Takee));
|
||||
yield return startCarrying;
|
||||
yield return goToBed;
|
||||
Toil toil = ToilMaker.MakeToil("MakeNewToils");
|
||||
toil.initAction = delegate
|
||||
{
|
||||
CheckMakeTakeePrisoner();
|
||||
if (Takee.playerSettings == null)
|
||||
{
|
||||
Takee.playerSettings = new Pawn_PlayerSettings(Takee);
|
||||
}
|
||||
};
|
||||
yield return toil;
|
||||
yield return Toils_Reserve.Release(TargetIndex.B);
|
||||
yield return Toils_Bed.TuckIntoBed(DropBed, pawn, Takee, TakeeRescued);
|
||||
yield return Toils_General.Do(delegate
|
||||
{
|
||||
if (!job.ritualTag.NullOrEmpty())
|
||||
{
|
||||
if (Takee.GetLord()?.LordJob is LordJob_Ritual lordJob_Ritual)
|
||||
{
|
||||
lordJob_Ritual.AddTagForPawn(Takee, job.ritualTag);
|
||||
}
|
||||
if (pawn.GetLord()?.LordJob is LordJob_Ritual lordJob_Ritual2)
|
||||
{
|
||||
lordJob_Ritual2.AddTagForPawn(pawn, job.ritualTag);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void CheckMakeTakeePrisoner()
|
||||
{
|
||||
if (job.def.makeTargetPrisoner)
|
||||
{
|
||||
if (Takee.guest.Released)
|
||||
{
|
||||
Takee.guest.Released = false;
|
||||
Takee.guest.SetExclusiveInteraction(PrisonerInteractionModeDefOf.MaintainOnly);
|
||||
GenGuest.RemoveHealthyPrisonerReleasedThoughts(Takee);
|
||||
}
|
||||
if (!Takee.IsPrisonerOfColony)
|
||||
{
|
||||
Takee.guest.CapturedBy(Faction.OfPlayer, pawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckMakeTakeeGuest()
|
||||
{
|
||||
if (!job.def.makeTargetPrisoner && Takee.Faction != Faction.OfPlayer && Takee.HostFaction != Faction.OfPlayer && Takee.guest != null && !Takee.IsWildMan() && Takee.DevelopmentalStage != DevelopmentalStage.Baby)
|
||||
{
|
||||
Takee.guest.SetGuestStatus(Faction.OfPlayer);
|
||||
QuestUtility.SendQuestTargetSignals(Takee.questTags, "Rescued", Takee.Named("SUBJECT"));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\JobDefs\Jobs_Work.xml`
|
||||
**相似度:** 0.6607
|
||||
|
||||
```xml
|
||||
<defName>Rescue</defName>
|
||||
<driverClass>JobDriver_TakeToBed</driverClass>
|
||||
<reportString>rescuing TargetA.</reportString>
|
||||
<casualInterruptible>false</casualInterruptible>
|
||||
<carryThingAfterJob>true</carryThingAfterJob>
|
||||
<dropThingBeforeJob>false</dropThingBeforeJob>
|
||||
</JobDef>
|
||||
|
||||
<JobDef>
|
||||
<defName>CarryToCryptosleepCasket</defName>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\JobDefs\Jobs_Misc.xml`
|
||||
**相似度:** 0.6320
|
||||
|
||||
```xml
|
||||
<defName>DeliverToBed</defName>
|
||||
<driverClass>JobDriver_TakeToBed</driverClass>
|
||||
<reportString>delivering TargetA.</reportString>
|
||||
<casualInterruptible>false</casualInterruptible>
|
||||
</JobDef>
|
||||
|
||||
<JobDef>
|
||||
<defName>TakeCountToInventory</defName>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\RestUtility.txt`
|
||||
**相似度:** 0.5085
|
||||
|
||||
```csharp
|
||||
public static class RestUtility
|
||||
{
|
||||
public const int NoSleepingDurationAfterBeingDisturbed = 400;
|
||||
|
||||
private static List<ThingDef> bedDefsBestToWorst_RestEffectiveness;
|
||||
|
||||
private static List<ThingDef> bedDefsBestToWorst_Medical;
|
||||
|
||||
private static List<ThingDef> bedDefsBestToWorst_SlabBed_RestEffectiveness;
|
||||
|
||||
private static List<ThingDef> bedDefsBestToWorst_SlabBed_Medical;
|
||||
|
||||
public static List<ThingDef> AllBedDefBestToWorst => bedDefsBestToWorst_RestEffectiveness;
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
bedDefsBestToWorst_RestEffectiveness = (from d in DefDatabase<ThingDef>.AllDefs
|
||||
where d.IsBed
|
||||
orderby d.building.bed_maxBodySize, d.GetStatValueAbstract(StatDefOf.BedRestEffectiveness) descending
|
||||
select d).ToList();
|
||||
bedDefsBestToWorst_SlabBed_RestEffectiveness = (from d in DefDatabase<ThingDef>.AllDefs
|
||||
where d.IsBed
|
||||
orderby (!d.building.bed_slabBed) ? 1 : 0, d.building.bed_maxBodySize, d.GetStatValueAbstract(StatDefOf.BedRestEffectiveness) descending
|
||||
select d).ToList();
|
||||
bedDefsBestToWorst_Medical = (from d in DefDatabase<ThingDef>.AllDefs
|
||||
where d.IsBed
|
||||
orderby d.building.bed_maxBodySize, d.GetStatValueAbstract(StatDefOf.MedicalTendQualityOffset) descending, d.GetStatValueAbstract(StatDefOf.BedRestEffectiveness) descending
|
||||
select d).ToList();
|
||||
bedDefsBestToWorst_SlabBed_Medical = (from d in DefDatabase<ThingDef>.AllDefs
|
||||
where d.IsBed
|
||||
orderby (!d.building.bed_slabBed) ? 1 : 0, d.building.bed_maxBodySize, d.GetStatValueAbstract(StatDefOf.MedicalTendQualityOffset) descending, d.GetStatValueAbstract(StatDefOf.BedRestEffectiveness) descending
|
||||
select d).ToList();
|
||||
}
|
||||
|
||||
public static bool BedOwnerWillShare(Building_Bed bed, Pawn sleeper, GuestStatus? guestStatus)
|
||||
{
|
||||
if (!bed.OwnersForReading.Any())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (sleeper.IsPrisoner || guestStatus == GuestStatus.Prisoner || sleeper.IsSlave || guestStatus == GuestStatus.Slave)
|
||||
{
|
||||
if (!bed.AnyUnownedSleepingSlot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bed.AnyUnownedSleepingSlot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!IsAnyOwnerLovePartnerOf(bed, sleeper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CanUseBedNow(Thing bedThing, Pawn sleeper, bool checkSocialProperness, bool allowMedBedEvenIfSetToNoCare = false, GuestStatus? guestStatusOverride = null)
|
||||
{
|
||||
if (!(bedThing is Building_Bed building_Bed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!building_Bed.Spawned)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.Map != sleeper.MapHeld)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.IsBurning())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (sleeper.HarmedByVacuum && building_Bed.Position.GetVacuum(bedThing.Map) >= 0.5f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!CanUseBedEver(sleeper, building_Bed.def))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.CompAssignableToPawn.IdeoligionForbids(sleeper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int? assignedSleepingSlot;
|
||||
bool flag = building_Bed.IsOwner(sleeper, out assignedSleepingSlot);
|
||||
int? sleepingSlot;
|
||||
bool flag2 = sleeper.CurrentBed(out sleepingSlot) == building_Bed;
|
||||
if (!building_Bed.AnyUnoccupiedSleepingSlot && !flag && !flag2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
GuestStatus? obj = guestStatusOverride ?? sleeper.GuestStatus;
|
||||
bool flag3 = obj == GuestStatus.Prisoner;
|
||||
bool flag4 = obj == GuestStatus.Slave;
|
||||
if (checkSocialProperness && !building_Bed.IsSociallyProper(sleeper, flag3))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.ForPrisoners != flag3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.ForSlaves != flag4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.ForPrisoners && !building_Bed.Position.IsInPrisonCell(building_Bed.Map))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.Medical)
|
||||
{
|
||||
if (!allowMedBedEvenIfSetToNoCare && !HealthAIUtility.ShouldEverReceiveMedicalCareFromPlayer(sleeper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!HealthAIUtility.ShouldSeekMedicalRest(sleeper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!flag && !BedOwnerWillShare(building_Bed, sleeper, guestStatusOverride))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (flag2 && sleepingSlot != assignedSleepingSlot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (sleeper.IsColonist && !flag3)
|
||||
{
|
||||
Job curJob = sleeper.CurJob;
|
||||
if ((curJob == null || !curJob.ignoreForbidden) && !sleeper.Downed && building_Bed.IsForbidden(sleeper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsValidBedFor(Thing bedThing, Pawn sleeper, Pawn traveler, bool checkSocialProperness, bool allowMedBedEvenIfSetToNoCare = false, bool ignoreOtherReservations = false, GuestStatus? guestStatus = null)
|
||||
{
|
||||
if (!CanUseBedNow(bedThing, sleeper, checkSocialProperness, allowMedBedEvenIfSetToNoCare, guestStatus))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Building_Bed building_Bed = (Building_Bed)bedThing;
|
||||
if (!traveler.CanReach(building_Bed, PathEndMode.OnCell, Danger.Some))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!sleeper.HasReserved(building_Bed) && !traveler.CanReserve(building_Bed, building_Bed.SleepingSlotsCount, 0, null, ignoreOtherReservations))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (traveler.HasReserved<JobDriver_TakeToBed>(building_Bed, sleeper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (building_Bed.IsForbidden(traveler))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool num = guestStatus == GuestStatus.Prisoner;
|
||||
bool flag = guestStatus == GuestStatus.Slave;
|
||||
if (!num && !flag && building_Bed.Faction != traveler.Faction && (traveler.HostFaction == null || building_Bed.Faction != traveler.HostFaction))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ModsConfig.AnomalyActive && sleeper.IsMutant && sleeper.needs.rest == null && sleeper.mutant.Def.entitledToMedicalCare && !building_Bed.Medical)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void TuckIntoBed(Building_Bed bed, Pawn taker, Pawn takee, bool rescued)
|
||||
{
|
||||
IntVec3 position = bed.Position;
|
||||
if (taker != takee)
|
||||
{
|
||||
taker.carryTracker.TryDropCarriedThing(position, ThingPlaceMode.Direct, out var _);
|
||||
}
|
||||
if (CanUseBedNow(bed, takee, checkSocialProperness: false))
|
||||
{
|
||||
takee.jobs.Notify_TuckedIntoBed(bed);
|
||||
if (taker != takee && rescued)
|
||||
{
|
||||
takee.relations.Notify_RescuedBy(taker);
|
||||
}
|
||||
takee.mindState.Notify_TuckedIntoBed();
|
||||
}
|
||||
if (takee.IsPrisonerOfColony)
|
||||
{
|
||||
LessonAutoActivator.TeachOpportunity(ConceptDefOf.PrisonerTab, takee, OpportunityType.GoodToKnow);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsAnyOwnerLovePartnerOf(Building_Bed bed, Pawn sleeper)
|
||||
{
|
||||
for (int i = 0; i < bed.OwnersForReading.Count; i++)
|
||||
{
|
||||
if (LovePartnerRelationUtility.LovePartnerRelationExists(sleeper, bed.OwnersForReading[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Building_Bed FindBedFor(Pawn p)
|
||||
{
|
||||
return FindBedFor(p, p, checkSocialProperness: true, ignoreOtherReservations: false, p.GuestStatus);
|
||||
}
|
||||
|
||||
public static Building_Bed FindBedFor(Pawn sleeper, Pawn traveler, bool checkSocialProperness, bool ignoreOtherReservations = false, GuestStatus? guestStatus = null)
|
||||
{
|
||||
if (sleeper.RaceProps.IsMechanoid)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (ModsConfig.BiotechActive && sleeper.Deathresting)
|
||||
{
|
||||
Building_Bed assignedDeathrestCasket = sleeper.ownership.AssignedDeathrestCasket;
|
||||
if (assignedDeathrestCasket != null && IsValidBedFor(assignedDeathrestCasket, sleeper, traveler, checkSocialProperness: true))
|
||||
{
|
||||
CompDeathrestBindable compDeathrestBindable = assignedDeathrestCasket.TryGetComp<CompDeathrestBindable>();
|
||||
if (compDeathrestBindable != null && (compDeathrestBindable.BoundPawn == sleeper || compDeathrestBindable.BoundPawn == null))
|
||||
{
|
||||
return assignedDeathrestCasket;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool flag = false;
|
||||
if (sleeper.Ideo != null)
|
||||
{
|
||||
foreach (Precept item in sleeper.Ideo.PreceptsListForReading)
|
||||
{
|
||||
if (item.def.prefersSlabBed)
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
List<ThingDef> list = (flag ? bedDefsBestToWorst_SlabBed_Medical : bedDefsBestToWorst_Medical);
|
||||
List<ThingDef> list2 = (flag ? bedDefsBestToWorst_SlabBed_RestEffectiveness : bedDefsBestToWorst_RestEffectiveness);
|
||||
if (HealthAIUtility.ShouldSeekMedicalRest(sleeper))
|
||||
{
|
||||
if (sleeper.InBed() && sleeper.CurrentBed().Medical && IsValidBedFor(sleeper.CurrentBed(), sleeper, traveler, checkSocialProperness, allowMedBedEvenIfSetToNoCare: false, ignoreOtherReservations, guestStatus))
|
||||
{
|
||||
return sleeper.CurrentBed();
|
||||
}
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
ThingDef thingDef = list[i];
|
||||
if (!CanUseBedEver(sleeper, thingDef))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
Danger maxDanger = ((j == 0) ? Danger.None : Danger.Deadly);
|
||||
Building_Bed building_Bed = (Building_Bed)GenClosest.ClosestThingReachable(sleeper.Position, sleeper.MapHeld, ThingRequest.ForDef(thingDef), PathEndMode.OnCell, TraverseParms.For(traveler), 9999f, (Thing b) => ((Building_Bed)b).Medical && (int)b.Position.GetDangerFor(sleeper, sleeper.Map) <= (int)maxDanger && IsValidBedFor(b, sleeper, traveler, checkSocialProperness, allowMedBedEvenIfSetToNoCare: false, ignoreOtherReservations, guestStatus));
|
||||
if (building_Bed != null)
|
||||
{
|
||||
return building_Bed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sleeper.RaceProps.Dryad)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (sleeper.ownership != null && sleeper.ownership.OwnedBed != null && IsValidBedFor(sleeper.ownership.OwnedBed, sleeper, traveler, checkSocialProperness, allowMedBedEvenIfSetToNoCare: false, ignoreOtherReservations, guestStatus))
|
||||
{
|
||||
return sleeper.ownership.OwnedBed;
|
||||
}
|
||||
DirectPawnRelation directPawnRelation = LovePartnerRelationUtility.ExistingMostLikedLovePartnerRel(sleeper, allowDead: false);
|
||||
if (directPawnRelation != null)
|
||||
{
|
||||
Building_Bed ownedBed = directPawnRelation.otherPawn.ownership.OwnedBed;
|
||||
if (ownedBed != null && IsValidBedFor(ownedBed, sleeper, traveler, checkSocialProperness, allowMedBedEvenIfSetToNoCare: false, ignoreOtherReservations, guestStatus))
|
||||
{
|
||||
return ownedBed;
|
||||
}
|
||||
}
|
||||
for (int dg = 0; dg < 3; dg++)
|
||||
{
|
||||
Danger maxDanger = ((dg <= 1) ? Danger.None : Danger.Deadly);
|
||||
for (int k = 0; k < list2.Count; k++)
|
||||
{
|
||||
ThingDef thingDef2 = list2[k];
|
||||
if (!CanUseBedEver(sleeper, thingDef2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Building_Bed building_Bed2 = (Building_Bed)GenClosest.ClosestThingReachable(sleeper.PositionHeld, sleeper.MapHeld, ThingRequest.ForDef(thingDef2), PathEndMode.OnCell, TraverseParms.For(traveler), 9999f, (Thing b) => !((Building_Bed)b).Medical && (int)b.Position.GetDangerFor(sleeper, sleeper.MapHeld) <= (int)maxDanger && IsValidBedFor(b, sleeper, traveler, checkSocialProperness, allowMedBedEvenIfSetToNoCare: false, ignoreOtherReservations, guestStatus) && (dg > 0 || !b.Position.GetItems(b.Map).Any((Thing thing) => thing.def.IsCorpse)));
|
||||
if (building_Bed2 != null)
|
||||
{
|
||||
return building_Bed2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Building_Bed FindPatientBedFor(Pawn pawn)
|
||||
{
|
||||
Predicate<Thing> medBedValidator = delegate(Thing t)
|
||||
{
|
||||
if (!(t is Building_Bed building_Bed2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!building_Bed2.Medical)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return IsValidBedFor(building_Bed2, pawn, pawn, checkSocialProperness: false, allowMedBedEvenIfSetToNoCare: true, ignoreOtherReservations: false, pawn.GuestStatus) ? true : false;
|
||||
};
|
||||
if (pawn.InBed() && medBedValidator(pawn.CurrentBed()))
|
||||
{
|
||||
return pawn.CurrentBed();
|
||||
}
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Danger maxDanger = ((i == 0) ? Danger.None : Danger.Deadly);
|
||||
Building_Bed building_Bed = (Building_Bed)GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.Bed), PathEndMode.OnCell, TraverseParms.For(pawn), 9999f, (Thing b) => (int)b.Position.GetDangerFor(pawn, pawn.Map) <= (int)maxDanger && medBedValidator(b));
|
||||
if (building_Bed != null)
|
||||
{
|
||||
return building_Bed;
|
||||
}
|
||||
}
|
||||
return FindBedFor(pawn);
|
||||
}
|
||||
|
||||
public static IntVec3 GetBedSleepingSlotPosFor(Pawn pawn, Building_Bed bed)
|
||||
{
|
||||
if (bed.IsOwner(pawn, out var assignedSleepingSlot))
|
||||
{
|
||||
return bed.GetSleepingSlotPos(assignedSleepingSlot.Value);
|
||||
}
|
||||
for (int i = 0; i < bed.SleepingSlotsCount; i++)
|
||||
{
|
||||
Pawn curOccupant = bed.GetCurOccupant(i);
|
||||
if ((i >= bed.OwnersForReading.Count || bed.OwnersForReading[i] == null) && curOccupant == pawn)
|
||||
{
|
||||
return bed.GetSleepingSlotPos(i);
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < bed.SleepingSlotsCount; j++)
|
||||
{
|
||||
Pawn curOccupant2 = bed.GetCurOccupant(j);
|
||||
if ((j >= bed.OwnersForReading.Count || bed.OwnersForReading[j] == null) && curOccupant2 == null)
|
||||
{
|
||||
return bed.GetSleepingSlotPos(j);
|
||||
}
|
||||
}
|
||||
Log.Error("Could not find good sleeping slot position for " + pawn?.ToString() + ". Perhaps AnyUnoccupiedSleepingSlot check is missing somewhere.");
|
||||
return bed.GetSleepingSlotPos(0);
|
||||
}
|
||||
|
||||
public static void KickOutOfBed(Pawn pawn, Building_Bed bed)
|
||||
{
|
||||
if (pawn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!pawn.Spawned)
|
||||
{
|
||||
Log.Error("Tried to kick unspawned pawn " + pawn.ToStringSafe() + " out of bed.");
|
||||
}
|
||||
if (!pawn.Dead && !pawn.GetPosture().InBed())
|
||||
{
|
||||
Log.Error("Tried to kick pawn " + pawn.ToStringSafe() + " out of bed when they weren't in bed.");
|
||||
}
|
||||
int? sleepingSlot;
|
||||
Building_Bed building_Bed = pawn.CurrentBed(out sleepingSlot);
|
||||
if (building_Bed != bed)
|
||||
{
|
||||
if (building_Bed == null)
|
||||
{
|
||||
bed = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Tried to kick pawn " + pawn.ToStringSafe() + " out of a bed they're not currently in.");
|
||||
}
|
||||
}
|
||||
pawn.jobs.posture &= ~PawnPosture.InBedMask;
|
||||
if (bed != null && (pawn.Downed || pawn.Deathresting))
|
||||
{
|
||||
pawn.Position = bed.GetFootSlotPos(sleepingSlot.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CanUseBedEver(Pawn p, ThingDef bedDef)
|
||||
{
|
||||
if (p.RaceProps.IsMechanoid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (p.BodySize > bedDef.building.bed_maxBodySize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (p.RaceProps.Humanlike != bedDef.building.bed_humanlike)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ModsConfig.BiotechActive && bedDef == ThingDefOf.DeathrestCasket && !p.CanDeathrest())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TimetablePreventsLayDown(Pawn pawn)
|
||||
{
|
||||
if (pawn.timetable?.CurrentAssignment != null && !pawn.timetable.CurrentAssignment.allowRest && pawn.needs?.rest != null && pawn.needs.rest.CurLevel >= 0.2f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool DisturbancePreventsLyingDown(Pawn pawn)
|
||||
{
|
||||
if (pawn.Downed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Find.TickManager.TicksGame - pawn.mindState.lastDisturbanceTick < 400;
|
||||
}
|
||||
|
||||
public static bool Awake(this Pawn p)
|
||||
{
|
||||
if (!p.health.capacities.CanBeAwake)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (p.CurJob != null && p.jobs.curDriver != null)
|
||||
{
|
||||
return !p.jobs.curDriver.asleep;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsSelfShutdown(this Pawn p)
|
||||
{
|
||||
if (p.needs?.energy == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return p.needs.energy.IsSelfShutdown;
|
||||
}
|
||||
|
||||
public static bool IsDeactivated(this Pawn p)
|
||||
{
|
||||
return p.TryGetComp<CompMechanoid>()?.Deactivated ?? false;
|
||||
}
|
||||
|
||||
public static bool IsActivityDormant(this Pawn p)
|
||||
{
|
||||
if (p.GetComp<CompActivity>() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return p.GetComp<CompActivity>().IsActive;
|
||||
}
|
||||
|
||||
public static bool IsCharging(this Pawn p)
|
||||
{
|
||||
return p.needs?.energy?.currentCharger != null;
|
||||
}
|
||||
|
||||
public static Building_Bed CurrentBed(this Pawn p)
|
||||
{
|
||||
int? sleepingSlot;
|
||||
return p.CurrentBed(out sleepingSlot);
|
||||
}
|
||||
|
||||
public static Building_Bed CurrentBed(this Pawn p, out int? sleepingSlot)
|
||||
{
|
||||
sleepingSlot = null;
|
||||
if (!p.Spawned || p.CurJob == null || !p.GetPosture().InBed())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Building_Bed building_Bed = null;
|
||||
List<Thing> thingList = p.Position.GetThingList(p.Map);
|
||||
for (int i = 0; i < thingList.Count; i++)
|
||||
{
|
||||
building_Bed = thingList[i] as Building_Bed;
|
||||
if (building_Bed != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (building_Bed == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
for (int j = 0; j < building_Bed.SleepingSlotsCount; j++)
|
||||
{
|
||||
if (building_Bed.GetCurOccupant(j) == p)
|
||||
{
|
||||
sleepingSlot = j;
|
||||
return building_Bed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool InBed(this Pawn p)
|
||||
{
|
||||
return p.CurrentBed() != null;
|
||||
}
|
||||
|
||||
public static bool IsLayingForJobCleanup(Pawn p)
|
||||
{
|
||||
if (!p.InBed())
|
||||
{
|
||||
if (p.CurJob != null && p.CurJob.def == JobDefOf.LayDown)
|
||||
{
|
||||
return p.GetPosture().Laying();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void WakeUp(Pawn p, bool startNewJob = true)
|
||||
{
|
||||
if (p.CurJob != null && (p.GetPosture().Laying() || p.CurJobDef == JobDefOf.LayDown) && !p.Downed)
|
||||
{
|
||||
p.jobs.EndCurrentJob(JobCondition.InterruptForced, startNewJob);
|
||||
}
|
||||
p.GetComp<CompCanBeDormant>()?.WakeUp();
|
||||
if (p.mindState != null)
|
||||
{
|
||||
p.mindState.hibernationEndedTick = GenTicks.TicksGame;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ShouldWakeUp(Pawn pawn)
|
||||
{
|
||||
if (pawn.Deathresting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pawn.needs?.rest != null && !(pawn.needs.rest.CurLevel >= WakeThreshold(pawn)))
|
||||
{
|
||||
return pawn.health.hediffSet.HasHediffBlocksSleeping();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CanFallAsleep(Pawn pawn)
|
||||
{
|
||||
if (pawn.Deathresting)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Pawn_NeedsTracker needs = pawn.needs;
|
||||
if (needs != null && needs.food?.Starving == true && !pawn.ageTracker.CurLifeStage.canSleepWhenStarving)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pawn.mindState != null && Find.TickManager.TicksGame - pawn.mindState.lastDisturbanceTick < 400)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pawn.needs?.rest?.CurLevel < FallAsleepMaxLevel(pawn) && !pawn.health.hediffSet.HasHediffBlocksSleeping())
|
||||
{
|
||||
return pawn.CurJobDef?.sleepCanInterrupt ?? true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static float WakeThreshold(Pawn p)
|
||||
{
|
||||
Lord lord = p.GetLord();
|
||||
if (lord != null && lord.CurLordToil != null && lord.CurLordToil.CustomWakeThreshold.HasValue)
|
||||
{
|
||||
return lord.CurLordToil.CustomWakeThreshold.Value;
|
||||
}
|
||||
return p.ageTracker.CurLifeStage?.naturalWakeThresholdOverride ?? 1f;
|
||||
}
|
||||
|
||||
private static float FallAsleepMaxLevel(Pawn p)
|
||||
{
|
||||
return Mathf.Min(p.ageTracker.CurLifeStage?.fallAsleepMaxThresholdOverride ?? 0.75f, WakeThreshold(p) - 0.01f);
|
||||
}
|
||||
}
|
||||
```
|
||||
70
MCP/vector_cache/JobDriver_EnterCryptosleepCasket.txt
Normal file
70
MCP/vector_cache/JobDriver_EnterCryptosleepCasket.txt
Normal file
@@ -0,0 +1,70 @@
|
||||
根据向量相似度分析,与 'JobDriver_EnterCryptosleepCasket' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobDriver_EnterCryptosleepCasket.txt`
|
||||
|
||||
```csharp
|
||||
public class JobDriver_EnterCryptosleepCasket : JobDriver
|
||||
{
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
return pawn.Reserve(job.targetA, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
this.FailOnDespawnedOrNull(TargetIndex.A);
|
||||
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.InteractionCell);
|
||||
Toil toil = Toils_General.Wait(500);
|
||||
toil.FailOnCannotTouch(TargetIndex.A, PathEndMode.InteractionCell);
|
||||
toil.WithProgressBarToilDelay(TargetIndex.A);
|
||||
yield return toil;
|
||||
Toil enter = ToilMaker.MakeToil("MakeNewToils");
|
||||
_003C_003Ec__DisplayClass1_0 CS_0024_003C_003E8__locals0;
|
||||
enter.initAction = delegate
|
||||
{
|
||||
Building_CryptosleepCasket pod = (Building_CryptosleepCasket)((Pawn)(object)CS_0024_003C_003E8__locals0).CurJob.targetA.Thing;
|
||||
Action action = delegate
|
||||
{
|
||||
bool flag = ((Thing)(object)CS_0024_003C_003E8__locals0).DeSpawnOrDeselect(DestroyMode.Vanish);
|
||||
if (pod.TryAcceptThing((Thing)(object)CS_0024_003C_003E8__locals0) && flag)
|
||||
{
|
||||
Find.Selector.Select(CS_0024_003C_003E8__locals0, playSound: false, forceDesignatorDeselect: false);
|
||||
}
|
||||
};
|
||||
if (!pod.def.building.isPlayerEjectable)
|
||||
{
|
||||
if (base.Map.mapPawns.FreeColonistsSpawnedOrInPlayerEjectablePodsCount <= 1)
|
||||
{
|
||||
Find.WindowStack.Add(Dialog_MessageBox.CreateConfirmation("CasketWarning".Translate(CS_0024_003C_003E8__locals0.Named("PAWN")).AdjustedFor((Pawn)(object)CS_0024_003C_003E8__locals0), action));
|
||||
}
|
||||
else
|
||||
{
|
||||
action();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
action();
|
||||
}
|
||||
};
|
||||
enter.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||
yield return enter;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\JobDefs\Jobs_Misc.xml`
|
||||
**相似度:** 0.5540
|
||||
|
||||
```xml
|
||||
<defName>EnterCryptosleepCasket</defName>
|
||||
<driverClass>JobDriver_EnterCryptosleepCasket</driverClass>
|
||||
<reportString>entering cryptosleep casket.</reportString>
|
||||
<taleOnCompletion>EnteredCryptosleep</taleOnCompletion>
|
||||
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
|
||||
</JobDef>
|
||||
|
||||
<JobDef>
|
||||
<defName>UseNeurotrainer</defName>
|
||||
```
|
||||
535
MCP/vector_cache/PawnKindDef-lifeStages.txt
Normal file
535
MCP/vector_cache/PawnKindDef-lifeStages.txt
Normal file
@@ -0,0 +1,535 @@
|
||||
根据向量相似度分析,与 'PawnKindDef, lifeStages' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\PawnKindDef.txt`
|
||||
|
||||
```csharp
|
||||
public class PawnKindDef : Def
|
||||
{
|
||||
public ThingDef race;
|
||||
|
||||
[LoadAlias("defaultFactionType")]
|
||||
public FactionDef defaultFactionDef;
|
||||
|
||||
[NoTranslate]
|
||||
public List<BackstoryCategoryFilter> backstoryFilters;
|
||||
|
||||
[NoTranslate]
|
||||
public List<BackstoryCategoryFilter> backstoryFiltersOverride;
|
||||
|
||||
[NoTranslate]
|
||||
public List<string> backstoryCategories;
|
||||
|
||||
[MustTranslate]
|
||||
public string labelPlural;
|
||||
|
||||
public List<PawnKindLifeStage> lifeStages = new List<PawnKindLifeStage>();
|
||||
|
||||
public List<AlternateGraphic> alternateGraphics;
|
||||
|
||||
[XmlInheritanceAllowDuplicateNodes]
|
||||
public List<TraitRequirement> forcedTraits;
|
||||
|
||||
[XmlInheritanceAllowDuplicateNodes]
|
||||
public List<TraitRequirement> disallowedTraitsWithDegree;
|
||||
|
||||
public List<TraitDef> disallowedTraits;
|
||||
|
||||
public float alternateGraphicChance;
|
||||
|
||||
public MutantDef mutant;
|
||||
|
||||
public XenotypeSet xenotypeSet;
|
||||
|
||||
public bool useFactionXenotypes = true;
|
||||
|
||||
[LoadAlias("hairTags")]
|
||||
public List<StyleItemTagWeighted> styleItemTags;
|
||||
|
||||
public HairDef forcedHair;
|
||||
|
||||
public Color? forcedHairColor;
|
||||
|
||||
public List<MissingPart> missingParts;
|
||||
|
||||
public RulePackDef nameMaker;
|
||||
|
||||
public RulePackDef nameMakerFemale;
|
||||
|
||||
public List<AbilityDef> abilities;
|
||||
|
||||
public bool preventIdeo;
|
||||
|
||||
public bool studiableAsPrisoner;
|
||||
|
||||
public bool isBoss;
|
||||
|
||||
public Dictionary<string, float> moveSpeedFactorByTerrainTag = new Dictionary<string, float>();
|
||||
|
||||
public List<BackstoryDef> fixedChildBackstories = new List<BackstoryDef>();
|
||||
|
||||
public List<BackstoryDef> fixedAdultBackstories = new List<BackstoryDef>();
|
||||
|
||||
public float backstoryCryptosleepCommonality;
|
||||
|
||||
public FloatRange? chronologicalAgeRange;
|
||||
|
||||
public int minGenerationAge;
|
||||
|
||||
public int maxGenerationAge = 999999;
|
||||
|
||||
public bool factionLeader;
|
||||
|
||||
public Gender? fixedGender;
|
||||
|
||||
public bool allowOldAgeInjuries = true;
|
||||
|
||||
public bool generateInitialNonFamilyRelations = true;
|
||||
|
||||
public DevelopmentalStage? pawnGroupDevelopmentStage;
|
||||
|
||||
public bool destroyGearOnDrop;
|
||||
|
||||
public bool canStrip = true;
|
||||
|
||||
public float defendPointRadius = -1f;
|
||||
|
||||
public bool factionHostileOnKill;
|
||||
|
||||
public bool factionHostileOnDeath;
|
||||
|
||||
public bool hostileToAll;
|
||||
|
||||
public FloatRange? initialResistanceRange;
|
||||
|
||||
public FloatRange? initialWillRange;
|
||||
|
||||
public bool forceNoDeathNotification;
|
||||
|
||||
public bool skipResistant;
|
||||
|
||||
public float controlGroupPortraitZoom = 1f;
|
||||
|
||||
public float? overrideDeathOnDownedChance;
|
||||
|
||||
public bool forceDeathOnDowned;
|
||||
|
||||
public bool immuneToGameConditionEffects;
|
||||
|
||||
public bool immuneToTraps;
|
||||
|
||||
public bool collidesWithPawns = true;
|
||||
|
||||
public bool ignoresPainShock;
|
||||
|
||||
public bool canMeleeAttack = true;
|
||||
|
||||
public float basePrisonBreakMtbDays = 60f;
|
||||
|
||||
public bool useFixedRotation;
|
||||
|
||||
public Rot4 fixedRotation;
|
||||
|
||||
public bool showInDebugSpawner = true;
|
||||
|
||||
public bool canOpenAnyDoor;
|
||||
|
||||
public bool canOpenDoors = true;
|
||||
|
||||
[NoTranslate]
|
||||
public string overrideDebugActionCategory;
|
||||
|
||||
public float royalTitleChance;
|
||||
|
||||
public RoyalTitleDef titleRequired;
|
||||
|
||||
public RoyalTitleDef minTitleRequired;
|
||||
|
||||
public List<RoyalTitleDef> titleSelectOne;
|
||||
|
||||
public bool allowRoyalRoomRequirements = true;
|
||||
|
||||
public bool allowRoyalApparelRequirements = true;
|
||||
|
||||
public List<InfectionPathwayDef> meleeAttackInfectionPathways;
|
||||
|
||||
public List<InfectionPathwayDef> rangedAttackInfectionPathways;
|
||||
|
||||
public bool isFighter = true;
|
||||
|
||||
public float combatPower = -1f;
|
||||
|
||||
public bool canArriveManhunter = true;
|
||||
|
||||
public bool canBeSapper;
|
||||
|
||||
public bool isGoodBreacher;
|
||||
|
||||
public bool allowInMechClusters = true;
|
||||
|
||||
public int maxPerGroup = int.MaxValue;
|
||||
|
||||
public bool isGoodPsychicRitualInvoker;
|
||||
|
||||
public bool canBeScattered = true;
|
||||
|
||||
public bool appearsRandomlyInCombatGroups = true;
|
||||
|
||||
public bool aiAvoidCover;
|
||||
|
||||
public FloatRange fleeHealthThresholdRange = new FloatRange(-0.4f, 0.4f);
|
||||
|
||||
public float acceptArrestChanceFactor = 1f;
|
||||
|
||||
public bool canUseAvoidGrid;
|
||||
|
||||
public QualityCategory itemQuality = QualityCategory.Normal;
|
||||
|
||||
public QualityCategory? forceWeaponQuality;
|
||||
|
||||
public bool forceNormalGearQuality;
|
||||
|
||||
public FloatRange gearHealthRange = FloatRange.One;
|
||||
|
||||
public FloatRange weaponMoney = FloatRange.Zero;
|
||||
|
||||
[NoTranslate]
|
||||
public List<string> weaponTags;
|
||||
|
||||
public ThingDef weaponStuffOverride;
|
||||
|
||||
public ThingStyleDef weaponStyleDef;
|
||||
|
||||
public FloatRange apparelMoney = FloatRange.Zero;
|
||||
|
||||
public List<ThingDef> apparelRequired;
|
||||
|
||||
[NoTranslate]
|
||||
public List<string> apparelTags;
|
||||
|
||||
[NoTranslate]
|
||||
public List<string> apparelDisallowTags;
|
||||
|
||||
public float apparelAllowHeadgearChance = 1f;
|
||||
|
||||
public bool apparelIgnoreSeasons;
|
||||
|
||||
public bool apparelIgnorePollution;
|
||||
|
||||
public bool ignoreFactionApparelStuffRequirements;
|
||||
|
||||
public Color apparelColor = Color.white;
|
||||
|
||||
public Color? skinColorOverride;
|
||||
|
||||
public ColorDef favoriteColor;
|
||||
|
||||
public bool ignoreIdeoApparelColors;
|
||||
|
||||
public List<SpecificApparelRequirement> specificApparelRequirements;
|
||||
|
||||
public List<ThingDef> techHediffsRequired;
|
||||
|
||||
public FloatRange techHediffsMoney = FloatRange.Zero;
|
||||
|
||||
[NoTranslate]
|
||||
public List<string> techHediffsTags;
|
||||
|
||||
[NoTranslate]
|
||||
public List<string> techHediffsDisallowTags;
|
||||
|
||||
public float techHediffsChance;
|
||||
|
||||
public int techHediffsMaxAmount = 1;
|
||||
|
||||
public float biocodeWeaponChance;
|
||||
|
||||
public float humanPregnancyChance = 0.03f;
|
||||
|
||||
public List<StartingHediff> startingHediffs;
|
||||
|
||||
public float nakedChance;
|
||||
|
||||
public List<MiscDamage> existingDamage = new List<MiscDamage>();
|
||||
|
||||
public QualityCategory minApparelQuality;
|
||||
|
||||
public QualityCategory maxApparelQuality = QualityCategory.Excellent;
|
||||
|
||||
public List<ThingDefCountClass> fixedInventory = new List<ThingDefCountClass>();
|
||||
|
||||
public PawnInventoryOption inventoryOptions;
|
||||
|
||||
public float invNutrition;
|
||||
|
||||
public ThingDef invFoodDef;
|
||||
|
||||
public float chemicalAddictionChance;
|
||||
|
||||
public float combatEnhancingDrugsChance;
|
||||
|
||||
public IntRange combatEnhancingDrugsCount = IntRange.Zero;
|
||||
|
||||
public List<ChemicalDef> forcedAddictions = new List<ChemicalDef>();
|
||||
|
||||
public bool trader;
|
||||
|
||||
public List<SkillRange> skills;
|
||||
|
||||
public WorkTags requiredWorkTags;
|
||||
|
||||
public WorkTags disabledWorkTags;
|
||||
|
||||
public int extraSkillLevels;
|
||||
|
||||
public int minTotalSkillLevels;
|
||||
|
||||
public int minBestSkillLevel;
|
||||
|
||||
[MustTranslate]
|
||||
public string labelMale;
|
||||
|
||||
[MustTranslate]
|
||||
public string labelMalePlural;
|
||||
|
||||
[MustTranslate]
|
||||
public string labelFemale;
|
||||
|
||||
[MustTranslate]
|
||||
public string labelFemalePlural;
|
||||
|
||||
public IntRange wildGroupSize = IntRange.One;
|
||||
|
||||
public float ecoSystemWeight = 1f;
|
||||
|
||||
[NoTranslate]
|
||||
public string flyingAnimationFramePathPrefix;
|
||||
|
||||
[NoTranslate]
|
||||
public string flyingAnimationFramePathPrefixFemale;
|
||||
|
||||
public int flyingAnimationFrameCount;
|
||||
|
||||
public int flyingAnimationTicksPerFrame = -1;
|
||||
|
||||
public float flyingAnimationDrawSize = 1f;
|
||||
|
||||
public bool flyingAnimationDrawSizeIsMultiplier;
|
||||
|
||||
public bool flyingAnimationInheritColors;
|
||||
|
||||
private const int MaxWeaponMoney = 999999;
|
||||
|
||||
public RaceProperties RaceProps => race.race;
|
||||
|
||||
public override void ResolveReferences()
|
||||
{
|
||||
base.ResolveReferences();
|
||||
for (int i = 0; i < lifeStages.Count; i++)
|
||||
{
|
||||
lifeStages[i].ResolveReferences();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetLabelPlural(int count = -1)
|
||||
{
|
||||
if (!labelPlural.NullOrEmpty())
|
||||
{
|
||||
return labelPlural;
|
||||
}
|
||||
return Find.ActiveLanguageWorker.Pluralize(label, count);
|
||||
}
|
||||
|
||||
public string GetLabelGendered(Gender gender)
|
||||
{
|
||||
if (gender == Gender.Female && !labelFemale.NullOrEmpty())
|
||||
{
|
||||
return labelFemale;
|
||||
}
|
||||
if (gender == Gender.Male && !labelMale.NullOrEmpty())
|
||||
{
|
||||
return labelMale;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
public RulePackDef GetNameMaker(Gender gender)
|
||||
{
|
||||
if (gender == Gender.Female && nameMakerFemale != null)
|
||||
{
|
||||
return nameMakerFemale;
|
||||
}
|
||||
if (nameMaker != null)
|
||||
{
|
||||
return nameMaker;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void PostLoad()
|
||||
{
|
||||
if (backstoryCategories != null && backstoryCategories.Count > 0)
|
||||
{
|
||||
if (backstoryFilters == null)
|
||||
{
|
||||
backstoryFilters = new List<BackstoryCategoryFilter>();
|
||||
}
|
||||
backstoryFilters.Add(new BackstoryCategoryFilter
|
||||
{
|
||||
categories = backstoryCategories
|
||||
});
|
||||
}
|
||||
LongEventHandler.ExecuteWhenFinished(delegate
|
||||
{
|
||||
foreach (PawnKindLifeStage lifeStage in lifeStages)
|
||||
{
|
||||
if (lifeStage.swimmingGraphicData != null && lifeStage.swimmingGraphicData.shaderType == null)
|
||||
{
|
||||
lifeStage.swimmingGraphicData.shaderType = ShaderTypeDefOf.Transparent;
|
||||
}
|
||||
if (lifeStage.femaleSwimmingGraphicData != null && lifeStage.femaleSwimmingGraphicData.shaderType == null)
|
||||
{
|
||||
lifeStage.femaleSwimmingGraphicData.shaderType = ShaderTypeDefOf.Transparent;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public float GetAnimalPointsToHuntOrSlaughter()
|
||||
{
|
||||
return combatPower * 5f * (1f + RaceProps.manhunterOnDamageChance * 0.5f) * (1f + RaceProps.manhunterOnTameFailChance * 0.2f) * (1f + race.GetStatValueAbstract(StatDefOf.Wildness)) + race.BaseMarketValue;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string item in base.ConfigErrors())
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (backstoryFilters != null && backstoryFiltersOverride != null)
|
||||
{
|
||||
yield return "both backstoryCategories and backstoryCategoriesOverride are defined";
|
||||
}
|
||||
if (race == null)
|
||||
{
|
||||
yield return "no race";
|
||||
}
|
||||
if (combatPower < 0f)
|
||||
{
|
||||
yield return defName + " has no combatPower.";
|
||||
}
|
||||
if (weaponMoney != FloatRange.Zero)
|
||||
{
|
||||
if (weaponTags == null)
|
||||
{
|
||||
yield return "weaponMoney is set but weaponTags is not.";
|
||||
}
|
||||
else
|
||||
{
|
||||
float num = 999999f;
|
||||
int i;
|
||||
for (i = 0; i < weaponTags.Count; i++)
|
||||
{
|
||||
IEnumerable<ThingDef> source = DefDatabase<ThingDef>.AllDefs.Where((ThingDef d) => d.weaponTags != null && d.weaponTags.Contains(weaponTags[i]));
|
||||
if (source.Any())
|
||||
{
|
||||
num = Mathf.Min(num, source.Min((Func<ThingDef, float>)PawnWeaponGenerator.CheapestNonDerpPriceFor));
|
||||
}
|
||||
}
|
||||
if (num < 999999f && num > weaponMoney.min)
|
||||
{
|
||||
yield return "Cheapest weapon with one of my weaponTags costs " + num + " but weaponMoney min is " + weaponMoney.min + ", so could end up weaponless.";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!RaceProps.Humanlike && lifeStages.Count != RaceProps.lifeStageAges.Count)
|
||||
{
|
||||
yield return "PawnKindDef defines " + lifeStages.Count + " lifeStages while race def defines " + RaceProps.lifeStageAges.Count;
|
||||
}
|
||||
if (apparelRequired != null)
|
||||
{
|
||||
for (int i = 0; i < apparelRequired.Count; i++)
|
||||
{
|
||||
for (int j = i + 1; j < apparelRequired.Count; j++)
|
||||
{
|
||||
if (!ApparelUtility.CanWearTogether(apparelRequired[i], apparelRequired[j], race.race.body))
|
||||
{
|
||||
yield return "required apparel can't be worn together (" + apparelRequired[i]?.ToString() + ", " + apparelRequired[j]?.ToString() + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (alternateGraphics != null)
|
||||
{
|
||||
foreach (AlternateGraphic alternateGraphic in alternateGraphics)
|
||||
{
|
||||
if (alternateGraphic.Weight < 0f)
|
||||
{
|
||||
yield return "alternate graphic has negative weight.";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RaceProps.Humanlike && !initialResistanceRange.HasValue)
|
||||
{
|
||||
yield return "initial resistance range is undefined for humanlike pawn kind.";
|
||||
}
|
||||
if (RaceProps.Humanlike && !initialWillRange.HasValue)
|
||||
{
|
||||
yield return "initial will range is undefined for humanlike pawn kind.";
|
||||
}
|
||||
if (startingHediffs == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (StartingHediff startingHediff in startingHediffs)
|
||||
{
|
||||
if (startingHediff.durationTicksRange.HasValue && startingHediff.def.CompProps<HediffCompProperties_Disappears>() == null)
|
||||
{
|
||||
yield return "starting hediff " + startingHediff.def.defName + " has duration ticks set but doesn't have Disappears comp.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static PawnKindDef Named(string defName)
|
||||
{
|
||||
return DefDatabase<PawnKindDef>.GetNamed(defName);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Anomaly\Defs\PawnKinds\PawnKinds_Fleshbeasts.xml`
|
||||
**相似度:** 0.5160
|
||||
|
||||
```xml
|
||||
<PawnKindDef Name="BaseFleshbeastKind" Abstract="True">
|
||||
<defaultFactionDef>Entities</defaultFactionDef>
|
||||
<overrideDebugActionCategory>Entity</overrideDebugActionCategory>
|
||||
<meleeAttackInfectionPathways>
|
||||
<li>EntityAttacked</li>
|
||||
</meleeAttackInfectionPathways>
|
||||
</PawnKindDef>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Anomaly\Defs\PawnKinds\PawnKinds_Fleshbeasts.xml`
|
||||
**相似度:** 0.5160
|
||||
|
||||
```xml
|
||||
<defName>Bulbfreak</defName>
|
||||
<label>bulbfreak</label>
|
||||
<overrideDeathOnDownedChance>0.9</overrideDeathOnDownedChance>
|
||||
<race>Bulbfreak</race>
|
||||
<combatPower>360</combatPower>
|
||||
<lifeStages>
|
||||
<li>
|
||||
<bodyGraphicData>
|
||||
<texPath>Things/Pawn/Fleshbeast/Bulbfreak/Bulbfreak</texPath>
|
||||
<graphicClass>Graphic_Multi</graphicClass>
|
||||
<drawSize>3</drawSize>
|
||||
</bodyGraphicData>
|
||||
</li>
|
||||
</lifeStages>
|
||||
</PawnKindDef>
|
||||
|
||||
<PawnKindDef ParentName="BaseFleshbeastKind">
|
||||
<defName>Fingerspike</defName>
|
||||
```
|
||||
4149
MCP/vector_cache/Pawn_InventoryTracker-get_FirstUnloadableThing.txt
Normal file
4149
MCP/vector_cache/Pawn_InventoryTracker-get_FirstUnloadableThing.txt
Normal file
File diff suppressed because it is too large
Load Diff
655
MCP/vector_cache/Projectile-TickInterval-Verse.txt
Normal file
655
MCP/vector_cache/Projectile-TickInterval-Verse.txt
Normal file
@@ -0,0 +1,655 @@
|
||||
根据向量相似度分析,与 'TickInterval, Projectile, Verse' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\Projectile.txt`
|
||||
|
||||
```csharp
|
||||
public abstract class Projectile : ThingWithComps
|
||||
{
|
||||
private static readonly Material shadowMaterial = MaterialPool.MatFrom("Things/Skyfaller/SkyfallerShadowCircle", ShaderDatabase.Transparent);
|
||||
|
||||
protected Vector3 origin;
|
||||
|
||||
protected Vector3 destination;
|
||||
|
||||
public LocalTargetInfo usedTarget;
|
||||
|
||||
public LocalTargetInfo intendedTarget;
|
||||
|
||||
protected Thing equipment;
|
||||
|
||||
protected ThingDef equipmentDef;
|
||||
|
||||
protected Thing launcher;
|
||||
|
||||
protected ThingDef targetCoverDef;
|
||||
|
||||
private ProjectileHitFlags desiredHitFlags = ProjectileHitFlags.All;
|
||||
|
||||
protected bool preventFriendlyFire;
|
||||
|
||||
protected int lifetime;
|
||||
|
||||
protected QualityCategory equipmentQuality = QualityCategory.Normal;
|
||||
|
||||
public float stoppingPower;
|
||||
|
||||
public DamageDef damageDefOverride;
|
||||
|
||||
public List<ExtraDamage> extraDamages = new List<ExtraDamage>();
|
||||
|
||||
protected bool landed;
|
||||
|
||||
protected int ticksToImpact;
|
||||
|
||||
private Sustainer ambientSustainer;
|
||||
|
||||
private static List<IntVec3> checkedCells = new List<IntVec3>();
|
||||
|
||||
public DamageDef DamageDef => damageDefOverride ?? def.projectile.damageDef;
|
||||
|
||||
public IEnumerable<ExtraDamage> ExtraDamages
|
||||
{
|
||||
get
|
||||
{
|
||||
List<ExtraDamage> first = extraDamages;
|
||||
IEnumerable<ExtraDamage> enumerable = def.projectile.extraDamages;
|
||||
return first.Concat(enumerable ?? Enumerable.Empty<ExtraDamage>());
|
||||
}
|
||||
}
|
||||
|
||||
public ProjectileHitFlags HitFlags
|
||||
{
|
||||
get
|
||||
{
|
||||
if (def.projectile.alwaysFreeIntercept)
|
||||
{
|
||||
return ProjectileHitFlags.All;
|
||||
}
|
||||
if (def.projectile.flyOverhead)
|
||||
{
|
||||
return ProjectileHitFlags.None;
|
||||
}
|
||||
return desiredHitFlags;
|
||||
}
|
||||
set
|
||||
{
|
||||
desiredHitFlags = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected float StartingTicksToImpact
|
||||
{
|
||||
get
|
||||
{
|
||||
float num = (origin - destination).magnitude / def.projectile.SpeedTilesPerTick;
|
||||
if (num <= 0f)
|
||||
{
|
||||
num = 0.001f;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
protected IntVec3 DestinationCell => new IntVec3(destination);
|
||||
|
||||
public virtual Vector3 ExactPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector3 vector = (destination - origin).Yto0() * DistanceCoveredFraction;
|
||||
return origin.Yto0() + vector + Vector3.up * def.Altitude;
|
||||
}
|
||||
}
|
||||
|
||||
protected float DistanceCoveredFraction => Mathf.Clamp01(1f - (float)ticksToImpact / StartingTicksToImpact);
|
||||
|
||||
protected float DistanceCoveredFractionArc => Mathf.Clamp01(1f - (float)(landed ? lifetime : ticksToImpact) / StartingTicksToImpact);
|
||||
|
||||
public virtual Quaternion ExactRotation => Quaternion.LookRotation((destination - origin).Yto0());
|
||||
|
||||
public virtual bool AnimalsFleeImpact => false;
|
||||
|
||||
public override Vector3 DrawPos => ExactPosition;
|
||||
|
||||
public virtual Material DrawMat => def.graphic.MatSingleFor(this);
|
||||
|
||||
public virtual int DamageAmount => def.projectile.GetDamageAmount(equipment);
|
||||
|
||||
public virtual float ArmorPenetration => def.projectile.GetArmorPenetration(equipment);
|
||||
|
||||
public ThingDef EquipmentDef => equipmentDef;
|
||||
|
||||
public Thing Launcher => launcher;
|
||||
|
||||
public override int UpdateRateTicks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (base.Spawned && Find.CurrentMap == base.Map && Find.CameraDriver.InViewOf(this))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
private float ArcHeightFactor
|
||||
{
|
||||
get
|
||||
{
|
||||
float num = def.projectile.arcHeightFactor;
|
||||
float num2 = (destination - origin).MagnitudeHorizontalSquared();
|
||||
if (num * num > num2 * 0.2f * 0.2f)
|
||||
{
|
||||
num = Mathf.Sqrt(num2) * 0.2f;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref origin, "origin");
|
||||
Scribe_Values.Look(ref destination, "destination");
|
||||
Scribe_Values.Look(ref ticksToImpact, "ticksToImpact", 0);
|
||||
Scribe_TargetInfo.Look(ref usedTarget, "usedTarget");
|
||||
Scribe_TargetInfo.Look(ref intendedTarget, "intendedTarget");
|
||||
Scribe_References.Look(ref launcher, "launcher");
|
||||
Scribe_References.Look(ref equipment, "equipment");
|
||||
Scribe_Defs.Look(ref equipmentDef, "equipmentDef");
|
||||
Scribe_Defs.Look(ref targetCoverDef, "targetCoverDef");
|
||||
Scribe_Values.Look(ref desiredHitFlags, "desiredHitFlags", ProjectileHitFlags.All);
|
||||
Scribe_Values.Look(ref preventFriendlyFire, "preventFriendlyFire", defaultValue: false);
|
||||
Scribe_Values.Look(ref landed, "landed", defaultValue: false);
|
||||
Scribe_Values.Look(ref lifetime, "lifetime", 0);
|
||||
Scribe_Values.Look(ref equipmentQuality, "equipmentQuality", QualityCategory.Normal);
|
||||
}
|
||||
|
||||
public void Launch(Thing launcher, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null)
|
||||
{
|
||||
Launch(launcher, base.Position.ToVector3Shifted(), usedTarget, intendedTarget, hitFlags, preventFriendlyFire, equipment);
|
||||
}
|
||||
|
||||
public virtual void Launch(Thing launcher, Vector3 origin, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null, ThingDef targetCoverDef = null)
|
||||
{
|
||||
this.launcher = launcher;
|
||||
this.origin = origin;
|
||||
this.usedTarget = usedTarget;
|
||||
this.intendedTarget = intendedTarget;
|
||||
this.targetCoverDef = targetCoverDef;
|
||||
this.preventFriendlyFire = preventFriendlyFire;
|
||||
HitFlags = hitFlags;
|
||||
stoppingPower = def.projectile.stoppingPower;
|
||||
if (stoppingPower == 0f && def.projectile.damageDef != null)
|
||||
{
|
||||
stoppingPower = def.projectile.damageDef.defaultStoppingPower;
|
||||
}
|
||||
if (equipment != null)
|
||||
{
|
||||
this.equipment = equipment;
|
||||
equipmentDef = equipment.def;
|
||||
equipment.TryGetQuality(out equipmentQuality);
|
||||
if (equipment.TryGetComp(out CompUniqueWeapon comp))
|
||||
{
|
||||
foreach (WeaponTraitDef item in comp.TraitsListForReading)
|
||||
{
|
||||
if (!Mathf.Approximately(item.additionalStoppingPower, 0f))
|
||||
{
|
||||
stoppingPower += item.additionalStoppingPower;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
equipmentDef = null;
|
||||
}
|
||||
destination = usedTarget.Cell.ToVector3Shifted() + Gen.RandomHorizontalVector(0.3f);
|
||||
ticksToImpact = Mathf.CeilToInt(StartingTicksToImpact);
|
||||
if (ticksToImpact < 1)
|
||||
{
|
||||
ticksToImpact = 1;
|
||||
}
|
||||
lifetime = ticksToImpact;
|
||||
if (!def.projectile.soundAmbient.NullOrUndefined())
|
||||
{
|
||||
ambientSustainer = def.projectile.soundAmbient.TrySpawnSustainer(SoundInfo.InMap(this, MaintenanceType.PerTick));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
if (ticksToImpact == 60 && Find.TickManager.CurTimeSpeed == TimeSpeed.Normal && def.projectile.soundImpactAnticipate != null)
|
||||
{
|
||||
def.projectile.soundImpactAnticipate.PlayOneShot(this);
|
||||
}
|
||||
if (ambientSustainer != null)
|
||||
{
|
||||
ambientSustainer.Maintain();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void TickInterval(int delta)
|
||||
{
|
||||
base.TickInterval(delta);
|
||||
lifetime -= delta;
|
||||
if (landed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vector3 exactPosition = ExactPosition;
|
||||
ticksToImpact -= delta;
|
||||
if (!ExactPosition.InBounds(base.Map))
|
||||
{
|
||||
ticksToImpact += delta;
|
||||
base.Position = ExactPosition.ToIntVec3();
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
Vector3 exactPosition2 = ExactPosition;
|
||||
if (CheckForFreeInterceptBetween(exactPosition, exactPosition2))
|
||||
{
|
||||
return;
|
||||
}
|
||||
base.Position = ExactPosition.ToIntVec3();
|
||||
if (ticksToImpact <= 0)
|
||||
{
|
||||
if (DestinationCell.InBounds(base.Map))
|
||||
{
|
||||
base.Position = DestinationCell;
|
||||
}
|
||||
ImpactSomething();
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckForFreeInterceptBetween(Vector3 lastExactPos, Vector3 newExactPos)
|
||||
{
|
||||
if (lastExactPos == newExactPos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
List<Thing> list = base.Map.listerThings.ThingsInGroup(ThingRequestGroup.ProjectileInterceptor);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (list[i].TryGetComp<CompProjectileInterceptor>().CheckIntercept(this, lastExactPos, newExactPos))
|
||||
{
|
||||
Impact(null, blockedByShield: true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
IntVec3 intVec = lastExactPos.ToIntVec3();
|
||||
IntVec3 intVec2 = newExactPos.ToIntVec3();
|
||||
if (intVec2 == intVec)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!intVec.InBounds(base.Map) || !intVec2.InBounds(base.Map))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (intVec2.AdjacentToCardinal(intVec))
|
||||
{
|
||||
return CheckForFreeIntercept(intVec2);
|
||||
}
|
||||
if (VerbUtility.InterceptChanceFactorFromDistance(origin, intVec2) <= 0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Vector3 vect = lastExactPos;
|
||||
Vector3 v = newExactPos - lastExactPos;
|
||||
Vector3 vector = v.normalized * 0.2f;
|
||||
int num = (int)(v.MagnitudeHorizontal() / 0.2f);
|
||||
checkedCells.Clear();
|
||||
int num2 = 0;
|
||||
IntVec3 intVec3;
|
||||
do
|
||||
{
|
||||
vect += vector;
|
||||
intVec3 = vect.ToIntVec3();
|
||||
if (!checkedCells.Contains(intVec3))
|
||||
{
|
||||
if (CheckForFreeIntercept(intVec3))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
checkedCells.Add(intVec3);
|
||||
}
|
||||
num2++;
|
||||
if (num2 > num)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (!(intVec3 == intVec2));
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CheckForFreeIntercept(IntVec3 c)
|
||||
{
|
||||
if (destination.ToIntVec3() == c)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
float num = VerbUtility.InterceptChanceFactorFromDistance(origin, c);
|
||||
if (num <= 0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool flag = false;
|
||||
List<Thing> thingList = c.GetThingList(base.Map);
|
||||
for (int i = 0; i < thingList.Count; i++)
|
||||
{
|
||||
Thing thing = thingList[i];
|
||||
if (!CanHit(thing))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bool flag2 = false;
|
||||
if (thing.def.Fillage == FillCategory.Full)
|
||||
{
|
||||
if (!(thing is Building_Door { Open: not false }))
|
||||
{
|
||||
ThrowDebugText("int-wall", c);
|
||||
Impact(thing);
|
||||
return true;
|
||||
}
|
||||
flag2 = true;
|
||||
}
|
||||
float num2 = 0f;
|
||||
if (thing is Pawn pawn)
|
||||
{
|
||||
num2 = 0.4f * Mathf.Clamp(pawn.BodySize, 0.1f, 2f);
|
||||
if (pawn.GetPosture() != 0)
|
||||
{
|
||||
num2 *= 0.1f;
|
||||
}
|
||||
if (launcher != null && pawn.Faction != null && launcher.Faction != null && !pawn.Faction.HostileTo(launcher.Faction))
|
||||
{
|
||||
if (preventFriendlyFire)
|
||||
{
|
||||
num2 = 0f;
|
||||
ThrowDebugText("ff-miss", c);
|
||||
}
|
||||
else
|
||||
{
|
||||
num2 *= Find.Storyteller.difficulty.friendlyFireChanceFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (thing.def.fillPercent > 0.2f)
|
||||
{
|
||||
num2 = (flag2 ? 0.05f : ((!DestinationCell.AdjacentTo8Way(c)) ? (thing.def.fillPercent * 0.15f) : (thing.def.fillPercent * 1f)));
|
||||
}
|
||||
num2 *= num;
|
||||
if (num2 > 1E-05f)
|
||||
{
|
||||
if (Rand.Chance(num2))
|
||||
{
|
||||
ThrowDebugText("int-" + num2.ToStringPercent(), c);
|
||||
Impact(thing);
|
||||
return true;
|
||||
}
|
||||
flag = true;
|
||||
ThrowDebugText(num2.ToStringPercent(), c);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
ThrowDebugText("o", c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ThrowDebugText(string text, IntVec3 c)
|
||||
{
|
||||
if (DebugViewSettings.drawShooting)
|
||||
{
|
||||
MoteMaker.ThrowText(c.ToVector3Shifted(), base.Map, text);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DrawAt(Vector3 drawLoc, bool flip = false)
|
||||
{
|
||||
float num = ArcHeightFactor * GenMath.InverseParabola(DistanceCoveredFractionArc);
|
||||
Vector3 vector = drawLoc + new Vector3(0f, 0f, 1f) * num;
|
||||
if (def.projectile.shadowSize > 0f)
|
||||
{
|
||||
DrawShadow(drawLoc, num);
|
||||
}
|
||||
Quaternion rotation = ExactRotation;
|
||||
if (def.projectile.spinRate != 0f)
|
||||
{
|
||||
float num2 = 60f / def.projectile.spinRate;
|
||||
rotation = Quaternion.AngleAxis((float)Find.TickManager.TicksGame % num2 / num2 * 360f, Vector3.up);
|
||||
}
|
||||
if (def.projectile.useGraphicClass)
|
||||
{
|
||||
Graphic.Draw(vector, base.Rotation, this, rotation.eulerAngles.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
Graphics.DrawMesh(MeshPool.GridPlane(def.graphicData.drawSize), vector, rotation, DrawMat, 0);
|
||||
}
|
||||
Comps_PostDraw();
|
||||
}
|
||||
|
||||
protected bool CanHit(Thing thing)
|
||||
{
|
||||
if (!thing.Spawned)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (thing == launcher)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ProjectileHitFlags hitFlags = HitFlags;
|
||||
if (hitFlags == ProjectileHitFlags.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (thing.Map != base.Map)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (CoverUtility.ThingCovered(thing, base.Map))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (thing == intendedTarget && (hitFlags & ProjectileHitFlags.IntendedTarget) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (thing != intendedTarget)
|
||||
{
|
||||
if (thing is Pawn)
|
||||
{
|
||||
if ((hitFlags & ProjectileHitFlags.NonTargetPawns) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if ((hitFlags & ProjectileHitFlags.NonTargetWorld) != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (thing == intendedTarget && thing.def.Fillage == FillCategory.Full)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void ImpactSomething()
|
||||
{
|
||||
if (def.projectile.flyOverhead)
|
||||
{
|
||||
RoofDef roofDef = base.Map.roofGrid.RoofAt(base.Position);
|
||||
if (roofDef != null)
|
||||
{
|
||||
if (roofDef.isThickRoof)
|
||||
{
|
||||
ThrowDebugText("hit-thick-roof", base.Position);
|
||||
if (!def.projectile.soundHitThickRoof.NullOrUndefined())
|
||||
{
|
||||
def.projectile.soundHitThickRoof.PlayOneShot(new TargetInfo(base.Position, base.Map));
|
||||
}
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
if (base.Position.GetEdifice(base.Map) == null || base.Position.GetEdifice(base.Map).def.Fillage != FillCategory.Full)
|
||||
{
|
||||
RoofCollapserImmediate.DropRoofInCells(base.Position, base.Map);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (usedTarget.HasThing && CanHit(usedTarget.Thing))
|
||||
{
|
||||
if (usedTarget.Thing is Pawn p && p.GetPosture() != 0 && (origin - destination).MagnitudeHorizontalSquared() >= 20.25f && !Rand.Chance(0.5f))
|
||||
{
|
||||
ThrowDebugText("miss-laying", base.Position);
|
||||
Impact(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Impact(usedTarget.Thing);
|
||||
}
|
||||
return;
|
||||
}
|
||||
List<Thing> list = VerbUtility.ThingsToHit(base.Position, base.Map, CanHit);
|
||||
list.Shuffle();
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
Thing thing = list[i];
|
||||
float num;
|
||||
if (thing is Pawn pawn)
|
||||
{
|
||||
num = 0.5f * Mathf.Clamp(pawn.BodySize, 0.1f, 2f);
|
||||
if (pawn.GetPosture() != 0 && (origin - destination).MagnitudeHorizontalSquared() >= 20.25f)
|
||||
{
|
||||
num *= 0.5f;
|
||||
}
|
||||
if (launcher != null && pawn.Faction != null && launcher.Faction != null && !pawn.Faction.HostileTo(launcher.Faction))
|
||||
{
|
||||
num *= VerbUtility.InterceptChanceFactorFromDistance(origin, base.Position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num = 1.5f * thing.def.fillPercent;
|
||||
}
|
||||
if (Rand.Chance(num))
|
||||
{
|
||||
ThrowDebugText("hit-" + num.ToStringPercent(), base.Position);
|
||||
Impact(list.RandomElement());
|
||||
return;
|
||||
}
|
||||
ThrowDebugText("miss-" + num.ToStringPercent(), base.Position);
|
||||
}
|
||||
Impact(null);
|
||||
}
|
||||
|
||||
protected virtual void Impact(Thing hitThing, bool blockedByShield = false)
|
||||
{
|
||||
GenClamor.DoClamor(this, 12f, ClamorDefOf.Impact);
|
||||
if (!blockedByShield && def.projectile.landedEffecter != null)
|
||||
{
|
||||
def.projectile.landedEffecter.Spawn(base.Position, base.Map).Cleanup();
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
|
||||
private void DrawShadow(Vector3 drawLoc, float height)
|
||||
{
|
||||
if (!(shadowMaterial == null))
|
||||
{
|
||||
float num = def.projectile.shadowSize * Mathf.Lerp(1f, 0.6f, height);
|
||||
Vector3 s = new Vector3(num, 1f, num);
|
||||
Vector3 vector = new Vector3(0f, -0.01f, 0f);
|
||||
Matrix4x4 matrix = default(Matrix4x4);
|
||||
matrix.SetTRS(drawLoc + vector, Quaternion.identity, s);
|
||||
Graphics.DrawMesh(MeshPool.plane10, matrix, shadowMaterial, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\CompRitualEffect_IntervalSpawn.txt`
|
||||
**相似度:** 0.5662
|
||||
|
||||
```csharp
|
||||
public abstract class CompRitualEffect_IntervalSpawn : RitualVisualEffectComp
|
||||
{
|
||||
public int lastSpawnTick = -1;
|
||||
|
||||
public int ticksPassed;
|
||||
|
||||
protected int burstsDone;
|
||||
|
||||
protected CompProperties_RitualEffectIntervalSpawn Props => (CompProperties_RitualEffectIntervalSpawn)props;
|
||||
|
||||
public override bool ShouldSpawnNow(LordJob_Ritual ritual)
|
||||
{
|
||||
if (Props.delay > 0 && ticksPassed < Props.delay)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Props.maxBursts > 0 && burstsDone >= Props.maxBursts)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (lastSpawnTick != -1)
|
||||
{
|
||||
return GenTicks.TicksGame - lastSpawnTick >= Props.spawnIntervalTicks;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void TickInterval(int delta)
|
||||
{
|
||||
base.TickInterval(delta);
|
||||
ticksPassed += delta;
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref lastSpawnTick, "lastSpawnTick", -1);
|
||||
Scribe_Values.Look(ref burstsDone, "burstsDone", 0);
|
||||
Scribe_Values.Look(ref ticksPassed, "ticksPassed", 0);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse\Gene_Clotting.txt`
|
||||
**相似度:** 0.5078
|
||||
|
||||
```csharp
|
||||
public class Gene_Clotting : Gene
|
||||
{
|
||||
private const int ClotCheckInterval = 360;
|
||||
|
||||
private static readonly FloatRange TendingQualityRange = new FloatRange(0.2f, 0.7f);
|
||||
|
||||
public override void TickInterval(int delta)
|
||||
{
|
||||
base.TickInterval(delta);
|
||||
if (!pawn.IsHashIntervalTick(360, delta))
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<Hediff> hediffs = pawn.health.hediffSet.hediffs;
|
||||
for (int num = hediffs.Count - 1; num >= 0; num--)
|
||||
{
|
||||
if (hediffs[num].Bleeding)
|
||||
{
|
||||
hediffs[num].Tended(TendingQualityRange.RandomInRange, TendingQualityRange.TrueMax, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
871
MCP/vector_cache/PsychicRitualDef.txt
Normal file
871
MCP/vector_cache/PsychicRitualDef.txt
Normal file
@@ -0,0 +1,871 @@
|
||||
根据向量相似度分析,与 'PsychicRitualDef' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef.txt`
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef : Def
|
||||
{
|
||||
public ResearchProjectDef researchPrerequisite;
|
||||
|
||||
public bool allowsDrafting;
|
||||
|
||||
public bool allowsFloatMenu;
|
||||
|
||||
public int cooldownHours;
|
||||
|
||||
public bool nonRequiredPawnsMayLeave;
|
||||
|
||||
public float rolePowerFactor = 0.2f;
|
||||
|
||||
public bool aiCastable;
|
||||
|
||||
public bool playerCastable = true;
|
||||
|
||||
public float minThreatPoints;
|
||||
|
||||
public bool castableOnPocketMaps = true;
|
||||
|
||||
public List<PlanetLayerDef> layerWhitelist = new List<PlanetLayerDef>();
|
||||
|
||||
[MustTranslate]
|
||||
public string letterAICompleteLabel;
|
||||
|
||||
[MustTranslate]
|
||||
public string letterAICompleteText;
|
||||
|
||||
[MustTranslate]
|
||||
public string letterAIArrivedText;
|
||||
|
||||
[NoTranslate]
|
||||
public string iconPath;
|
||||
|
||||
public Texture2D uiIcon = BaseContent.BadTex;
|
||||
|
||||
private List<PsychicRitualRoleDef> rolesBackingList = new List<PsychicRitualRoleDef>(8);
|
||||
|
||||
private static readonly List<Pawn> tmpPawnsIterationList = new List<Pawn>(16);
|
||||
|
||||
public virtual List<PsychicRitualRoleDef> Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
rolesBackingList.Clear();
|
||||
return rolesBackingList;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!playerCastable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (DebugSettings.godMode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (researchPrerequisite == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!researchPrerequisite.IsFinished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostLoad()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(iconPath))
|
||||
{
|
||||
LongEventHandler.ExecuteWhenFinished(delegate
|
||||
{
|
||||
uiIcon = ContentFinder<Texture2D>.Get(iconPath);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public virtual AcceptanceReport AllowsDrafting(Pawn pawn)
|
||||
{
|
||||
if (allowsDrafting)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return new AcceptanceReport("ParticipatingInPsychicRitual".Translate(pawn, label));
|
||||
}
|
||||
|
||||
public virtual AcceptanceReport AllowsFloatMenu(Pawn pawn)
|
||||
{
|
||||
if (allowsFloatMenu)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return new AcceptanceReport("ParticipatingInPsychicRitual".Translate(pawn, label));
|
||||
}
|
||||
|
||||
public virtual bool BlocksSocialInteraction(Pawn pawn)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual AcceptanceReport AbilityAllowed(Ability ability)
|
||||
{
|
||||
return new AcceptanceReport("AbilityDisabledInPsychicRitual".Translate(ability.pawn, label));
|
||||
}
|
||||
|
||||
public virtual PsychicRitualGraph CreateGraph()
|
||||
{
|
||||
return new PsychicRitualGraph();
|
||||
}
|
||||
|
||||
public virtual List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
throw new NotImplementedException("You must subclass PsychicRitualDef and override CreateToils() to return a list of toils.");
|
||||
}
|
||||
|
||||
public virtual PsychicRitualCandidatePool FindCandidatePool()
|
||||
{
|
||||
return new PsychicRitualCandidatePool(new List<Pawn>(Find.CurrentMap.mapPawns.FreeColonistsAndPrisonersSpawned.Where((Pawn p) => !p.IsSubhuman)), new List<Pawn>());
|
||||
}
|
||||
|
||||
public virtual PsychicRitualRoleAssignments BuildRoleAssignments(TargetInfo target)
|
||||
{
|
||||
return new PsychicRitualRoleAssignments(Roles, target);
|
||||
}
|
||||
|
||||
public static bool OfferingReachable(Map map, List<Pawn> pawns, IngredientCount offering, out int reachableCount)
|
||||
{
|
||||
using (new ProfilerBlock("Offering reachable"))
|
||||
{
|
||||
reachableCount = 0;
|
||||
float num = offering.GetBaseCount();
|
||||
if (num <= 0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
List<Thing> list;
|
||||
using (new ProfilerBlock("ThingsMatchingFilter"))
|
||||
{
|
||||
list = map.listerThings.ThingsMatchingFilter(offering.filter);
|
||||
}
|
||||
foreach (Thing item in list)
|
||||
{
|
||||
if (num <= 0f)
|
||||
{
|
||||
break;
|
||||
}
|
||||
foreach (Pawn pawn in pawns)
|
||||
{
|
||||
if (pawn.CanReserveAndReach(item, PathEndMode.Touch, pawn.NormalMaxDanger()) && !item.IsForbidden(pawn) && !item.Fogged())
|
||||
{
|
||||
num -= (float)item.stackCount;
|
||||
reachableCount += item.stackCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num <= 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> BlockingIssues(PsychicRitualRoleAssignments assignments, Map map)
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
public virtual TaggedString PsychicRitualBegunMessage(PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
return "PsychicRitualBegun".Translate(label);
|
||||
}
|
||||
|
||||
public virtual TaggedString PsychicRitualCompletedMessage()
|
||||
{
|
||||
return "PsychicRitualCompleted".Translate(label);
|
||||
}
|
||||
|
||||
public virtual TaggedString PsychicRitualCanceledMessage(TaggedString reason)
|
||||
{
|
||||
if (reason.NullOrEmpty())
|
||||
{
|
||||
return "PsychicRitualCanceled".Translate(label);
|
||||
}
|
||||
return "PsychicRitualCanceledBecause".Translate(label, reason);
|
||||
}
|
||||
|
||||
public virtual TaggedString LeftPsychicRitualMessage(Pawn pawn, TaggedString reason)
|
||||
{
|
||||
if (reason.NullOrEmpty())
|
||||
{
|
||||
return "PsychicRitualLeft".Translate(pawn, label);
|
||||
}
|
||||
return "PsychicRitualLeftBecause".Translate(pawn, label, reason);
|
||||
}
|
||||
|
||||
public virtual string GetPawnReport(PsychicRitual psychicRitual, Pawn pawn)
|
||||
{
|
||||
return "PsychicRitualAttending".Translate(label.Named("RITUALNAME"));
|
||||
}
|
||||
|
||||
public virtual Lord MakeNewLord(PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
Lord lord = LordMaker.MakeNewLord(Faction.OfPlayer, new LordJob_PsychicRitual(this, assignments), Find.CurrentMap, assignments.AllAssignedPawns);
|
||||
if (assignments.Target.Thing is Building b)
|
||||
{
|
||||
lord.AddBuilding(b);
|
||||
}
|
||||
return lord;
|
||||
}
|
||||
|
||||
public virtual bool IsValidTarget(TargetInfo target, out AnyEnum reason)
|
||||
{
|
||||
reason = AnyEnum.None;
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual TaggedString InvalidTargetReason(AnyEnum reason)
|
||||
{
|
||||
if (reason == AnyEnum.None)
|
||||
{
|
||||
return TaggedString.Empty;
|
||||
}
|
||||
throw new InvalidOperationException("Unknown enum type " + reason.enumType.ToStringSafe() + "; did you forget to override `InvalidTargetReason` in a child class?");
|
||||
}
|
||||
|
||||
public virtual void CalculateMaxPower(PsychicRitualRoleAssignments assignments, List<QualityFactor> powerFactorsOut, out float power)
|
||||
{
|
||||
power = 0f;
|
||||
int num = 0;
|
||||
IReadOnlyDictionary<PsychicRitualRoleDef, List<Pawn>> roleAssignments = assignments.RoleAssignments;
|
||||
PsychicRitualRoleDef key;
|
||||
List<Pawn> value;
|
||||
foreach (KeyValuePair<PsychicRitualRoleDef, List<Pawn>> item in roleAssignments)
|
||||
{
|
||||
item.Deconstruct(out key, out value);
|
||||
PsychicRitualRoleDef psychicRitualRoleDef = key;
|
||||
List<Pawn> list = value;
|
||||
if (psychicRitualRoleDef.applyPowerOffset)
|
||||
{
|
||||
num += list.Count;
|
||||
}
|
||||
if (psychicRitualRoleDef.MaxCount != psychicRitualRoleDef.MinCount)
|
||||
{
|
||||
float num2 = (float)(list.Count - psychicRitualRoleDef.MinCount) / (float)(psychicRitualRoleDef.MaxCount - psychicRitualRoleDef.MinCount);
|
||||
power += rolePowerFactor * num2;
|
||||
powerFactorsOut?.Add(new QualityFactor
|
||||
{
|
||||
count = $"{list.Count} / {psychicRitualRoleDef.MaxCount}",
|
||||
label = Find.ActiveLanguageWorker.Pluralize(psychicRitualRoleDef.LabelCap),
|
||||
positive = (list.Count >= psychicRitualRoleDef.MinCount),
|
||||
quality = rolePowerFactor * num2,
|
||||
toolTip = psychicRitualRoleDef.description.CapitalizeFirst().EndWithPeriod()
|
||||
});
|
||||
}
|
||||
}
|
||||
if (num > 0)
|
||||
{
|
||||
float num3 = 0f;
|
||||
foreach (KeyValuePair<PsychicRitualRoleDef, List<Pawn>> item2 in roleAssignments)
|
||||
{
|
||||
item2.Deconstruct(out key, out value);
|
||||
PsychicRitualRoleDef psychicRitualRoleDef2 = key;
|
||||
List<Pawn> list2 = value;
|
||||
if (!psychicRitualRoleDef2.applyPowerOffset)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (Pawn item3 in list2)
|
||||
{
|
||||
num3 += item3.GetStatValue(StatDefOf.PsychicRitualQualityOffset) / (float)num;
|
||||
}
|
||||
}
|
||||
if (!Mathf.Approximately(num3, 0f))
|
||||
{
|
||||
power += num3;
|
||||
powerFactorsOut?.Add(new QualityFactor
|
||||
{
|
||||
label = "PsychicRitualDef_InvocationCircle_QualityFactor_Ideoligion".Translate(),
|
||||
positive = (num3 > 0f),
|
||||
count = num3.ToStringPercent(),
|
||||
quality = num3,
|
||||
toolTip = "PsychicRitualDef_InvocationCircle_QualityFactor_Ideoligion_Tooltip".Translate()
|
||||
});
|
||||
}
|
||||
}
|
||||
power = Mathf.Clamp01(power);
|
||||
}
|
||||
|
||||
public virtual void RemoveIncapablePawns(PsychicRitual psychicRitual)
|
||||
{
|
||||
foreach (var (psychicRitualRoleDef2, collection) in psychicRitual.assignments.RoleAssignments)
|
||||
{
|
||||
tmpPawnsIterationList.Clear();
|
||||
tmpPawnsIterationList.AddRange(collection);
|
||||
foreach (Pawn tmpPawnsIteration in tmpPawnsIterationList)
|
||||
{
|
||||
if (!psychicRitualRoleDef2.PawnCanDo(PsychicRitualRoleDef.Context.Runtime, tmpPawnsIteration, psychicRitual.assignments.Target, out var reason) && psychicRitual.LeaveOrCancelPsychicRitual(psychicRitualRoleDef2, tmpPawnsIteration, reason.ToPlayerReadable()) == PsychicRitual.LeftOrCanceled.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void CheckPsychicRitualCancelConditions(PsychicRitual psychicRitual)
|
||||
{
|
||||
TargetInfo target = psychicRitual.assignments.Target;
|
||||
if (target.ThingDestroyed)
|
||||
{
|
||||
psychicRitual.CancelPsychicRitual("PsychicRitualDef_TargetDestroyed".Translate(target.Thing.Named("TARGET")));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual TaggedString OutcomeDescription(FloatRange qualityRange, string qualityNumber, PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
return TaggedString.Empty;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<TaggedString> OutcomeWarnings(PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
return Enumerable.Empty<TaggedString>();
|
||||
}
|
||||
|
||||
public virtual TaggedString TimeAndOfferingLabel()
|
||||
{
|
||||
return TaggedString.Empty;
|
||||
}
|
||||
|
||||
public virtual void InitializeCast(Map map)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual IntVec3 GetBestStandableRolePosition(bool playerRitual, IntVec3 origin, IntVec3 ritualPosition, Map map, float radius = 8f)
|
||||
{
|
||||
if (playerRitual)
|
||||
{
|
||||
return origin;
|
||||
}
|
||||
IntVec3 result = CellFinder.StandableCellNear(origin, map, radius, (IntVec3 c) => map.reachability.CanReach(ritualPosition, c, PathEndMode.OnCell, TraverseMode.NoPassClosedDoorsOrWater));
|
||||
if (result.IsValid)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> GetPawnTooltipExtras(Pawn pawn)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_NeurosisPulse.txt`
|
||||
**相似度:** 0.7397
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_NeurosisPulse : PsychicRitualDef_InvocationCircle
|
||||
{
|
||||
public SimpleCurve durationDaysFromQualityCurve;
|
||||
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph graph)
|
||||
{
|
||||
List<PsychicRitualToil> list = base.CreateToils(psychicRitual, graph);
|
||||
list.Add(new PsychicRitualToil_NeurosisPulse(InvokerRole));
|
||||
return list;
|
||||
}
|
||||
|
||||
public override TaggedString OutcomeDescription(FloatRange qualityRange, string qualityNumber, PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
return outcomeDescription.Formatted(Mathf.FloorToInt(durationDaysFromQualityCurve.Evaluate(qualityRange.min) * 60000f).ToStringTicksToDays());
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_Psychophagy.txt`
|
||||
**相似度:** 0.7324
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_Psychophagy : PsychicRitualDef_InvocationCircle
|
||||
{
|
||||
public FloatRange brainDamageRange;
|
||||
|
||||
public SimpleCurve effectDurationDaysFromQualityCurve;
|
||||
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
List<PsychicRitualToil> list = base.CreateToils(psychicRitual, parent);
|
||||
list.Add(new PsychicRitualToil_Psychophagy(InvokerRole, TargetRole, brainDamageRange));
|
||||
list.Add(new PsychicRitualToil_TargetCleanup(InvokerRole, TargetRole));
|
||||
return list;
|
||||
}
|
||||
|
||||
public override TaggedString OutcomeDescription(FloatRange qualityRange, string qualityNumber, PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
string text = Mathf.FloorToInt(effectDurationDaysFromQualityCurve.Evaluate(qualityRange.min) * 60000f).ToStringTicksToDays();
|
||||
IntRange disappearsAfterTicks = HediffDefOf.DarkPsychicShock.CompProps<HediffCompProperties_Disappears>().disappearsAfterTicks;
|
||||
FloatRange floatRange = new FloatRange(Mathf.FloorToInt(disappearsAfterTicks.min.TicksToDays()), Mathf.FloorToInt(disappearsAfterTicks.max.TicksToDays()));
|
||||
return outcomeDescription.Formatted(text, floatRange.ToString(), brainDamageRange.ToString());
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI.Group\PsychicRitualToil_PleasurePulse.txt`
|
||||
**相似度:** 0.7237
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualToil_PleasurePulse : PsychicRitualToil
|
||||
{
|
||||
private PsychicRitualRoleDef invokerRole;
|
||||
|
||||
protected PsychicRitualToil_PleasurePulse()
|
||||
{
|
||||
}
|
||||
|
||||
public PsychicRitualToil_PleasurePulse(PsychicRitualRoleDef invokerRole)
|
||||
{
|
||||
this.invokerRole = invokerRole;
|
||||
}
|
||||
|
||||
public override void Start(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
base.Start(psychicRitual, parent);
|
||||
Pawn pawn = psychicRitual.assignments.FirstAssignedPawn(invokerRole);
|
||||
float duration = ((PsychicRitualDef_PleasurePulse)psychicRitual.def).durationDaysFromQualityCurve.Evaluate(psychicRitual.PowerPercent);
|
||||
psychicRitual.ReleaseAllPawnsAndBuildings();
|
||||
if (pawn != null)
|
||||
{
|
||||
ApplyOutcome(psychicRitual, pawn, duration);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyOutcome(PsychicRitual psychicRitual, Pawn invoker, float duration)
|
||||
{
|
||||
foreach (Pawn item in invoker.Map.mapPawns.AllHumanlikeSpawned)
|
||||
{
|
||||
if (!(item.GetStatValue(StatDefOf.PsychicSensitivity) <= 0f))
|
||||
{
|
||||
Hediff firstHediffOfDef = item.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.NeurosisPulse);
|
||||
if (firstHediffOfDef != null)
|
||||
{
|
||||
item.health.RemoveHediff(firstHediffOfDef);
|
||||
}
|
||||
Hediff hediff = HediffMaker.MakeHediff(HediffDefOf.PleasurePulse, item);
|
||||
HediffComp_Disappears hediffComp_Disappears = hediff.TryGetComp<HediffComp_Disappears>();
|
||||
if (hediffComp_Disappears != null)
|
||||
{
|
||||
hediffComp_Disappears.ticksToDisappear = Mathf.RoundToInt(duration * 60000f);
|
||||
}
|
||||
item.health.AddHediff(hediff);
|
||||
}
|
||||
}
|
||||
Find.LetterStack.ReceiveLetter("PsychicRitualCompleteLabel".Translate(psychicRitual.def.label), "PleasurePulseCompleteText".Translate(invoker, Mathf.FloorToInt(duration * 60000f).ToStringTicksToDays(), psychicRitual.def.Named("RITUAL")), LetterDefOf.NeutralEvent);
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Defs.Look(ref invokerRole, "invokerRole");
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_InvocationCircle.txt`
|
||||
**相似度:** 0.7220
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_InvocationCircle : PsychicRitualDef
|
||||
{
|
||||
public enum InvalidTargetReasonEnum
|
||||
{
|
||||
None,
|
||||
AreaNotClear
|
||||
}
|
||||
|
||||
private class RitualQualityOffsetCount
|
||||
{
|
||||
public float offset;
|
||||
|
||||
public int count;
|
||||
|
||||
public RitualQualityOffsetCount(int count, float offset)
|
||||
{
|
||||
this.count = count;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
public FloatRange hoursUntilHoraxEffect;
|
||||
|
||||
public FloatRange hoursUntilOutcome;
|
||||
|
||||
public float invocationCircleRadius = 3.9f;
|
||||
|
||||
[MustTranslate]
|
||||
public string outcomeDescription;
|
||||
|
||||
public float psychicSensitivityPowerFactor = 0.25f;
|
||||
|
||||
protected PsychicRitualRoleDef invokerRole;
|
||||
|
||||
protected PsychicRitualRoleDef chanterRole;
|
||||
|
||||
protected PsychicRitualRoleDef targetRole;
|
||||
|
||||
protected PsychicRitualRoleDef defenderRole;
|
||||
|
||||
protected IngredientCount requiredOffering;
|
||||
|
||||
protected string timeAndOfferingLabelCached;
|
||||
|
||||
public static readonly SimpleCurve PsychicSensitivityToPowerFactor = new SimpleCurve
|
||||
{
|
||||
new CurvePoint(0f, 0f),
|
||||
new CurvePoint(1f, 0.5f),
|
||||
new CurvePoint(2f, 0.9f),
|
||||
new CurvePoint(3f, 1f)
|
||||
};
|
||||
|
||||
protected const int DurationTicksWaitPostEffect = 120;
|
||||
|
||||
private static Dictionary<PsychicRitualRoleDef, List<IntVec3>> tmpParticipants = new Dictionary<PsychicRitualRoleDef, List<IntVec3>>(8);
|
||||
|
||||
private List<Pawn> tmpGatheringPawns = new List<Pawn>(8);
|
||||
|
||||
public virtual PsychicRitualRoleDef InvokerRole => invokerRole;
|
||||
|
||||
public virtual PsychicRitualRoleDef ChanterRole => chanterRole;
|
||||
|
||||
public virtual PsychicRitualRoleDef TargetRole => targetRole;
|
||||
|
||||
public virtual PsychicRitualRoleDef DefenderRole => defenderRole;
|
||||
|
||||
public virtual IngredientCount RequiredOffering => requiredOffering;
|
||||
|
||||
public TaggedString CooldownLabel => "PsychicRitualCooldownLabel".Translate() + ": " + (cooldownHours * 2500).ToStringTicksToPeriod();
|
||||
|
||||
public override List<PsychicRitualRoleDef> Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
List<PsychicRitualRoleDef> roles = base.Roles;
|
||||
if (InvokerRole != null)
|
||||
{
|
||||
roles.Add(InvokerRole);
|
||||
}
|
||||
if (TargetRole != null)
|
||||
{
|
||||
roles.Add(TargetRole);
|
||||
}
|
||||
if (ChanterRole != null)
|
||||
{
|
||||
roles.Add(ChanterRole);
|
||||
}
|
||||
if (DefenderRole != null)
|
||||
{
|
||||
roles.Add(DefenderRole);
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ResolveReferences()
|
||||
{
|
||||
base.ResolveReferences();
|
||||
requiredOffering?.ResolveReferences();
|
||||
invokerRole = invokerRole ?? PsychicRitualRoleDefOf.Invoker;
|
||||
chanterRole = chanterRole ?? PsychicRitualRoleDefOf.Chanter;
|
||||
}
|
||||
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
float randomInRange = hoursUntilOutcome.RandomInRange;
|
||||
IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> readOnlyDictionary = GenerateRolePositions(psychicRitual.assignments);
|
||||
return new List<PsychicRitualToil>
|
||||
{
|
||||
new PsychicRitualToil_GatherForInvocation(psychicRitual, this, readOnlyDictionary),
|
||||
new PsychicRitualToil_InvokeHorax(InvokerRole, readOnlyDictionary.TryGetValue(InvokerRole), TargetRole, readOnlyDictionary.TryGetValue(TargetRole), ChanterRole, readOnlyDictionary.TryGetValue(ChanterRole), DefenderRole, readOnlyDictionary.TryGetValue(DefenderRole), RequiredOffering)
|
||||
{
|
||||
hoursUntilHoraxEffect = hoursUntilHoraxEffect.RandomInRange,
|
||||
hoursUntilOutcome = randomInRange
|
||||
},
|
||||
new PsychicRitualToil_Wait(120)
|
||||
};
|
||||
}
|
||||
|
||||
public override bool IsValidTarget(TargetInfo target, out AnyEnum reason)
|
||||
{
|
||||
foreach (IntVec3 item in GenRadial.RadialCellsAround(target.Cell, invocationCircleRadius, useCenter: true))
|
||||
{
|
||||
if (!item.Standable(target.Map))
|
||||
{
|
||||
reason = AnyEnum.FromEnum(InvalidTargetReasonEnum.AreaNotClear);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
reason = AnyEnum.None;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override TaggedString InvalidTargetReason(AnyEnum reason)
|
||||
{
|
||||
InvalidTargetReasonEnum? invalidTargetReasonEnum = reason.As<InvalidTargetReasonEnum>();
|
||||
if (invalidTargetReasonEnum.HasValue)
|
||||
{
|
||||
InvalidTargetReasonEnum valueOrDefault = invalidTargetReasonEnum.GetValueOrDefault();
|
||||
return valueOrDefault switch
|
||||
{
|
||||
InvalidTargetReasonEnum.None => TaggedString.Empty,
|
||||
InvalidTargetReasonEnum.AreaNotClear => "PsychicRitualDef_InvocationCircle_AreaMustBeClear".Translate(),
|
||||
_ => throw new InvalidOperationException($"Unknown reason {valueOrDefault}"),
|
||||
};
|
||||
}
|
||||
return base.InvalidTargetReason(reason);
|
||||
}
|
||||
|
||||
public override TaggedString OutcomeDescription(FloatRange qualityRange, string qualityNumber, PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
return outcomeDescription.Formatted();
|
||||
}
|
||||
|
||||
public override IEnumerable<TaggedString> OutcomeWarnings(PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
foreach (Pawn item in assignments.AssignedPawns(TargetRole))
|
||||
{
|
||||
if (item.HomeFaction != null && item.HomeFaction != Faction.OfPlayer && item.HomeFaction.def.humanlikeFaction && !item.HomeFaction.def.PermanentlyHostileTo(FactionDefOf.PlayerColony) && !item.HomeFaction.temporary && !item.HomeFaction.Hidden)
|
||||
{
|
||||
yield return "PsychicRitualFactionWarning".Translate(item.Named("PAWN"), item.HomeFaction.Named("FACTION")).Colorize(ColoredText.WarningColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override TaggedString TimeAndOfferingLabel()
|
||||
{
|
||||
if (timeAndOfferingLabelCached != null)
|
||||
{
|
||||
return timeAndOfferingLabelCached;
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine(DurationLabel());
|
||||
stringBuilder.Append(CooldownLabel);
|
||||
if (!OfferingLabel().NullOrEmpty())
|
||||
{
|
||||
stringBuilder.AppendLine();
|
||||
stringBuilder.Append(OfferingLabel());
|
||||
}
|
||||
timeAndOfferingLabelCached = stringBuilder.ToString();
|
||||
return timeAndOfferingLabelCached;
|
||||
}
|
||||
|
||||
private TaggedString OfferingLabel()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (RequiredOffering != null)
|
||||
{
|
||||
stringBuilder.Append("PsychicRitualRequiredOffering".Translate().CapitalizeFirst());
|
||||
stringBuilder.Append(": ");
|
||||
stringBuilder.Append(RequiredOffering.SummaryFilterFirst);
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public TaggedString DurationLabel()
|
||||
{
|
||||
string value = ((int)(hoursUntilOutcome.Average * 2500f)).ToStringTicksToPeriod();
|
||||
TaggedString taggedString = ((hoursUntilOutcome.min != hoursUntilOutcome.max) ? "ExpectedLordJobDuration".Translate().CapitalizeFirst() : "PsychicRitualExpectedDurationLabel".Translate().CapitalizeFirst());
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append(taggedString);
|
||||
stringBuilder.Append(": ");
|
||||
stringBuilder.Append(value);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> GenerateRolePositions(PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
tmpParticipants.ClearAndPoolValueLists();
|
||||
foreach (PsychicRitualRoleDef role in Roles)
|
||||
{
|
||||
tmpParticipants[role] = SimplePool<List<IntVec3>>.Get();
|
||||
}
|
||||
int num = assignments.RoleAssignedCount(ChanterRole) + assignments.RoleAssignedCount(InvokerRole);
|
||||
int num2 = 0;
|
||||
foreach (Pawn item in assignments.AssignedPawns(InvokerRole))
|
||||
{
|
||||
_ = item;
|
||||
int num3 = 0;
|
||||
IntVec3 cell;
|
||||
do
|
||||
{
|
||||
cell = assignments.Target.Cell;
|
||||
cell += IntVec3.FromPolar(360f * (float)num2++ / (float)num, invocationCircleRadius);
|
||||
}
|
||||
while (!cell.Walkable(assignments.Target.Map) && num3++ <= 10);
|
||||
if (num3 >= 10)
|
||||
{
|
||||
cell = assignments.Target.Cell;
|
||||
}
|
||||
tmpParticipants[InvokerRole].Add(cell);
|
||||
}
|
||||
foreach (Pawn item2 in assignments.AssignedPawns(ChanterRole))
|
||||
{
|
||||
_ = item2;
|
||||
IntVec3 cell2 = assignments.Target.Cell;
|
||||
cell2 += IntVec3.FromPolar(360f * (float)num2++ / (float)num, invocationCircleRadius);
|
||||
tmpParticipants[ChanterRole].Add(cell2);
|
||||
}
|
||||
foreach (Pawn item3 in assignments.AssignedPawns(TargetRole))
|
||||
{
|
||||
_ = item3;
|
||||
tmpParticipants[TargetRole].Add(assignments.Target.Cell);
|
||||
}
|
||||
if (DefenderRole != null)
|
||||
{
|
||||
num2 = 0;
|
||||
int num4 = assignments.RoleAssignedCount(DefenderRole);
|
||||
bool playerRitual = assignments.AllAssignedPawns.Any((Pawn x) => x.Faction == Faction.OfPlayer);
|
||||
foreach (Pawn item4 in assignments.AssignedPawns(DefenderRole))
|
||||
{
|
||||
_ = item4;
|
||||
IntVec3 cell3 = assignments.Target.Cell;
|
||||
cell3 += IntVec3.FromPolar(360f * (float)num2++ / (float)num4, invocationCircleRadius + 5f);
|
||||
cell3 = GetBestStandableRolePosition(playerRitual, cell3, assignments.Target.Cell, assignments.Target.Map);
|
||||
tmpParticipants[DefenderRole].Add(cell3);
|
||||
}
|
||||
}
|
||||
return tmpParticipants;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> BlockingIssues(PsychicRitualRoleAssignments assignments, Map map)
|
||||
{
|
||||
using (new ProfilerBlock("PsychicRitualDef.BlockingIssues"))
|
||||
{
|
||||
tmpGatheringPawns.Clear();
|
||||
foreach (var (psychicRitualRoleDef2, collection) in assignments.RoleAssignments)
|
||||
{
|
||||
if (psychicRitualRoleDef2.CanHandleOfferings)
|
||||
{
|
||||
tmpGatheringPawns.AddRange(collection);
|
||||
}
|
||||
}
|
||||
tmpGatheringPawns.RemoveAll(map, (Map _map, Pawn _pawn) => _pawn.MapHeld != _map);
|
||||
if (TargetRole != null && InvokerRole != null)
|
||||
{
|
||||
Pawn pawn = assignments.FirstAssignedPawn(TargetRole);
|
||||
if (pawn != null)
|
||||
{
|
||||
Pawn pawn2 = assignments.FirstAssignedPawn(InvokerRole);
|
||||
if (pawn2 != null && pawn.IsPrisoner && !map.reachability.CanReach(assignments.Target.Cell, pawn.PositionHeld, PathEndMode.Touch, TraverseParms.For(pawn2)))
|
||||
{
|
||||
yield return "PsychicRitualTargetUnreachableByInvoker".Translate(pawn.Named("TARGET"), pawn2.Named("INVOKER"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RequiredOffering != null && !PsychicRitualDef.OfferingReachable(map, tmpGatheringPawns, RequiredOffering, out var reachableCount))
|
||||
{
|
||||
yield return "PsychicRitualOfferingsInsufficient".Translate(RequiredOffering.SummaryFilterFirst, reachableCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void CalculateMaxPower(PsychicRitualRoleAssignments assignments, List<QualityFactor> powerFactorsOut, out float power)
|
||||
{
|
||||
power = 0f;
|
||||
foreach (Pawn item in assignments.AssignedPawns(InvokerRole))
|
||||
{
|
||||
float statValue = item.GetStatValue(StatDefOf.PsychicSensitivity);
|
||||
float num = PsychicSensitivityToPowerFactor.Evaluate(statValue);
|
||||
num *= psychicSensitivityPowerFactor;
|
||||
powerFactorsOut?.Add(new QualityFactor
|
||||
{
|
||||
label = "PsychicRitualDef_InvocationCircle_QualityFactor_PsychicSensitivity".Translate(item.Named("PAWN")),
|
||||
positive = (statValue >= 1f),
|
||||
count = statValue.ToStringPercent(),
|
||||
quality = num,
|
||||
toolTip = "PsychicRitualDef_InvocationCircle_QualityFactor_PsychicSensitivity_Tooltip".Translate(item.Named("PAWN"))
|
||||
});
|
||||
power += num;
|
||||
}
|
||||
base.CalculateMaxPower(assignments, powerFactorsOut, out var power2);
|
||||
power += power2;
|
||||
if (assignments.Target.Thing is Building building)
|
||||
{
|
||||
CalculateFacilityQualityOffset(powerFactorsOut, ref power, building);
|
||||
}
|
||||
power = Mathf.Clamp01(power);
|
||||
}
|
||||
|
||||
private static void CalculateFacilityQualityOffset(List<QualityFactor> powerFactorsOut, ref float power, Building building)
|
||||
{
|
||||
Dictionary<ThingDef, RitualQualityOffsetCount> dictionary = new Dictionary<ThingDef, RitualQualityOffsetCount>();
|
||||
List<Thing> linkedFacilitiesListForReading = building.GetComp<CompAffectedByFacilities>().LinkedFacilitiesListForReading;
|
||||
for (int i = 0; i < linkedFacilitiesListForReading.Count; i++)
|
||||
{
|
||||
Thing thing = linkedFacilitiesListForReading[i];
|
||||
CompFacility compFacility = thing.TryGetComp<CompFacility>();
|
||||
if (compFacility?.StatOffsets == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < compFacility.StatOffsets.Count; j++)
|
||||
{
|
||||
StatModifier statModifier = compFacility.StatOffsets[j];
|
||||
if (statModifier.stat == StatDefOf.PsychicRitualQuality)
|
||||
{
|
||||
if (dictionary.TryGetValue(thing.def, out var value))
|
||||
{
|
||||
value.count++;
|
||||
value.offset += statModifier.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
dictionary.Add(thing.def, new RitualQualityOffsetCount(1, statModifier.value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<ThingDef, RitualQualityOffsetCount> item in dictionary)
|
||||
{
|
||||
powerFactorsOut?.Add(new QualityFactor
|
||||
{
|
||||
label = Find.ActiveLanguageWorker.Pluralize(item.Key.label).CapitalizeFirst(),
|
||||
positive = true,
|
||||
count = item.Value.count + " / " + item.Key.GetCompProperties<CompProperties_Facility>().maxSimultaneous,
|
||||
quality = item.Value.offset,
|
||||
toolTip = "PsychicRitualDef_InvocationCircle_QualityFactor_Increase_Tooltip".Translate().CapitalizeFirst().EndWithPeriod()
|
||||
});
|
||||
power += item.Value.offset;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<StatDrawEntry> SpecialDisplayStats(StatRequest req)
|
||||
{
|
||||
foreach (StatDrawEntry item in base.SpecialDisplayStats(req))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (requiredOffering != null)
|
||||
{
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.PsychicRituals, "StatsReport_Offering".Translate(), requiredOffering.SummaryFilterFirst, "StatsReport_Offering_Desc".Translate(), 1000);
|
||||
}
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.PsychicRituals, "StatsReport_RitualDuration".Translate(), Mathf.FloorToInt(hoursUntilOutcome.min * 2500f).ToStringTicksToPeriod(), "StatsReport_RitualDuration_Desc".Translate(), 500);
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.PsychicRituals, "StatsReport_RitualCooldown".Translate(), (cooldownHours * 2500).ToStringTicksToPeriod(), "StatsReport_RitualCooldown_Desc".Translate(), 100);
|
||||
}
|
||||
|
||||
public override void CheckPsychicRitualCancelConditions(PsychicRitual psychicRitual)
|
||||
{
|
||||
base.CheckPsychicRitualCancelConditions(psychicRitual);
|
||||
if (!psychicRitual.canceled && invokerRole != null)
|
||||
{
|
||||
Pawn pawn = psychicRitual.assignments.FirstAssignedPawn(InvokerRole);
|
||||
if (pawn != null && pawn.DeadOrDowned)
|
||||
{
|
||||
psychicRitual.CancelPsychicRitual("PsychicRitualDef_InvocationCircle_InvokerLost".Translate(pawn.Named("PAWN")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
573
MCP/vector_cache/PsychicRitualDef_InvocationCircle.txt
Normal file
573
MCP/vector_cache/PsychicRitualDef_InvocationCircle.txt
Normal file
@@ -0,0 +1,573 @@
|
||||
根据向量相似度分析,与 'PsychicRitualDef_InvocationCircle' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_InvocationCircle.txt`
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_InvocationCircle : PsychicRitualDef
|
||||
{
|
||||
public enum InvalidTargetReasonEnum
|
||||
{
|
||||
None,
|
||||
AreaNotClear
|
||||
}
|
||||
|
||||
private class RitualQualityOffsetCount
|
||||
{
|
||||
public float offset;
|
||||
|
||||
public int count;
|
||||
|
||||
public RitualQualityOffsetCount(int count, float offset)
|
||||
{
|
||||
this.count = count;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
public FloatRange hoursUntilHoraxEffect;
|
||||
|
||||
public FloatRange hoursUntilOutcome;
|
||||
|
||||
public float invocationCircleRadius = 3.9f;
|
||||
|
||||
[MustTranslate]
|
||||
public string outcomeDescription;
|
||||
|
||||
public float psychicSensitivityPowerFactor = 0.25f;
|
||||
|
||||
protected PsychicRitualRoleDef invokerRole;
|
||||
|
||||
protected PsychicRitualRoleDef chanterRole;
|
||||
|
||||
protected PsychicRitualRoleDef targetRole;
|
||||
|
||||
protected PsychicRitualRoleDef defenderRole;
|
||||
|
||||
protected IngredientCount requiredOffering;
|
||||
|
||||
protected string timeAndOfferingLabelCached;
|
||||
|
||||
public static readonly SimpleCurve PsychicSensitivityToPowerFactor = new SimpleCurve
|
||||
{
|
||||
new CurvePoint(0f, 0f),
|
||||
new CurvePoint(1f, 0.5f),
|
||||
new CurvePoint(2f, 0.9f),
|
||||
new CurvePoint(3f, 1f)
|
||||
};
|
||||
|
||||
protected const int DurationTicksWaitPostEffect = 120;
|
||||
|
||||
private static Dictionary<PsychicRitualRoleDef, List<IntVec3>> tmpParticipants = new Dictionary<PsychicRitualRoleDef, List<IntVec3>>(8);
|
||||
|
||||
private List<Pawn> tmpGatheringPawns = new List<Pawn>(8);
|
||||
|
||||
public virtual PsychicRitualRoleDef InvokerRole => invokerRole;
|
||||
|
||||
public virtual PsychicRitualRoleDef ChanterRole => chanterRole;
|
||||
|
||||
public virtual PsychicRitualRoleDef TargetRole => targetRole;
|
||||
|
||||
public virtual PsychicRitualRoleDef DefenderRole => defenderRole;
|
||||
|
||||
public virtual IngredientCount RequiredOffering => requiredOffering;
|
||||
|
||||
public TaggedString CooldownLabel => "PsychicRitualCooldownLabel".Translate() + ": " + (cooldownHours * 2500).ToStringTicksToPeriod();
|
||||
|
||||
public override List<PsychicRitualRoleDef> Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
List<PsychicRitualRoleDef> roles = base.Roles;
|
||||
if (InvokerRole != null)
|
||||
{
|
||||
roles.Add(InvokerRole);
|
||||
}
|
||||
if (TargetRole != null)
|
||||
{
|
||||
roles.Add(TargetRole);
|
||||
}
|
||||
if (ChanterRole != null)
|
||||
{
|
||||
roles.Add(ChanterRole);
|
||||
}
|
||||
if (DefenderRole != null)
|
||||
{
|
||||
roles.Add(DefenderRole);
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ResolveReferences()
|
||||
{
|
||||
base.ResolveReferences();
|
||||
requiredOffering?.ResolveReferences();
|
||||
invokerRole = invokerRole ?? PsychicRitualRoleDefOf.Invoker;
|
||||
chanterRole = chanterRole ?? PsychicRitualRoleDefOf.Chanter;
|
||||
}
|
||||
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
float randomInRange = hoursUntilOutcome.RandomInRange;
|
||||
IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> readOnlyDictionary = GenerateRolePositions(psychicRitual.assignments);
|
||||
return new List<PsychicRitualToil>
|
||||
{
|
||||
new PsychicRitualToil_GatherForInvocation(psychicRitual, this, readOnlyDictionary),
|
||||
new PsychicRitualToil_InvokeHorax(InvokerRole, readOnlyDictionary.TryGetValue(InvokerRole), TargetRole, readOnlyDictionary.TryGetValue(TargetRole), ChanterRole, readOnlyDictionary.TryGetValue(ChanterRole), DefenderRole, readOnlyDictionary.TryGetValue(DefenderRole), RequiredOffering)
|
||||
{
|
||||
hoursUntilHoraxEffect = hoursUntilHoraxEffect.RandomInRange,
|
||||
hoursUntilOutcome = randomInRange
|
||||
},
|
||||
new PsychicRitualToil_Wait(120)
|
||||
};
|
||||
}
|
||||
|
||||
public override bool IsValidTarget(TargetInfo target, out AnyEnum reason)
|
||||
{
|
||||
foreach (IntVec3 item in GenRadial.RadialCellsAround(target.Cell, invocationCircleRadius, useCenter: true))
|
||||
{
|
||||
if (!item.Standable(target.Map))
|
||||
{
|
||||
reason = AnyEnum.FromEnum(InvalidTargetReasonEnum.AreaNotClear);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
reason = AnyEnum.None;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override TaggedString InvalidTargetReason(AnyEnum reason)
|
||||
{
|
||||
InvalidTargetReasonEnum? invalidTargetReasonEnum = reason.As<InvalidTargetReasonEnum>();
|
||||
if (invalidTargetReasonEnum.HasValue)
|
||||
{
|
||||
InvalidTargetReasonEnum valueOrDefault = invalidTargetReasonEnum.GetValueOrDefault();
|
||||
return valueOrDefault switch
|
||||
{
|
||||
InvalidTargetReasonEnum.None => TaggedString.Empty,
|
||||
InvalidTargetReasonEnum.AreaNotClear => "PsychicRitualDef_InvocationCircle_AreaMustBeClear".Translate(),
|
||||
_ => throw new InvalidOperationException($"Unknown reason {valueOrDefault}"),
|
||||
};
|
||||
}
|
||||
return base.InvalidTargetReason(reason);
|
||||
}
|
||||
|
||||
public override TaggedString OutcomeDescription(FloatRange qualityRange, string qualityNumber, PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
return outcomeDescription.Formatted();
|
||||
}
|
||||
|
||||
public override IEnumerable<TaggedString> OutcomeWarnings(PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
foreach (Pawn item in assignments.AssignedPawns(TargetRole))
|
||||
{
|
||||
if (item.HomeFaction != null && item.HomeFaction != Faction.OfPlayer && item.HomeFaction.def.humanlikeFaction && !item.HomeFaction.def.PermanentlyHostileTo(FactionDefOf.PlayerColony) && !item.HomeFaction.temporary && !item.HomeFaction.Hidden)
|
||||
{
|
||||
yield return "PsychicRitualFactionWarning".Translate(item.Named("PAWN"), item.HomeFaction.Named("FACTION")).Colorize(ColoredText.WarningColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override TaggedString TimeAndOfferingLabel()
|
||||
{
|
||||
if (timeAndOfferingLabelCached != null)
|
||||
{
|
||||
return timeAndOfferingLabelCached;
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine(DurationLabel());
|
||||
stringBuilder.Append(CooldownLabel);
|
||||
if (!OfferingLabel().NullOrEmpty())
|
||||
{
|
||||
stringBuilder.AppendLine();
|
||||
stringBuilder.Append(OfferingLabel());
|
||||
}
|
||||
timeAndOfferingLabelCached = stringBuilder.ToString();
|
||||
return timeAndOfferingLabelCached;
|
||||
}
|
||||
|
||||
private TaggedString OfferingLabel()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (RequiredOffering != null)
|
||||
{
|
||||
stringBuilder.Append("PsychicRitualRequiredOffering".Translate().CapitalizeFirst());
|
||||
stringBuilder.Append(": ");
|
||||
stringBuilder.Append(RequiredOffering.SummaryFilterFirst);
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public TaggedString DurationLabel()
|
||||
{
|
||||
string value = ((int)(hoursUntilOutcome.Average * 2500f)).ToStringTicksToPeriod();
|
||||
TaggedString taggedString = ((hoursUntilOutcome.min != hoursUntilOutcome.max) ? "ExpectedLordJobDuration".Translate().CapitalizeFirst() : "PsychicRitualExpectedDurationLabel".Translate().CapitalizeFirst());
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append(taggedString);
|
||||
stringBuilder.Append(": ");
|
||||
stringBuilder.Append(value);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> GenerateRolePositions(PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
tmpParticipants.ClearAndPoolValueLists();
|
||||
foreach (PsychicRitualRoleDef role in Roles)
|
||||
{
|
||||
tmpParticipants[role] = SimplePool<List<IntVec3>>.Get();
|
||||
}
|
||||
int num = assignments.RoleAssignedCount(ChanterRole) + assignments.RoleAssignedCount(InvokerRole);
|
||||
int num2 = 0;
|
||||
foreach (Pawn item in assignments.AssignedPawns(InvokerRole))
|
||||
{
|
||||
_ = item;
|
||||
int num3 = 0;
|
||||
IntVec3 cell;
|
||||
do
|
||||
{
|
||||
cell = assignments.Target.Cell;
|
||||
cell += IntVec3.FromPolar(360f * (float)num2++ / (float)num, invocationCircleRadius);
|
||||
}
|
||||
while (!cell.Walkable(assignments.Target.Map) && num3++ <= 10);
|
||||
if (num3 >= 10)
|
||||
{
|
||||
cell = assignments.Target.Cell;
|
||||
}
|
||||
tmpParticipants[InvokerRole].Add(cell);
|
||||
}
|
||||
foreach (Pawn item2 in assignments.AssignedPawns(ChanterRole))
|
||||
{
|
||||
_ = item2;
|
||||
IntVec3 cell2 = assignments.Target.Cell;
|
||||
cell2 += IntVec3.FromPolar(360f * (float)num2++ / (float)num, invocationCircleRadius);
|
||||
tmpParticipants[ChanterRole].Add(cell2);
|
||||
}
|
||||
foreach (Pawn item3 in assignments.AssignedPawns(TargetRole))
|
||||
{
|
||||
_ = item3;
|
||||
tmpParticipants[TargetRole].Add(assignments.Target.Cell);
|
||||
}
|
||||
if (DefenderRole != null)
|
||||
{
|
||||
num2 = 0;
|
||||
int num4 = assignments.RoleAssignedCount(DefenderRole);
|
||||
bool playerRitual = assignments.AllAssignedPawns.Any((Pawn x) => x.Faction == Faction.OfPlayer);
|
||||
foreach (Pawn item4 in assignments.AssignedPawns(DefenderRole))
|
||||
{
|
||||
_ = item4;
|
||||
IntVec3 cell3 = assignments.Target.Cell;
|
||||
cell3 += IntVec3.FromPolar(360f * (float)num2++ / (float)num4, invocationCircleRadius + 5f);
|
||||
cell3 = GetBestStandableRolePosition(playerRitual, cell3, assignments.Target.Cell, assignments.Target.Map);
|
||||
tmpParticipants[DefenderRole].Add(cell3);
|
||||
}
|
||||
}
|
||||
return tmpParticipants;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> BlockingIssues(PsychicRitualRoleAssignments assignments, Map map)
|
||||
{
|
||||
using (new ProfilerBlock("PsychicRitualDef.BlockingIssues"))
|
||||
{
|
||||
tmpGatheringPawns.Clear();
|
||||
foreach (var (psychicRitualRoleDef2, collection) in assignments.RoleAssignments)
|
||||
{
|
||||
if (psychicRitualRoleDef2.CanHandleOfferings)
|
||||
{
|
||||
tmpGatheringPawns.AddRange(collection);
|
||||
}
|
||||
}
|
||||
tmpGatheringPawns.RemoveAll(map, (Map _map, Pawn _pawn) => _pawn.MapHeld != _map);
|
||||
if (TargetRole != null && InvokerRole != null)
|
||||
{
|
||||
Pawn pawn = assignments.FirstAssignedPawn(TargetRole);
|
||||
if (pawn != null)
|
||||
{
|
||||
Pawn pawn2 = assignments.FirstAssignedPawn(InvokerRole);
|
||||
if (pawn2 != null && pawn.IsPrisoner && !map.reachability.CanReach(assignments.Target.Cell, pawn.PositionHeld, PathEndMode.Touch, TraverseParms.For(pawn2)))
|
||||
{
|
||||
yield return "PsychicRitualTargetUnreachableByInvoker".Translate(pawn.Named("TARGET"), pawn2.Named("INVOKER"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (RequiredOffering != null && !PsychicRitualDef.OfferingReachable(map, tmpGatheringPawns, RequiredOffering, out var reachableCount))
|
||||
{
|
||||
yield return "PsychicRitualOfferingsInsufficient".Translate(RequiredOffering.SummaryFilterFirst, reachableCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void CalculateMaxPower(PsychicRitualRoleAssignments assignments, List<QualityFactor> powerFactorsOut, out float power)
|
||||
{
|
||||
power = 0f;
|
||||
foreach (Pawn item in assignments.AssignedPawns(InvokerRole))
|
||||
{
|
||||
float statValue = item.GetStatValue(StatDefOf.PsychicSensitivity);
|
||||
float num = PsychicSensitivityToPowerFactor.Evaluate(statValue);
|
||||
num *= psychicSensitivityPowerFactor;
|
||||
powerFactorsOut?.Add(new QualityFactor
|
||||
{
|
||||
label = "PsychicRitualDef_InvocationCircle_QualityFactor_PsychicSensitivity".Translate(item.Named("PAWN")),
|
||||
positive = (statValue >= 1f),
|
||||
count = statValue.ToStringPercent(),
|
||||
quality = num,
|
||||
toolTip = "PsychicRitualDef_InvocationCircle_QualityFactor_PsychicSensitivity_Tooltip".Translate(item.Named("PAWN"))
|
||||
});
|
||||
power += num;
|
||||
}
|
||||
base.CalculateMaxPower(assignments, powerFactorsOut, out var power2);
|
||||
power += power2;
|
||||
if (assignments.Target.Thing is Building building)
|
||||
{
|
||||
CalculateFacilityQualityOffset(powerFactorsOut, ref power, building);
|
||||
}
|
||||
power = Mathf.Clamp01(power);
|
||||
}
|
||||
|
||||
private static void CalculateFacilityQualityOffset(List<QualityFactor> powerFactorsOut, ref float power, Building building)
|
||||
{
|
||||
Dictionary<ThingDef, RitualQualityOffsetCount> dictionary = new Dictionary<ThingDef, RitualQualityOffsetCount>();
|
||||
List<Thing> linkedFacilitiesListForReading = building.GetComp<CompAffectedByFacilities>().LinkedFacilitiesListForReading;
|
||||
for (int i = 0; i < linkedFacilitiesListForReading.Count; i++)
|
||||
{
|
||||
Thing thing = linkedFacilitiesListForReading[i];
|
||||
CompFacility compFacility = thing.TryGetComp<CompFacility>();
|
||||
if (compFacility?.StatOffsets == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < compFacility.StatOffsets.Count; j++)
|
||||
{
|
||||
StatModifier statModifier = compFacility.StatOffsets[j];
|
||||
if (statModifier.stat == StatDefOf.PsychicRitualQuality)
|
||||
{
|
||||
if (dictionary.TryGetValue(thing.def, out var value))
|
||||
{
|
||||
value.count++;
|
||||
value.offset += statModifier.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
dictionary.Add(thing.def, new RitualQualityOffsetCount(1, statModifier.value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<ThingDef, RitualQualityOffsetCount> item in dictionary)
|
||||
{
|
||||
powerFactorsOut?.Add(new QualityFactor
|
||||
{
|
||||
label = Find.ActiveLanguageWorker.Pluralize(item.Key.label).CapitalizeFirst(),
|
||||
positive = true,
|
||||
count = item.Value.count + " / " + item.Key.GetCompProperties<CompProperties_Facility>().maxSimultaneous,
|
||||
quality = item.Value.offset,
|
||||
toolTip = "PsychicRitualDef_InvocationCircle_QualityFactor_Increase_Tooltip".Translate().CapitalizeFirst().EndWithPeriod()
|
||||
});
|
||||
power += item.Value.offset;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<StatDrawEntry> SpecialDisplayStats(StatRequest req)
|
||||
{
|
||||
foreach (StatDrawEntry item in base.SpecialDisplayStats(req))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (requiredOffering != null)
|
||||
{
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.PsychicRituals, "StatsReport_Offering".Translate(), requiredOffering.SummaryFilterFirst, "StatsReport_Offering_Desc".Translate(), 1000);
|
||||
}
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.PsychicRituals, "StatsReport_RitualDuration".Translate(), Mathf.FloorToInt(hoursUntilOutcome.min * 2500f).ToStringTicksToPeriod(), "StatsReport_RitualDuration_Desc".Translate(), 500);
|
||||
yield return new StatDrawEntry(StatCategoryDefOf.PsychicRituals, "StatsReport_RitualCooldown".Translate(), (cooldownHours * 2500).ToStringTicksToPeriod(), "StatsReport_RitualCooldown_Desc".Translate(), 100);
|
||||
}
|
||||
|
||||
public override void CheckPsychicRitualCancelConditions(PsychicRitual psychicRitual)
|
||||
{
|
||||
base.CheckPsychicRitualCancelConditions(psychicRitual);
|
||||
if (!psychicRitual.canceled && invokerRole != null)
|
||||
{
|
||||
Pawn pawn = psychicRitual.assignments.FirstAssignedPawn(InvokerRole);
|
||||
if (pawn != null && pawn.DeadOrDowned)
|
||||
{
|
||||
psychicRitual.CancelPsychicRitual("PsychicRitualDef_InvocationCircle_InvokerLost".Translate(pawn.Named("PAWN")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI.Group\PsychicRitualToil_GatherForInvocation.txt`
|
||||
**相似度:** 0.7802
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualToil_GatherForInvocation : PsychicRitualToil_Multiplex
|
||||
{
|
||||
protected PsychicRitualToil_Goto fallbackToil;
|
||||
|
||||
protected PsychicRitualGraph invokerToil;
|
||||
|
||||
protected PsychicRitualToil_Goto invokerFinalToil;
|
||||
|
||||
private static List<Pawn> blockingPawns = new List<Pawn>(16);
|
||||
|
||||
protected PsychicRitualToil_GatherForInvocation()
|
||||
{
|
||||
}
|
||||
|
||||
protected PsychicRitualToil_GatherForInvocation(PsychicRitualDef_InvocationCircle def, PsychicRitualToil_Goto fallbackToil, PsychicRitualGraph invokerToil)
|
||||
: base(new Dictionary<PsychicRitualRoleDef, PsychicRitualToil> { { def.InvokerRole, invokerToil } }, fallbackToil)
|
||||
{
|
||||
this.fallbackToil = fallbackToil;
|
||||
this.invokerToil = invokerToil;
|
||||
invokerFinalToil = (PsychicRitualToil_Goto)invokerToil.GetToil(invokerToil.ToilCount - 1);
|
||||
}
|
||||
|
||||
public PsychicRitualToil_GatherForInvocation(PsychicRitual psychicRitual, PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
: this(def, FallbackToil(psychicRitual, def, rolePositions), InvokerToil(def, rolePositions))
|
||||
{
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_References.Look(ref fallbackToil, "fallbackToil");
|
||||
Scribe_References.Look(ref invokerToil, "invokerToil");
|
||||
Scribe_References.Look(ref invokerFinalToil, "invokerFinalToil");
|
||||
}
|
||||
|
||||
public override string GetReport(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
blockingPawns.Clear();
|
||||
blockingPawns.AddRange(fallbackToil.BlockingPawns);
|
||||
if (invokerToil.CurrentToil == invokerFinalToil)
|
||||
{
|
||||
blockingPawns.AddRange(invokerFinalToil.BlockingPawns);
|
||||
}
|
||||
else
|
||||
{
|
||||
blockingPawns.AddRange(invokerFinalToil.ControlledPawns(psychicRitual));
|
||||
}
|
||||
string text = "PsychicRitualToil_GatherForInvocation_Report".Translate();
|
||||
string text2 = blockingPawns.Select((Pawn pawn) => pawn.LabelShortCap).ToCommaList();
|
||||
return text + ": " + text2;
|
||||
}
|
||||
|
||||
public static PsychicRitualToil_Goto FallbackToil(PsychicRitual psychicRitual, PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
return new PsychicRitualToil_Goto(rolePositions.Slice(rolePositions.Keys.Except(def.InvokerRole)));
|
||||
}
|
||||
|
||||
public static PsychicRitualGraph InvokerToil(PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
return new PsychicRitualGraph(InvokerGatherPhaseToils(def, rolePositions))
|
||||
{
|
||||
willAdvancePastLastToil = false
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<PsychicRitualToil> InvokerGatherPhaseToils(PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
if (def.RequiredOffering != null)
|
||||
{
|
||||
yield return new PsychicRitualToil_GatherOfferings(def.InvokerRole, def.RequiredOffering);
|
||||
}
|
||||
if (def.TargetRole != null)
|
||||
{
|
||||
yield return new PsychicRitualToil_CarryAndGoto(def.InvokerRole, def.TargetRole, rolePositions);
|
||||
}
|
||||
yield return new PsychicRitualToil_Goto(rolePositions.Slice(def.InvokerRole));
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_SkipAbduction.txt`
|
||||
**相似度:** 0.7696
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_SkipAbduction : PsychicRitualDef_InvocationCircle
|
||||
{
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph graph)
|
||||
{
|
||||
List<PsychicRitualToil> list = base.CreateToils(psychicRitual, graph);
|
||||
list.Add(new PsychicRitualToil_SkipAbduction(InvokerRole));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_BloodRain.txt`
|
||||
**相似度:** 0.7621
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_BloodRain : PsychicRitualDef_InvocationCircle
|
||||
{
|
||||
private FloatRange durationHoursFromQualityRange;
|
||||
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph graph)
|
||||
{
|
||||
List<PsychicRitualToil> list = base.CreateToils(psychicRitual, graph);
|
||||
list.Add(new PsychicRitualToil_BloodRain(InvokerRole, durationHoursFromQualityRange));
|
||||
return list;
|
||||
}
|
||||
|
||||
public override TaggedString OutcomeDescription(FloatRange qualityRange, string qualityNumber, PsychicRitualRoleAssignments assignments)
|
||||
{
|
||||
return outcomeDescription.Formatted(Mathf.FloorToInt(durationHoursFromQualityRange.LerpThroughRange(qualityRange.min) * 2500f).ToStringTicksToPeriod());
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_SummonFleshbeasts.txt`
|
||||
**相似度:** 0.7620
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_SummonFleshbeasts : PsychicRitualDef_InvocationCircle
|
||||
{
|
||||
public SimpleCurve fleshbeastPointsFromThreatPointsCurve;
|
||||
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph graph)
|
||||
{
|
||||
List<PsychicRitualToil> list = base.CreateToils(psychicRitual, graph);
|
||||
list.Add(new PsychicRitualToil_SummonFleshbeastsCultist(InvokerRole));
|
||||
return list;
|
||||
}
|
||||
|
||||
public override void CalculateMaxPower(PsychicRitualRoleAssignments assignments, List<QualityFactor> powerFactorsOut, out float power)
|
||||
{
|
||||
power = 0f;
|
||||
if (assignments.FirstAssignedPawn(InvokerRole)?.GetLord()?.LordJob is LordJob_PsychicRitual lordJob_PsychicRitual)
|
||||
{
|
||||
power = Mathf.Max(power, lordJob_PsychicRitual.points);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_SummonPitGate.txt`
|
||||
**相似度:** 0.7581
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualDef_SummonPitGate : PsychicRitualDef_InvocationCircle
|
||||
{
|
||||
private FloatRange combatPointMultiplierFromQualityRange;
|
||||
|
||||
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph graph)
|
||||
{
|
||||
List<PsychicRitualToil> list = base.CreateToils(psychicRitual, graph);
|
||||
list.Add(new PsychicRitualToil_SummonPitGate(InvokerRole, combatPointMultiplierFromQualityRange));
|
||||
return list;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> BlockingIssues(PsychicRitualRoleAssignments assignments, Map map)
|
||||
{
|
||||
foreach (string item in base.BlockingIssues(assignments, map))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (map.listerThings.ThingsOfDef(ThingDefOf.PitGate).Count > 0 || map.listerThings.ThingsOfDef(ThingDefOf.PitGateSpawner).Count > 0)
|
||||
{
|
||||
yield return "PitGateAlreadyExists".Translate();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
103
MCP/vector_cache/PsychicRitualToil_GatherForInvocation.txt
Normal file
103
MCP/vector_cache/PsychicRitualToil_GatherForInvocation.txt
Normal file
@@ -0,0 +1,103 @@
|
||||
根据向量相似度分析,与 'PsychicRitualToil_GatherForInvocation' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI.Group\PsychicRitualToil_GatherForInvocation.txt`
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualToil_GatherForInvocation : PsychicRitualToil_Multiplex
|
||||
{
|
||||
protected PsychicRitualToil_Goto fallbackToil;
|
||||
|
||||
protected PsychicRitualGraph invokerToil;
|
||||
|
||||
protected PsychicRitualToil_Goto invokerFinalToil;
|
||||
|
||||
private static List<Pawn> blockingPawns = new List<Pawn>(16);
|
||||
|
||||
protected PsychicRitualToil_GatherForInvocation()
|
||||
{
|
||||
}
|
||||
|
||||
protected PsychicRitualToil_GatherForInvocation(PsychicRitualDef_InvocationCircle def, PsychicRitualToil_Goto fallbackToil, PsychicRitualGraph invokerToil)
|
||||
: base(new Dictionary<PsychicRitualRoleDef, PsychicRitualToil> { { def.InvokerRole, invokerToil } }, fallbackToil)
|
||||
{
|
||||
this.fallbackToil = fallbackToil;
|
||||
this.invokerToil = invokerToil;
|
||||
invokerFinalToil = (PsychicRitualToil_Goto)invokerToil.GetToil(invokerToil.ToilCount - 1);
|
||||
}
|
||||
|
||||
public PsychicRitualToil_GatherForInvocation(PsychicRitual psychicRitual, PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
: this(def, FallbackToil(psychicRitual, def, rolePositions), InvokerToil(def, rolePositions))
|
||||
{
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_References.Look(ref fallbackToil, "fallbackToil");
|
||||
Scribe_References.Look(ref invokerToil, "invokerToil");
|
||||
Scribe_References.Look(ref invokerFinalToil, "invokerFinalToil");
|
||||
}
|
||||
|
||||
public override string GetReport(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
blockingPawns.Clear();
|
||||
blockingPawns.AddRange(fallbackToil.BlockingPawns);
|
||||
if (invokerToil.CurrentToil == invokerFinalToil)
|
||||
{
|
||||
blockingPawns.AddRange(invokerFinalToil.BlockingPawns);
|
||||
}
|
||||
else
|
||||
{
|
||||
blockingPawns.AddRange(invokerFinalToil.ControlledPawns(psychicRitual));
|
||||
}
|
||||
string text = "PsychicRitualToil_GatherForInvocation_Report".Translate();
|
||||
string text2 = blockingPawns.Select((Pawn pawn) => pawn.LabelShortCap).ToCommaList();
|
||||
return text + ": " + text2;
|
||||
}
|
||||
|
||||
public static PsychicRitualToil_Goto FallbackToil(PsychicRitual psychicRitual, PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
return new PsychicRitualToil_Goto(rolePositions.Slice(rolePositions.Keys.Except(def.InvokerRole)));
|
||||
}
|
||||
|
||||
public static PsychicRitualGraph InvokerToil(PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
return new PsychicRitualGraph(InvokerGatherPhaseToils(def, rolePositions))
|
||||
{
|
||||
willAdvancePastLastToil = false
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<PsychicRitualToil> InvokerGatherPhaseToils(PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
if (def.RequiredOffering != null)
|
||||
{
|
||||
yield return new PsychicRitualToil_GatherOfferings(def.InvokerRole, def.RequiredOffering);
|
||||
}
|
||||
if (def.TargetRole != null)
|
||||
{
|
||||
yield return new PsychicRitualToil_CarryAndGoto(def.InvokerRole, def.TargetRole, rolePositions);
|
||||
}
|
||||
yield return new PsychicRitualToil_Goto(rolePositions.Slice(def.InvokerRole));
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\PsychicRitualDef_InvocationCircle.txt`
|
||||
**相似度:** 0.7275
|
||||
|
||||
```csharp
|
||||
private class RitualQualityOffsetCount
|
||||
{
|
||||
public float offset;
|
||||
|
||||
public int count;
|
||||
|
||||
public RitualQualityOffsetCount(int count, float offset)
|
||||
{
|
||||
this.count = count;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
```
|
||||
270
MCP/vector_cache/PsychicRitualToil_GatherOfferings.txt
Normal file
270
MCP/vector_cache/PsychicRitualToil_GatherOfferings.txt
Normal file
@@ -0,0 +1,270 @@
|
||||
根据向量相似度分析,与 'PsychicRitualToil_GatherOfferings' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI.Group\PsychicRitualToil_GatherOfferings.txt`
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualToil_GatherOfferings : PsychicRitualToil
|
||||
{
|
||||
protected PsychicRitualRoleDef gathererRole;
|
||||
|
||||
protected bool offeringsGathered;
|
||||
|
||||
protected IngredientCount requiredOffering;
|
||||
|
||||
protected PsychicRitualToil_GatherOfferings()
|
||||
{
|
||||
}
|
||||
|
||||
public PsychicRitualToil_GatherOfferings(PsychicRitualRoleDef offeringGatherer, IngredientCount requiredOffering)
|
||||
{
|
||||
gathererRole = offeringGatherer;
|
||||
this.requiredOffering = requiredOffering;
|
||||
}
|
||||
|
||||
public override void UpdateAllDuties(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
DutyDef def;
|
||||
if (offeringsGathered || PawnsHaveOfferings(psychicRitual))
|
||||
{
|
||||
offeringsGathered = true;
|
||||
def = DutyDefOf.Idle;
|
||||
}
|
||||
else
|
||||
{
|
||||
def = DutyDefOf.GatherOfferingsForPsychicRitual;
|
||||
}
|
||||
foreach (Pawn item in psychicRitual.assignments.AssignedPawns(gathererRole))
|
||||
{
|
||||
SetPawnDuty(item, psychicRitual, parent, def);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Tick(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
return offeringsGathered;
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Defs.Look(ref gathererRole, "gathererRole");
|
||||
Scribe_Values.Look(ref offeringsGathered, "offeringsGathered", defaultValue: false);
|
||||
Scribe_Deep.Look(ref requiredOffering, "requiredOffering");
|
||||
}
|
||||
|
||||
public static float PawnsOfferingCount(IEnumerable<Pawn> pawns, IngredientCount offering)
|
||||
{
|
||||
float num = 0f;
|
||||
foreach (Pawn pawn in pawns)
|
||||
{
|
||||
foreach (Thing item in (IEnumerable<Thing>)pawn.inventory.GetDirectlyHeldThings())
|
||||
{
|
||||
if (offering.filter.Allows(item))
|
||||
{
|
||||
num += (float)item.stackCount;
|
||||
if (num >= offering.GetBaseCount())
|
||||
{
|
||||
return offering.GetBaseCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private bool PawnsHaveOfferings(PsychicRitual psychicRitual)
|
||||
{
|
||||
float baseCount = requiredOffering.GetBaseCount();
|
||||
return PawnsOfferingCount(psychicRitual.assignments.AssignedPawns(gathererRole), requiredOffering) >= baseCount;
|
||||
}
|
||||
|
||||
public override void Notify_PawnJobDone(PsychicRitual psychicRitual, PsychicRitualGraph parent, Pawn pawn, Job job, JobCondition condition)
|
||||
{
|
||||
base.Notify_PawnJobDone(psychicRitual, parent, pawn, job, condition);
|
||||
if (psychicRitual.assignments.RoleForPawn(pawn) == gathererRole && (offeringsGathered || PawnsHaveOfferings(psychicRitual)))
|
||||
{
|
||||
offeringsGathered = true;
|
||||
SetPawnDuty(pawn, psychicRitual, parent, DutyDefOf.Idle);
|
||||
}
|
||||
}
|
||||
|
||||
public override ThinkResult Notify_DutyResult(PsychicRitual psychicRitual, PsychicRitualGraph parent, ThinkResult result, Pawn pawn, JobIssueParams issueParams)
|
||||
{
|
||||
result = base.Notify_DutyResult(psychicRitual, parent, result, pawn, issueParams);
|
||||
if (result.Job != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (psychicRitual.assignments.RoleForPawn(pawn) != gathererRole)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (offeringsGathered || PawnsHaveOfferings(psychicRitual))
|
||||
{
|
||||
offeringsGathered = true;
|
||||
SetPawnDuty(pawn, psychicRitual, parent, DutyDefOf.Idle);
|
||||
return new ThinkResult(JobMaker.MakeJob(JobDefOf.Wait, 1), null);
|
||||
}
|
||||
TaggedString reason = "PsychicRitualToil_GatherOfferings_OfferingUnavailable".Translate(pawn.Named("PAWN"), requiredOffering.filter.Summary);
|
||||
psychicRitual.LeaveOrCancelPsychicRitual(gathererRole, pawn, reason);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetJobReport(PsychicRitual psychicRitual, PsychicRitualGraph parent, Pawn pawn)
|
||||
{
|
||||
if (psychicRitual.assignments.RoleForPawn(pawn) == gathererRole)
|
||||
{
|
||||
return "PsychicRitualToil_GatherOfferings_JobReport".Translate();
|
||||
}
|
||||
return base.GetJobReport(psychicRitual, parent, pawn);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\JobGiver_GatherOfferingsForPsychicRitual.txt`
|
||||
**相似度:** 0.8171
|
||||
|
||||
```csharp
|
||||
public class JobGiver_GatherOfferingsForPsychicRitual : ThinkNode_JobGiver
|
||||
{
|
||||
protected override Job TryGiveJob(Pawn pawn)
|
||||
{
|
||||
Lord lord = pawn.GetLord();
|
||||
if (lord == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!(lord.CurLordToil is LordToil_PsychicRitual lordToil_PsychicRitual))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PsychicRitualDef def = lordToil_PsychicRitual.RitualData.psychicRitual.def;
|
||||
PsychicRitualDef_InvocationCircle ritualDef = def as PsychicRitualDef_InvocationCircle;
|
||||
if (ritualDef == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (ritualDef.RequiredOffering == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PsychicRitual psychicRitual = lordToil_PsychicRitual.RitualData.psychicRitual;
|
||||
PsychicRitualRoleDef psychicRitualRoleDef = psychicRitual.assignments.RoleForPawn(pawn);
|
||||
if (psychicRitualRoleDef == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
float num = PsychicRitualToil_GatherOfferings.PawnsOfferingCount(psychicRitual.assignments.AssignedPawns(psychicRitualRoleDef), ritualDef.RequiredOffering);
|
||||
int needed = Mathf.CeilToInt(ritualDef.RequiredOffering.GetBaseCount() - num);
|
||||
if (needed == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Thing thing2 = GenClosest.ClosestThingReachable(pawn.PositionHeld, pawn.MapHeld, ThingRequest.ForGroup(ThingRequestGroup.HaulableAlways), PathEndMode.Touch, TraverseParms.For(pawn), 9999f, delegate(Thing thing)
|
||||
{
|
||||
if (!ritualDef.RequiredOffering.filter.Allows(thing))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (thing.IsForbidden(pawn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int stackCount = Mathf.Min(needed, thing.stackCount);
|
||||
return pawn.CanReserve(thing, 10, stackCount) ? true : false;
|
||||
});
|
||||
if (thing2 == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Job job = JobMaker.MakeJob(JobDefOf.TakeCountToInventory, thing2);
|
||||
job.count = Mathf.Min(needed, thing2.stackCount);
|
||||
return job;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\Verse.AI.Group\PsychicRitualToil_GatherForInvocation.txt`
|
||||
**相似度:** 0.7774
|
||||
|
||||
```csharp
|
||||
public class PsychicRitualToil_GatherForInvocation : PsychicRitualToil_Multiplex
|
||||
{
|
||||
protected PsychicRitualToil_Goto fallbackToil;
|
||||
|
||||
protected PsychicRitualGraph invokerToil;
|
||||
|
||||
protected PsychicRitualToil_Goto invokerFinalToil;
|
||||
|
||||
private static List<Pawn> blockingPawns = new List<Pawn>(16);
|
||||
|
||||
protected PsychicRitualToil_GatherForInvocation()
|
||||
{
|
||||
}
|
||||
|
||||
protected PsychicRitualToil_GatherForInvocation(PsychicRitualDef_InvocationCircle def, PsychicRitualToil_Goto fallbackToil, PsychicRitualGraph invokerToil)
|
||||
: base(new Dictionary<PsychicRitualRoleDef, PsychicRitualToil> { { def.InvokerRole, invokerToil } }, fallbackToil)
|
||||
{
|
||||
this.fallbackToil = fallbackToil;
|
||||
this.invokerToil = invokerToil;
|
||||
invokerFinalToil = (PsychicRitualToil_Goto)invokerToil.GetToil(invokerToil.ToilCount - 1);
|
||||
}
|
||||
|
||||
public PsychicRitualToil_GatherForInvocation(PsychicRitual psychicRitual, PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
: this(def, FallbackToil(psychicRitual, def, rolePositions), InvokerToil(def, rolePositions))
|
||||
{
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_References.Look(ref fallbackToil, "fallbackToil");
|
||||
Scribe_References.Look(ref invokerToil, "invokerToil");
|
||||
Scribe_References.Look(ref invokerFinalToil, "invokerFinalToil");
|
||||
}
|
||||
|
||||
public override string GetReport(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||
{
|
||||
blockingPawns.Clear();
|
||||
blockingPawns.AddRange(fallbackToil.BlockingPawns);
|
||||
if (invokerToil.CurrentToil == invokerFinalToil)
|
||||
{
|
||||
blockingPawns.AddRange(invokerFinalToil.BlockingPawns);
|
||||
}
|
||||
else
|
||||
{
|
||||
blockingPawns.AddRange(invokerFinalToil.ControlledPawns(psychicRitual));
|
||||
}
|
||||
string text = "PsychicRitualToil_GatherForInvocation_Report".Translate();
|
||||
string text2 = blockingPawns.Select((Pawn pawn) => pawn.LabelShortCap).ToCommaList();
|
||||
return text + ": " + text2;
|
||||
}
|
||||
|
||||
public static PsychicRitualToil_Goto FallbackToil(PsychicRitual psychicRitual, PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
return new PsychicRitualToil_Goto(rolePositions.Slice(rolePositions.Keys.Except(def.InvokerRole)));
|
||||
}
|
||||
|
||||
public static PsychicRitualGraph InvokerToil(PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
return new PsychicRitualGraph(InvokerGatherPhaseToils(def, rolePositions))
|
||||
{
|
||||
willAdvancePastLastToil = false
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<PsychicRitualToil> InvokerGatherPhaseToils(PsychicRitualDef_InvocationCircle def, IReadOnlyDictionary<PsychicRitualRoleDef, List<IntVec3>> rolePositions)
|
||||
{
|
||||
if (def.RequiredOffering != null)
|
||||
{
|
||||
yield return new PsychicRitualToil_GatherOfferings(def.InvokerRole, def.RequiredOffering);
|
||||
}
|
||||
if (def.TargetRole != null)
|
||||
{
|
||||
yield return new PsychicRitualToil_CarryAndGoto(def.InvokerRole, def.TargetRole, rolePositions);
|
||||
}
|
||||
yield return new PsychicRitualToil_Goto(rolePositions.Slice(def.InvokerRole));
|
||||
}
|
||||
}
|
||||
```
|
||||
1333
MCP/vector_cache/Source-StartCarryThing-Toil-Toils_Haul.txt
Normal file
1333
MCP/vector_cache/Source-StartCarryThing-Toil-Toils_Haul.txt
Normal file
File diff suppressed because it is too large
Load Diff
502
MCP/vector_cache/StatDef.txt
Normal file
502
MCP/vector_cache/StatDef.txt
Normal file
@@ -0,0 +1,502 @@
|
||||
根据向量相似度分析,与 'StatDef' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\StatDef.txt`
|
||||
|
||||
```csharp
|
||||
public class StatDef : Def
|
||||
{
|
||||
private static HashSet<StatDef> mutableStats;
|
||||
|
||||
public StatCategoryDef category;
|
||||
|
||||
public Type workerClass = typeof(StatWorker);
|
||||
|
||||
public string labelForFullStatList;
|
||||
|
||||
public bool forInformationOnly;
|
||||
|
||||
[MustTranslate]
|
||||
private string offsetLabel;
|
||||
|
||||
public float hideAtValue = -2.1474836E+09f;
|
||||
|
||||
public bool alwaysHide;
|
||||
|
||||
public bool showNonAbstract = true;
|
||||
|
||||
public bool showIfUndefined = true;
|
||||
|
||||
public bool showOnPawns = true;
|
||||
|
||||
public bool showOnHumanlikes = true;
|
||||
|
||||
public bool showOnNonWildManHumanlikes = true;
|
||||
|
||||
public bool showOnAnimals = true;
|
||||
|
||||
public bool showOnMechanoids = true;
|
||||
|
||||
public bool showOnNonWorkTables = true;
|
||||
|
||||
public bool showOnEntities = true;
|
||||
|
||||
public bool showOnDrones = true;
|
||||
|
||||
public bool showOnNonPowerPlants = true;
|
||||
|
||||
public bool showOnDefaultValue = true;
|
||||
|
||||
public bool showOnUnhaulables = true;
|
||||
|
||||
public bool showOnUntradeables = true;
|
||||
|
||||
public List<string> showIfModsLoaded;
|
||||
|
||||
public List<string> showIfModsLoadedAny;
|
||||
|
||||
public List<HediffDef> showIfHediffsPresent;
|
||||
|
||||
public bool neverDisabled;
|
||||
|
||||
public bool showZeroBaseValue;
|
||||
|
||||
public bool showOnSlavesOnly;
|
||||
|
||||
public bool showOnPlayerMechanoids;
|
||||
|
||||
public DevelopmentalStage showDevelopmentalStageFilter = DevelopmentalStage.Baby | DevelopmentalStage.Child | DevelopmentalStage.Adult;
|
||||
|
||||
public bool hideInClassicMode;
|
||||
|
||||
public List<PawnKindDef> showOnPawnKind;
|
||||
|
||||
public bool overridesHideStats;
|
||||
|
||||
public int displayPriorityInCategory;
|
||||
|
||||
public ToStringNumberSense toStringNumberSense = ToStringNumberSense.Absolute;
|
||||
|
||||
public ToStringStyle toStringStyle;
|
||||
|
||||
private ToStringStyle? toStringStyleUnfinalized;
|
||||
|
||||
[MustTranslate]
|
||||
public string formatString;
|
||||
|
||||
[MustTranslate]
|
||||
public string formatStringUnfinalized;
|
||||
|
||||
public bool finalizeEquippedStatOffset = true;
|
||||
|
||||
[MustTranslate]
|
||||
public string statFactorsExplanationHeader;
|
||||
|
||||
public float defaultBaseValue = 1f;
|
||||
|
||||
public List<SkillNeed> skillNeedOffsets;
|
||||
|
||||
public float noSkillOffset;
|
||||
|
||||
public List<PawnCapacityOffset> capacityOffsets;
|
||||
|
||||
public List<StatDef> statFactors;
|
||||
|
||||
public bool applyFactorsIfNegative = true;
|
||||
|
||||
public List<SkillNeed> skillNeedFactors;
|
||||
|
||||
public float noSkillFactor = 1f;
|
||||
|
||||
public List<PawnCapacityFactor> capacityFactors;
|
||||
|
||||
public SimpleCurve postProcessCurve;
|
||||
|
||||
public List<StatDef> postProcessStatFactors;
|
||||
|
||||
public float minValue = -9999999f;
|
||||
|
||||
public float maxValue = 9999999f;
|
||||
|
||||
public float valueIfMissing;
|
||||
|
||||
public bool roundValue;
|
||||
|
||||
public float roundToFiveOver = float.MaxValue;
|
||||
|
||||
public bool minifiedThingInherits;
|
||||
|
||||
public bool supressDisabledError;
|
||||
|
||||
public bool cacheable;
|
||||
|
||||
public bool displayMaxWhenAboveOrEqual;
|
||||
|
||||
public bool scenarioRandomizable;
|
||||
|
||||
public SkillDef disableIfSkillDisabled;
|
||||
|
||||
public List<StatPart> parts;
|
||||
|
||||
[Unsaved(false)]
|
||||
private StatWorker workerInt;
|
||||
|
||||
[Unsaved(false)]
|
||||
public bool immutable;
|
||||
|
||||
public StatWorker Worker
|
||||
{
|
||||
get
|
||||
{
|
||||
if (workerInt == null)
|
||||
{
|
||||
if (parts != null)
|
||||
{
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
parts[i].parentStat = this;
|
||||
}
|
||||
}
|
||||
workerInt = (StatWorker)Activator.CreateInstance(workerClass);
|
||||
workerInt.InitSetStat(this);
|
||||
}
|
||||
return workerInt;
|
||||
}
|
||||
}
|
||||
|
||||
public ToStringStyle ToStringStyleUnfinalized
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!toStringStyleUnfinalized.HasValue)
|
||||
{
|
||||
return toStringStyle;
|
||||
}
|
||||
return toStringStyleUnfinalized.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public string LabelForFullStatList
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!labelForFullStatList.NullOrEmpty())
|
||||
{
|
||||
return labelForFullStatList;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
public string LabelForFullStatListCap => LabelForFullStatList.CapitalizeFirst(this);
|
||||
|
||||
public string OffsetLabel => offsetLabel ?? label;
|
||||
|
||||
public string OffsetLabelCap => OffsetLabel.CapitalizeFirst();
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string item in base.ConfigErrors())
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
if (capacityFactors != null)
|
||||
{
|
||||
foreach (PawnCapacityFactor capacityFactor in capacityFactors)
|
||||
{
|
||||
if (capacityFactor.weight > 1f)
|
||||
{
|
||||
yield return defName + " has activity factor with weight > 1";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parts == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
foreach (string item2 in parts[i].ConfigErrors())
|
||||
{
|
||||
yield return defName + " has error in StatPart " + parts[i].ToString() + ": " + item2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ValueToString(float val, ToStringNumberSense numberSense = ToStringNumberSense.Absolute, bool finalized = true)
|
||||
{
|
||||
return Worker.ValueToString(val, finalized, numberSense);
|
||||
}
|
||||
|
||||
public static StatDef Named(string defName)
|
||||
{
|
||||
return DefDatabase<StatDef>.GetNamed(defName);
|
||||
}
|
||||
|
||||
public override void PostLoad()
|
||||
{
|
||||
base.PostLoad();
|
||||
if (parts != null)
|
||||
{
|
||||
List<StatPart> partsCopy = parts.ToList();
|
||||
parts.SortBy((StatPart x) => 0f - x.priority, (StatPart x) => partsCopy.IndexOf(x));
|
||||
}
|
||||
}
|
||||
|
||||
public T GetStatPart<T>() where T : StatPart
|
||||
{
|
||||
return parts.OfType<T>().FirstOrDefault();
|
||||
}
|
||||
|
||||
public bool CanShowWithLoadedMods()
|
||||
{
|
||||
if (!showIfModsLoaded.NullOrEmpty())
|
||||
{
|
||||
for (int i = 0; i < showIfModsLoaded.Count; i++)
|
||||
{
|
||||
if (!ModsConfig.IsActive(showIfModsLoaded[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!showIfModsLoadedAny.NullOrEmpty())
|
||||
{
|
||||
bool result = false;
|
||||
for (int j = 0; j < showIfModsLoadedAny.Count; j++)
|
||||
{
|
||||
if (ModsConfig.IsActive(showIfModsLoadedAny[j]))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void PopulateMutableStats()
|
||||
{
|
||||
mutableStats = new HashSet<StatDef>();
|
||||
foreach (TraitDef item in DefDatabase<TraitDef>.AllDefsListForReading)
|
||||
{
|
||||
foreach (TraitDegreeData degreeData in item.degreeDatas)
|
||||
{
|
||||
AddStatsFromModifiers(degreeData.statOffsets);
|
||||
AddStatsFromModifiers(degreeData.statFactors);
|
||||
}
|
||||
}
|
||||
foreach (HediffDef item2 in DefDatabase<HediffDef>.AllDefsListForReading)
|
||||
{
|
||||
if (item2.stages == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (HediffStage stage in item2.stages)
|
||||
{
|
||||
AddStatsFromModifiers(stage.statOffsets);
|
||||
AddStatsFromModifiers(stage.statFactors);
|
||||
if (stage.statOffsetEffectMultiplier != null)
|
||||
{
|
||||
mutableStats.Add(stage.statOffsetEffectMultiplier);
|
||||
}
|
||||
if (stage.statFactorEffectMultiplier != null)
|
||||
{
|
||||
mutableStats.Add(stage.statFactorEffectMultiplier);
|
||||
}
|
||||
if (stage.capacityFactorEffectMultiplier != null)
|
||||
{
|
||||
mutableStats.Add(stage.capacityFactorEffectMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (PreceptDef item3 in DefDatabase<PreceptDef>.AllDefsListForReading)
|
||||
{
|
||||
AddStatsFromModifiers(item3.statOffsets);
|
||||
AddStatsFromModifiers(item3.statFactors);
|
||||
if (item3.roleEffects != null)
|
||||
{
|
||||
foreach (RoleEffect roleEffect in item3.roleEffects)
|
||||
{
|
||||
if (roleEffect is RoleEffect_PawnStatOffset roleEffect_PawnStatOffset)
|
||||
{
|
||||
mutableStats.Add(roleEffect_PawnStatOffset.statDef);
|
||||
}
|
||||
if (roleEffect is RoleEffect_PawnStatFactor roleEffect_PawnStatFactor)
|
||||
{
|
||||
mutableStats.Add(roleEffect_PawnStatFactor.statDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item3.abilityStatFactors == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (AbilityStatModifiers abilityStatFactor in item3.abilityStatFactors)
|
||||
{
|
||||
AddStatsFromModifiers(abilityStatFactor.modifiers);
|
||||
}
|
||||
}
|
||||
foreach (GeneDef item4 in DefDatabase<GeneDef>.AllDefsListForReading)
|
||||
{
|
||||
AddStatsFromModifiers(item4.statOffsets);
|
||||
AddStatsFromModifiers(item4.statFactors);
|
||||
if (item4.conditionalStatAffecters == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (ConditionalStatAffecter conditionalStatAffecter in item4.conditionalStatAffecters)
|
||||
{
|
||||
AddStatsFromModifiers(conditionalStatAffecter.statOffsets);
|
||||
AddStatsFromModifiers(conditionalStatAffecter.statFactors);
|
||||
}
|
||||
}
|
||||
foreach (ThingDef item5 in DefDatabase<ThingDef>.AllDefsListForReading)
|
||||
{
|
||||
AddStatsFromModifiers(item5.equippedStatOffsets);
|
||||
if (!item5.HasAssignableCompFrom(typeof(CompFacility)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CompProperties_Facility compProperties = item5.GetCompProperties<CompProperties_Facility>();
|
||||
if (compProperties?.statOffsets != null)
|
||||
{
|
||||
AddStatsFromModifiers(compProperties.statOffsets);
|
||||
}
|
||||
if (!(compProperties is CompProperties_FacilityQualityBased compProperties_FacilityQualityBased))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (StatDef key in compProperties_FacilityQualityBased.statOffsetsPerQuality.Keys)
|
||||
{
|
||||
mutableStats.Add(key);
|
||||
}
|
||||
}
|
||||
foreach (WeaponTraitDef item6 in DefDatabase<WeaponTraitDef>.AllDefsListForReading)
|
||||
{
|
||||
AddStatsFromModifiers(item6.equippedStatOffsets);
|
||||
}
|
||||
foreach (LifeStageDef item7 in DefDatabase<LifeStageDef>.AllDefsListForReading)
|
||||
{
|
||||
AddStatsFromModifiers(item7.statFactors);
|
||||
AddStatsFromModifiers(item7.statOffsets);
|
||||
}
|
||||
foreach (InspirationDef item8 in DefDatabase<InspirationDef>.AllDefsListForReading)
|
||||
{
|
||||
AddStatsFromModifiers(item8.statOffsets);
|
||||
AddStatsFromModifiers(item8.statFactors);
|
||||
}
|
||||
static void AddStatsFromModifiers(List<StatModifier> mods)
|
||||
{
|
||||
if (mods != null)
|
||||
{
|
||||
mutableStats.AddRange(mods.Select((StatModifier mod) => mod.stat));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsImmutable()
|
||||
{
|
||||
if (workerClass != typeof(StatWorker))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!skillNeedOffsets.NullOrEmpty() || !skillNeedFactors.NullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!capacityOffsets.NullOrEmpty() || !capacityFactors.NullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!statFactors.NullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!parts.NullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!postProcessStatFactors.NullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (mutableStats.Contains(this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void SetImmutability()
|
||||
{
|
||||
PopulateMutableStats();
|
||||
foreach (StatDef item in DefDatabase<StatDef>.AllDefsListForReading)
|
||||
{
|
||||
item.immutable = item.IsImmutable();
|
||||
item.Worker.SetCacheability(item.immutable);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ResetStaticData()
|
||||
{
|
||||
mutableStats = null;
|
||||
foreach (StatDef item in DefDatabase<StatDef>.AllDefsListForReading)
|
||||
{
|
||||
item.immutable = false;
|
||||
item.Worker.DeleteStatCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Core\Defs\Stats\Stats_Building_Special.xml`
|
||||
**相似度:** 0.5742
|
||||
|
||||
```xml
|
||||
<StatDef>
|
||||
<defName>WorkToBuild</defName>
|
||||
<label>work to build</label>
|
||||
<description>The base amount of work it takes to build a structure, once all materials are gathered.\n\nThe work required to deconstruct the structure is also based on this.</description>
|
||||
<category>Building</category>
|
||||
<defaultBaseValue>1</defaultBaseValue>
|
||||
<minValue>0</minValue>
|
||||
<toStringStyle>WorkAmount</toStringStyle>
|
||||
<roundToFiveOver>300</roundToFiveOver>
|
||||
<showIfUndefined>false</showIfUndefined>
|
||||
<scenarioRandomizable>true</scenarioRandomizable>
|
||||
<displayPriorityInCategory>3101</displayPriorityInCategory>
|
||||
</StatDef>
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\Royalty\Defs\Stats\Stats_Basics_Special.xml`
|
||||
**相似度:** 0.5197
|
||||
|
||||
```xml
|
||||
<StatDef>
|
||||
<defName>MeditationPlantGrowthOffset</defName>
|
||||
<label>meditation plant growth offset</label>
|
||||
<description>An offset applied to the growth rate of plants, like anima grass, from meditation. This value can change based on the number of artificial buildings nearby.</description>
|
||||
<category>Meditation</category>
|
||||
<defaultBaseValue>0</defaultBaseValue>
|
||||
<showIfUndefined>false</showIfUndefined>
|
||||
<showZeroBaseValue>false</showZeroBaseValue>
|
||||
<showOnDefaultValue>false</showOnDefaultValue>
|
||||
<displayPriorityInCategory>4000</displayPriorityInCategory>
|
||||
<toStringStyle>PercentZero</toStringStyle>
|
||||
<parts>
|
||||
<li Class="StatPart_ArtificialBuildingsNearbyOffset">
|
||||
<radius>27.9</radius>
|
||||
<curve>
|
||||
<points>
|
||||
<li>(0, 0.0)</li>
|
||||
<li>(5, -0.08)</li>
|
||||
<li>(10, -0.15)</li>
|
||||
<li>(50, -0.3)</li>
|
||||
</points>
|
||||
</curve>
|
||||
</li>
|
||||
</parts>
|
||||
</StatDef>
|
||||
```
|
||||
507
MCP/vector_cache/WorkGiver_Scanner.txt
Normal file
507
MCP/vector_cache/WorkGiver_Scanner.txt
Normal file
@@ -0,0 +1,507 @@
|
||||
根据向量相似度分析,与 'WorkGiver_Scanner' 最相关的代码定义如下:
|
||||
|
||||
---
|
||||
**文件路径 (精确匹配):** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_Scanner.txt`
|
||||
|
||||
```csharp
|
||||
public abstract class WorkGiver_Scanner : WorkGiver
|
||||
{
|
||||
public virtual ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.Undefined);
|
||||
|
||||
public virtual int MaxRegionsToScanBeforeGlobalSearch => -1;
|
||||
|
||||
public virtual bool Prioritized => false;
|
||||
|
||||
public virtual bool AllowUnreachable => false;
|
||||
|
||||
public virtual PathEndMode PathEndMode => PathEndMode.Touch;
|
||||
|
||||
public virtual IEnumerable<IntVec3> PotentialWorkCellsGlobal(Pawn pawn)
|
||||
{
|
||||
return Enumerable.Empty<IntVec3>();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual Danger MaxPathDanger(Pawn pawn)
|
||||
{
|
||||
return pawn.NormalMaxDanger();
|
||||
}
|
||||
|
||||
public virtual bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
return JobOnThing(pawn, t, forced) != null;
|
||||
}
|
||||
|
||||
public virtual string JobInfo(Pawn pawn, Job job)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public virtual Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual bool HasJobOnCell(Pawn pawn, IntVec3 c, bool forced = false)
|
||||
{
|
||||
return JobOnCell(pawn, c, forced) != null;
|
||||
}
|
||||
|
||||
public virtual Job JobOnCell(Pawn pawn, IntVec3 cell, bool forced = false)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual float GetPriority(Pawn pawn, TargetInfo t)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public virtual string PostProcessedGerund(Job job)
|
||||
{
|
||||
return def.gerund;
|
||||
}
|
||||
|
||||
public float GetPriority(Pawn pawn, IntVec3 cell)
|
||||
{
|
||||
return GetPriority(pawn, new TargetInfo(cell, pawn.Map));
|
||||
}
|
||||
|
||||
public virtual ReservationLayerDef GetReservationLayer(Pawn pawn, LocalTargetInfo target)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_HaulToSubcoreScanner.txt`
|
||||
**相似度:** 0.5742
|
||||
|
||||
```csharp
|
||||
public class WorkGiver_HaulToSubcoreScanner : WorkGiver_Scanner
|
||||
{
|
||||
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.SubcoreScanner);
|
||||
|
||||
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
if (!ModLister.CheckBiotech("Haul to subcore scanner"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(t is Building_SubcoreScanner { State: SubcoreScannerState.WaitingForIngredients } building_SubcoreScanner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!pawn.CanReserve(t, 1, -1, null, forced))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return FindIngredients(pawn, building_SubcoreScanner).Thing != null;
|
||||
}
|
||||
|
||||
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
if (!(t is Building_SubcoreScanner { State: SubcoreScannerState.WaitingForIngredients } building_SubcoreScanner))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ThingCount thingCount = FindIngredients(pawn, building_SubcoreScanner);
|
||||
if (thingCount.Thing != null)
|
||||
{
|
||||
Job job = HaulAIUtility.HaulToContainerJob(pawn, thingCount.Thing, t);
|
||||
job.count = Mathf.Min(job.count, thingCount.Count);
|
||||
return job;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ThingCount FindIngredients(Pawn pawn, Building_SubcoreScanner scanner)
|
||||
{
|
||||
Thing thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.HaulableEver), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 9999f, Validator);
|
||||
if (thing == null)
|
||||
{
|
||||
return default(ThingCount);
|
||||
}
|
||||
int requiredCountOf = scanner.GetRequiredCountOf(thing.def);
|
||||
return new ThingCount(thing, Mathf.Min(thing.stackCount, requiredCountOf));
|
||||
bool Validator(Thing x)
|
||||
{
|
||||
if (!pawn.CanReserve(x))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (x.IsForbidden(pawn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return scanner.CanAcceptIngredient(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_HaulToBiosculpterPod.txt`
|
||||
**相似度:** 0.5453
|
||||
|
||||
```csharp
|
||||
public class WorkGiver_HaulToBiosculpterPod : WorkGiver_Scanner
|
||||
{
|
||||
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDefOf.BiosculpterPod);
|
||||
|
||||
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||
|
||||
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
if (!ModLister.CheckIdeology("Biosculpting"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!pawn.CanReserve(t, 1, -1, null, forced))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pawn.Map.designationManager.DesignationOn(t, DesignationDefOf.Deconstruct) != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
CompBiosculpterPod compBiosculpterPod = t.TryGetComp<CompBiosculpterPod>();
|
||||
if (compBiosculpterPod == null || !compBiosculpterPod.PowerOn || compBiosculpterPod.State != 0 || (!forced && !compBiosculpterPod.autoLoadNutrition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (t.IsBurning())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (compBiosculpterPod.RequiredNutritionRemaining > 0f)
|
||||
{
|
||||
if (FindNutrition(pawn, compBiosculpterPod).Thing == null)
|
||||
{
|
||||
JobFailReason.Is("NoFood".Translate());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
CompBiosculpterPod compBiosculpterPod = t.TryGetComp<CompBiosculpterPod>();
|
||||
if (compBiosculpterPod == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (compBiosculpterPod.RequiredNutritionRemaining > 0f)
|
||||
{
|
||||
ThingCount thingCount = FindNutrition(pawn, compBiosculpterPod);
|
||||
if (thingCount.Thing != null)
|
||||
{
|
||||
Job job = HaulAIUtility.HaulToContainerJob(pawn, thingCount.Thing, t);
|
||||
job.count = Mathf.Min(job.count, thingCount.Count);
|
||||
return job;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ThingCount FindNutrition(Pawn pawn, CompBiosculpterPod pod)
|
||||
{
|
||||
Thing thing = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForGroup(ThingRequestGroup.FoodSourceNotPlantOrTree), PathEndMode.ClosestTouch, TraverseParms.For(pawn), 9999f, Validator);
|
||||
if (thing == null)
|
||||
{
|
||||
return default(ThingCount);
|
||||
}
|
||||
int b = Mathf.CeilToInt(pod.RequiredNutritionRemaining / thing.GetStatValue(StatDefOf.Nutrition));
|
||||
return new ThingCount(thing, Mathf.Min(thing.stackCount, b));
|
||||
bool Validator(Thing x)
|
||||
{
|
||||
if (x.IsForbidden(pawn) || !pawn.CanReserve(x))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!pod.CanAcceptNutrition(x))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_ConstructFinishFrames.txt`
|
||||
**相似度:** 0.5184
|
||||
|
||||
```csharp
|
||||
public class WorkGiver_ConstructFinishFrames : WorkGiver_Scanner
|
||||
{
|
||||
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||
|
||||
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.BuildingFrame);
|
||||
|
||||
public override Danger MaxPathDanger(Pawn pawn)
|
||||
{
|
||||
return Danger.Deadly;
|
||||
}
|
||||
|
||||
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||
{
|
||||
if (t.Faction != pawn.Faction)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!(t is Frame frame))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!frame.IsCompleted())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!GenConstruct.CanTouchTargetFromValidCell(frame, pawn))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (GenConstruct.FirstBlockingThing(frame, pawn) != null)
|
||||
{
|
||||
return GenConstruct.HandleBlockingThingJob(frame, pawn, forced);
|
||||
}
|
||||
if (!GenConstruct.CanConstruct(frame, pawn, checkSkills: true, forced))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return JobMaker.MakeJob(JobDefOf.FinishFrame, frame);
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_CookFillHopper.txt`
|
||||
**相似度:** 0.5093
|
||||
|
||||
```csharp
|
||||
public class WorkGiver_CookFillHopper : WorkGiver_Scanner
|
||||
{
|
||||
private static string TheOnlyAvailableFoodIsInStorageOfHigherPriorityTrans;
|
||||
|
||||
private static string NoFoodToFillHopperTrans;
|
||||
|
||||
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDefOf.Hopper);
|
||||
|
||||
public override PathEndMode PathEndMode => PathEndMode.ClosestTouch;
|
||||
|
||||
public WorkGiver_CookFillHopper()
|
||||
{
|
||||
if (TheOnlyAvailableFoodIsInStorageOfHigherPriorityTrans == null)
|
||||
{
|
||||
TheOnlyAvailableFoodIsInStorageOfHigherPriorityTrans = "TheOnlyAvailableFoodIsInStorageOfHigherPriority".Translate();
|
||||
}
|
||||
if (NoFoodToFillHopperTrans == null)
|
||||
{
|
||||
NoFoodToFillHopperTrans = "NoFoodToFillHopper".Translate();
|
||||
}
|
||||
}
|
||||
|
||||
public override Job JobOnThing(Pawn pawn, Thing thing, bool forced = false)
|
||||
{
|
||||
if (!(thing is ISlotGroupParent hopperSgp))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!pawn.CanReserve(thing.Position))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
float num = 0f;
|
||||
List<Thing> list = pawn.Map.thingGrid.ThingsListAt(thing.Position);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
Thing thing2 = list[i];
|
||||
if (Building_NutrientPasteDispenser.IsAcceptableFeedstock(thing2.def))
|
||||
{
|
||||
num = (float)thing2.stackCount / (float)thing2.def.stackLimit;
|
||||
}
|
||||
}
|
||||
if (num > 0.35f)
|
||||
{
|
||||
JobFailReason.Is("AlreadyFilledLower".Translate());
|
||||
return null;
|
||||
}
|
||||
return HopperFillFoodJob(pawn, hopperSgp, forced);
|
||||
}
|
||||
|
||||
public static Job HopperFillFoodJob(Pawn pawn, ISlotGroupParent hopperSgp, bool forced)
|
||||
{
|
||||
Building building = (Building)hopperSgp;
|
||||
if (!pawn.CanReserveAndReach(building.Position, PathEndMode.Touch, pawn.NormalMaxDanger()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ThingDef thingDef = null;
|
||||
Thing firstItem = building.Position.GetFirstItem(building.Map);
|
||||
if (firstItem != null)
|
||||
{
|
||||
if (!Building_NutrientPasteDispenser.IsAcceptableFeedstock(firstItem.def))
|
||||
{
|
||||
if (firstItem.IsForbidden(pawn))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return HaulAIUtility.HaulAsideJobFor(pawn, firstItem);
|
||||
}
|
||||
thingDef = firstItem.def;
|
||||
}
|
||||
List<Thing> list = ((thingDef != null) ? pawn.Map.listerThings.ThingsOfDef(thingDef) : pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.FoodSourceNotPlantOrTree));
|
||||
bool flag = false;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
Thing thing = list[i];
|
||||
if (!thing.def.IsNutritionGivingIngestible || (thing.def.ingestible.preferability != FoodPreferability.RawBad && thing.def.ingestible.preferability != FoodPreferability.RawTasty) || !HaulAIUtility.PawnCanAutomaticallyHaul(pawn, thing, forced) || !pawn.Map.haulDestinationManager.SlotGroupAt(building.Position).Settings.AllowedToAccept(thing))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((int)StoreUtility.CurrentStoragePriorityOf(thing, forced) >= (int)hopperSgp.GetSlotGroup().Settings.Priority)
|
||||
{
|
||||
flag = true;
|
||||
JobFailReason.Is(TheOnlyAvailableFoodIsInStorageOfHigherPriorityTrans);
|
||||
continue;
|
||||
}
|
||||
Job job = HaulAIUtility.HaulToCellStorageJob(pawn, thing, building.Position, fitInStoreCell: true);
|
||||
if (job != null)
|
||||
{
|
||||
return job;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
JobFailReason.Is(NoFoodToFillHopperTrans);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
---
|
||||
**文件路径:** `C:\Steam\steamapps\common\RimWorld\Data\dll1.6\RimWorld\WorkGiver_InteractAnimal.txt`
|
||||
**相似度:** 0.5082
|
||||
|
||||
```csharp
|
||||
public abstract class WorkGiver_InteractAnimal : WorkGiver_Scanner
|
||||
{
|
||||
protected static string NoUsableFoodTrans;
|
||||
|
||||
protected static string AnimalInteractedTooRecentlyTrans;
|
||||
|
||||
private static string CantInteractAnimalDownedTrans;
|
||||
|
||||
private static string CantInteractAnimalAsleepTrans;
|
||||
|
||||
private static string CantInteractAnimalBusyTrans;
|
||||
|
||||
protected bool canInteractWhileSleeping;
|
||||
|
||||
public override PathEndMode PathEndMode => PathEndMode.OnCell;
|
||||
|
||||
public static void ResetStaticData()
|
||||
{
|
||||
NoUsableFoodTrans = "NoUsableFood".Translate();
|
||||
AnimalInteractedTooRecentlyTrans = "AnimalInteractedTooRecently".Translate();
|
||||
CantInteractAnimalDownedTrans = "CantInteractAnimalDowned".Translate();
|
||||
CantInteractAnimalAsleepTrans = "CantInteractAnimalAsleep".Translate();
|
||||
CantInteractAnimalBusyTrans = "CantInteractAnimalBusy".Translate();
|
||||
}
|
||||
|
||||
protected virtual bool CanInteractWithAnimal(Pawn pawn, Pawn animal, bool forced)
|
||||
{
|
||||
if (CanInteractWithAnimal(pawn, animal, out var jobFailReason, forced, canInteractWhileSleeping))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (jobFailReason != null)
|
||||
{
|
||||
JobFailReason.Is(jobFailReason);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CanInteractWithAnimal(Pawn pawn, Pawn animal, out string jobFailReason, bool forced, bool canInteractWhileSleeping = false, bool ignoreSkillRequirements = false, bool canInteractWhileRoaming = false)
|
||||
{
|
||||
jobFailReason = null;
|
||||
if (!pawn.CanReserve(animal, 1, -1, null, forced))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (animal.Downed)
|
||||
{
|
||||
jobFailReason = CantInteractAnimalDownedTrans;
|
||||
return false;
|
||||
}
|
||||
if (!animal.Awake() && !canInteractWhileSleeping)
|
||||
{
|
||||
jobFailReason = CantInteractAnimalAsleepTrans;
|
||||
return false;
|
||||
}
|
||||
if (!animal.CanCasuallyInteractNow(twoWayInteraction: false, canInteractWhileSleeping, canInteractWhileRoaming))
|
||||
{
|
||||
jobFailReason = CantInteractAnimalBusyTrans;
|
||||
return false;
|
||||
}
|
||||
int num = TrainableUtility.MinimumHandlingSkill(animal);
|
||||
if (!ignoreSkillRequirements && num > pawn.skills.GetSkill(SkillDefOf.Animals).Level)
|
||||
{
|
||||
jobFailReason = "AnimalsSkillTooLow".Translate(num);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected bool HasFoodToInteractAnimal(Pawn pawn, Pawn tamee)
|
||||
{
|
||||
ThingOwner<Thing> innerContainer = pawn.inventory.innerContainer;
|
||||
int num = 0;
|
||||
float num2 = JobDriver_InteractAnimal.RequiredNutritionPerFeed(tamee);
|
||||
float num3 = 0f;
|
||||
for (int i = 0; i < innerContainer.Count; i++)
|
||||
{
|
||||
Thing thing = innerContainer[i];
|
||||
if (!tamee.WillEat(thing, pawn) || (int)thing.def.ingestible.preferability > 5 || thing.def.IsDrug)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int j = 0; j < thing.stackCount; j++)
|
||||
{
|
||||
num3 += thing.GetStatValue(StatDefOf.Nutrition);
|
||||
if (num3 >= num2)
|
||||
{
|
||||
num++;
|
||||
num3 = 0f;
|
||||
}
|
||||
if (num >= 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Job TakeFoodForAnimalInteractJob(Pawn pawn, Pawn tamee)
|
||||
{
|
||||
ThingDef foodDef;
|
||||
Thing thing = FoodUtility.BestFoodSourceOnMap(pawn, tamee, desperate: false, out foodDef, FoodPreferability.RawTasty, allowPlant: false, allowDrug: false, allowCorpse: false, allowDispenserFull: false, allowDispenserEmpty: false, allowForbidden: false, allowSociallyImproper: false, allowHarvest: false, forceScanWholeMap: false, ignoreReservations: false, calculateWantedStackCount: false, FoodPreferability.Undefined, JobDriver_InteractAnimal.RequiredNutritionPerFeed(tamee) * 2f * 4f);
|
||||
if (thing == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
float wantedNutrition = JobDriver_InteractAnimal.RequiredNutritionPerFeed(tamee) * 2f * 4f;
|
||||
float nutrition = FoodUtility.GetNutrition(tamee, thing, foodDef);
|
||||
int count = FoodUtility.StackCountForNutrition(wantedNutrition, nutrition);
|
||||
Job job = JobMaker.MakeJob(JobDefOf.TakeInventory, thing);
|
||||
job.count = count;
|
||||
return job;
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user