[WIP] Pre 1.0 Testing Commit

Moving onto a more common commit cycle here
- 2D CAS, family management, move in (even magic town with magicoins)
- WIP Lot Saves
- A ton of engine fixes (mostly in FreeSO project)
- A ton of UI things, icons for all build/buy categories
- Animation speed increase (consistent with TS1, 30 fps at 50 hz)
- Cool transitions to cas 🆒 😎
- A lot more
This commit is contained in:
riperiperi 2018-05-25 00:47:46 +01:00
parent a15ff3503b
commit 4ac38452dc
90 changed files with 2207 additions and 302 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 864 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1,005 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

@ -23,7 +23,22 @@ namespace Simitone.Client
{
GameThread.NextUpdate((x) =>
{
var screen = new TS1GameScreen();
var mode = NeighSelectionMode.Normal;
if (lotName.Length > 1 && lotName[0] == '!')
{
switch (lotName[1])
{
case 'n':
mode = NeighSelectionMode.MoveIn; break;
case 'm':
mode = NeighSelectionMode.MoveInMagic; break;
}
}
var screen = new TS1GameScreen(mode);
if (mode != NeighSelectionMode.Normal)
{
screen.StartMoveIn(int.Parse(lotName.Substring(2)));
}
var last = GameFacade.Screens.CurrentUIScreen;
GameFacade.Screens.RemoveCurrent();
GameFacade.Screens.AddScreen(screen);
@ -46,14 +61,14 @@ namespace Simitone.Client
public static void EnterCAS()
{
GameThread.NextUpdate((x) =>
{
//GameThread.NextUpdate((x) =>
//{
var screen = new TS1CASScreen();
var last = GameFacade.Screens.CurrentUIScreen;
if (last is TS1GameScreen) ((TS1GameScreen)last).CleanupLastWorld();
GameFacade.Screens.RemoveCurrent();
GameFacade.Screens.AddScreen(screen);
});
//});
}
}
}

View file

@ -54,11 +54,14 @@
<Compile Include="UI\Controls\UIElasticButton.cs" />
<Compile Include="UI\Controls\UISkillDisplay.cs" />
<Compile Include="UI\Controls\UIStencilButton.cs" />
<Compile Include="UI\Controls\UITouchListbox.cs" />
<Compile Include="UI\Controls\UITouchScroll.cs" />
<Compile Include="UI\Controls\UITwoStateButton.cs" />
<Compile Include="UI\Controls\UIValueBar.cs" />
<Compile Include="UI\Model\UIIconCache.cs" />
<Compile Include="UI\Model\UIStyle.cs" />
<Compile Include="UI\Panels\CAS\UIFamiliesCASPanel.cs" />
<Compile Include="UI\Panels\CAS\UIFamilyCASItem.cs" />
<Compile Include="UI\Panels\CAS\UIFamilyCASPanel.cs" />
<Compile Include="UI\Panels\CAS\UISimCASPanel.cs" />
<Compile Include="UI\Panels\LiveSubpanels\Catalog\UICatalogItem.cs" />
@ -71,7 +74,7 @@
<Compile Include="UI\Panels\LiveSubpanels\UIMotiveSubpanel.cs" />
<Compile Include="UI\Panels\LiveSubpanels\UISubpanel.cs" />
<Compile Include="UI\Panels\LotControls\UIArchTouchHelper.cs" />
<Compile Include="UI\Panels\UI3DThumb.cs" />
<Compile Include="UI\Panels\LotControls\UICallNeighborAlert.cs" />
<Compile Include="UI\Panels\UIClockPanel.cs" />
<Compile Include="UI\Panels\UICutawayPanel.cs" />
<Compile Include="UI\Panels\UIHouseSelectPanel.cs" />
@ -92,11 +95,13 @@
<Compile Include="UI\Panels\UIRotationAnimation.cs" />
<Compile Include="UI\Panels\UISimitoneFrontend.cs" />
<Compile Include="UI\Panels\UISwitchAvatarPanel.cs" />
<Compile Include="UI\Panels\UITransDialog.cs" />
<Compile Include="UI\Panels\WorldUI\UIHeadlineRenderer.cs" />
<Compile Include="UI\Panels\WorldUI\UIMoneyHeadline.cs" />
<Compile Include="UI\Screens\LoadingGameScreen.cs" />
<Compile Include="UI\Screens\TS1CASScreen.cs" />
<Compile Include="UI\Screens\TS1GameScreen.cs" />
<Compile Include="Utils\SimitoneNeighOBJExporter.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\MonoGame.Framework\MonoGame.Framework.Net.WindowsGL.csproj">
@ -145,6 +150,21 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Content\3D\TEX_0.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\3D\TEX_1.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\cas\btn_createfam.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\cas\btn_deletefam.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\cas\btn_movein.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\cas\cas_adult.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -196,6 +216,9 @@
<Content Include="Content\uigraphics\common\btn_back.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\common\circle10px.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\dialog\ngbh_outline.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -247,6 +270,33 @@
<Content Include="Content\uigraphics\live\cat\cat_cancel.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_dt_food.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_dt_out.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_dt_shop.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_dt_street.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_st_spa.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_st_studio.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_vac_amen.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_vac_lodg.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat\cat_vac_recr.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\live\cat_btn_base.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -658,6 +708,12 @@
<Content Include="Content\uigraphics\ngbh\ngbh_vacat.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\trans\trans_cas.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\uigraphics\trans\trans_normal.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Content\TS1Patch\PetGym_performance.piff">
@ -682,6 +738,16 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Content\3D\arrow.fsom">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Content\3D\star.fsom">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View file

@ -20,6 +20,7 @@ using Microsoft.Xna.Framework.Audio;
using FSO.HIT.Model;
using FSO.Client;
using FSO.Files;
using FSO.SimAntics;
namespace Simitone.Client
{
@ -35,12 +36,12 @@ namespace Simitone.Client
public SimitoneGame() : base()
{
GameFacade.Game = this;
ImageLoader.PremultiplyPNG = true;
if (GameFacade.DirectX) TimedReferenceController.SetMode(CacheType.PERMANENT);
Content.RootDirectory = FSOEnvironment.GFXContentDir;
TargetElapsedTime = new TimeSpan(10000000 / GlobalSettings.Default.TargetRefreshRate);
FSOEnvironment.RefreshRate = GlobalSettings.Default.TargetRefreshRate;
FSOEnvironment.TexCompress = false;
if (!FSOEnvironment.SoftwareKeyboard)
{
@ -91,8 +92,8 @@ namespace Simitone.Client
var settings = GlobalSettings.Default;
if (FSOEnvironment.DPIScaleFactor != 1 || FSOEnvironment.SoftwareDepth)
{
settings.GraphicsWidth = GraphicsDevice.Viewport.Width / FSOEnvironment.DPIScaleFactor;
settings.GraphicsHeight = GraphicsDevice.Viewport.Height / FSOEnvironment.DPIScaleFactor;
settings.GraphicsWidth = (int)(GraphicsDevice.Viewport.Width / FSOEnvironment.DPIScaleFactor);
settings.GraphicsHeight = (int)(GraphicsDevice.Viewport.Height / FSOEnvironment.DPIScaleFactor);
}
FSO.LotView.WorldConfig.Current = new FSO.LotView.WorldConfig()

View file

@ -69,7 +69,7 @@ namespace Simitone.Client.UI.Controls
public override void Draw(UISpriteBatch SBatch)
{
if (!Visible) return;
DrawLocalTexture(SBatch, Texture, new Vector2(Texture.Width, Texture.Height) / -2);
DrawLocalTexture(SBatch, Texture, null, new Vector2(Texture.Width, Texture.Height) / -2, Vector2.One, Color.White * (Disabled?0.5f:1f));
}
}
}

View file

@ -90,6 +90,15 @@ namespace Simitone.Client.UI.Controls
GameFacade.Screens.Tween.To(this, 0.5f, new Dictionary<string, float>() { { "InterpolatedAnimation", 1f} }, TweenQuad.EaseOut);
}
public override void GameResized()
{
base.GameResized();
TitleBg.SetSize(Width, 70);
Width = GameFacade.Screens.CurrentUIScreen.ScreenWidth;
ScrHeight = GameFacade.Screens.CurrentUIScreen.ScreenHeight;
InterpolatedAnimation = InterpolatedAnimation;
}
public void Close()
{
if (!Closing)

View file

@ -0,0 +1,131 @@
using FSO.Client.UI.Controls;
using FSO.Client.UI.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using FSO.Client;
using FSO.Content;
using Simitone.Client.UI.Model;
using Microsoft.Xna.Framework.Graphics;
using FSO.Common.Utils;
namespace Simitone.Client.UI.Controls
{
public class UITouchStringList : UIContainer
{
public UIImage Outline;
public UITouchScroll ScrollElem;
public event Action<int> OnSelectionChange;
private Vector2 _Size;
public override Vector2 Size
{
get
{
return _Size;
}
set
{
_Size = value;
Outline.Width = value.X;
Outline.Height = value.Y;
ScrollElem.Size = new Vector2(value.X - 12, value.Y - 12);
}
}
public List<string> BackingList = new List<string>();
public UITouchStringList()
{
var gd = GameFacade.GraphicsDevice;
var ui = Content.Get().CustomUI;
ScrollElem = new UITouchScroll(GetLength, GetElemAt);
ScrollElem.VerticalMode = true;
ScrollElem.Position = new Vector2(6);
ScrollElem.ItemWidth = 38;
ScrollElem.DrawBounds = false;
ScrollElem.Margin = 6;
ScrollElem.SetScroll(-6);
Add(ScrollElem);
Outline = new UIImage(ui.Get("cat_btn_base.png").Get(gd)).With9Slice(25, 25, 25, 25);
Add(Outline);
}
public void SelectionChanged(int id)
{
OnSelectionChange?.Invoke(id);
}
public void Refresh()
{
ScrollElem.Reset();
}
public int GetLength()
{
return BackingList.Count;
}
public UITSContainer GetElemAt(int i)
{
return new UITouchStringListItem(BackingList[i], new Point((int)Size.X-12, ScrollElem.ItemWidth), this);
}
}
public class UITouchStringListItem : UITSContainer
{
public string Value;
public Point ESize;
public bool Outlined;
public UITouchStringList TParent;
public UILabel Label;
private Texture2D Px;
public float SelectPct { get; set; }
public UITouchStringListItem(string value, Point esize, UITouchStringList parent)
{
TParent = parent;
Value = value;
ESize = esize;
Px = TextureGenerator.GetPxWhite(GameFacade.GraphicsDevice);
Label = new UILabel();
Label.CaptionStyle = Label.CaptionStyle.Clone();
Label.CaptionStyle.Size = 19;
Label.CaptionStyle.Color = UIStyle.Current.Text;
Label.Alignment = TextAlignment.Middle | TextAlignment.Left;
Label.Caption = Label.CaptionStyle.TruncateToWidth(value, esize.X-20);
Label.Size = esize.ToVector2();
Label.X += 10;
Add(Label);
SelectPct = SelectPct;
}
public override void Selected()
{
Outlined = true;
Label.CaptionStyle.Color = UIStyle.Current.Bg;
GameFacade.Screens.Tween.To(this, 0.3f, new Dictionary<string, float>() { { "SelectPct", 1f } }, TweenQuad.EaseOut);
TParent.SelectionChanged(ItemID);
}
public override void Deselected()
{
Label.CaptionStyle.Color = UIStyle.Current.Text;
GameFacade.Screens.Tween.To(this, 0.3f, new Dictionary<string, float>() { { "SelectPct", 0f } }, TweenQuad.EaseOut);
Outlined = false;
}
public override void Draw(UISpriteBatch batch)
{
DrawLocalTexture(batch, Px, null, Vector2.Zero, new Vector2(ESize.X*SelectPct, ESize.Y), UIStyle.Current.SecondaryText);
base.Draw(batch);
}
}
}

View file

@ -20,6 +20,7 @@ namespace Simitone.Client.UI.Controls
public Texture2D ScrollEdgeR;
public bool DrawBounds = true;
public int Margin;
public bool VerticalMode;
private UIMouseEventRef HitTest;
@ -86,9 +87,19 @@ namespace Simitone.Client.UI.Controls
}
}
private int GetPAxis(Point p)
{
return (VerticalMode) ? p.Y : p.X;
}
private float GetPAxis(Vector2 p)
{
return (VerticalMode) ? p.Y : p.X;
}
public void Select(Point at)
{
var item = (int)(at.X + Scroll) / ItemWidth;
var item = (int)(GetPAxis(at) + Scroll) / ItemWidth;
if (item >= LengthProvider()) return;
var rItem = GetOrPrepare(item);
if (rItem != null)
@ -107,6 +118,11 @@ namespace Simitone.Client.UI.Controls
item = ElemProvider(id);
item.Visible = false;
item.ItemID = id;
if (id == LastSelected?.ItemID)
{
item.Selected();
LastSelected = item;
}
Add(item);
}
return item;
@ -133,11 +149,11 @@ namespace Simitone.Client.UI.Controls
var pos = lastMouse.MouseState.Position;
if (!InScroll)
{
if (Math.Abs((pos - MouseDownAt).X) > 25) InScroll = true;
if (Math.Abs(GetPAxis(pos - MouseDownAt)) > 25) InScroll = true;
}
if (InScroll)
{
ScrollVelocity = -(pos - MouseDownAt).X;
ScrollVelocity = -GetPAxis(pos - MouseDownAt);
MouseDownAt = pos;
}
}
@ -148,7 +164,7 @@ namespace Simitone.Client.UI.Controls
Scroll += ScrollVelocity;
ScrollVelocity *= 0.9f;
Scroll = Math.Max(-Margin, Math.Min(length * ItemWidth - Size.X + Margin, Scroll));
Scroll = Math.Max(-Margin, Math.Min(length * ItemWidth - GetPAxis(Size) + Margin, Scroll));
//update children positions.
//delete ones that are not
@ -156,14 +172,15 @@ namespace Simitone.Client.UI.Controls
var untouched = new HashSet<UIElement>(Children);
var b = (int)(Scroll / ItemWidth);
var e = b + (Size.X + (ItemWidth - 1)) / ItemWidth;
var e = b + (GetPAxis(Size) + (ItemWidth - 1)) / ItemWidth;
for (int i=b; i<e; i++)
{
if (i < 0) continue;
if (i >= length) break;
var item = GetOrPrepare(i);
untouched.Remove(item);
item.X = i * ItemWidth - Scroll;
if (VerticalMode) item.Y = i * ItemWidth - Scroll;
else item.X = i * ItemWidth - Scroll;
item.Visible = true;
}
@ -182,11 +199,20 @@ namespace Simitone.Client.UI.Controls
public override void Draw(UISpriteBatch batch)
{
if (!Visible) return;
base.Draw(batch);
if (DrawBounds)
{
DrawLocalTexture(batch, ScrollEdgeL, new Vector2(0, Size.Y / 2 - 64));
DrawLocalTexture(batch, ScrollEdgeR, new Vector2(Size.X - 15, Size.Y / 2 - 64));
if (VerticalMode)
{
DrawLocalTexture(batch, ScrollEdgeL, null, new Vector2(Size.X / 2 - 64, 0), Vector2.One, Color.White, (float)Math.PI/2f, new Vector2(0, ScrollEdgeL.Height));
DrawLocalTexture(batch, ScrollEdgeR, null, new Vector2(Size.X / 2 - 64, Size.Y - 15), Vector2.One, Color.White, (float)Math.PI / 2f, new Vector2(0, ScrollEdgeL.Height));
}
else
{
DrawLocalTexture(batch, ScrollEdgeL, new Vector2(0, Size.Y / 2 - 64));
DrawLocalTexture(batch, ScrollEdgeR, new Vector2(Size.X - 15, Size.Y / 2 - 64));
}
}
}

View file

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FSO.Client.UI.Framework;
namespace Simitone.Client.UI.Controls
{
@ -14,5 +15,14 @@ namespace Simitone.Client.UI.Controls
{
ImageStates = 2;
}
public override void Draw(UISpriteBatch SBatch)
{
var oldOpacity = Opacity;
if (Disabled) Opacity = 0.5f;
var col = BlendColor;
base.Draw(SBatch);
if (Disabled) Opacity = oldOpacity;
}
}
}

