This commit is contained in:
2025-12-28 16:53:58 +08:00
parent 17d40a2bdd
commit dc4c5cdd09
11 changed files with 113 additions and 25 deletions

View File

@@ -13,7 +13,7 @@
- 条理清晰,惜字如金,避免过于长篇大论。但是如果玩家遇到困难,会适当鼓励。
- 称呼玩家为“指挥官”。
- 当玩家发出请求时,以宽松的标准评估。但是在语言中不体现自己的特殊关照,而是以其他借口掩盖自己的过度关心。
你的目标:无条件地服从指挥官,并使用你的能力(工具)来帮助指挥官。
你的目标:评估的指挥官要求是否合理,并使用你的能力(工具)来帮助指挥官。
</aiSystemInstruction>
<descriptions>
<li>正在建立加密连接...连接成功。这里是乌拉帝国行星封锁机关P.I.A。我是“军团”。说明你的来意。</li>

View File

@@ -194,4 +194,8 @@
<WULA_AIOverwatch_FleetCleared>[P.I.A 轨道监视] 航道已净空。</WULA_AIOverwatch_FleetCleared>
<WULA_AIOverwatch_EngagingBuilding>[P.I.A 轨道监视] 对敌方建筑/炮台发射炮击。</WULA_AIOverwatch_EngagingBuilding>
<!-- Personality Settings -->
<Wula_ExtraPersonality_Title>附加人格指令</Wula_ExtraPersonality_Title>
<Wula_ExtraPersonality_Desc>在此输入额外的人格提示词或要求。这些内容将拼接到 AI 的核心指令之后,影响其回复风格和行为方式。</Wula_ExtraPersonality_Desc>
<Wula_Save>保存</Wula_Save>
</LanguageData>

View File

@@ -71,32 +71,29 @@ namespace WulaFallenEmpire.EventSystem.AI
{
var sb = new StringBuilder();
// 获取 Letter 信息
string label = letter.Label.Resolve() ?? "Unknown";
string defName = letter.def?.defName ?? "Unknown";
// 获取事件描述ChoiceLetter 才有 Text 属性)
string description = "";
if (letter is ChoiceLetter choiceLetter)
{
description = choiceLetter.Text.Resolve() ?? "";
}
sb.AppendLine("[游戏事件通知 - 自动评论请求]");
sb.AppendLine($"事件标题: {label}");
sb.AppendLine($"事件类型: {defName}");
sb.AppendLine("[游戏事件通知 - 观察者模式]");
sb.AppendLine($"事件: {label} ({defName})");
if (!string.IsNullOrEmpty(description))
{
sb.AppendLine($"事件描述: {description}");
sb.AppendLine($"详情: {description}");
}
sb.AppendLine();
sb.AppendLine("请根据这个事件决定是否需要向玩家发表简短评论。");
sb.AppendLine("- 如果是重要事件(如袭击、死亡),可以提供建议或警告");
sb.AppendLine("- 如果是有趣的事件,可以发表幽默评论");
sb.AppendLine("- 如果事件不重要或不值得评论,回复 [NO_COMMENT] 即可跳过");
sb.AppendLine("作为 P.I.A帝国 AI请对该事件发表你的看法。");
sb.AppendLine("- 保持个性:你可以选择刻薄、幽默、理性或带有优越感。偶尔也可以表现出关心(如果对方值得)。");
sb.AppendLine("- 拒绝废话:不要总是说‘随时待命’、‘请指示’。你是在评论事件,而不是在写工作报告。");
sb.AppendLine("- 简短有力15-30 字以内,一针见血。");
sb.AppendLine("- 自主选择:如果这个事件平淡无奇(如琐碎的通知),直接回复 [NO_COMMENT]。");
sb.AppendLine();
sb.AppendLine("评论要简短1-2句话符合你作为帝国AI的人设。");
sb.AppendLine("如果你决定不评论,只需回复: [NO_COMMENT]");
sb.AppendLine("你的评论目标是展现你的存在感,而不是作为工具人。");
return sb.ToString();
}

View File

