diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..73d1437
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,59 @@
+name: Build Simitone
+
+on:
+ workflow_dispatch:
+ inputs:
+ configuration:
+ description: 'Build configuration'
+ required: false
+ default: 'Release'
+ type: choice
+ options:
+ - Release
+ - Debug
+
+jobs:
+ build:
+ runs-on: windows-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Setup .NET 9
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '9.0.x'
+
+ - name: Run Protobuild
+ shell: pwsh
+ run: |
+ cd FreeSO/Other/libs/FSOMonoGame/
+ ./protobuild.exe --generate
+ continue-on-error: true
+
+ - name: Restore Simitone dependencies
+ run: dotnet restore Client/Simitone/Simitone.sln
+
+ - name: Restore FreeSO dependencies
+ run: dotnet restore FreeSO/TSOClient/FreeSO.sln
+ continue-on-error: true
+
+ - name: Restore Roslyn dependencies
+ shell: pwsh
+ run: |
+ cd FreeSO/TSOClient/FSO.SimAntics.JIT.Roslyn/
+ dotnet restore
+ continue-on-error: true
+
+ - name: Build
+ run: dotnet build Client/Simitone/Simitone.sln -c ${{ inputs.configuration || 'Release' }} --no-restore
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: SimitoneWindows-${{ inputs.configuration || 'Release' }}
+ path: Client/Simitone/Simitone.Windows/bin/${{ inputs.configuration || 'Release' }}/net9.0-windows/
+ if-no-files-found: error
diff --git a/Client/Simitone/Simitone.Client/Content/uigraphics/live/modes/opt_freewill.png b/Client/Simitone/Simitone.Client/Content/uigraphics/live/modes/opt_freewill.png
new file mode 100644
index 0000000..045e3fc
Binary files /dev/null and b/Client/Simitone/Simitone.Client/Content/uigraphics/live/modes/opt_freewill.png differ
diff --git a/Client/Simitone/Simitone.Client/Simitone.Client.csproj b/Client/Simitone/Simitone.Client/Simitone.Client.csproj
index 1e2baf0..743a658 100644
--- a/Client/Simitone/Simitone.Client/Simitone.Client.csproj
+++ b/Client/Simitone/Simitone.Client/Simitone.Client.csproj
@@ -473,6 +473,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
diff --git a/Client/Simitone/Simitone.Client/SimitoneGame.cs b/Client/Simitone/Simitone.Client/SimitoneGame.cs
index 52ca85b..075182d 100644
--- a/Client/Simitone/Simitone.Client/SimitoneGame.cs
+++ b/Client/Simitone/Simitone.Client/SimitoneGame.cs
@@ -133,6 +133,10 @@ protected override void Initialize()
if (FSOEnvironment.Enable3D) FSO.Files.RC.DGRP3DMesh.InitRCWorkers();
//FSO.Content.Content.Init(GlobalSettings.Default.StartupPath, GraphicsDevice);
FSO.SimAntics.VMAvatar.MissingIconProvider = Simitone.Client.UI.Model.UIIconCache.GetObject;
+
+ // Initialize Free Will setting from config
+ VM.FreeWillEnabled = GlobalSettings.Default.TS1FreeWill;
+
base.Initialize();
GameFacade.GameThread = Thread.CurrentThread;
diff --git a/Client/Simitone/Simitone.Client/UI/Panels/UIMainPanel.cs b/Client/Simitone/Simitone.Client/UI/Panels/UIMainPanel.cs
index 1d98575..5394f97 100644
--- a/Client/Simitone/Simitone.Client/UI/Panels/UIMainPanel.cs
+++ b/Client/Simitone/Simitone.Client/UI/Panels/UIMainPanel.cs
@@ -2,6 +2,7 @@
using FSO.Client.UI.Framework;
using FSO.Common.Utils;
using FSO.Content;
+using FSO.SimAntics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Simitone.Client.UI.Controls;
@@ -242,6 +243,7 @@ public void Switcher_OnCategorySelect(int obj)
new UICatFunc(GameFacade.Strings.GetString("145", "1"), "opt_neigh.png", () => { Game.ReturnToNeighbourhood(); }),
new UICatFunc(GameFacade.Strings.GetString("145", "5"), "opt_quit.png", () => { Game.CloseAttempt(); }),
});
+ AddFreeWillToggle(panel);
break;
}
SetSubpanel(panel);
@@ -434,6 +436,47 @@ public void ShowSelect()
};
}
+ private void AddFreeWillToggle(UISubpanel parent)
+ {
+ // Index 3 (4th button) to match spacing of existing buttons
+ // Existing buttons use: 50 + i * 120f for button X, 50 + i * 120f - 27 for label X
+ int index = 3;
+ float buttonX = 50 + index * 120f;
+ float labelX = buttonX - 27;
+
+ var label = new UILabel();
+ label.Alignment = TextAlignment.Middle | TextAlignment.Center;
+ label.Wrapped = true;
+ label.Position = new Vector2(labelX - 77, 106);
+ label.Size = new Vector2(120, 1);
+ label.CaptionStyle = label.CaptionStyle.Clone();
+ label.CaptionStyle.Size = 12;
+ label.CaptionStyle.Color = UIStyle.Current.Text;
+
+ Action updateLabel = () => {
+ bool enabled = VM.FreeWillEnabled;
+ label.Caption = "Free Will:\n" + (enabled ? "ON" : "OFF");
+ label.CaptionStyle.Color = enabled ? UIStyle.Current.Text : UIStyle.Current.NegMoney;
+ };
+
+ var toggleButton = new UICatButton(Content.Get().CustomUI.Get("opt_freewill.png").Get(GameFacade.GraphicsDevice));
+ toggleButton.Position = new Vector2(buttonX - 50, 16);
+ toggleButton.OnButtonClick += (btn) => {
+ VM.FreeWillEnabled = !VM.FreeWillEnabled;
+ GlobalSettings.Default.TS1FreeWill = VM.FreeWillEnabled;
+ GlobalSettings.Default.Save();
+ updateLabel();
+ };
+
+ // Animate in like other buttons
+ GameFacade.Screens.Tween.To(label, 0.5f, new Dictionary() { { "X", labelX } }, TweenQuad.EaseOut);
+ GameFacade.Screens.Tween.To(toggleButton, 0.5f, new Dictionary() { { "X", buttonX } }, TweenQuad.EaseOut);
+
+ parent.Add(label);
+ parent.Add(toggleButton);
+ updateLabel();
+ }
+
public override void GameResized()
{
base.GameResized();
diff --git a/FreeSO b/FreeSO
index f86bbd3..3072dfc 160000
--- a/FreeSO
+++ b/FreeSO
@@ -1 +1 @@
-Subproject commit f86bbd34b2112296ed786741f640a0535886d180
+Subproject commit 3072dfcdebd07c7f2630a3148657ff15bc25d851
diff --git a/README.md b/README.md
index 54e32fd..7562fda 100644
--- a/README.md
+++ b/README.md
@@ -27,3 +27,8 @@ On modern operating systems, The Sims has a few nagging issues that make it less
Simitone -> Semitone -> musical term -> C# -> a note
Further questions can be directed at my PR manager, uh, ... burglar cop.
+
+
+# Attributions
+
+Icon for Free Will option: Creativity And Resourcefulness icon by Icons8
\ No newline at end of file