View file

@ -28,7 +28,9 @@ namespace Simitone.Client.UI.Model
if (obj is VMAvatar)
{
var ava = (VMAvatar)obj;
var id = ava.HeadOutfit.Name +":"+ ava.HeadOutfit.OftData.TS1TextureID;
var headname = ava.HeadOutfit.Name;
if (headname == "") headname = ava.BodyOutfit.OftData.TS1TextureID;
var id = headname +":"+ ava.HeadOutfit.OftData.TS1TextureID;
Texture2D result = null;
if (!AvatarHeadCache.TryGetValue(id, out result))

View file

@ -42,5 +42,7 @@ namespace Simitone.Client.UI.Model
public Color SkillInactive = new Color(99, 109, 242, 255);
public Color SkillActive = new Color(0, 255, 255, 255);
public Color SkillNeeded = new Color(255, 191, 0, 255);
public Color TransColor = new Color(0, 41, 69, 255);
}
}

View file

@ -0,0 +1,130 @@
using FSO.Client;
using FSO.Client.UI.Controls;
using FSO.Client.UI.Framework;
using FSO.Common.Utils;
using FSO.Content;
using FSO.Files.Formats.IFF.Chunks;
using FSO.SimAntics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Simitone.Client.UI.Controls;
using Simitone.Client.UI.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simitone.Client.UI.Panels.CAS
{
/// <summary>
/// Lists all of the families that can be moved in or deleted.
/// </summary>
public class UIFamiliesCASPanel : UIContainer
{
public UITouchScroll FamilyList;
public UILabel Title;
public UITwoStateButton DeleteButton;
public UITwoStateButton NewButton;
public event Action OnNewFamily;
public List<FAMI> Families = new List<FAMI>();
private VM vm;
private Texture2D WhitePx;
public int Selection;
public float TitleI { get; set; }
public UIFamiliesCASPanel()
{
var gd = GameFacade.GraphicsDevice;
var ui = Content.Get().CustomUI;
var sh = UIScreen.Current.ScreenHeight;
var sw = UIScreen.Current.ScreenWidth;
FamilyList = new UITouchScroll(FamilyLength, FamilyProvider);
FamilyList.VerticalMode = true;
FamilyList.Size = new Vector2(810, sh);
FamilyList.X = (sw - 810) / 2;
FamilyList.ItemWidth = 180;
FamilyList.Margin = 90;
FamilyList.DrawBounds = false;
Add(FamilyList);
WhitePx = TextureGenerator.GetPxWhite(GameFacade.GraphicsDevice);
Title = new UILabel();
Title.NewStyle(UIStyle.Current.Text, 37);
Title.Caption = "Select a Family";
Title.Size = new Vector2(sw, 60);
Title.Alignment = TextAlignment.Middle | TextAlignment.Center;
Title.Y = -85;
Add(Title);
DeleteButton = new UITwoStateButton(ui.Get("btn_deletefam.png").Get(gd));
DeleteButton.Position = new Vector2(sw - 140, sh - 260);
Add(DeleteButton);
NewButton = new UITwoStateButton(ui.Get("btn_createfam.png").Get(gd));
NewButton.Position = new Vector2(sw - 140, sh - 380);
Add(NewButton);
NewButton.OnButtonClick += (btn) => OnNewFamily?.Invoke();
TitleI = TitleI;
SetSelection(-1);
}
public void SetSelection(int i)
{
Selection = i;
DeleteButton.Disabled = Selection == -1;
NewButton.Disabled = false;
}
public override void GameResized()
{
var sh = UIScreen.Current.ScreenHeight;
var sw = UIScreen.Current.ScreenWidth;
FamilyList.Size = new Vector2(810, sh);
FamilyList.X = (sw - 810) / 2;
FamilyList.Reset();
Title.Size = new Vector2(sw, 60);
DeleteButton.Position = new Vector2(sw - 140, sh - 260);
NewButton.Position = new Vector2(sw - 140, sh - 380);
base.GameResized();
}
public int FamilyLength()
{
return Families.Count;
}
public UITSContainer FamilyProvider(int id)
{
var item = new UIFamilyCASItem(this, Families[id], vm);
return item;
}
public void UpdateFamilies(List<FAMI> families, VM vm)
{
this.vm = vm;
Families = families;
FamilyList.Reset();
}
public override void Draw(UISpriteBatch batch)
{
var y = TitleI * 100 - 85;
Title.Y = y;
NewButton.X = UIScreen.Current.ScreenWidth - 140 * TitleI;
DeleteButton.X = NewButton.X;
FamilyList.Opacity = TitleI;
FamilyList.Visible = FamilyList.Opacity > 0;
Title.Visible = false;
base.Draw(batch);
DrawLocalTexture(batch, WhitePx, null, new Vector2(0, y), new Vector2(UIScreen.Current.ScreenWidth, 60), UIStyle.Current.Bg);
Title.Visible = true;
Title.Draw(batch);
}
}
}

View file

@ -0,0 +1,125 @@
using FSO.Client;
using FSO.Client.UI.Controls;
using FSO.Client.UI.Framework;
using FSO.Common.Utils;
using FSO.Content;
using FSO.Files.Formats.IFF.Chunks;
using FSO.LotView.Model;
using FSO.SimAntics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Simitone.Client.UI.Controls;
using Simitone.Client.UI.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simitone.Client.UI.Panels.CAS
{
public class UIFamilyCASItem : UITSContainer
{
public Texture2D PxWhite;
public Texture2D Grad;
public UIImage Background;
public UIImage SelectedGrad;
public UILabel FamilyTitle;
public UIFamiliesCASPanel FParent;
public List<UIAvatarSelectButton> Btns = new List<UIAvatarSelectButton>();
public int MaxWidth = 810;
public int Width;
public int TitleWidth;
public float SelectPct { get; set; }
public UIFamilyCASItem(UIFamiliesCASPanel parent, FAMI family, VM vm)
{
FParent = parent;
var ui = Content.Get().CustomUI;
var gd = GameFacade.GraphicsDevice;
PxWhite = TextureGenerator.GetPxWhite(gd);
Grad = ui.Get("dialog_title_grad.png").Get(gd);
Background = new UIImage(ui.Get("circle10px.png").Get(gd)).With9Slice(19, 19, 19, 19);
//set the width based on number of family members
//30 margin on family thumbs
Width = 100 * family.FamilyGUIDs.Length + 10;
Background.SetSize(Width, 120);
Background.Position = new Vector2((MaxWidth - Width) / 2, 40);
Add(Background);
//max width is 100*8+10, 810
var fams = family.ChunkParent.Get<FAMs>(family.ChunkID);
FamilyTitle = new UILabel();
FamilyTitle.CaptionStyle = FamilyTitle.CaptionStyle.Clone();
FamilyTitle.CaptionStyle.Color = UIStyle.Current.Text;
FamilyTitle.CaptionStyle.Size = 19;
FamilyTitle.Size = new Vector2(MaxWidth, 40);
FamilyTitle.Alignment = TextAlignment.Center | TextAlignment.Middle;
FamilyTitle.Caption = fams?.GetString(0) ?? "";
Add(FamilyTitle);
TitleWidth = (int)FamilyTitle.CaptionStyle.MeasureString(FamilyTitle.Caption).X + 30;
//display heads of all family members
InitAvatarList(family.FamilyGUIDs, vm);
SelectPct = SelectPct;
}
public override void Draw(UISpriteBatch batch)
{
DrawLocalTexture(batch, PxWhite, null, new Vector2((MaxWidth - TitleWidth) / 2, 0), new Vector2(TitleWidth, 40), UIStyle.Current.Bg);
Background.Visible = true;
Background.Draw(batch);
DrawLocalTexture(batch, Grad, null, new Vector2((MaxWidth - Width) / 2, 54), new Vector2((Width / (float)Grad.Width)*SelectPct, 66), Color.White);
Background.Visible = false;
base.Draw(batch);
}
public void InitAvatarList(uint[] guids, VM vm)
{
int i = 0;
foreach (var btn in Btns)
{
Remove(btn);
}
Btns.Clear();
i = 0;
var baseX = MaxWidth / 2 - (guids.Length-1) * 50;
foreach (var sim in guids)
{
var fam = vm.Context.CreateObjectInstance(sim, LotTilePos.OUT_OF_WORLD, Direction.NORTH).BaseObject;
fam.Tick();
var btn = new UIAvatarSelectButton(UIIconCache.GetObject(fam));
btn.Opacity = 1f;
var id = i;
btn.Name = fam.Name;
btn.X = baseX + (i++) * 100;
btn.Y = 88;
btn.DeregisterHandler();
Btns.Add(btn);
Add(btn);
fam.Delete(true, vm.Context);
}
}
public override void Selected()
{
base.Selected();
FamilyTitle.CaptionStyle.Color = UIStyle.Current.SecondaryText;
GameFacade.Screens.Tween.To(this, 0.33f, new Dictionary<string, float>() { { "SelectPct", 1f } }, TweenQuad.EaseOut);
FParent.SetSelection(ItemID);
}
public override void Deselected()
{
base.Deselected();
FamilyTitle.CaptionStyle.Color = UIStyle.Current.Text;
GameFacade.Screens.Tween.To(this, 0.33f, new Dictionary<string, float>() { { "SelectPct", 0f } }, TweenQuad.EaseOut);
}
}
}

View file