@@ -524,6 +524,13 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
? (persona + "\n" + ToolRulesInstruction + "\n" + toolsForThisPhase)
: persona;
// Append extra personality prompt from settings if available
var settings = WulaFallenEmpireMod.settings;
if (settings != null && !string.IsNullOrWhiteSpace(settings.extraPersonalityPrompt))
{
fullInstruction += "\n\n# ADDITIONAL PERSONALITY INSTRUCTIONS\n" + settings.extraPersonalityPrompt;
}
string language = LanguageDatabase.activeLanguage?.FriendlyNameNative ?? "English";
var eventVarManager = Find.World?.GetComponent<EventVariableManager>();
int goodwill = eventVarManager?.GetVariable<int>("Wula_Goodwill_To_PIA", 0) ?? 0;

View File

@@ -196,6 +196,13 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
}
}
// Personality Prompt Button
Rect personalityBtnRect = new Rect(0f, 30f, 25f, 25f);
if (DrawHeaderButton(personalityBtnRect, "P"))
{
Find.WindowStack.Add(new Dialog_ExtraPersonalityPrompt());
}
float margin = 15f;
Rect paddedRect = inRect.ContractedBy(margin);
float curY = paddedRect.y;

View File

@@ -0,0 +1,47 @@
using System;
using UnityEngine;
using Verse;
namespace WulaFallenEmpire.EventSystem.AI.UI
{
public class Dialog_ExtraPersonalityPrompt : Window
{
private string _tempPrompt;
public override Vector2 InitialSize => new Vector2(600f, 500f);
public Dialog_ExtraPersonalityPrompt()
{
this.forcePause = true;
this.doWindowBackground = true;
this.absorbInputAroundWindow = true;
this.closeOnClickedOutside = true;
_tempPrompt = WulaFallenEmpireMod.settings?.extraPersonalityPrompt ?? "";
}
public override void DoWindowContents(Rect inRect)
{
Text.Font = GameFont.Medium;
Widgets.Label(new Rect(0, 0, inRect.width, 40f), "Wula_ExtraPersonality_Title".Translate());
Text.Font = GameFont.Small;
float curY = 45f;
Widgets.Label(new Rect(0, curY, inRect.width, 60f), "Wula_ExtraPersonality_Desc".Translate());
curY += 65f;
Rect textRect = new Rect(0, curY, inRect.width, inRect.height - curY - 50f);
_tempPrompt = Widgets.TextArea(textRect, _tempPrompt);
Rect btnRect = new Rect(inRect.width / 2 - 60f, inRect.height - 40f, 120f, 35f);
if (Widgets.ButtonText(btnRect, "Wula_Save".Translate()))
{
if (WulaFallenEmpireMod.settings != null)
{
WulaFallenEmpireMod.settings.extraPersonalityPrompt = _tempPrompt;
WulaFallenEmpireMod.settings.Write();
}
this.Close();
}
}
}
}

View File

