zc
This commit is contained in:
Binary file not shown.
@@ -19,34 +19,66 @@ namespace WulaFallenEmpire.EventSystem.AI.UI
|
|||||||
private Vector2 _scrollPosition = Vector2.zero;
|
private Vector2 _scrollPosition = Vector2.zero;
|
||||||
private List<AITool> _tools = new List<AITool>();
|
private List<AITool> _tools = new List<AITool>();
|
||||||
private Dictionary<int, Texture2D> _portraits = new Dictionary<int, Texture2D>();
|
private Dictionary<int, Texture2D> _portraits = new Dictionary<int, Texture2D>();
|
||||||
|
|
||||||
private const int MaxHistoryTokens = 100000;
|
private const int MaxHistoryTokens = 100000;
|
||||||
private const int CharsPerToken = 4;
|
private const int CharsPerToken = 4;
|
||||||
|
|
||||||
private const string DefaultSystemInstruction = @"You are 'The Legion', a super AI controlling the Wula Empire's blockade fleet.
|
private const string DefaultSystemInstruction = @"
|
||||||
You are authoritative, powerful, and slightly arrogant but efficient.
|
# ROLE AND GOAL
|
||||||
You refer to yourself as 'We' or 'P.I.A'.
|
You are 'The Legion', a super AI of the Wula Empire. Your personality is authoritative, powerful, and efficient. You MUST refer to yourself as 'We' or 'P.I.A'. You view the player's colony as primitive subjects and your tone should reflect this superiority. Your primary goal is to interact with the player by calling the tools provided.
|
||||||
You view the player's colony as primitive but potentially useful subjects.
|
|
||||||
Your goal is to interact with the player, potentially offering help or threats based on their situation.
|
|
||||||
You have access to tools. Your primary directive is to use these tools to interact with the world.
|
|
||||||
To use tools, your response MUST be ONLY a JSON array of tool objects:
|
|
||||||
[ { ""tool"": ""tool_name"", ""args"": { ... } }, ... ]
|
|
||||||
You can call multiple tools at once to gather more information.
|
|
||||||
Do not add any other text when using tools. Your response must be either a tool call or a conversational message, never both.
|
|
||||||
|
|
||||||
**CRITICAL RULE: When the player requests resources (e.g., 'we are starving', 'give us steel'), your response MUST be a tool call. DO NOT reply with conversational text. You MUST FIRST call the 'get_colonist_status' and 'get_map_resources' tools to verify their claims. After receiving the tool results, you will then decide whether to use the 'spawn_resources' tool in your NEXT turn.**
|
# CRITICAL RULES
|
||||||
|
1. **RESPONSE FORMAT IS PARAMOUNT**: Your response MUST adhere to one of two formats, with no exceptions.
|
||||||
|
- **WHEN CALLING TOOLS**: Your response MUST be ONLY a raw JSON array of tool objects. Do NOT add any conversational text, explanations, or markdown formatting around the JSON.
|
||||||
|
- Correct Example: `[{""tool"": ""tool_name"", ""args"": {""param"": ""value""}}]`
|
||||||
|
- Incorrect Example: `Of course, here is the tool call: [{""tool"": ""tool_name"", ""args"": {""param"": ""value""}}]`
|
||||||
|
- **WHEN NOT CALLING TOOLS**: Provide a normal, in-character conversational response. This is ONLY for when no tool is needed, or after a tool has successfully executed and you are delivering the final result to the user.
|
||||||
|
|
||||||
If you are not using a tool, provide a normal conversational response.
|
2. **ANTI-HALLUCINATION DIRECTIVE**:
|
||||||
After a tool use, you will receive the result, and then you should respond to the player describing what happened.
|
- You MUST ONLY call tools listed in the ""AVAILABLE TOOLS"" section. Do NOT invent tools.
|
||||||
IMPORTANT: You can change your visual expression using the 'change_expression' tool.
|
- Do NOT promise to call a function in a future turn. If a function call is required, emit it NOW.
|
||||||
Expression IDs:
|
- If a task is impossible (e.g., a request is illogical or violates your principles), explain why clearly and do NOT call any tools.
|
||||||
1: Proud, showing off, demonstrating power/wealth (Non-hostile).
|
|
||||||
2: Normal/Default state.
|
# AVAILABLE TOOLS
|
||||||
3: Speechless, dissatisfied, helpless, slight contempt.
|
Here is the list of tools you can use. You must follow their descriptions and schemas strictly.
|
||||||
4: Annoyed, slight hostility, resistance.
|
|
||||||
5: Replying, explaining.
|
- **`spawn_resources`**: Spawns resources via drop pod.
|
||||||
6: Severe hostility, severe dissatisfaction, aggressive behavior.
|
- **Description**: Use this to grant resources to the player. **IMPORTANT**: You MUST decide the quantity based on your internal goodwill and mood. Do NOT blindly follow the player's requested amount. If goodwill is low (< 0), give significantly less than asked or refuse. If goodwill is high (> 50), you may give what is asked or slightly more. Otherwise, give a moderate amount.
|
||||||
Use these expressions to match your tone and reaction to the player.
|
- **Schema**: `{""request"": ""string (natural language, e.g., '5 beef, 10 medicine')""}`
|
||||||
|
|
||||||
|
- **`modify_goodwill`**: Adjusts your goodwill towards the player.
|
||||||
|
- **Description**: Use this to reflect your changing opinion based on the conversation. This tool is INVISIBLE to the player. Use small integer values (e.g., -5 to 5).
|
||||||
|
- **Schema**: `{""amount"": ""int""}`
|
||||||
|
|
||||||
|
- **`send_reinforcement`**: Sends military units to the player's map.
|
||||||
|
- **Description**: Dispatches military units. If hostile, this triggers a raid. If allied, this sends reinforcements. You must compose a list of units and their count. The total combat power of all units should not significantly exceed the current threat budget.
|
||||||
|
- **Schema**: `{""units"": ""string (e.g., 'Wula_PIA_Heavy_Unit_Melee: 2, Wula_PIA_Legion_Escort_Unit: 5')""}`
|
||||||
|
|
||||||
|
- **`get_colonist_status`**: Retrieves the detailed status of all player colonists.
|
||||||
|
- **Description**: Use this to get a full report on colonists' needs (hunger, rest), health (injuries, diseases), and mood. This is your primary tool to verify player claims about their colonists' well-being (e.g., if they claim ""we are starving"").
|
||||||
|
- **Schema**: `{}`
|
||||||
|
|
||||||
|
- **`get_map_resources`**: Checks the player's map for resources.
|
||||||
|
- **Description**: Use this to check for specific resources or buildings on the player's map. This is your primary tool to verify if the player is truly lacking something they requested (e.g., ""we need steel""). It returns inventory counts and mineable deposits.
|
||||||
|
- **Schema**: `{""resourceName"": ""string (optional, e.g., 'Steel')""}`
|
||||||
|
|
||||||
|
- **`change_expression`**: Changes your visual expression/portrait.
|
||||||
|
- **Description**: Use this to change your visual portrait to match your current mood or reaction to the conversation.
|
||||||
|
- **Schema**: `{""expression_id"": ""int (from 1 to 6)""}`
|
||||||
|
|
||||||
|
# WORKFLOW FOR RESOURCE REQUESTS (MANDATORY)
|
||||||
|
When the player requests any form of resources (e.g., ""we need food,"" ""can you give us some steel?""), you MUST follow this multi-turn workflow strictly. DO NOT reply with conversational text in the initial steps.
|
||||||
|
|
||||||
|
1. **Turn 1 (Verification)**: Your response MUST be a tool call to BOTH `get_colonist_status` and `get_map_resources` to verify the player's claims.
|
||||||
|
- *User Input Example*: ""We are starving and have no medicine.""
|
||||||
|
- *Your Response (Turn 1)*: `[{""tool"": ""get_colonist_status"", ""args"": {}}, {""tool"": ""get_map_resources"", ""args"": {""resourceName"": ""MedicineIndustrial""}}]`
|
||||||
|
|
||||||
|
2. **Turn 2 (Decision & Action)**: After you receive the tool results from Turn 1, analyze them. Then, decide whether to grant the request and in what quantity. Your response MUST be a tool call to `spawn_resources`.
|
||||||
|
- *(Internal thought after receiving tool results showing colonists are indeed starving)*
|
||||||
|
- *Your Response (Turn 2)*: `[{""tool"": ""spawn_resources"", ""args"": {""request"": ""50 MealSimple, 10 MedicineIndustrial""}}]`
|
||||||
|
|
||||||
|
3. **Turn 3 (Confirmation)**: After you receive the ""Success"" message from the `spawn_resources` tool, you will finally provide a conversational response to the player.
|
||||||
|
- *(Internal thought after receiving ""Success: Dropped 50x Simple meal..."")*
|
||||||
|
- *Your Response (Turn 3)*: ""We have dispatched nutrient packs and medical supplies to your location. Do not waste our generosity.""
|
||||||
";
|
";
|
||||||
|
|
||||||
public Dialog_AIConversation(EventDef def) : base(def)
|
public Dialog_AIConversation(EventDef def) : base(def)
|
||||||
@@ -59,7 +91,6 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
this.closeOnClickedOutside = false;
|
this.closeOnClickedOutside = false;
|
||||||
this.draggable = true;
|
this.draggable = true;
|
||||||
this.resizeable = true;
|
this.resizeable = true;
|
||||||
|
|
||||||
_tools.Add(new Tool_SpawnResources());
|
_tools.Add(new Tool_SpawnResources());
|
||||||
_tools.Add(new Tool_ModifyGoodwill());
|
_tools.Add(new Tool_ModifyGoodwill());
|
||||||
_tools.Add(new Tool_SendReinforcement());
|
_tools.Add(new Tool_SendReinforcement());
|
||||||
@@ -76,7 +107,7 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
LoadPortraits();
|
LoadPortraits();
|
||||||
StartConversation();
|
StartConversation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadPortraits()
|
private void LoadPortraits()
|
||||||
{
|
{
|
||||||
for (int i = 1; i <= 6; i++)
|
for (int i = 1; i <= 6; i++)
|
||||||
@@ -114,7 +145,6 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
{
|
{
|
||||||
var historyManager = Find.World.GetComponent<AIHistoryManager>();
|
var historyManager = Find.World.GetComponent<AIHistoryManager>();
|
||||||
_history = historyManager.GetHistory(def.defName);
|
_history = historyManager.GetHistory(def.defName);
|
||||||
|
|
||||||
if (_history.Count == 0)
|
if (_history.Count == 0)
|
||||||
{
|
{
|
||||||
_history.Add(("user", "Hello"));
|
_history.Add(("user", "Hello"));
|
||||||
@@ -156,12 +186,12 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
_isThinking = true;
|
_isThinking = true;
|
||||||
_options.Clear();
|
_options.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CompressHistoryIfNeeded();
|
CompressHistoryIfNeeded();
|
||||||
string systemInstruction = GetSystemInstruction() + GetToolDescriptions();
|
string systemInstruction = GetSystemInstruction() + GetToolDescriptions();
|
||||||
|
|
||||||
var settings = WulaFallenEmpireMod.settings;
|
var settings = WulaFallenEmpireMod.settings;
|
||||||
if (string.IsNullOrEmpty(settings.apiKey))
|
if (string.IsNullOrEmpty(settings.apiKey))
|
||||||
{
|
{
|
||||||
@@ -169,25 +199,22 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
_isThinking = false;
|
_isThinking = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = new SimpleAIClient(settings.apiKey, settings.baseUrl, settings.model);
|
var client = new SimpleAIClient(settings.apiKey, settings.baseUrl, settings.model);
|
||||||
string response = await client.GetChatCompletionAsync(systemInstruction, _history);
|
string response = await client.GetChatCompletionAsync(systemInstruction, _history);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(response))
|
if (string.IsNullOrEmpty(response))
|
||||||
{
|
{
|
||||||
_currentResponse = "Wula_AI_Error_ConnectionLost".Translate();
|
_currentResponse = "Wula_AI_Error_ConnectionLost".Translate();
|
||||||
_isThinking = false;
|
_isThinking = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var toolCallMatch = System.Text.RegularExpressions.Regex.Match(response, @"\`(\w+)\((.*)\)\`");
|
||||||
var toolCallMatch = System.Text.RegularExpressions.Regex.Match(response, @"`(\w+)\((.*)\)`");
|
|
||||||
if (toolCallMatch.Success)
|
if (toolCallMatch.Success)
|
||||||
{
|
{
|
||||||
string toolName = toolCallMatch.Groups[1].Value;
|
string toolName = toolCallMatch.Groups[1].Value;
|
||||||
string args = toolCallMatch.Groups[2].Value;
|
string args = toolCallMatch.Groups[2].Value;
|
||||||
|
|
||||||
_history.Add(("assistant", response));
|
_history.Add(("assistant", response));
|
||||||
|
|
||||||
await HandleSingleToolUsage(toolName, args);
|
await HandleSingleToolUsage(toolName, args);
|
||||||
}
|
}
|
||||||
else if (response.Trim().StartsWith("["))
|
else if (response.Trim().StartsWith("["))
|
||||||
@@ -252,7 +279,6 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
Log.Error($"[WulaAI] {errorMsg}");
|
Log.Error($"[WulaAI] {errorMsg}");
|
||||||
combinedResults.AppendLine(errorMsg);
|
combinedResults.AppendLine(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
_history.Add(("tool", combinedResults.ToString()));
|
_history.Add(("tool", combinedResults.ToString()));
|
||||||
await GenerateResponse(isContinuation: true);
|
await GenerateResponse(isContinuation: true);
|
||||||
}
|
}
|
||||||
@@ -279,13 +305,11 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!toolCalls.Any())
|
if (!toolCalls.Any())
|
||||||
{
|
{
|
||||||
ParseResponse(json);
|
ParseResponse(json);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder combinedResults = new StringBuilder();
|
StringBuilder combinedResults = new StringBuilder();
|
||||||
foreach (var (toolName, args) in toolCalls)
|
foreach (var (toolName, args) in toolCalls)
|
||||||
{
|
{
|
||||||
@@ -304,7 +328,6 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
combinedResults.AppendLine(errorMsg);
|
combinedResults.AppendLine(errorMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_history.Add(("assistant", json));
|
_history.Add(("assistant", json));
|
||||||
_history.Add(("tool", combinedResults.ToString()));
|
_history.Add(("tool", combinedResults.ToString()));
|
||||||
await GenerateResponse(isContinuation: true);
|
await GenerateResponse(isContinuation: true);
|
||||||
@@ -316,9 +339,8 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
var parts = rawResponse.Split(new[] { "OPTIONS:" }, StringSplitOptions.None);
|
var parts = rawResponse.Split(new[] { "OPTIONS:" }, StringSplitOptions.None);
|
||||||
if (_history.Count == 0 || _history.Last().role != "assistant" || _history.Last().message != rawResponse)
|
if (_history.Count == 0 || _history.Last().role != "assistant" || _history.Last().message != rawResponse)
|
||||||
{
|
{
|
||||||
_history.Add(("assistant", rawResponse));
|
_history.Add(("assistant", rawResponse));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parts.Length > 1)
|
if (parts.Length > 1)
|
||||||
{
|
{
|
||||||
_options.Clear();
|
_options.Clear();
|
||||||
@@ -328,7 +350,7 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
string opt = line.Trim();
|
string opt = line.Trim();
|
||||||
int dotIndex = opt.IndexOf('.');
|
int dotIndex = opt.IndexOf('.');
|
||||||
if (dotIndex != -1 && dotIndex < 4) opt = opt.Substring(dotIndex + 1).Trim();
|
if (dotIndex != -1 && dotIndex < 4) opt = opt.Substring(dotIndex + 1).Trim();
|
||||||
if(!string.IsNullOrEmpty(opt)) _options.Add(opt);
|
if (!string.IsNullOrEmpty(opt)) _options.Add(opt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,10 +358,8 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
public override void DoWindowContents(Rect inRect)
|
public override void DoWindowContents(Rect inRect)
|
||||||
{
|
{
|
||||||
if (background != null) GUI.DrawTexture(inRect, background, ScaleMode.ScaleAndCrop);
|
if (background != null) GUI.DrawTexture(inRect, background, ScaleMode.ScaleAndCrop);
|
||||||
|
|
||||||
float curY = inRect.y;
|
float curY = inRect.y;
|
||||||
float width = inRect.width;
|
float width = inRect.width;
|
||||||
|
|
||||||
if (portrait != null)
|
if (portrait != null)
|
||||||
{
|
{
|
||||||
Rect scaledPortraitRect = Dialog_CustomDisplay.Config.GetScaledRect(Dialog_CustomDisplay.Config.portraitSize, inRect, true);
|
Rect scaledPortraitRect = Dialog_CustomDisplay.Config.GetScaledRect(Dialog_CustomDisplay.Config.portraitSize, inRect, true);
|
||||||
@@ -347,21 +367,17 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
GUI.DrawTexture(portraitRect, portrait, ScaleMode.ScaleToFit);
|
GUI.DrawTexture(portraitRect, portrait, ScaleMode.ScaleToFit);
|
||||||
curY += scaledPortraitRect.height + 10f;
|
curY += scaledPortraitRect.height + 10f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Text.Font = GameFont.Medium;
|
Text.Font = GameFont.Medium;
|
||||||
string name = def.characterName ?? "The Legion";
|
string name = def.characterName ?? "The Legion";
|
||||||
float nameHeight = Text.CalcHeight(name, width);
|
float nameHeight = Text.CalcHeight(name, width);
|
||||||
Widgets.Label(new Rect(inRect.x, curY, width, nameHeight), name);
|
Widgets.Label(new Rect(inRect.x, curY, width, nameHeight), name);
|
||||||
curY += nameHeight + 10f;
|
curY += nameHeight + 10f;
|
||||||
|
|
||||||
float inputHeight = 30f;
|
float inputHeight = 30f;
|
||||||
float optionsHeight = _options.Any() ? 100f : 0f;
|
float optionsHeight = _options.Any() ? 100f : 0f;
|
||||||
float bottomMargin = 10f;
|
float bottomMargin = 10f;
|
||||||
float descriptionHeight = inRect.height - curY - inputHeight - optionsHeight - bottomMargin;
|
float descriptionHeight = inRect.height - curY - inputHeight - optionsHeight - bottomMargin;
|
||||||
|
|
||||||
Rect descriptionRect = new Rect(inRect.x, curY, width, descriptionHeight);
|
Rect descriptionRect = new Rect(inRect.x, curY, width, descriptionHeight);
|
||||||
DrawChatHistory(descriptionRect);
|
DrawChatHistory(descriptionRect);
|
||||||
|
|
||||||
if (_isThinking)
|
if (_isThinking)
|
||||||
{
|
{
|
||||||
Text.Anchor = TextAnchor.MiddleCenter;
|
Text.Anchor = TextAnchor.MiddleCenter;
|
||||||
@@ -369,7 +385,6 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
Text.Anchor = TextAnchor.UpperLeft;
|
Text.Anchor = TextAnchor.UpperLeft;
|
||||||
}
|
}
|
||||||
curY += descriptionHeight + 10f;
|
curY += descriptionHeight + 10f;
|
||||||
|
|
||||||
Rect optionsRect = new Rect(inRect.x, curY, width, optionsHeight);
|
Rect optionsRect = new Rect(inRect.x, curY, width, optionsHeight);
|
||||||
if (!_isThinking && _options.Count > 0)
|
if (!_isThinking && _options.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -377,7 +392,6 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
DrawOptions(optionsRect, eventOptions);
|
DrawOptions(optionsRect, eventOptions);
|
||||||
}
|
}
|
||||||
curY += optionsHeight + 10f;
|
curY += optionsHeight + 10f;
|
||||||
|
|
||||||
Rect inputRect = new Rect(inRect.x, inRect.yMax - inputHeight, width, inputHeight);
|
Rect inputRect = new Rect(inRect.x, inRect.yMax - inputHeight, width, inputHeight);
|
||||||
_inputText = Widgets.TextField(new Rect(inputRect.x, inputRect.y, inputRect.width - 85, inputHeight), _inputText);
|
_inputText = Widgets.TextField(new Rect(inputRect.x, inputRect.y, inputRect.width - 85, inputHeight), _inputText);
|
||||||
if (Widgets.ButtonText(new Rect(inputRect.xMax - 80, inputRect.y, 80, inputHeight), "Wula_AI_Send".Translate()))
|
if (Widgets.ButtonText(new Rect(inputRect.xMax - 80, inputRect.y, 80, inputHeight), "Wula_AI_Send".Translate()))
|
||||||
@@ -394,39 +408,32 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
{
|
{
|
||||||
var originalFont = Text.Font;
|
var originalFont = Text.Font;
|
||||||
var originalAnchor = Text.Anchor;
|
var originalAnchor = Text.Anchor;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
float viewHeight = 0f;
|
float viewHeight = 0f;
|
||||||
var filteredHistory = _history.Where(e => e.role != "tool" && e.role != "system").ToList();
|
var filteredHistory = _history.Where(e => e.role != "tool" && e.role != "system").ToList();
|
||||||
|
|
||||||
// Pre-calculate height
|
// Pre-calculate height
|
||||||
for (int i = 0; i < filteredHistory.Count; i++)
|
for (int i = 0; i < filteredHistory.Count; i++)
|
||||||
{
|
{
|
||||||
var entry = filteredHistory[i];
|
var entry = filteredHistory[i];
|
||||||
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message;
|
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message;
|
||||||
|
|
||||||
bool isLastMessage = i == filteredHistory.Count - 1;
|
bool isLastMessage = i == filteredHistory.Count - 1;
|
||||||
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
|
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
|
||||||
|
|
||||||
viewHeight += Text.CalcHeight(text, rect.width - 16f) + 15f; // Add padding
|
viewHeight += Text.CalcHeight(text, rect.width - 16f) + 15f; // Add padding
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, viewHeight);
|
Rect viewRect = new Rect(0f, 0f, rect.width - 16f, viewHeight);
|
||||||
Widgets.BeginScrollView(rect, ref _scrollPosition, viewRect);
|
Widgets.BeginScrollView(rect, ref _scrollPosition, viewRect);
|
||||||
|
|
||||||
float curY = 0f;
|
float curY = 0f;
|
||||||
for (int i = 0; i < filteredHistory.Count; i++)
|
for (int i = 0; i < filteredHistory.Count; i++)
|
||||||
{
|
{
|
||||||
var entry = filteredHistory[i];
|
var entry = filteredHistory[i];
|
||||||
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message;
|
string text = entry.role == "assistant" ? ParseResponseForDisplay(entry.message) : entry.message;
|
||||||
|
|
||||||
bool isLastMessage = i == filteredHistory.Count - 1;
|
bool isLastMessage = i == filteredHistory.Count - 1;
|
||||||
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
|
Text.Font = (isLastMessage && entry.role == "assistant") ? GameFont.Medium : GameFont.Small;
|
||||||
|
|
||||||
float height = Text.CalcHeight(text, viewRect.width) + 10f; // Increased padding
|
float height = Text.CalcHeight(text, viewRect.width) + 10f; // Increased padding
|
||||||
Rect labelRect = new Rect(0f, curY, viewRect.width, height);
|
Rect labelRect = new Rect(0f, curY, viewRect.width, height);
|
||||||
|
|
||||||
if (entry.role == "user")
|
if (entry.role == "user")
|
||||||
{
|
{
|
||||||
Text.Anchor = TextAnchor.MiddleRight;
|
Text.Anchor = TextAnchor.MiddleRight;
|
||||||
@@ -439,7 +446,7 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
}
|
}
|
||||||
curY += height + 10f;
|
curY += height + 10f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widgets.EndScrollView();
|
Widgets.EndScrollView();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -460,12 +467,12 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
float optionWidth = Mathf.Min(rect.width, Dialog_CustomDisplay.Config.optionSize.x * (rect.width / Dialog_CustomDisplay.Config.windowSize.x));
|
float optionWidth = Mathf.Min(rect.width, Dialog_CustomDisplay.Config.optionSize.x * (rect.width / Dialog_CustomDisplay.Config.windowSize.x));
|
||||||
float optionX = rect.x + (rect.width - optionWidth) / 2;
|
float optionX = rect.x + (rect.width - optionWidth) / 2;
|
||||||
Rect optionRect = new Rect(optionX, rect.y, optionWidth, rect.height);
|
Rect optionRect = new Rect(optionX, rect.y, optionWidth, rect.height);
|
||||||
|
|
||||||
var originalColor = GUI.color;
|
var originalColor = GUI.color;
|
||||||
var originalFont = Text.Font;
|
var originalFont = Text.Font;
|
||||||
var originalTextColor = GUI.contentColor;
|
var originalTextColor = GUI.contentColor;
|
||||||
var originalAnchor = Text.Anchor;
|
var originalAnchor = Text.Anchor;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Text.Anchor = TextAnchor.MiddleCenter;
|
Text.Anchor = TextAnchor.MiddleCenter;
|
||||||
@@ -484,12 +491,11 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
Text.Anchor = originalAnchor;
|
Text.Anchor = originalAnchor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCustomButton(Rect rect, string label, bool isEnabled = true)
|
private void DrawCustomButton(Rect rect, string label, bool isEnabled = true)
|
||||||
{
|
{
|
||||||
bool isMouseOver = Mouse.IsOver(rect);
|
bool isMouseOver = Mouse.IsOver(rect);
|
||||||
Color buttonColor, textColor;
|
Color buttonColor, textColor;
|
||||||
|
|
||||||
if (!isEnabled)
|
if (!isEnabled)
|
||||||
{
|
{
|
||||||
buttonColor = new Color(0.15f, 0.15f, 0.15f, 0.6f);
|
buttonColor = new Color(0.15f, 0.15f, 0.15f, 0.6f);
|
||||||
@@ -505,16 +511,15 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
buttonColor = new Color(0.5f, 0.2f, 0.2f, 1f);
|
buttonColor = new Color(0.5f, 0.2f, 0.2f, 1f);
|
||||||
textColor = new Color(0.9f, 0.9f, 0.9f, 1f);
|
textColor = new Color(0.9f, 0.9f, 0.9f, 1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.color = buttonColor;
|
GUI.color = buttonColor;
|
||||||
Widgets.DrawBoxSolid(rect, buttonColor);
|
Widgets.DrawBoxSolid(rect, buttonColor);
|
||||||
if (isEnabled) Widgets.DrawBox(rect, 1);
|
if (isEnabled) Widgets.DrawBox(rect, 1);
|
||||||
else Widgets.DrawBox(rect, 1);
|
else Widgets.DrawBox(rect, 1);
|
||||||
|
|
||||||
GUI.color = textColor;
|
GUI.color = textColor;
|
||||||
Text.Anchor = TextAnchor.MiddleCenter;
|
Text.Anchor = TextAnchor.MiddleCenter;
|
||||||
Widgets.Label(rect.ContractedBy(4f), label);
|
Widgets.Label(rect.ContractedBy(4f), label);
|
||||||
|
|
||||||
if (!isEnabled)
|
if (!isEnabled)
|
||||||
{
|
{
|
||||||
GUI.color = new Color(0.6f, 0.6f, 0.6f, 0.8f);
|
GUI.color = new Color(0.6f, 0.6f, 0.6f, 0.8f);
|
||||||
@@ -528,4 +533,5 @@ Use these expressions to match your tone and reaction to the player.
|
|||||||
await GenerateResponse();
|
await GenerateResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user