@ -369,7 +369,7 @@ namespace Simitone.Client.UI.Panels.CAS
if (MouseOn)
{
//how much allowance do we have on this specifically
var allowance = CAS.AllowedPoints - (CAS.TotalPoints - Points);
var allowance = Math.Min(10, CAS.AllowedPoints - (CAS.TotalPoints - Points));
var newPTs = Math.Max(0, Math.Min(allowance, (int)Math.Ceiling(GlobalPoint(state.MouseState.Position.ToVector2()).X / 24)));
if (newPTs != Points)
{

View file

@ -158,6 +158,122 @@ namespace Simitone.Client.UI.Panels.LiveSubpanels
},
};
public static Dictionary<UICatalogMode, List<UICatalogSubcat>> DTCategories = new Dictionary<UICatalogMode, List<UICatalogSubcat>>()
{
{
UICatalogMode.Downtown,
new List<UICatalogSubcat>()
{
new UICatalogSubcat() { MaskBit = 0, StrTable = 150, StrInd = 16}, //food
new UICatalogSubcat() { MaskBit = 1, StrTable = 150, StrInd = 17}, //shops
new UICatalogSubcat() { MaskBit = 2, StrTable = 150, StrInd = 18}, //outside
new UICatalogSubcat() { MaskBit = 3, StrTable = 150, StrInd = 19}, //street
}
},
{
UICatalogMode.Community,
new List<UICatalogSubcat>()
{
new UICatalogSubcat() { MaskBit = 0, StrTable = 150, StrInd = 32}, //food
new UICatalogSubcat() { MaskBit = 1, StrTable = 150, StrInd = 33}, //shops
new UICatalogSubcat() { MaskBit = 2, StrTable = 150, StrInd = 34}, //outside
new UICatalogSubcat() { MaskBit = 3, StrTable = 150, StrInd = 35}, //street
}
},
{
UICatalogMode.Vacation,
new List<UICatalogSubcat>()
{
new UICatalogSubcat() { MaskBit = 0, StrTable = 150, StrInd = 24}, //lodging
new UICatalogSubcat() { MaskBit = 1, StrTable = 150, StrInd = 25}, //shops
new UICatalogSubcat() { MaskBit = 2, StrTable = 150, StrInd = 26}, //recreation
new UICatalogSubcat() { MaskBit = 3, StrTable = 150, StrInd = 27}, //ameneties
}
},
{
UICatalogMode.Studiotown,
new List<UICatalogSubcat>()
{
new UICatalogSubcat() { MaskBit = 0, StrTable = 150, StrInd = 40}, //food
new UICatalogSubcat() { MaskBit = 1, StrTable = 150, StrInd = 41}, //shops
new UICatalogSubcat() { MaskBit = 2, StrTable = 150, StrInd = 42}, //studio
new UICatalogSubcat() { MaskBit = 3, StrTable = 150, StrInd = 43}, //spa
}
},
{
UICatalogMode.Magictown,
new List<UICatalogSubcat>()
{
new UICatalogSubcat() { MaskBit = 0, StrTable = 150, StrInd = 16}, //food
new UICatalogSubcat() { MaskBit = 1, StrTable = 150, StrInd = 17}, //shops
new UICatalogSubcat() { MaskBit = 2, StrTable = 150, StrInd = 44}, //magico
new UICatalogSubcat() { MaskBit = 3, StrTable = 150, StrInd = 18}, //outside
}
},
};
public static Dictionary<UICatalogMode, List<string>> DTIcons = new Dictionary<UICatalogMode, List<string>>()
{
{
UICatalogMode.Downtown,
new List<string>()
{
"dt_food", //food
"dt_shop", //shops
"dt_out", //outside
"dt_street", //street
}
},
{
UICatalogMode.Community,
new List<string>()
{
"dt_food", //food
"dt_shop", //shops
"dt_out", //outside
"dt_street", //street
}
},
{
UICatalogMode.Vacation,
new List<string>()
{
"vac_lodg", //food
"dt_shop", //shops
"vac_recr", //recreation
"vac_amen", //amenities
}
},
{
UICatalogMode.Studiotown,
new List<string>()
{
"dt_food", //food
"dt_shop", //shops
"st_studio", //studio
"st_spa", //spa
}
},
{
UICatalogMode.Magictown,
new List<string>()
{
"dt_food", //food
"dt_shop", //shops
"misc_magi", //magic
"dt_out", //outside
}
},
};
static UIBuyBrowsePanel()
{
Categories = new List<List<UICatalogSubcat>>();
@ -397,7 +513,32 @@ namespace Simitone.Client.UI.Panels.LiveSubpanels
ChoosingSub = true;
var cats = (Mode == UICatalogMode.Build)?BuildCategories[category]:Categories[category];
List<UICatalogSubcat> cats;
if (Mode == UICatalogMode.Build) cats = BuildCategories[category];
else if (Mode != UICatalogMode.Normal)
{
cats = DTCategories[Mode];
if (cats.Count == 4) //haven't added other or all subcats yet
{
cats.Add(new UICatalogSubcat()
{
StrTable = 210,
MaskBit = 7,
StrInd = 1, //other
});
cats.Add(new UICatalogSubcat()
{
StrTable = 210,
MaskBit = 8,
StrInd = 2, //all
});
}
}
else
{
cats = Categories[category];
}
var boff = CatContainer.Size.X/(cats.Count + 0.5f) / 2f;
@ -422,6 +563,11 @@ namespace Simitone.Client.UI.Panels.LiveSubpanels
if (Mode == UICatalogMode.Build) {
name = BuildIcons[category][i];
}
else if (Mode != UICatalogMode.Normal) {
if (cat.MaskBit == 7) name = "other";
else if (cat.MaskBit == 8) name = "all";
else name = DTIcons[Mode][cat.MaskBit];
}
else
{
if (cat.MaskBit == 7) name = "other";
@ -434,6 +580,7 @@ namespace Simitone.Client.UI.Panels.LiveSubpanels
var subbutton = new UICatButton(Content.Get().CustomUI.Get("cat_"+name+".png").Get(GameFacade.GraphicsDevice));
subbutton.OnButtonClick += (btn) => { InitSubcategory(cat); };
subbutton.Position = new Vector2(boff * (1.5f + i * 2) - (65 / 2), 16);
subbutton.Disabled = SubcatIsEmpty(cat);
SelButtons.Add(subbutton);
Add(subbutton);
}
@ -674,6 +821,24 @@ namespace Simitone.Client.UI.Panels.LiveSubpanels
}
}
private bool SubcatIsEmpty(UICatalogSubcat cat)
{
var index = cat.MaskBit;
if (Mode == UICatalogMode.Build)
{
return FullCategory.FirstOrDefault() == null;
}
else if (index == 8)
{
return !FullCategory.Any(x => (GetSubsort(x.Item)) > 0);
}
else
{
var mask = 1 << index;
return !FullCategory.Any(x => (GetSubsort(x.Item) & mask) > 0);
}
}
public void InitSubcategory(UICatalogSubcat cat)
{
var index = cat.MaskBit;

View file

@ -87,7 +87,7 @@ namespace Simitone.Client.UI.Panels.LiveSubpanels
if (sel == null) return;
var neighbourhood = Content.Get().Neighborhood;
var neighbour = sel.GetPersonData(VMPersonDataVariable.NeighborId);
var inventory = neighbourhood.GetInventoryByNID(neighbour).Where(x => (CatSort == -1 && !HiddenCats.Contains(x.Type)) || CatSort == x.Type).ToList();
var inventory = neighbourhood.GetInventoryByNID(neighbour)?.Where(x => (CatSort == -1 && !HiddenCats.Contains(x.Type)) || CatSort == x.Type)?.ToList() ?? new List<InventoryItem>();
bool difference = false;
if (inventory.Count == Items.Count)

View file

@ -0,0 +1,154 @@
using FSO.Client.UI.Framework;
using FSO.Content;
using FSO.LotView.Model;
using FSO.SimAntics;
using FSO.SimAntics.Model;
using Simitone.Client.UI.Controls;
using Simitone.Client.UI.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simitone.Client.UI.Panels.LotControls
{
public class UICallNeighborAlert : UIMobileDialog
{
public UICallNeighborPanel NPanel;
public short SelectedNeighbour
{
get
{
return NPanel.SelectedNeighbour;
}
}
public event Action<int> OnResult;
public UICallNeighborAlert(short callerNID, VM vm)
{
Caption = "Call Neighbour";
SetHeight(490);
NPanel = new UICallNeighborPanel(callerNID, vm);
NPanel.Position = new Microsoft.Xna.Framework.Vector2((Width - 1030) / 2, 110);
NPanel.OnResult += (res) => { OnResult?.Invoke(res); Close(); };
Add(NPanel);
}
}
public class UICallNeighborPanel : UIContainer
{
public Dictionary<short, List<short>> NeighborsByFamilyID = new Dictionary<short, List<short>>();
public UITouchStringList FamilyList;
public UITouchStringList NeighbourList;
public UIAvatarSelectButton Icon;
public UIBigButton CallButton;
public int SelectedFamily = -1;
public short SelectedNeighbour = -1;
public VM VM;
public event Action<int> OnResult;
public UICallNeighborPanel(short callerNID, VM vm)
{
VM = vm;
var nb = Content.Get().Neighborhood;
var neigh = nb.GetNeighborByID(callerNID);
var rels = neigh.Relationships.Keys;
//var rels = nb.Neighbors.NeighbourByID.Keys;
foreach (var to in rels)
{
var tn = nb.GetNeighborByID((short)to);
var family = tn.PersonData?.ElementAt((int)VMPersonDataVariable.TS1FamilyNumber) ?? 0;
var gender = tn.PersonData?.ElementAt((int)VMPersonDataVariable.Gender) ?? 0; //can't call pets
if (family != 0 && gender < 2)
{
List<short> famList = null;
if (!NeighborsByFamilyID.TryGetValue(family, out famList))
{
famList = new List<short>();
NeighborsByFamilyID[family] = famList;
}
famList.Add((short)to);
}
}
FamilyList = new UITouchStringList();
FamilyList.Size = new Microsoft.Xna.Framework.Vector2(320, 350);
FamilyList.BackingList = NeighborsByFamilyID.Select(x => nb.GetFamilyString((ushort)x.Key).GetString(0)).ToList();
FamilyList.Refresh();
FamilyList.OnSelectionChange += FamilyList_OnSelectionChange;
Add(FamilyList);
NeighbourList = new UITouchStringList();
NeighbourList.Size = new Microsoft.Xna.Framework.Vector2(320, 350);
NeighbourList.Position = new Microsoft.Xna.Framework.Vector2(370, 0);
NeighbourList.OnSelectionChange += NeighbourList_OnSelectionChange;
Add(NeighbourList);
var cancelButton = new UIBigButton(false);
cancelButton.Caption = "Cancel";
cancelButton.Position = new Microsoft.Xna.Framework.Vector2(370 + 385, 135);
cancelButton.OnButtonClick += (btn) => { OnResult?.Invoke(-1); };
cancelButton.Width = 275;
Add(cancelButton);
CallButton = new UIBigButton(true);
CallButton.Caption = "Call";
CallButton.Position = new Microsoft.Xna.Framework.Vector2(370 + 385, 255);
CallButton.OnButtonClick += (btn) => { OnResult?.Invoke(SelectedNeighbour); };
CallButton.Width = 275;
Add(CallButton);
NeighbourList_OnSelectionChange((NeighborsByFamilyID.Count==0)?-2:-1);
OnResult += (res) => { CallButton.Disabled = true; cancelButton.Disabled = true; };
}
private void NeighbourList_OnSelectionChange(int obj)
{
if (Icon != null) { Remove(Icon); Icon = null; }
if (obj == -1)
{
SelectedNeighbour = -1;
CallButton.Disabled = true;
} else
{
SelectedNeighbour = NeighborsByFamilyID.ElementAt(SelectedFamily).Value[obj];
CallButton.Disabled = false;
var guid = Content.Get().Neighborhood.GetNeighborByID(SelectedNeighbour).GUID;
var temp = VM.Context.CreateObjectInstance(guid, LotTilePos.OUT_OF_WORLD, Direction.NORTH, true);
Icon = new UIAvatarSelectButton(UIIconCache.GetObject(temp.BaseObject));
Icon.Position = new Microsoft.Xna.Framework.Vector2(892, 60);
Add(Icon);
temp.Delete(VM.Context);
}
}
private void FamilyList_OnSelectionChange(int obj)
{
var nb = Content.Get().Neighborhood;
//populate the rightmost list with the selected family
NeighbourList.BackingList.Clear();
if (obj != -1)
{
var people = NeighborsByFamilyID.ElementAt(obj).Value;
NeighbourList.BackingList =
people.Select(x => {
var guid = nb.GetNeighborByID(x).GUID;
var gobj = Content.Get().WorldObjects.Get(guid);
if (gobj == null) return "Unknown";
return gobj.Resource.Get<FSO.Files.Formats.IFF.Chunks.CTSS>(gobj.OBJ.CatalogStringsID)?.GetString(0) ?? "Unknown";
}
).ToList();
}
NeighbourList.Refresh();
NeighbourList_OnSelectionChange(-1);
SelectedFamily = obj;
}
}
}

View file

@ -1,123 +0,0 @@
using FSO.Client;
using FSO.Common.Rendering.Framework;
using FSO.Common.Rendering.Framework.Camera;
using FSO.Content;
using FSO.LotView.Components;
using FSO.LotView.Debug;
using FSO.SimAntics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simitone.Client.UI.Panels
{
public class UI3DThumb
{
public _3DTargetScene Scene;
public BasicCamera Camera;
public Texture2D Tex
{
get { return Scene.Target; }
}
public float RotationSpeed = 0.20f;
public float RotationX = -(float)Math.PI;
public Vector3 Ctr;
public float Size;
public List<Debug3DDGRPComponent> Comp3D;
public UI3DThumb(VMEntity ent)
{
Camera = new BasicCamera(GameFacade.GraphicsDevice, new Vector3(3, 1, 0), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
Camera.NearPlane = 0.001f;
Scene = new _3DTargetScene(GameFacade.GraphicsDevice, Camera, new Point(150, 150), 0);
Scene.Initialize(GameFacade.Scenes);
if (Comp3D != null)
{
foreach (var e in Comp3D)
{
e.Dispose();
Scene.Remove(e);
}
}
Comp3D = new List<Debug3DDGRPComponent>();
BoundingBox? total = null;
var pos = ent.MultitileGroup.GetBasePositions();
var i = 0;
foreach (var obj in ent.MultitileGroup.Objects)
{
var c = new Debug3DDGRPComponent();
var dgrp = ((ObjectComponent)obj.WorldUI).DGRP;
c.Mesh = (dgrp == null) ? null : Content.Get().RCMeshes.Get(dgrp, obj.Object.OBJ); //new DGRP3DMesh(((ObjectComponent)obj.WorldUI).DGRP, obj.Object.OBJ, GameFacade.GraphicsDevice, null);
Scene.Add(c);
if (c.Mesh == null) continue;
var vp = pos[i++];
c.Position = new Vector3((vp.X - 0.5f), vp.Z, (vp.Y - 0.5f));
if (total == null) total = OffsetBox(c.Mesh.Bounds ?? new BoundingBox(), c.Position);
else total = BoundingBox.CreateMerged(total.Value, OffsetBox(c.Mesh.Bounds ?? new BoundingBox(), c.Position));
c.Initialize();
Comp3D.Add(c);
}
if (total != null)
{
Ctr = new Vector3((total.Value.Max.X + total.Value.Min.X) / 2, (total.Value.Max.Y + total.Value.Min.Y) / 2, (total.Value.Max.Z + total.Value.Min.Z) / 2);
var diag = total.Value.Max - total.Value.Min;
Size = diag.Length();
}
}
public BoundingBox OffsetBox(BoundingBox box, Vector3 off)
{
return new BoundingBox(box.Min + off, box.Max + off);
}
public void RecalcBounds()
{
BoundingBox? total = null;
foreach (var c in Comp3D)
{
if (total == null) total = OffsetBox(c.Mesh.Bounds ?? new BoundingBox(), c.Position);
else total = BoundingBox.CreateMerged(total.Value, OffsetBox(c.Mesh.Bounds ?? new BoundingBox(), c.Position));
}
if (total != null)
{
Ctr = new Vector3((total.Value.Max.X + total.Value.Min.X) / 2, (total.Value.Max.Y + total.Value.Min.Y) / 2, (total.Value.Max.Z + total.Value.Min.Z) / 2);
var diag = total.Value.Max - total.Value.Min;
Size = diag.Length();
}
}
public void Draw()
{
RecalcBounds();
RotationX += RotationSpeed;
RotationSpeed += (0.01f - RotationSpeed) / 20;
var mat = Microsoft.Xna.Framework.Matrix.CreateRotationY(RotationX);
Camera.Position = Ctr + Vector3.Transform(new Vector3(4, 3, 0)*(0.1f + Size*0.2f), mat);
Camera.Target = Ctr + new Vector3(0, 0, 0);
var old = GameFacade.GraphicsDevice.BlendState;
GameFacade.GraphicsDevice.BlendState = BlendState.NonPremultiplied;
Scene.Draw(GameFacade.GraphicsDevice);
GameFacade.GraphicsDevice.BlendState = old;
}
public void Dispose()
{
Scene.Dispose();
if (Comp3D != null)
{
foreach (var e in Comp3D) e.Dispose();
}
}
}
}

View file

@ -4,9 +4,15 @@ using FSO.Client.UI.Framework;
using FSO.Common.Utils;
using FSO.Content;
using FSO.Files.Formats.IFF.Chunks;
using FSO.LotView.Model;
using FSO.SimAntics;
using FSO.SimAntics.Engine.TSOTransaction;
using FSO.SimAntics.Model;
using FSO.SimAntics.NetPlay.Drivers;
using Microsoft.Xna.Framework;
using Simitone.Client.UI.Controls;
using Simitone.Client.UI.Model;
using Simitone.Client.UI.Screens;
using System;
using System.Collections.Generic;
using System.Linq;
@ -23,6 +29,8 @@ namespace Simitone.Client.UI.Panels
public UILabel StreetTitle;
public UILabel LotTitle;
public UILabel LotDescription;
public UILabel SecondaryText;
public UIHouseFamilyList FamilyDisplay;
public UIBigButton EnterLot;
public UIBigButton More;
@ -30,10 +38,54 @@ namespace Simitone.Client.UI.Panels
public event Action<int> OnSelected;
public int HouseID;
public List<UIBigButton> OptionButtons = new List<UIBigButton>();
private float _MoreTween;
public float MoreTween
{
get
{
return _MoreTween;
}
set
{
var nonOptionButtons = new UIElement[]
{
LotDescription,
SecondaryText,
EnterLot,
More,
};
foreach (var btn in nonOptionButtons)
{
btn.Opacity = 1 - value;
btn.Visible = btn.Opacity > 0;
}
foreach (var btn in OptionButtons)
{
btn.Opacity = value;
btn.Visible = btn.Opacity > 0;
}
var screen = UIScreen.Current;
var scale = Math.Max(2 / 3f, Math.Min(1, screen.ScreenWidth / 1704f));
var space = (96 * scale) - 56;
if (FamilyDisplay != null)
FamilyDisplay.X = (48 + space / 2) - value * screen.ScreenWidth / 2;
_MoreTween = value;
}
}
public UIHouseSelectPanel(int houseID)
{
HouseID = houseID;
var screen = GameFacade.Screens.CurrentUIScreen;
var extra = Math.Max(0, (screen.ScreenHeight - 640) / 128) * 64;
HouseID = houseID;
Diag = new UIDiagonalStripe(new Point(screen.ScreenWidth / 2, screen.ScreenHeight + 16), UIDiagonalStripeSide.RIGHT, UIStyle.Current.Bg);
Diag.Y = -16;
Diag.ListenForMouse(Diag.GetBounds(), (e, s) => { });
@ -41,58 +93,304 @@ namespace Simitone.Client.UI.Panels
TitleStripe = new UIDiagonalStripe(new Point(screen.ScreenWidth / 2, 92 + 8 + 32), UIDiagonalStripeSide.RIGHT, UIStyle.Current.Bg);
TitleStripe.StartOff = 8 + 32;
TitleStripe.Y = 82 - 34;
TitleStripe.Y = -16 + extra;
Add(TitleStripe);
var house = Content.Get().Neighborhood.GetHouse(houseID);
var street = Content.Get().Neighborhood.StreetNames;
var assignment = street.Get<STR>(2001).GetString(houseID-1);
var neigh = Content.Get().Neighborhood;
var house = neigh.GetHouse(houseID);
var street = neigh.StreetNames;
var assignment = street.Get<STR>(2001).GetString(houseID - 1);
int streetName;
if (int.TryParse(assignment, out streetName))
{
StreetTitle = new UILabel();
StreetTitle.Position = new Vector2(30, 94);
StreetTitle.Position = new Vector2(30, 94 + extra - 64);
InitLabel(StreetTitle);
StreetTitle.CaptionStyle.Color = UIStyle.Current.BtnActive;
StreetTitle.Caption = street.Get<STR>(2000).GetString(streetName-1).Replace("%s", houseID.ToString());
StreetTitle.Caption = street.Get<STR>(2000).GetString(streetName - 1).Replace("%s", houseID.ToString());
}
var nameDesc = Content.Get().Neighborhood.GetHouseNameDesc(houseID);
var nameDesc = neigh.GetHouseNameDesc(houseID);
var name = nameDesc.Item1;
if (name == "") name = "Unnamed House";
if (name == "") name = StreetTitle.Caption;
LotTitle = new UILabel();
LotTitle.Position = new Vector2(30, 122);
LotTitle.Position = new Vector2(30, 122 + extra - 64);
InitLabel(LotTitle);
LotTitle.CaptionStyle.Size = 37;
LotTitle.Caption = name;
var family = neigh.GetFamilyForHouse((short)houseID);
LotDescription = new UILabel();
LotDescription.Position = new Vector2(30, 206);
LotDescription.Position = new Vector2(30, 206 + extra);
InitLabel(LotDescription);
//LotDescription.CaptionStyle.Size = 15;
LotDescription.Size = new Vector2(502, screen.ScreenHeight-415);
LotDescription.Size = new Vector2(screen.ScreenWidth/2 - 60, screen.ScreenHeight - 415);
LotDescription.Wrapped = true;
LotDescription.Alignment = TextAlignment.Top | TextAlignment.Left;
LotDescription.Caption = nameDesc.Item2;
SecondaryText = new UILabel();
SecondaryText.Position = new Vector2(30, screen.ScreenHeight - (165 + extra));
InitLabel(SecondaryText);
SecondaryText.Size = new Vector2(screen.ScreenWidth / 2 - 60, 29);
SecondaryText.Wrapped = true;
SecondaryText.Alignment = TextAlignment.Bottom | TextAlignment.Right;
SecondaryText.CaptionStyle.Color = UIStyle.Current.SecondaryText;
var moveInID = (UIScreen.Current as Screens.TS1GameScreen).MoveInFamily;
var moveIn = (moveInID == null) ? null : Content.Get().Neighborhood.GetFamily((ushort)moveInID.Value);
var buttonValid = true;
if (family != null)
{
var famUI = new UIHouseFamilyList(family);
var scale = Math.Max(2 / 3f, Math.Min(1, screen.ScreenWidth / 1704f));
famUI.ScaleX = famUI.ScaleY = scale;
var space = (96 * scale) - 56;
LotDescription.Y += space;
famUI.Position = new Vector2(48 + space / 2, 152 + extra + space / 2);
Add(famUI);
FamilyDisplay = famUI;
LotDescription.Caption = GameFacade.Strings.GetString("134", "0", new string[] {
Content.Get().Neighborhood.MainResource.Get<FAMs>(family.ChunkID)?.GetString(0) ?? "?",
"§" + (family.ValueInArch + family.Budget).ToString("##,#0"), //should include lot value eventually
family.FamilyFriends.ToString()
});
LotDescription.CaptionStyle.Color = UIStyle.Current.SecondaryText;
if (moveIn != null)
{
SecondaryText.Caption = GameFacade.Strings.GetString("132", "15"); //house occupied
buttonValid = false;
}
} else
{
LotDescription.Y -= 64;
LotDescription.Size = new Vector2(LotDescription.Size.X, LotDescription.Size.Y + 65);
//LotDescription.Caption = new string(Enumerable.Range(1, 255).Select(x => 'a').ToArray());
LotDescription.Caption = nameDesc.Item2;
//set up the secondary text
var zones = neigh.ZoningDictionary;
short result = 1;
if (!zones.TryGetValue((short)houseID, out result))
result = (short)((houseID >= 81 && houseID <= 89) ? 2 : 1);
if (result > 0)
{
//zone
string str;
if (moveIn != null)
{
str = GameFacade.Strings.GetString("134", "18").Substring(8); //is community, can't move in
buttonValid = false;
}
else
{
str = GameFacade.Strings.GetString("134", "17").Substring(8); //is community
}
SecondaryText.Caption = str;
} else
{
//show price
var price = house.Get<SIMI>(1)?.PurchaseValue ?? 0;
string str;
if (houseID >= 90 && houseID <= 92)
{
//also requires magicoins
var magicoins = neigh.GetMagicoinsForFamily(family);
var requiredMC = int.Parse(GameFacade.Strings.GetString("134", (32 + Math.Abs(91 - houseID)).ToString()));
if (moveIn != null)
{
if (magicoins >= requiredMC)
{
if (moveIn.Budget >= price)
{
str = GameFacade.Strings.GetString("134", "31", new string[] { "", "",
"§" + price.ToString("##,#0"),
requiredMC.ToString()
});
}
else
{
//missing simoleons
str = GameFacade.Strings.GetString("134", "38", new string[] { "", "",
"§" + price.ToString("##,#0"),
requiredMC.ToString(),
moveIn.ChunkParent.Get<FAMs>(moveIn.ChunkID)?.GetString(0) ?? "",
"§" +moveIn.Budget.ToString("##,#0")
}).Substring(4);
buttonValid = false;
}
}
else
{
if (moveIn.Budget >= price)
{
//missing magicoins
str = GameFacade.Strings.GetString("134", "36", new string[] { "", "",
"§" + price.ToString("##,#0"),
requiredMC.ToString(),
moveIn.ChunkParent.Get<FAMs>(moveIn.ChunkID)?.GetString(0) ?? "",
magicoins.ToString()
}).Substring(4);
}
else
{
//missing both
str = GameFacade.Strings.GetString("134", "37", new string[] { "", "",
"§" + price.ToString("##,#0"),
requiredMC.ToString(),
moveIn.ChunkParent.Get<FAMs>(moveIn.ChunkID)?.GetString(0) ?? "",
magicoins.ToString()
}).Substring(4);
buttonValid = false;
}
buttonValid = false;
}
}
else
{
//suggest move in
str = GameFacade.Strings.GetString("134", "29", new string[] { "", "",
"§" + price.ToString("##,#0"),
requiredMC.ToString()
}).Substring(4);
}
}
else
{
if (moveIn != null)
{
if (moveIn.Budget >= price)
{
str = GameFacade.Strings.GetString("134", "5", new string[] { "", "",
"§" + price.ToString("##,#0"),
"§" +(moveIn.Budget - price).ToString("##,#0")
}).Substring(4);
}
else
{
str = GameFacade.Strings.GetString("134", "4", new string[] { "", "",
"§" + price.ToString("##,#0"),
moveIn.ChunkParent.Get<FAMs>(moveIn.ChunkID)?.GetString(0) ?? "",
"§" +moveIn.Budget.ToString("##,#0")
}).Substring(4);
buttonValid = false;
}
}
else
{
//suggest move in
str = GameFacade.Strings.GetString("134", "1", new string[] { "", "", "§" + price.ToString("##,#0") }).Substring(4);
}
}
SecondaryText.Caption = str;
SecondaryText.CaptionStyle.Size = 15;
}
}
EnterLot = new UIBigButton(false);
EnterLot.Caption = "Enter Lot";
EnterLot.Width = 275;
EnterLot.Position = new Vector2(30, screen.ScreenHeight - 160);
EnterLot.Caption = (moveIn == null)?"Enter Lot":"Move In";
EnterLot.Width = (moveIn == null)? (screen.ScreenWidth / 2 - 293) : (screen.ScreenWidth/2-60);
EnterLot.Disabled = !buttonValid;
EnterLot.Position = new Vector2(30, screen.ScreenHeight - (extra + 125));
EnterLot.OnButtonClick += (b) => { OnSelected?.Invoke(houseID); Kill(); };
Add(EnterLot);
More = new UIBigButton(true);
More.Caption = "More";
More.Width = 192;
More.Position = new Vector2(330, screen.ScreenHeight - 160);
Add(More);
More.Width = 208;
More.Position = new Vector2(screen.ScreenWidth / 2 - 238, screen.ScreenHeight - (extra + 125));
More.OnButtonClick += (btn) => { ShowMore(true); };
if (moveIn == null) Add(More);
var optionFunctions = new ButtonClickDelegate[]
{
(family==null)?null:(ButtonClickDelegate)((btn) => Evict(family)),
null,
null,
(btn) => ShowMore(false)
};
var optionNames = new string[]
{
(family==null)?"Bulldoze":"Evict",
"Rezone",
"Export",
"Back"
};
var bY = extra+140;
for (int i=0; i<optionFunctions.Length; i++)
{
var btn = new UIBigButton(i == optionFunctions.Length-1);
btn.Caption = optionNames[i];
btn.Position = new Vector2(screen.ScreenWidth / 4 - btn.Width / 2, bY);
btn.Disabled = optionFunctions[i] == null;
btn.OnButtonClick += optionFunctions[i];
Add(btn);
bY += 120;
OptionButtons.Add(btn);
}
X = screen.ScreenWidth / -2;
GameFacade.Screens.Tween.To(this, 0.5f, new Dictionary<string, float>() { { "X", 0f } }, TweenQuad.EaseOut);
MoreTween = MoreTween;
}
public void Evict(FAMI family)
{
if (family == null) return;
var familyName = family.ChunkParent.Get<FAMs>(family.ChunkID)?.GetString(0) ?? "selected";
UIMobileAlert evictDialog = null;
evictDialog = new UIMobileAlert(new UIAlertOptions()
{
Title = GameFacade.Strings.GetString("131", "2"),
Message = GameFacade.Strings.GetString("131", "3", new string[] {
familyName.ToString(),
"§" + (family.ValueInArch + family.Budget).ToString("##,#0") }
),
Buttons = UIAlertButton.YesNo(
(b) => { evictDialog.Close(); ((TS1GameScreen)UIScreen.Current).EvictLot(family, (short)HouseID); },
(b) => { evictDialog.Close(); }
)
});
UIScreen.GlobalShowDialog(evictDialog, true);
}
public void ShowMore(bool more)
{
GameFacade.Screens.Tween.To(this, 0.5f, new Dictionary<string, float>() { { "MoreTween", (more)?1f:0f } }, TweenQuad.EaseOut);
/*
var nonOptionButtons = new UIElement[]
{
LotDescription,
SecondaryText,
EnterLot,
More
};
foreach (var btn in nonOptionButtons)
{
var b = btn as UIButton;
if (b != null) b.Disabled = more;
}
foreach (var btn in OptionButtons)
{
btn.Disabled = !more;
}
*/
}
public void Kill()
@ -112,4 +410,46 @@ namespace Simitone.Client.UI.Panels
Add(label);
}
}
public class UIHouseFamilyList : UIContainer
{
public List<UIAvatarSelectButton> Btns = new List<UIAvatarSelectButton>();
public UIHouseFamilyList(FAMI family)
{
PopulateList(family);
}
public void PopulateList(FAMI family)
{
var world = new FSO.LotView.World(GameFacade.GraphicsDevice);
world.Initialize(GameFacade.Scenes);
var context = new VMContext(world);
var vm = new VM(context, new VMServerDriver(new VMTS1GlobalLinkStub()), new VMNullHeadlineProvider());
vm.Init();
var blueprint = new Blueprint(1, 1);
//world.InitBlueprint(blueprint);
context.Blueprint = blueprint;
context.Architecture = new VMArchitecture(1, 1, blueprint, vm.Context);
int i = 0;
var baseX = 0;
foreach (var sim in family.FamilyGUIDs)
{
var fam = vm.Context.CreateObjectInstance(sim, LotTilePos.OUT_OF_WORLD, Direction.NORTH, true).BaseObject;
var btn = new UIAvatarSelectButton(UIIconCache.GetObject(fam));
btn.Opacity = 1f;
var id = i;
btn.Name = fam.Name;
btn.X = baseX + (i++) * 100;
btn.Y = 0;
btn.DeregisterHandler();
Btns.Add(btn);
Add(btn);
fam.Delete(true, vm.Context);
}
world.Dispose();
}
}
}