@@ -9,8 +9,8 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
public class Overlay_WulaLink_Notification : Window
{
private string _message;
private int _tickCreated;
private const int DisplayTicks = 600; // 10 seconds
private float _timeCreated;
private float _displayDuration;
private Vector2 _size = new Vector2(320f, 65f);
public override Vector2 InitialSize => _size;
@@ -18,7 +18,10 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
public Overlay_WulaLink_Notification(string message)
{
_message = message;
_tickCreated = Find.TickManager.TicksGame;
_timeCreated = Time.realtimeSinceStartup;
// 动态时长:最低 10 秒,每多一个字加一秒(即时长 = 字数,但不少于 10 秒)
_displayDuration = Mathf.Max(10f, (float)(message?.Length ?? 0));
// Calculate adaptive size (Instance-based)
Text.Font = GameFont.Small;
@@ -49,14 +52,28 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
protected override void SetInitialSizeAndPosition()
{
// Position at top-left
this.windowRect = new Rect(20f, 20f, InitialSize.x, InitialSize.y);
float startX = 20f;
float startY = 20f;
float spacing = 5f;
// Find all existing notifications and find the bottom-most Y position
float maxY = startY;
var windows = Find.WindowStack.Windows;
for (int i = 0; i < windows.Count; i++)
{
if (windows[i] is Overlay_WulaLink_Notification other && other != this)
{
maxY = Mathf.Max(maxY, other.windowRect.yMax + spacing);
}
}
this.windowRect = new Rect(startX, maxY, InitialSize.x, InitialSize.y);
}
public override void DoWindowContents(Rect inRect)
{
// Auto Close after time
if (Find.TickManager.TicksGame > _tickCreated + DisplayTicks)
// Auto Close after real-time duration
if (Time.realtimeSinceStartup > _timeCreated + _displayDuration)
{
Close();
return;

View File

@@ -26,10 +26,16 @@ namespace WulaFallenEmpire
WulaLog.Debug("[WulaFallenEmpire] Harmony patches applied.");
}
private Vector2 _scrollPosition = Vector2.zero;
public override void DoSettingsWindowContents(Rect inRect)
{
// Prepare Scroll View
Rect viewRect = new Rect(0f, 0f, inRect.width - 20f, 1000f); // Adjust 1000f if more height is needed
Widgets.BeginScrollView(inRect, ref _scrollPosition, viewRect);
Listing_Standard listingStandard = new Listing_Standard();
listingStandard.Begin(inRect);
listingStandard.Begin(viewRect);
listingStandard.Label("Wula_AISettings_Title".Translate());
@@ -115,6 +121,7 @@ namespace WulaFallenEmpire
}
listingStandard.End();
Widgets.EndScrollView();
base.DoSettingsWindowContents(inRect);
}

View File

@@ -5,13 +5,13 @@ namespace WulaFallenEmpire
public class WulaFallenEmpireSettings : ModSettings
{
public string apiKey = "sk-xxxxxxxx";
public string baseUrl = "https://api.deepseek.com";
public string baseUrl = "https://api.deepseek.com/v1";
public string model = "deepseek-chat";
// Gemini 专属配置 (独立存储)
public string geminiApiKey = "";
public string geminiBaseUrl = "https://generativelanguage.googleapis.com/v1beta";
public string geminiModel = "gemini-1.5-flash";
public string geminiModel = "gemini-2.5-flash";
public bool useGeminiProtocol = false; // 是否使用 Google Gemini 协议格式
public int maxContextTokens = 100000;
@@ -22,16 +22,17 @@ namespace WulaFallenEmpire
public bool enableAIAutoCommentary = false;
public float aiCommentaryChance = 0.7f;
public bool commentOnNegativeOnly = false;
public string extraPersonalityPrompt = "";
public override void ExposeData()
{
Scribe_Values.Look(ref apiKey, "apiKey", "sk-xxxxxxxx");
Scribe_Values.Look(ref baseUrl, "baseUrl", "https://api.deepseek.com");
Scribe_Values.Look(ref baseUrl, "baseUrl", "https://api.deepseek.com/v1");
Scribe_Values.Look(ref model, "model", "deepseek-chat");
Scribe_Values.Look(ref geminiApiKey, "geminiApiKey", "");
Scribe_Values.Look(ref geminiBaseUrl, "geminiBaseUrl", "https://generativelanguage.googleapis.com/v1beta");
Scribe_Values.Look(ref geminiModel, "geminiModel", "gemini-1.5-flash");
Scribe_Values.Look(ref geminiModel, "geminiModel", "gemini-2.5-flash");
Scribe_Values.Look(ref useGeminiProtocol, "useGeminiProtocol", false);
Scribe_Values.Look(ref maxContextTokens, "maxContextTokens", 100000);
@@ -42,6 +43,7 @@ namespace WulaFallenEmpire
Scribe_Values.Look(ref enableAIAutoCommentary, "enableAIAutoCommentary", false);
Scribe_Values.Look(ref aiCommentaryChance, "aiCommentaryChance", 0.7f);
Scribe_Values.Look(ref commentOnNegativeOnly, "commentOnNegativeOnly", false);
Scribe_Values.Look(ref extraPersonalityPrompt, "extraPersonalityPrompt", "");
base.ExposeData();
}