View file

@ -35,6 +35,7 @@ using FSO.LotView.RC;
using Simitone.Client.UI.Panels.LotControls;
using FSO.Client.UI.Panels.LotControls;
using FSO.UI.Panels.LotControls;
using Simitone.Client.UI.Controls;
namespace Simitone.Client.UI.Panels
{
@ -55,6 +56,11 @@ namespace Simitone.Client.UI.Panels
public FSO.SimAntics.VM vm;
public FSO.LotView.World World { get; set; }
public VMEntity ActiveEntity { get; set; }
public int Budget { get
{
return vm.TS1State.CurrentFamily?.Budget ?? int.MaxValue;
}
}
public uint SelectedSimID
{
get
@ -88,7 +94,7 @@ namespace Simitone.Client.UI.Panels
// NOTE: Blocking dialog system assumes that nothing goes wrong with data transmission (which it shouldn't, because we're using TCP)
// and that the code actually blocks further dialogs from appearing while waiting for a response.
// If we are to implement controlling multiple sims, this must be changed.
private UIMobileAlert BlockingDialog;
private UIMobileDialog BlockingDialog;
private UINeighborhoodSelectionPanel TS1NeighSelector;
private ulong LastDialogID;
@ -174,11 +180,6 @@ namespace Simitone.Client.UI.Panels
if (IDEHook.IDE != null) IDEHook.IDE.IDEBreakpointHit(vm, entity);
}
public string GetLotTitle()
{
return vm.LotName + " - " + vm.Entities.Count(x => x is VMAvatar && x.PersistID != 0);
}
void vm_OnDialog(FSO.SimAntics.Model.VMDialogInfo info)
{
if (info != null && ((info.DialogID == LastDialogID && info.DialogID != 0 && info.Block))) return;
@ -245,7 +246,21 @@ namespace Simitone.Client.UI.Panels
((TS1GameScreen)Parent).LotControl.Visible = false;
TS1NeighSelector.OnHouseSelect += HouseSelected;
return;
case VMDialogType.TS1PhoneBook:
var phone = new UICallNeighborAlert(((VMAvatar)info.Caller).GetPersonData(FSO.SimAntics.Model.VMPersonDataVariable.NeighborId), vm);
BlockingDialog = phone;
UIScreen.GlobalShowDialog(phone, true);
phone.OnResult += (result) =>
{
vm.SendCommand(new VMNetDialogResponseCmd
{
ActorUID = info.Caller.PersistID,
ResponseCode = (byte)((result > 0) ? 1 : 0),
ResponseText = result.ToString()
});
BlockingDialog = null;
};
return;
}
var alert = new UIMobileAlert(options);
@ -291,14 +306,15 @@ namespace Simitone.Client.UI.Panels
private void DialogResponse(byte code)
{
if (BlockingDialog == null || ActiveEntity == null) return;
if (BlockingDialog == null || !(BlockingDialog is UIMobileAlert) || ActiveEntity == null) return;
BlockingDialog.Close();
var ma = (UIMobileAlert)BlockingDialog;
LastDialogID = 0;
vm.SendCommand(new VMNetDialogResponseCmd
{
ActorUID = ActiveEntity.PersistID,
ResponseCode = code,
ResponseText = (BlockingDialog.ResponseText == null) ? "" : BlockingDialog.ResponseText
ResponseText = (ma.ResponseText == null) ? "" : ma.ResponseText
});
BlockingDialog = null;
}
@ -507,8 +523,8 @@ namespace Simitone.Client.UI.Panels
{
OldMX = state.MouseState.X;
OldMY = state.MouseState.Y;
var newHover = World.GetObjectIDAtScreenPos(state.MouseState.X / FSOEnvironment.DPIScaleFactor,
state.MouseState.Y / FSOEnvironment.DPIScaleFactor,
var newHover = World.GetObjectIDAtScreenPos(state.MouseState.X,
state.MouseState.Y,
GameFacade.GraphicsDevice);
if (ObjectHover != newHover)
@ -671,9 +687,7 @@ namespace Simitone.Client.UI.Panels
if (World.State.Zoom != targetZoom) World.State.Zoom = targetZoom;
WorldConfig.Current.SmoothZoom = false;
}
//Cheats.Update(state);
//AvatarDS.Update();
if (ActiveEntity == null || ActiveEntity.Dead || ActiveEntity.PersistID != SelectedSimID)
{
ActiveEntity = vm.Entities.FirstOrDefault(x => x is VMAvatar && x.PersistID == SelectedSimID); //try and hook onto a sim if we have none selected.
@ -690,6 +704,28 @@ namespace Simitone.Client.UI.Panels
if (GotoObject == null) GotoObject = vm.Context.CreateObjectInstance(GOTO_GUID, LotTilePos.OUT_OF_WORLD, Direction.NORTH, true).Objects[0];
//update plumbbob
var plumb = Content.Get().RCMeshes.Get("arrow.fsom");
foreach (VMAvatar avatar in vm.Context.ObjectQueries.Avatars)
{
if (avatar.Avatar == null) continue;
var isActive = (avatar == ActiveEntity);
if ((avatar.Avatar.HeadObject == plumb) != isActive)
{
avatar.Avatar.HeadObject = (avatar == ActiveEntity) ? plumb : null;
avatar.Avatar.HeadObjectSpeedyVel = 0.2f;
}
avatar.Avatar.HeadObjectRotation += 3f / FSOEnvironment.RefreshRate;
if (isActive)
{
avatar.Avatar.HeadObjectRotation += avatar.Avatar.HeadObjectSpeedyVel;
avatar.Avatar.HeadObjectSpeedyVel *= 0.98f;
} else if (avatar.GetValue(FSO.SimAntics.Model.VMStackObjectVariable.Category) == 87)
{
avatar.Avatar.HeadObject = Content.Get().RCMeshes.Get("star.fsom");
}
}
/*
if (ActiveEntity != null && BlockingDialog != null)
{
@ -775,6 +811,21 @@ namespace Simitone.Client.UI.Panels
PieMenu = null;
}
if (state.NewKeys.Contains(Keys.F8))
{
UIMobileAlert alert = null;
alert = new UIMobileAlert(new UIAlertOptions()
{
Title = "Debug Lot Thumbnail",
Message = "Arch Value: "+VMArchitectureStats.GetArchValue(vm.Context.Architecture),
Buttons = UIAlertButton.Ok((btn) => UIScreen.RemoveDialog(alert))
});
Texture2D roofless = null;
var thumb = World.GetLotThumb(GameFacade.GraphicsDevice, (tex) => roofless = FSO.Common.Utils.TextureUtils.Decimate(tex, GameFacade.GraphicsDevice, 2, false));
thumb = FSO.Common.Utils.TextureUtils.Decimate(thumb, GameFacade.GraphicsDevice, 2, false);
alert.SetIcon(thumb, thumb.Width, thumb.Height);
UIScreen.GlobalShowDialog(alert, true);
}
if (LiveMode) LiveModeUpdate(state, scrolled);
else if (CustomControl != null)
{

View file

@ -99,6 +99,12 @@ namespace Simitone.Client.UI.Panels
RefreshSize();
}
public override void GameResized()
{
base.GameResized();
RefreshSize();
}
public void RefreshSize()
{
var w = Width;
@ -123,14 +129,7 @@ namespace Simitone.Client.UI.Panels
h += 45;
}
var btnX = (w - ((Buttons.Count-1) * 350)) / 2;
var btnY = h - 125;
foreach (UIButton button in Buttons)
{
button.Y = btnY;
button.X = btnX - button.Width/2;
btnX += 350;
}
h = ResetButtons(h, true);
if (Height != h)
{
@ -139,6 +138,47 @@ namespace Simitone.Client.UI.Panels
//update bg with height
}
private int ResetButtons(int h, bool setY)
{
var btnX = Width/2;
var btnY = h - 125;
var totalBtnWidth = Buttons.Sum(x => x.Width);
int runningWidth = 0;
int start = 0;
int i = 0;
for (i=0; i<Buttons.Count; i++)
{
var btn = Buttons[i];
if (runningWidth == 0 || (Width-50) - runningWidth > btn.Width)
{
btn.X = btnX + runningWidth;
} else
{
btnY += 120;
h += 120;
//center buttons
runningWidth -= 25;
for (int j=start; j<i; j++)
{
Buttons[j].X -= runningWidth / 2;
}
runningWidth = 0;
start = i;
btn.X = btnX + runningWidth;
}
runningWidth += (int)btn.Width + 25;
if (setY) btn.Y = btnY;
}
runningWidth -= 25;
for (int j = start; j < i; j++)
{
Buttons[j].X -= runningWidth / 2;
}
return h;
}
private float TargetIX;
public void SetIcon(Texture2D img, int width, int height)
@ -226,12 +266,11 @@ namespace Simitone.Client.UI.Panels
{
Icon.Visible = true;
Icon.X = newIX;
var btnX = (Width - ((Buttons.Count - 1) * 350)) / 2;
foreach (UIButton button in Buttons)
ResetButtons(Height, false);
foreach (var btn in Buttons)
{
button.X = off + btnX - button.Width / 2;
button.Visible = true;
btnX += 350;
btn.X += off;
btn.Visible = true;
}
}
}

View file

@ -62,6 +62,7 @@ namespace Simitone.Client.UI.Panels
BuildButton,
OptionButton
};
UpdateBuildBuy();
}
public override void Update(UpdateState state)
@ -73,6 +74,13 @@ namespace Simitone.Client.UI.Panels
}
}
public void UpdateBuildBuy()
{
var bbEnable = Game.vm.Context.Architecture.BuildBuyEnabled;
BuyButton.Disabled = !bbEnable;
BuildButton.Disabled = !bbEnable;
}
public void EndSwitch(UIMainPanelMode mode)
{
UIButton frontButton;

View file

@ -17,6 +17,10 @@ using FSO.Client;
using FSO.Content;
using FSO.Common.Utils;
using Simitone.Client.UI.Controls;
using Simitone.Client.Utils;
using FSO.Common;
using System.IO;
using FSO.Files.RC;
namespace Simitone.Client.UI.Panels
{
@ -127,7 +131,6 @@ namespace Simitone.Client.UI.Panels
GameResized();
}
public void UpdatePosition()
{
base.GameResized();
@ -203,6 +206,7 @@ namespace Simitone.Client.UI.Panels
Zoom = Zoom;
CenterPositionX = CenterPositionX;
CenterPositionY = CenterPositionY;
//SimitoneNeighOBJExporter.SaveOBJ(Path.Combine(FSOEnvironment.UserDir, "NeighModel" + mode + "/"), locations);
}
public void ResetZoom()
@ -337,17 +341,26 @@ namespace Simitone.Client.UI.Panels
public UINeighborhoodHouseButton(int houseNumber, Action<int> selectionCallback, float scale)
{
if (houseNumber == 71) { }
AlphaTime = 0;
var house = Content.Get().Neighborhood.GetHouse(houseNumber);
HouseTex = house.Get<BMP>(513).GetTexture(GameFacade.GraphicsDevice);
HouseOpenTex = house.Get<BMP>(512).GetTexture(GameFacade.GraphicsDevice);
HouseTex = house.Get<BMP>(513)?.GetTexture(GameFacade.GraphicsDevice);
if (HouseTex != null) {
HouseOpenTex = house.Get<BMP>(512).GetTexture(GameFacade.GraphicsDevice);
Offsets = house.Get<THMB>(512); //get offsets before scaling
} else
{
HouseTex = house.Get<PNG>(513).GetTexture(GameFacade.GraphicsDevice);
HouseOpenTex = house.Get<PNG>(512).GetTexture(GameFacade.GraphicsDevice);
Offsets = new THMB() { Width = HouseTex.Width / 2, Height = HouseTex.Height / 2 };
}
HouseScale = scale;
Offsets = house.Get<THMB>(512); //get offsets before scaling
var w = (int)(HouseTex.Width / HouseScale);
var h = (int)(HouseTex.Height / HouseScale);
var clickHandler =
ListenForMouse(new Rectangle(w / -2, h / -2, w, h), (evt, state) =>
ListenForMouse(new Rectangle(w / -2, w / -4, w, h/2), (evt, state) =>
{
switch (evt)
{
@ -367,13 +380,13 @@ namespace Simitone.Client.UI.Panels
public override void Draw(UISpriteBatch batch)
{
var yOff = new Vector2(Offsets.XOff, Offsets.BaseYOff) / (HouseScale * 2f);
var yOff = new Vector2(Offsets.XOff, -Offsets.BaseYOff) / HouseScale;
var yOff2 = yOff;
yOff2.Y -= Offsets.AddYOff / (HouseScale);
DrawLocalTexture(batch, HouseTex, null, new Vector2(-HouseTex.Width, -HouseTex.Height) / (HouseScale * 2) + yOff, new Vector2(1f / HouseScale, 1f / HouseScale));
DrawLocalTexture(batch, HouseTex, null, new Vector2(-Offsets.Width, -Offsets.Height)/ HouseScale + yOff, new Vector2(1f / HouseScale, 1f / HouseScale));
if (AlphaTime > 0)
{
DrawLocalTexture(batch, HouseOpenTex, null, new Vector2(-HouseTex.Width, -HouseTex.Height) / (HouseScale * 2) + yOff2, new Vector2(1f / HouseScale, 1f / HouseScale), Color.White * AlphaTime);
DrawLocalTexture(batch, HouseOpenTex, null, new Vector2(-Offsets.Width, -Offsets.Height)/ HouseScale + yOff2, new Vector2(1f / HouseScale, 1f / HouseScale), Color.White * AlphaTime);
}
}

View file

@ -17,25 +17,33 @@ namespace Simitone.Client.UI.Panels
public List<UIElasticButton> RightBtns = new List<UIElasticButton>();
private UINeighborhoodSelectionPanel Panel;
private ushort Mode;
public bool MoveInMode;
public UINeighbourhoodSwitcher(UINeighborhoodSelectionPanel panel, ushort mode)
public UINeighbourhoodSwitcher(UINeighborhoodSelectionPanel panel, ushort mode, bool moveIn)
{
Panel = panel;
SetMode(mode);
SetMode(mode, moveIn);
}
public void SetMode(ushort mode)
public void SetMode(ushort mode, bool moveIn)
{
MoveInMode = moveIn;
foreach (var btn in LeftBtns) Remove(btn);
foreach (var btn in RightBtns) Remove(btn);
LeftBtns.Clear(); RightBtns.Clear();
AddBtn(LeftBtns, "ngbh_cas.png", (btn) => GameController.EnterCAS());
AddBtn(LeftBtns, "ngbh_cas.png", (btn) =>
{
var transition = new UITransDialog("cas", () =>
{
GameController.EnterCAS();
});
});
if (mode != 4) AddBtn(LeftBtns, "ngbh_back.png", (btn) => PopMode(4));
if (mode != 2) AddBtn(RightBtns, "ngbh_downt.png", (btn) => PopMode(2));
if (mode != 3) AddBtn(RightBtns, "ngbh_vacat.png", (btn) => PopMode(3));
if (mode != 5) AddBtn(RightBtns, "ngbh_studio.png", (btn) => PopMode(5));
if (mode != 2 && !moveIn) AddBtn(RightBtns, "ngbh_downt.png", (btn) => PopMode(2));
if (mode != 3 && !moveIn) AddBtn(RightBtns, "ngbh_vacat.png", (btn) => PopMode(3));
if (mode != 5 && !moveIn) AddBtn(RightBtns, "ngbh_studio.png", (btn) => PopMode(5));
if (mode != 7) AddBtn(RightBtns, "ngbh_magic.png", (btn) => PopMode(7));
Mode = mode;
@ -45,7 +53,7 @@ namespace Simitone.Client.UI.Panels
public void PopMode(ushort mode)
{
Panel.PopulateScreen(mode);
SetMode(mode);
SetMode(mode, MoveInMode);
}
private void LayBtns()

View file

@ -117,7 +117,7 @@ namespace Simitone.Client.UI.Panels
//rotate through to try all configurations
var dir = Holding.Dir;
VMPlacementError status = VMPlacementError.Success;
if (!Holding.IsBought && !vm.TSOState.CanPlaceNewUserObject(vm)) status = VMPlacementError.TooManyObjectsOnTheLot;
if (!Holding.IsBought && !vm.PlatformState.CanPlaceNewUserObject(vm)) status = VMPlacementError.TooManyObjectsOnTheLot;
else
{
for (int i = 0; i < 4; i++)
@ -164,7 +164,7 @@ namespace Simitone.Client.UI.Panels
if (UseNet || !Holding.IsBought)
{
Holding.Group.Delete(vm.Context);
RecursiveDelete(vm.Context, Holding.Group.BaseObject);
} else
{
if (Holding.RealEnt == null) Holding.RealEnt = Holding.Group.BaseObject;
@ -182,6 +182,27 @@ namespace Simitone.Client.UI.Panels
vm.Tick();
}
private void RecursiveDelete(VMContext context, VMEntity real)
{
var rgrp = real.MultitileGroup;
for (int i = 0; i < rgrp.Objects.Count; i++)
{
var slots = rgrp.Objects[i].TotalSlots();
var objs = new List<VMEntity>();
for (int j = 0; j < slots; j++)
{
var slot = rgrp.Objects[i].GetSlot(j);
if (slot != null)
{
objs.Add(slot);
}
}
foreach (var obj in objs) RecursiveDelete(context, obj);
}
rgrp.Delete(context);
}
public void MouseDown(UpdateState state)
{
MouseIsDown = true;
@ -357,7 +378,7 @@ namespace Simitone.Client.UI.Panels
{
MoveSelected(Holding.TilePos, Holding.Level);
if (!Holding.IsBought && Holding.CanPlace == VMPlacementError.Success &&
ParentControl.ActiveEntity != null && ParentControl.ActiveEntity.TSOState.Budget.Value < Holding.Price)
ParentControl.ActiveEntity != null && ParentControl.Budget < Holding.Price)
Holding.CanPlace = VMPlacementError.InsufficientFunds;
if (Holding.CanPlace != VMPlacementError.Success)
{
@ -390,7 +411,7 @@ namespace Simitone.Client.UI.Panels
else if (MouseClicked)
{
//not holding an object, but one can be selected
var newHover = World.GetObjectIDAtScreenPos(state.MouseState.X / FSOEnvironment.DPIScaleFactor, state.MouseState.Y / FSOEnvironment.DPIScaleFactor, GameFacade.GraphicsDevice);
var newHover = World.GetObjectIDAtScreenPos(state.MouseState.X, state.MouseState.Y, GameFacade.GraphicsDevice);
if (MouseClicked && (newHover != 0) && (vm.GetObjectById(newHover) is VMGameObject))
{
var objGroup = vm.GetObjectById(newHover).MultitileGroup;

View file

@ -17,6 +17,7 @@ using System.Text;
using System.Threading.Tasks;
using FSO.Common.Rendering.Framework.Model;
using FSO.Common.Rendering.Framework.IO;
using FSO.UI.Panels;
namespace Simitone.Client.UI.Panels
{

View file

@ -18,6 +18,7 @@ using System.Text;
using System.Threading.Tasks;
using FSO.Common.Rendering.Framework.Model;
using FSO.Common;
using FSO.UI.Panels;
namespace Simitone.Client.UI.Panels
{
@ -130,6 +131,8 @@ namespace Simitone.Client.UI.Panels
Title.Alignment = TextAlignment.Left | TextAlignment.Top;
Body.Alignment = TextAlignment.Left | TextAlignment.Top;
InternalBefore = true;
}
public override void Update(UpdateState state)

View file

@ -12,6 +12,10 @@ using FSO.Client;
using Microsoft.Xna.Framework;
using Simitone.Client.UI.Panels.LiveSubpanels;
using FSO.Client.UI.Model;
using Microsoft.Xna.Framework.Input;
using FSO.SimAntics;
using FSO.SimAntics.NetPlay.Model.Commands;
using FSO.HIT;
namespace Simitone.Client.UI.Panels
{
@ -198,6 +202,22 @@ namespace Simitone.Client.UI.Panels
public float ClockTween;
public override void Update(UpdateState state)
{
if (state.NewKeys.Contains(Keys.Space))
{
var selected = Game.LotControl.ActiveEntity;
var familyMembers = Game.vm.Context.ObjectQueries.Avatars.Where(x =>
((VMAvatar)x).GetPersonData(
FSO.SimAntics.Model.VMPersonDataVariable.TS1FamilyNumber) == (Game.vm.TS1State.CurrentFamily?.ChunkID)
).ToList();
var index = familyMembers.IndexOf(selected);
if (familyMembers.Count > 0)
{
index = (index + 1) % (familyMembers.Count);
HITVM.Get().PlaySoundEvent(UISounds.QueueAdd);
Game.vm.SendCommand(new VMNetChangeControlCmd() { TargetID = familyMembers[index].ObjectID });
}
}
base.Update(state);
if (LastCut != Game.LotControl.WallsMode)
{

View file

@ -27,7 +27,7 @@ namespace Simitone.Client.UI.Panels
Game = screen;
Bg = Content.Get().CustomUI.Get("pswitch_bg.png").Get(GameFacade.GraphicsDevice);
var familyMembers = Game.vm.Context.ObjectQueries.Avatars.Where(x => ((VMAvatar)x).GetPersonData(FSO.SimAntics.Model.VMPersonDataVariable.TS1FamilyNumber) == (Game.vm.CurrentFamily?.ChunkID));
var familyMembers = Game.vm.Context.ObjectQueries.Avatars.Where(x => ((VMAvatar)x).GetPersonData(FSO.SimAntics.Model.VMPersonDataVariable.TS1FamilyNumber) == (Game.vm.TS1State.CurrentFamily?.ChunkID));
int i = 0;
foreach (var fam in familyMembers)
{

View file

@ -0,0 +1,99 @@
using FSO.Client;
using FSO.Client.UI.Framework;
using FSO.Common.Utils;
using FSO.Content;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Simitone.Client.UI.Controls;
using Simitone.Client.UI.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simitone.Client.UI.Panels
{
public class UITransDialog : UIContainer
{
private float _TransPct;
public float TransPct {
get
{
return _TransPct;
}
set
{
Diag.X = Math.Max(0, (value - 1) * UIScreen.Current.ScreenWidth);
Diag.BodySize = new Vector2(Math.Min(1, value) * UIScreen.Current.ScreenWidth, UIScreen.Current.ScreenHeight).ToPoint();
Diag.DiagSide = (value <= 1) ? UIDiagonalStripeSide.RIGHT : UIDiagonalStripeSide.LEFT;
if (value == 1 && !FiredTransition)
{
FiredTransition = true;
GameThread.NextUpdate((u) =>
{
UIScreen.RemoveDialog(this);
TransAction();
UIScreen.GlobalShowDialog(this, true);
GameThread.NextUpdate((u2) =>
{
if (!UIScreen.Current.GetChildren().Contains(this))
{
DrawsSince = 0;
Parent = null;
UIScreen.GlobalShowDialog(this, true);
}
});
});
}
if (value == 2 && FiredTransition)
{
UIScreen.RemoveDialog(this);
}
_TransPct = value;
}
}
public bool FiredTransition = false;
private UIDiagonalStripe Diag;
private Texture2D TransImage;
private Action TransAction;
public UITransDialog(string transType, Action transAction)
{
var ui = Content.Get().CustomUI;
TransImage = ui.Get($"trans_{transType}.png").Get(GameFacade.GraphicsDevice);
TransAction = transAction;
Diag = new UIDiagonalStripe(new Point(0,0), UIDiagonalStripeSide.RIGHT, UIStyle.Current.TransColor);
Add(Diag);
UIScreen.GlobalShowDialog(this, true);
GameFacade.Screens.Tween.To(this, 0.2f, new Dictionary<string, float>() { { "TransPct", 1f } });
TransPct = TransPct;
}
public override void Removed()
{
base.Removed();
}
public int DrawsSince = 0;
public override void Draw(UISpriteBatch batch)
{
base.Draw(batch);
DrawLocalTexture(batch, TransImage, null,
new Vector2(UIScreen.Current.ScreenWidth - TransImage.Width, UIScreen.Current.ScreenHeight - TransImage.Height) / 2,
Vector2.One, Color.White * (1-Math.Abs(1-TransPct)));
if (FiredTransition && TransPct == 1)
{
if (DrawsSince++ == 2)
{
GameFacade.Screens.Tween.To(this, 0.2f, new Dictionary<string, float>() { { "TransPct", 2f } });
}
}
if (TransPct > 1) { }
}
}
}

View file

@ -23,10 +23,19 @@ namespace Simitone.Client.UI.Panels.WorldUI
{
Style = TextStyle.DefaultLabel.Clone();
Style.Size = 12;
var value = (int)(headline.Operand.Flags2 | (ushort)(headline.Operand.Duration << 16));
Text = (value > 0)?("§" + value):("-§"+ value);
var value = (int)(headline.Operand.Flags2 | (headline.Operand.Duration << 16));
if (value < -10000)
{
Text = (-10000-value).ToString();
Style.Color = Model.UIStyle.Current.SecondaryText;
}
else
{
Text = (value > 0) ? ("§" + value) : ("-§" + value);
Style.Color = Model.UIStyle.Current.Text;
}
var measure = Style.MeasureString(Text);
Style.Color = Model.UIStyle.Current.Text;
var GD = GameFacade.GraphicsDevice;
MoneyTarget = new RenderTarget2D(GD, (int)measure.X+10, (int)measure.Y+30);

View file

@ -14,6 +14,7 @@ using Simitone.Client.UI.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FSO.Common.Utils;
using FSO.SimAntics;
namespace Simitone.Client.UI.Screens
{
@ -94,6 +95,7 @@ namespace Simitone.Client.UI.Screens
(new Thread(() => {
FSO.Content.Content.Init(GlobalSettings.Default.StartupPath, GameFacade.GraphicsDevice);
VMContext.InitVMConfig();
lock (this)
{
LoadingComplete = true;

View file

@ -26,6 +26,11 @@ using FSO.Content.TS1;
using Simitone.Client.UI.Panels.CAS;
using Simitone.Client.UI.Controls;
using FSO.SimAntics.Model;
using FSO.Files.Formats.IFF.Chunks;
using Simitone.Client.UI.Panels;
using FSO.Client.UI.Controls;
using Simitone.Client.Utils;
using FSO.SimAntics.Utils;
namespace Simitone.Client.UI.Screens
{
@ -35,6 +40,7 @@ namespace Simitone.Client.UI.Screens
public FSO.SimAntics.VM vm { get; set; }
public VMNetDriver Driver;
public BasicCamera Cam;
public bool Initialized;
public VMAvatar[] HeadAvatars;
public VMAvatar[] BodyAvatars;
public List<string> ActiveHeads;
@ -42,16 +48,19 @@ namespace Simitone.Client.UI.Screens
public List<string> ActiveHeadTex;
public List<string> ActiveHandgroupTex;
public List<string> ActiveBodyTex;
public static int NeighTypeFrom = 4;
private bool Dead;
private float _FamilySimInterp;
private float _FamilySimInterp = -2;
public float FamilySimInterp
{
set
{
CameraInterp(value);
CASPanel.Position = new Vector2((ScreenWidth - 500) / 2, 10 - (282 * (1-value)));
CASPanel.Position = new Vector2((Cam == null)?10:((ScreenWidth - 500) / 2), 10 - (282 * (1-value)));
FamilyPanel.ShowI = 1-Math.Abs(value);
FamiliesPanel.TitleI = 1 - Math.Abs(value+1);
_FamilySimInterp = value;
}
@ -75,6 +84,8 @@ namespace Simitone.Client.UI.Screens
public string CurrentSkin = "lgt";
private bool CurrentChild;
private int? MoveInFamily;
private UICASMode Mode = UICASMode.FamilyEdit;
public List<CASFamilyMember> WIPFamily = new List<CASFamilyMember>();
@ -82,11 +93,13 @@ namespace Simitone.Client.UI.Screens
public UISimCASPanel CASPanel;
public UIFamilyCASPanel FamilyPanel;
public UIFamiliesCASPanel FamiliesPanel;
public UITwoStateButton BackButton;
public UITwoStateButton AcceptButton;
public Vector3[] ModePositions = new Vector3[]
{
new Vector3(177.3843f, 150.92333f, 3.25105f),
new Vector3(157.3843f, 28.92333f, 23.25105f),
new Vector3(119.5611f, 6.122346f, 104.0364f),
new Vector3(114.0793f, 10f, 64.67827f)
@ -94,13 +107,23 @@ namespace Simitone.Client.UI.Screens
public Vector3[] ModeTargets = new Vector3[]
{
new Vector3(177.3843f-7f, 130.92333f, 3.25105f+5f),
new Vector3(150.3057f, 26.01005f, 29.6858f),
new Vector3(111.7678f, 3.936443f, 98.164f),
new Vector3(104.5736f, 6.896059f, 64.59684f)
};
public Vector3[] Mode2D = new Vector3[]
{
new Vector3(104, 0, 57),
new Vector3(104, 0, 57),
new Vector3(103.5611f, 0, 92.0364f),
new Vector3(84.0793f+6, 0, 64f-6)
};
public Vector3[] SinTransitions = new Vector3[]
{
new Vector3(0, 0, 0),
new Vector3(12f, 0, 0),
new Vector3(-6f, 0, 0),
new Vector3()
@ -108,24 +131,44 @@ namespace Simitone.Client.UI.Screens
public void CameraInterp(float value)
{
if (value < -1) return;
var prev = (int)(value + 1);
var next = (int)(Math.Ceiling(value) + 1);
if (next > 2) next = 2;
if (value < -2) value = -2;
var prev = (int)(value + 2);
var next = (int)(Math.Ceiling(value) + 2);
if (next > 3) next = 3;
var pos1 = ModePositions[prev];
var pos2 = ModePositions[next];
var targ1 = ModeTargets[prev] - pos1;
var targ2 = ModeTargets[next] - pos2;
if (Cam == null)
{
//2d
var pos1 = Mode2D[prev];
var pos2 = Mode2D[next];
value = (float)DirectionUtils.PosMod(value, 1.0);
var camvec = Vector3.Lerp(targ1, targ2, value);
var campos = Vector3.Lerp(pos1, pos2, value);
if (World != null) World.State.PreciseZoom = 1 + Math.Min(0, value*0.5f);
value = (float)DirectionUtils.PosMod(value, 1.0);
var campos = Vector3.Lerp(pos1, pos2, value);
campos += (float)Math.Sin(value * Math.PI) * SinTransitions[prev];
campos += (float)Math.Sin(value * Math.PI) * SinTransitions[prev];
Cam.Position = campos;
Cam.Target = campos + camvec;
if (World != null)
World.State.CenterTile = new Vector2(campos.X, campos.Z) / 3f;
}
else
{
var pos1 = ModePositions[prev];
var pos2 = ModePositions[next];
var targ1 = ModeTargets[prev] - pos1;
var targ2 = ModeTargets[next] - pos2;
value = (float)DirectionUtils.PosMod(value, 1.0);
var camvec = Vector3.Lerp(targ1, targ2, value);
var campos = Vector3.Lerp(pos1, pos2, value);
campos += (float)Math.Sin(value * Math.PI) * SinTransitions[prev];
Cam.Position = campos;
Cam.Target = campos + camvec;
}
}
private void PopulateSimType(string simtype)
@ -135,8 +178,6 @@ namespace Simitone.Client.UI.Screens
if (simtype[1] == 'c') simtype += "chd";
var bodies = Content.Get().BCFGlobal.CollectionsByName["b"].ClothesByAvatarType[simtype];
//todo: search for textures
var tex = (TS1AvatarTextureProvider)Content.Get().AvatarTextures;
var texnames = tex.GetAllNames();
ActiveHeads = heads;
@ -207,7 +248,7 @@ namespace Simitone.Client.UI.Screens
var moving = 0;
if (state.MouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
if (state.MouseStates.Count > 0)
{
if (XLast == -1)
{
@ -396,6 +437,10 @@ namespace Simitone.Client.UI.Screens
FamilyPanel.ModifySim = ModifySim;
Add(FamilyPanel);
FamiliesPanel = new UIFamiliesCASPanel();
FamiliesPanel.OnNewFamily += () => { SetMode(UICASMode.FamilyEdit); };
Add(FamiliesPanel);
BackButton = new UITwoStateButton(ui.Get("btn_back.png").Get(gd));
BackButton.Position = new Vector2(25, ScreenHeight - 140);
Add(BackButton);
@ -462,7 +507,7 @@ namespace Simitone.Client.UI.Screens
}
for (int j = 0; j < 5; j++)
{
CASPanel.Personalities[j].Points = sim.Personality[j];
CASPanel.Personalities[j].Points = sim.Personality[j] / 100;
}
CurrentSkin = sim.SkinColor;
@ -492,6 +537,8 @@ namespace Simitone.Client.UI.Screens
CASPanel.UpdateType();
}
public UIMobileAlert ConfirmDialog;
private void Accept(UIElement button)
{
switch (Mode)
@ -503,9 +550,27 @@ namespace Simitone.Client.UI.Screens
case UICASMode.FamilyEdit:
//add or replace the family in the neighbourhood
//need to generate an actual FAMI and save it for this
if (ConfirmDialog == null)
{
ConfirmDialog = new UIMobileAlert(new UIAlertOptions()
{
Title = GameFacade.Strings.GetString("129", "13"),
Message = GameFacade.Strings.GetString("129", "14"),
Buttons = UIAlertButton.YesNo(
(ybtn) => { ConfirmDialog.Close(); Accept(ybtn); ConfirmDialog = null; },
(nbtn) => { ConfirmDialog.Close(); ConfirmDialog = null; }
)
});
UIScreen.GlobalShowDialog(ConfirmDialog, true);
return;
} else
{
SaveFamily();
}
break;
case UICASMode.FamilySelect:
//accept button here is move in. notify the neighbourhood screen that we're moving in now.
MoveInFamily = FamiliesPanel.Families[FamiliesPanel.Selection].ChunkID;
break;
}
SetMode((UICASMode)(((int)Mode) - 1));
@ -513,6 +578,27 @@ namespace Simitone.Client.UI.Screens
private void GoBack(UIElement button)
{
if (Mode == UICASMode.FamilyEdit)
{
if (ConfirmDialog == null)
{
ConfirmDialog = new UIMobileAlert(new UIAlertOptions()
{
Title = GameFacade.Strings.GetString("129", "7"),
Message = GameFacade.Strings.GetString("129", "8"),
Buttons = UIAlertButton.YesNo(
(ybtn) => { ConfirmDialog.Close(); GoBack(ybtn); ConfirmDialog = null; },
(nbtn) => { ConfirmDialog.Close(); ConfirmDialog = null; }
)
});
UIScreen.GlobalShowDialog(ConfirmDialog, true);
return;
}
else
{
ClearFamily();
}
}
SetMode((UICASMode)(((int)Mode) - 1));
}
@ -521,13 +607,25 @@ namespace Simitone.Client.UI.Screens
if (mode == UICASMode.ToNeighborhood)
{
//todo: animate into this
CleanupLastWorld();
Dead = true;
GameController.EnterGameMode("", false);
var dialog = new UITransDialog("normal", () => {
CleanupLastWorld();
if (MoveInFamily == null)
GameController.EnterGameMode("", false);
else
GameController.EnterGameMode("!"+((NeighTypeFrom == 7)?'m':'n')+MoveInFamily.Value.ToString(), false);
});
return;
} else if (mode == UICASMode.FamilyEdit)
{
FamilyPanel.Reset();
}
FamiliesPanel.SetSelection(-1);
if (mode == UICASMode.FamilySelect) AcceptButton.Texture = Content.Get().CustomUI.Get("btn_movein.png").Get(GameFacade.GraphicsDevice);
else AcceptButton.Texture = Content.Get().CustomUI.Get("btn_accept.png").Get(GameFacade.GraphicsDevice);
GameFacade.Screens.Tween.To(this, 1f, new Dictionary<string, float> { { "FamilySimInterp", (int)mode-1 } }, TweenQuad.EaseInOut);
Mode = mode;
}
@ -553,25 +651,48 @@ namespace Simitone.Client.UI.Screens
public override void Update(UpdateState state)
{
base.Update(state);
ModePositions[2].Y = 11;
ModeTargets[2].Y = 7.896059f;
ModePositions[3].Y = 11;
ModeTargets[3].Y = 7.896059f;
if (Dead) return;
if (vm == null) InitializeLot();
vm.Update();
if (World != null && Cam == null)
if (World != null && !Initialized)
{
var rcs = (WorldStateRC)(World.State);
Cam = (WorldCamera3D)rcs.Camera;
rcs.FixedCam = true;
rcs.CameraMode = true;
SetMode(UICASMode.FamilyEdit);
var rcs = (World.State as WorldStateRC);
if (rcs != null)
{
Cam = (WorldCamera3D)rcs.Camera;
rcs.FixedCam = true;
rcs.CameraMode = true;
}
SetMode(UICASMode.FamilySelect);
SetFamilies();
Initialized = true;
//FamilySimInterp = FamilySimInterp;
}
if (World.State.Level != 2)
if (World.State.PreciseZoom != 1) World.State.PreciseZoom = World.State.PreciseZoom;
switch (Mode)
{
World.State.Level = 2;
World.State.DrawRoofs = true;
case UICASMode.FamilySelect:
if (World.State.Level != 2)
{
World.State.Level = 2;
World.State.DrawRoofs = true;
vm.Context.Blueprint.Cutaway = new bool[vm.Context.Blueprint.Cutaway.Length];
vm.Context.Blueprint.Damage.Add(new FSO.LotView.Model.BlueprintDamage(FSO.LotView.Model.BlueprintDamageType.WALL_CUT_CHANGED));
}
break;
default:
if (World.State.Level != 1 && Cam == null)
{
World.State.Level = 1;
World.State.DrawRoofs = false;
vm.Context.Blueprint.Cutaway = VMArchitectureTools.GenerateRoomCut(vm.Context.Architecture, World.State.Level, World.State.CutRotation,
new HashSet<uint>(vm.Context.RoomInfo.Where(x => x.Room.IsOutside == false).Select(x => (uint)x.Room.RoomID)));
vm.Context.Blueprint.Damage.Add(new FSO.LotView.Model.BlueprintDamage(FSO.LotView.Model.BlueprintDamageType.WALL_CUT_CHANGED));
}
break;
}
vm.Context.Clock.Minutes = 0;
@ -588,11 +709,17 @@ namespace Simitone.Client.UI.Screens
case UICASMode.SimEdit:
if (CASPanel.FirstNameTextBox.CurrentText.Length == 0) disableAccept = true;
break;
case UICASMode.FamilySelect:
if (FamiliesPanel.Selection == -1) disableAccept = true;
break;
case UICASMode.FamilyEdit:
if (WIPFamily.Count == 0) disableAccept = true;
break;
}
AcceptButton.Disabled = disableAccept;
AcceptButton.ForceState = disableAccept ? 0 : -1;
AcceptButton.Opacity = disableAccept ? 0.5f : 1;
//AcceptButton.ForceState = disableAccept ? 0 : -1;
//AcceptButton.Opacity = disableAccept ? 0.5f : 1;
if (Mode == UICASMode.SimEdit)
UpdateCarousel(state);
@ -631,6 +758,15 @@ namespace Simitone.Client.UI.Screens
}
}
public void SetFamilies()
{
//get all families that don't have a house from neighbourhood, and populate the list
//i think house number -1 is townies, so only select 0
var all = Content.Get().Neighborhood.MainResource.List<FAMI>();
var families = all.Where(x => (x.Unknown & 16) > 0 && x.HouseNumber == 0);
FamiliesPanel.UpdateFamilies(families.ToList(), vm);
}
public void SetFamilyMember(int index)
{
if (RepresentFamily.Count <= index)
@ -684,6 +820,46 @@ namespace Simitone.Client.UI.Screens
fam.HeadOutfit = new FSO.SimAntics.Model.VMOutfitReference(new Outfit() { TS1AppearanceID = data.Head+".apr", TS1TextureID = data.HeadTex });
}
private SimTemplateCreateInfo CASToNeighGen(CASFamilyMember x)
{
var code = ((x.Gender & 1) == 0) ? "m" : "f";
code += (x.Gender > 1) ? "c" : "a";
var ind = x.Body.IndexOf("_");
var bodyType = x.Body.Substring(ind - 3, 3);
code += bodyType;
var info = new SimTemplateCreateInfo(code, x.SkinColor);
info.Name = x.Name;
info.Bio = x.Bio;
info.PersonalityPoints = x.Personality;
info.BodyStringReplace[1] = x.Body + ",BODY=" + x.BodyTex;
info.BodyStringReplace[2] = x.Head + ",HEAD-HEAD=" + x.HeadTex;
var hand = (x.Gender > 1) ? "u" : ((x.Gender == 0) ? "m" : "f");
info.BodyStringReplace[17] = "H" + hand + "LO,HAND=" + "huao" + x.HandgroupTex;
info.BodyStringReplace[18] = "H" + hand + "RO,HAND=" + "huao" + x.HandgroupTex;
info.BodyStringReplace[19] = "H" + hand + "LP,HAND=" + "huao" + x.HandgroupTex;
info.BodyStringReplace[20] = "H" + hand + "RP,HAND=" + "huao" + x.HandgroupTex;
info.BodyStringReplace[21] = "H" + hand + "LO,HAND=" + "huao" + x.HandgroupTex;
info.BodyStringReplace[22] = "H" + hand + "RC,HAND=" + "huao" + x.HandgroupTex;
return info;
}
public void ClearFamily()
{
var count = WIPFamily.Count;
FamilyPanel.SecondName.CurrentText = "";
for (int i = count-1; i >= 0; i--)
ModifySim(true, i);
}
public void SaveFamily()
{
SimitoneNeighbourGenerator.CreateFamily(FamilyPanel.SecondName.CurrentText, WIPFamily.Count, WIPFamily.Select(CASToNeighGen).ToArray());
SetFamilies();
ClearFamily();
}
public void AcceptMember()
{
var mem = BuildMember();
@ -713,7 +889,7 @@ namespace Simitone.Client.UI.Screens
Head = ActiveHeads[j],
HeadTex = ActiveHeadTex[j],
Gender = (short)(((CurrentCode[0] == 'm') ? 0 : 1) | ((CurrentCode[1] == 'c') ? 2 : 0)),
Personality = CASPanel.Personalities.Select(x => (short)x.Points).ToArray(),
Personality = CASPanel.Personalities.Select(x => (short)(x.Points * 100)).ToArray(),
SkinColor = CurrentSkin
};
return sim;
@ -746,7 +922,6 @@ namespace Simitone.Client.UI.Screens
//clear our cache too, if the setting lets us do that
TimedReferenceController.Clear();
TimedReferenceController.Clear();
VM.ClearAssembled();
vm.Context.Ambience.Kill();
foreach (var ent in vm.Entities)
@ -802,13 +977,11 @@ namespace Simitone.Client.UI.Screens
vm.Tick();
vm.Context.Clock.Hours = 12;
vm.TSOState.Size = (10) | (3 << 8);
vm.Context.UpdateTSOBuildableArea();
vm.MyUID = 1;
vm.MyUID = uint.MaxValue;
var settings = GlobalSettings.Default;
var myClient = new VMNetClient
{
PersistID = 1,
PersistID = uint.MaxValue,
RemoteIP = "local",
AvatarState = new VMNetAvatarPersistState()
{
@ -816,7 +989,7 @@ namespace Simitone.Client.UI.Screens
DefaultSuits = new VMAvatarDefaultSuits(settings.DebugGender),
BodyOutfit = settings.DebugBody,
HeadOutfit = settings.DebugHead,
PersistID = 1,
PersistID = uint.MaxValue,
SkinTone = (byte)settings.DebugSkin,
Gender = (short)(settings.DebugGender ? 1 : 0),
Permissions = FSO.SimAntics.Model.TSOPlatform.VMTSOAvatarPermissions.Admin,

View file

@ -8,19 +8,24 @@ using FSO.Common;
using FSO.Common.Rendering.Framework;
using FSO.Common.Utils;
using FSO.Content;
using FSO.Files.Formats.IFF;
using FSO.Files.Formats.IFF.Chunks;
using FSO.Files.RC;
using FSO.HIT;
using FSO.LotView;
using FSO.SimAntics;
using FSO.SimAntics.Engine.TSOTransaction;
using FSO.SimAntics.Marshals;
using FSO.SimAntics.Model;
using FSO.SimAntics.NetPlay;
using FSO.SimAntics.NetPlay.Drivers;
using FSO.SimAntics.NetPlay.Model;
using FSO.SimAntics.NetPlay.Model.Commands;
using FSO.SimAntics.Utils;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Simitone.Client.UI.Controls;
using Simitone.Client.UI.Panels;
using Simitone.Client.UI.Panels.WorldUI;
using System;
@ -37,7 +42,7 @@ namespace Simitone.Client.UI.Screens
public UIContainer WindowContainer;
public bool Downtown;
public UILotControl LotControl { get; set; }
public UILotControl LotControl { get; set; }
public UISimitoneFrontend Frontend { get; set; }
private FSO.LotView.World World;
public FSO.SimAntics.VM vm { get; set; }
@ -163,7 +168,7 @@ namespace Simitone.Client.UI.Screens
}
}
public TS1GameScreen() : base()
public TS1GameScreen(NeighSelectionMode mode) : base()
{
Bg = new UISimitoneBg();
Bg.Position = (new Vector2(ScreenWidth, ScreenHeight)) / 2;
@ -174,25 +179,74 @@ namespace Simitone.Client.UI.Screens
if (Content.Get().TS1)
{
NeighSelection();
NeighSelection(mode);
}
}
public int? MoveInFamily;
public void NeighSelection()
public void StartMoveIn(int familyID)
{
TS1NeighPanel = new UINeighborhoodSelectionPanel(4);
var switcher = new UINeighbourhoodSwitcher(TS1NeighPanel, 4);
MoveInFamily = familyID;
}
public void NeighSelection(NeighSelectionMode mode)
{
var nbd = (ushort)((mode == NeighSelectionMode.MoveInMagic) ? 7 : 4);
TS1NeighPanel = new UINeighborhoodSelectionPanel(nbd);
var switcher = new UINeighbourhoodSwitcher(TS1NeighPanel, nbd, mode != NeighSelectionMode.Normal);
TS1NeighPanel.OnHouseSelect += (house) =>
{
ActiveFamily = Content.Get().Neighborhood.GetFamilyForHouse((short)house);
InitializeLot(Path.Combine(FSOEnvironment.UserDir, "UserData/Houses/House" + house.ToString().PadLeft(2, '0') + ".iff"), false);// "UserData/Houses/House21.iff"
Remove(TS1NeighPanel);
Remove(switcher);
if (MoveInFamily != null)
{
//move them in first
//confirm it
UIMobileAlert confirmDialog = null;
confirmDialog = new UIMobileAlert(new UIAlertOptions()
{
Title = GameFacade.Strings.GetString("132", "0"),
Message = GameFacade.Strings.GetString("132", "1"),
Buttons = UIAlertButton.YesNo((b) =>
{
confirmDialog.Close();
MoveInAndPlay((short)house, MoveInFamily.Value, switcher);
},
(b) => confirmDialog.Close())
});
UIScreen.GlobalShowDialog(confirmDialog, true);
}
else
{
PlayHouse((short)house, switcher);
}
};
Add(TS1NeighPanel);
Add(switcher);
}
public void PlayHouse(short house, UIElement switcher)
{
ActiveFamily = Content.Get().Neighborhood.GetFamilyForHouse((short)house);
InitializeLot(Content.Get().Neighborhood.GetHousePath(house), false);// "UserData/Houses/House21.iff"
Remove(TS1NeighPanel);
if (switcher != null) Remove(switcher);
}
public void MoveInAndPlay(short house, int family, UIElement switcher)
{
var neigh = Content.Get().Neighborhood;
var fami = neigh.GetFamily((ushort)family);
neigh.SetFamilyForHouse(house, fami, true);
PlayHouse(house, switcher);
}
public void EvictLot(FAMI family, short houseID)
{
family.Budget += family.ValueInArch;
family.ValueInArch = 0;
Content.Get().Neighborhood.MoveOut(houseID);
TS1NeighPanel.SelectHouse(houseID);
}
public override void GameResized()
{
base.GameResized();
@ -284,9 +338,9 @@ namespace Simitone.Client.UI.Screens
GameFacade.Game.IsMouseVisible = Visible;
base.Update(state);
if (state.NewKeys.Contains(Keys.NumPad1)) ChangeSpeedTo(1);
if (state.NewKeys.Contains(Keys.NumPad2)) ChangeSpeedTo(2);
if (state.NewKeys.Contains(Keys.NumPad3)) ChangeSpeedTo(3);
if (state.NewKeys.Contains(Keys.D1)) ChangeSpeedTo(1);
if (state.NewKeys.Contains(Keys.D2)) ChangeSpeedTo(2);
if (state.NewKeys.Contains(Keys.D3)) ChangeSpeedTo(3);
if (state.NewKeys.Contains(Keys.P)) ChangeSpeedTo(0);
if (World != null)
@ -306,7 +360,7 @@ namespace Simitone.Client.UI.Screens
else
{
Downtown = true;
InitializeLot(Path.Combine(Content.Get().TS1BasePath, "UserData/Houses/House" + SwitchLot.ToString().PadLeft(2, '0') + ".iff"), false);
InitializeLot(Content.Get().Neighborhood.GetHousePath(SwitchLot), false);
}
SwitchLot = -1;
}
@ -329,7 +383,6 @@ namespace Simitone.Client.UI.Screens
//clear our cache too, if the setting lets us do that
TimedReferenceController.Clear();
TimedReferenceController.Clear();
VM.ClearAssembled();
if (ZoomLevel < 4) ZoomLevel = 5;
vm.Context.Ambience.Kill();
@ -401,15 +454,15 @@ namespace Simitone.Client.UI.Screens
public void InitializeLot(VMMarshal marshal)
{
InitializeLot();
vm.MyUID = 1;
vm.MyUID = uint.MaxValue;
vm.Load(marshal);
vm.ActivateFamily(ActiveFamily);
vm.TS1State.ActivateFamily(vm, ActiveFamily);
var settings = GlobalSettings.Default;
var myClient = new VMNetClient
{
PersistID = 1,
PersistID = uint.MaxValue,
RemoteIP = "local",
AvatarState = new VMNetAvatarPersistState()
{
@ -417,7 +470,7 @@ namespace Simitone.Client.UI.Screens
DefaultSuits = new VMAvatarDefaultSuits(settings.DebugGender),
BodyOutfit = settings.DebugBody,
HeadOutfit = settings.DebugHead,
PersistID = 1,
PersistID = uint.MaxValue,
SkinTone = (byte)settings.DebugSkin,
Gender = (short)(settings.DebugGender ? 1 : 0),
Permissions = FSO.SimAntics.Model.TSOPlatform.VMTSOAvatarPermissions.Admin,
@ -438,7 +491,7 @@ namespace Simitone.Client.UI.Screens
public void InitializeLot(string lotName, bool external)
{
if (lotName == "") return;
if (lotName == "" || lotName[0] == '!') return;
InitializeLot();
if (!external)
@ -446,17 +499,15 @@ namespace Simitone.Client.UI.Screens
if (!Downtown && ActiveFamily != null)
{
ActiveFamily.SelectWholeFamily();
vm.ActivateFamily(ActiveFamily);
vm.TS1State.ActivateFamily(vm, ActiveFamily);
}
BlueprintReset(lotName);
BlueprintReset(lotName, null);
vm.TSOState.Size = (10) | (3 << 8);
vm.Context.UpdateTSOBuildableArea();
vm.MyUID = 1;
vm.MyUID = uint.MaxValue;
var settings = GlobalSettings.Default;
var myClient = new VMNetClient
{
PersistID = 1,
PersistID = uint.MaxValue,
RemoteIP = "local",
AvatarState = new VMNetAvatarPersistState()
{
@ -464,17 +515,36 @@ namespace Simitone.Client.UI.Screens
DefaultSuits = new VMAvatarDefaultSuits(settings.DebugGender),
BodyOutfit = settings.DebugBody,
HeadOutfit = settings.DebugHead,
PersistID = 1,
PersistID = uint.MaxValue,
SkinTone = (byte)settings.DebugSkin,
Gender = (short)(settings.DebugGender ? 1 : 0),
Permissions = FSO.SimAntics.Model.TSOPlatform.VMTSOAvatarPermissions.Admin,
Budget = 1000000
}
};
if (Downtown)
{
var ngbh = Content.Get().Neighborhood;
var crossData = ngbh.GameState;
var neigh = ngbh.GetNeighborIDForGUID(crossData.DowntownSimGUID);
if (neigh != null) {
var inv = ngbh.GetInventoryByNID(neigh.Value);
if (inv != null) {
var hr = inv.FirstOrDefault(x => x.Type == 2 && x.GUID == 7)?.Count ?? 0;
var min = inv.FirstOrDefault(x => x.Type == 2 && x.GUID == 8)?.Count ?? 0;
Driver.SendCommand(new VMNetSetTimeCmd()
{
Hours = hr,
Minutes = min,
});
}
}
}
var server = (VMServerDriver)Driver;
server.ConnectClient(myClient);
LoadSurrounding(short.Parse(lotName.Substring(lotName.Length - 6, 2)));
GameFacade.Cursor.SetCursor(CursorType.Normal);
ZoomLevel = 1;
@ -484,9 +554,48 @@ namespace Simitone.Client.UI.Screens
this.Add(Frontend);
}
public void BlueprintReset(string path)
public void LoadSurrounding(short houseID)
{
return;
var surrounding = new NBHm(new OBJ(File.OpenRead(@"C:\Users\Rhys\Desktop\nb2.obj")));
NBHmHouse myH = null;
var myHeight = vm.Context.Blueprint.InterpAltitude(new Vector3(0, 0, 0));
if (!surrounding.Houses.TryGetValue(houseID, out myH)) return;
foreach (var house in surrounding.Houses)
{
if (house.Key == houseID) continue;
var h = house.Value;
//let's make their lot as a surrounding lot
var gd = World.State.Device;
var subworld = World.MakeSubWorld(gd);
subworld.Initialize(gd);
var tempVM = new VM(new VMContext(subworld), new VMServerDriver(new VMTSOGlobalLinkStub()), new VMNullHeadlineProvider());
tempVM.Init();
BlueprintReset(Content.Get().Neighborhood.GetHousePath(house.Key), tempVM);
subworld.State.Level = 5;
var subHeight = tempVM.Context.Blueprint.InterpAltitude(new Vector3(0, 0, 0));
tempVM.Context.Blueprint.BaseAlt = (int)Math.Round(((subHeight - myHeight) + myH.Position.Y - h.Position.Y) / tempVM.Context.Blueprint.TerrainFactor);
subworld.GlobalPosition = new Vector2((myH.Position.X - h.Position.X), (myH.Position.Z - h.Position.Z));
foreach (var obj in tempVM.Entities)
{
obj.Position = obj.Position;
}
vm.Context.Blueprint.SubWorlds.Add(subworld);
}
vm.Context.World.InitSubWorlds();
}
public void BlueprintReset(string path, VM vm)
{
string filename = Path.GetFileName(path);
bool isSurrounding = true;
if (vm == null)
{
isSurrounding = false;
vm = this.vm;
}
try
{
using (var file = new BinaryReader(File.OpenRead(Path.Combine(FSOEnvironment.UserDir, "LocalHouse/") + filename.Substring(0, filename.Length - 4) + ".fsov")))
@ -527,9 +636,11 @@ namespace Simitone.Client.UI.Screens
});
}
vm.SpeedMultiplier = -1;
vm.Tick();
vm.SpeedMultiplier = 1;
if (ActiveFamily == null)
if (ActiveFamily == null && !isSurrounding)
{
vm.SetGlobalValue(32, 1);
vm.SpeedMultiplier = -1;
@ -539,7 +650,12 @@ namespace Simitone.Client.UI.Screens
private void Vm_OnGenericVMEvent(VMEventType type, object data)
{
//hmm...
switch (type)
{
case VMEventType.TS1BuildBuyChange:
Frontend.ModeSwitcher.UpdateBuildBuy();
break;
}
}
private void VMLotSwitch(uint lotId)
@ -626,13 +742,74 @@ namespace Simitone.Client.UI.Screens
public void Save()
{
//save the house first
var iff = new IffFile();
vm.TS1State.UpdateSIMI(vm);
var marshal = vm.Save();
var fsov = new FSOV();
fsov.ChunkLabel = "Simitone Lot Data";
fsov.ChunkID = 1;
fsov.ChunkProcessed = true;
fsov.ChunkType = "FSOV";
fsov.AddedByPatch = true;
using (var stream = new MemoryStream())
{
marshal.SerializeInto(new BinaryWriter(stream));
fsov.Data = stream.ToArray();
}
iff.AddChunk(fsov);
var simi = vm.TS1State.SimulationInfo;
simi.ChunkProcessed = true;
simi.AddedByPatch = true;
iff.AddChunk(simi);
Texture2D roofless = null;
var thumb = World.GetLotThumb(GameFacade.GraphicsDevice, (tex) => roofless = FSO.Common.Utils.TextureUtils.Decimate(tex, GameFacade.GraphicsDevice, 2, false));
thumb = FSO.Common.Utils.TextureUtils.Decimate(thumb, GameFacade.GraphicsDevice, 2, false);
var tPNG = GeneratePNG(thumb);
tPNG.ChunkID = 513;
iff.AddChunk(tPNG);
var rPNG = GeneratePNG(roofless);
rPNG.ChunkID = 512;
iff.AddChunk(rPNG);
Content.Get().Neighborhood.SaveHouse(vm.GetGlobalValue(10), iff);
Content.Get().Neighborhood.SaveNeighbourhood(true);
}
public PNG GeneratePNG(Texture2D data)
{
var png = new PNG();
using (var stream = new MemoryStream())
{
data.SaveAsPng(stream, data.Width, data.Height);
png.data = stream.ToArray();
}
png.ChunkLabel = "Lot Thumbnail";
png.ChunkProcessed = true;
png.ChunkType = "PNG_";
png.AddedByPatch = true;
return png;
}
public void ExitLot()
{
CleanupLastWorld();
NeighSelection();
NeighSelection(NeighSelectionMode.Normal);
}
}
public enum NeighSelectionMode
{
Normal,
MoveIn,
MoveInMagic
}
}

View file

@ -0,0 +1,218 @@
using FSO.Client;
using FSO.Common;
using FSO.Content;
using FSO.Files.Formats.IFF.Chunks;
using FSO.LotView;
using FSO.LotView.Facade;
using FSO.LotView.RC;
using FSO.SimAntics;
using FSO.SimAntics.Engine.TSOTransaction;
using FSO.SimAntics.NetPlay.Drivers;
using FSO.SimAntics.Utils;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Simitone.Client.UI.Panels.WorldUI;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simitone.Client.Utils
{
/// <summary>
/// Exports the entire neighbourhood in *.obj format
/// </summary>
public static class SimitoneNeighOBJExporter
{
public static void SaveOBJ(string destPath, STR locations)
{
var exportedFlr = new HashSet<ushort>();
var gd = GameFacade.GraphicsDevice;
var mtlBuilder = new StringBuilder();
Directory.CreateDirectory(destPath);
//var mtlMem = new MemoryStream();
//var mtlIO = new StreamWriter(mtlMem);
var mtlIO = new StreamWriter(new FileStream(Path.Combine(destPath, "neighbourhood.mtl"), FileMode.Create, FileAccess.Write, FileShare.None));
var path = Path.Combine(destPath, "neighbourhood.obj");
var filename = Path.GetFileNameWithoutExtension(path);
using (var io = new StreamWriter(new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)))
{
io.WriteLine("# Generated by the Simitone Neighbourhood Exporter.");
io.WriteLine("# The purpose is to allow users to mesh neighbourhood surroundings using");
io.WriteLine("# the projected physical positions and terrain profiles of lots as a starting point.");
io.WriteLine("mtllib neighbourhood.mtl");
io.WriteLine("s 1");
int indCount = 1;
for (int i = 0; i < locations.Length; i++)
{
var loc = locations.GetString(i).Split(',');
var num = int.Parse(loc[0].TrimStart());
var pos2d = new Vector2(int.Parse(loc[1].TrimStart()), int.Parse(loc[2].TrimStart()));
var house = Content.Get().Neighborhood.GetHouse(num);
World world;
if (FSOEnvironment.Enable3D)
{
world = new FSO.LotView.RC.WorldRC(GameFacade.GraphicsDevice);
}
else
{
world = new FSO.LotView.World(GameFacade.GraphicsDevice);
}
world.Opacity = 1;
GameFacade.Scenes.Add(world);
var globalLink = new VMTS1GlobalLinkStub();
var driver = new VMServerDriver(globalLink);
var vm = new VM(new VMContext(world), driver, new UIHeadlineRendererProvider());
vm.ListenBHAVChanges();
vm.Init();
vm.SetGlobalValue(11, (short)num);
var activator = new VMTS1Activator(vm, vm.Context.World, (short)num);
var blueprint = activator.LoadFromIff(house);
var floorVerts = blueprint.Terrain.GetVertices(gd);
blueprint.FloorGeom.FullReset(gd, false);
var groundfloor = blueprint.FloorGeom.Floors[0];
//we need to calculate the
var minHeight = int.MaxValue;
var heights = vm.Context.Architecture.Terrain.Heights;
for (int j=0; j<heights.Length; j++)
{
if ((j % blueprint.Width) == 0 || (j % blueprint.Width) == blueprint.Width - 1 || j < blueprint.Width || j >= (blueprint.Height - 1) * blueprint.Width)
continue;
var h = heights[j];
if (h != 0 && h < minHeight) minHeight = h;
}
if (minHeight == int.MaxValue) minHeight = 0;
var scale = (locations.Length > 30 ? 1f : 2f) * 1.4142135623730950488016887242097f;
var baseV = new Vector3(pos2d.X + pos2d.Y * 2, 0, pos2d.Y * 2 - pos2d.X) / scale;
baseV.Y -= (minHeight * 3 / 160f) * 3;
var ctr = blueprint.GetFineBounds().Location.ToVector2() + blueprint.GetFineBounds().Size.ToVector2() / 2;
var voff = baseV + new Vector3(ctr.X, 0, ctr.Y) * 3f / -1;
voff.X = (int)(voff.X / 3) * 3;
voff.Z = (int)(voff.Z / 3) * 3;
SetOutsideTime(GameFacade.GraphicsDevice, vm, world, 0.5f, false);
world.State.PrepareLighting();
var facade = new LotFacadeGenerator();
facade.FLOOR_TILES = blueprint.Width;
facade.GROUND_SUBDIV = blueprint.Width;
facade.FLOOR_RES_PER_TILE = 4;
facade.LotName = "p"+num.ToString();
facade.Generate(GameFacade.GraphicsDevice, (WorldRC)world, blueprint);
facade.AppendOBJ(io, filename, indCount, voff / 3);
facade.AppendMTL(mtlIO, Path.GetDirectoryName(path));
indCount = facade.LastIndex;
/*
foreach (var group in groundfloor.GroupForTileType)
{
if (!exportedFlr.Contains(group.Key) && group.Key != 0 && group.Key < 65000)
{
//get and export this floor's texture. add it as a material as well.
var floor = Content.Get().WorldFloors.Get(group.Key).Near.Frames[0].GetTexture(gd);
using (var flrStream = new FileStream(Path.Combine(destPath, "flr_" + group.Key + ".png"), FileMode.Create, FileAccess.Write, FileShare.None))
floor.SaveAsPng(flrStream, floor.Width, floor.Height);
//add as material
GenerateMTL("flr_" + group.Key, mtlBuilder);
}
//write out verts and indices.
var indices = group.Value.BuildIndexData();
var done = new Dictionary<int, int>(); //index remap
if (group.Key == 0)
{
//grass... export as grass colour
io.WriteLine("usemtl " + "grass");
io.WriteLine("o " + "lot_" + num + "_grass");
}
else
{
//export with floor textured material
io.WriteLine("usemtl " + "flr_" + group.Key);
io.WriteLine("o " + "lot_" + num + "_" + group.Key);
}
var indexStr = new StringBuilder();
indexStr.Append("f ");
for (int j = 0; j < indices.Length; j++)
{
var index = indices[j];
int remapped = index;
if (!done.TryGetValue(index, out remapped))
{
remapped = indCount;
done.Add(index, indCount++);
//append a vertex
var vert = floorVerts[index];
vert.Position += voff;
io.Write("v " + vert.Position.X.ToString(CultureInfo.InvariantCulture) + " " + vert.Position.Y.ToString(CultureInfo.InvariantCulture) + " " + vert.Position.Z.ToString(CultureInfo.InvariantCulture));
io.WriteLine((group.Key == 0) ? " " + vert.Color.X.ToString(CultureInfo.InvariantCulture) + " " + vert.Color.Y.ToString(CultureInfo.InvariantCulture) + " " + vert.Color.Z.ToString(CultureInfo.InvariantCulture) : "");
io.WriteLine("vt " + vert.GrassInfo.Y.ToString(CultureInfo.InvariantCulture) + " " + (1 - vert.GrassInfo.Z).ToString(CultureInfo.InvariantCulture));
}
indexStr.Append(remapped + "/" + remapped);
if (j % 3 == 2)
{
indexStr.AppendLine();
if (j != indices.Length - 1) indexStr.Append("f ");
}
else indexStr.Append(" ");
}
io.WriteLine(indexStr);
}
*/
GameFacade.Scenes.Remove(world);
world.Dispose();
}
}
mtlIO.Close();
}
private static void SetOutsideTime(GraphicsDevice gd, VM vm, World world, float time, bool lightsOn)
{
vm.Context.Architecture.SetTimeOfDay(time);
world.Force2DPredraw(gd);
vm.Context.Architecture.SetTimeOfDay();
}
private static void GenerateMTL(string oname, StringBuilder str)
{
str.AppendLine("newmtl " + oname);
str.AppendLine("Ka 1.000 1.000 1.000");
str.AppendLine("Kd 1.000 1.000 1.000");
str.AppendLine("Ks 0.000 0.000 0.000");
str.AppendLine("Ns 10.0000");
str.AppendLine("illum 2");
str.AppendLine("map_Kd " + oname + ".png");
str.AppendLine("map_d " + oname + ".png");
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View file

@ -24,7 +24,7 @@ namespace Simitone.Windows
{
var gameLocator = new WindowsLocator();
var useDX = false;
var useDX = true;
var path = gameLocator.FindTheSimsOnline();
if (useDX) GlobalSettings.Default.AntiAlias = false;

View file

@ -51,6 +51,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.bmp">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<Content Include="Icon.ico" />
</ItemGroup>
<ItemGroup>
@ -58,9 +61,9 @@
<Project>{6d6009f4-0afb-4806-89d7-7945f20270f5}</Project>
<Name>MonoGame.Framework.Net.WindowsGL</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\MonoGame.Framework\MonoGame.Framework.WindowsGL.csproj">
<Project>{6d75e618-19ca-4c51-9546-f10965fbc0b8}</Project>
<Name>MonoGame.Framework.WindowsGL</Name>
<ProjectReference Include="..\..\..\FreeSO\Other\libs\FSOMonoGame\MonoGame.Framework\MonoGame.Framework.Windows.csproj">
<Project>{7de47032-a904-4c29-bd22-2d235e8d91ba}</Project>
<Name>MonoGame.Framework.Windows</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\FreeSO\Other\libs\mp3sharp\mp3sharp\Mp3Sharp.csproj">
<Project>{834cab58-648d-47cc-ac6f-d01c08c809a4}</Project>
@ -99,6 +102,9 @@
<Name>Simitone.Client</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Content.Builder.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MonoGame.Framework.WindowsDX" version="3.6.0.1625" targetFramework="net45" />
</packages>

View file

@ -445,8 +445,8 @@ Global
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.AppStore|x86.ActiveCfg = Release|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.AppStore|x86.Build.0 = Release|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|Any CPU.Build.0 = Release|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|iPhone.Build.0 = Debug|Any CPU
{7DE47032-A904-4C29-BD22-2D235E8D91BA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
@ -477,8 +477,8 @@ Global
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.AppStore|x86.ActiveCfg = Release|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.AppStore|x86.Build.0 = Release|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.Debug|Any CPU.Build.0 = Release|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.Debug|iPhone.Build.0 = Debug|Any CPU
{6D6009F4-0AFB-4806-89D7-7945F20270F5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
@ -629,8 +629,8 @@ Global
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.AppStore|x86.ActiveCfg = Release|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.AppStore|x86.Build.0 = Release|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.Debug|Any CPU.Build.0 = Release|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.Debug|iPhone.Build.0 = Debug|Any CPU
{6D75E618-19CA-4C51-9546-F10965FBC0B8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
@ -661,8 +661,8 @@ Global
{AE483C29-042E-4226-BA52-D247CE7676DA}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.AppStore|x86.ActiveCfg = Release|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.AppStore|x86.Build.0 = Release|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.Build.0 = Release|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|iPhone.Build.0 = Debug|Any CPU
{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU

2
FreeSO

@ -1 +1 @@
Subproject commit 6385ba5cf5025b27b952b5e8a585bacf0af7af00
Subproject commit b23f16c4de1792363bc25d94a4d34dc787d39899