start of update
This commit is contained in:
parent
d4bd862b04
commit
f7bc8738d1
38 changed files with 2001 additions and 3398 deletions
36
Android/.config/dotnet-tools.json
Normal file
36
Android/.config/dotnet-tools.json
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"dotnet-mgcb": {
|
||||||
|
"version": "3.8.1.303",
|
||||||
|
"commands": [
|
||||||
|
"mgcb"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dotnet-mgcb-editor": {
|
||||||
|
"version": "3.8.1.303",
|
||||||
|
"commands": [
|
||||||
|
"mgcb-editor"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dotnet-mgcb-editor-linux": {
|
||||||
|
"version": "3.8.1.303",
|
||||||
|
"commands": [
|
||||||
|
"mgcb-editor-linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dotnet-mgcb-editor-windows": {
|
||||||
|
"version": "3.8.1.303",
|
||||||
|
"commands": [
|
||||||
|
"mgcb-editor-windows"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dotnet-mgcb-editor-mac": {
|
||||||
|
"version": "3.8.1.303",
|
||||||
|
"commands": [
|
||||||
|
"mgcb-editor-mac"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,95 +1,95 @@
|
||||||
using System;
|
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Content.PM;
|
using Android.Content.PM;
|
||||||
using Android.Gms.Common;
|
|
||||||
using Android.Gms.Games;
|
using Android.Gms.Games;
|
||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using GameAnalyticsSDK;
|
using GameAnalyticsSDK;
|
||||||
|
using Java.Lang;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
using MLEM.Extensions;
|
using MLEM.Extensions;
|
||||||
using MLEM.Misc;
|
using MLEM.Misc;
|
||||||
using TouchyTickets;
|
using TouchyTickets;
|
||||||
using static Android.Views.SystemUiFlags;
|
using static Android.Views.ViewGroup;
|
||||||
using static Android.Views.ViewGroup.LayoutParams;
|
|
||||||
using Uri = Android.Net.Uri;
|
using Uri = Android.Net.Uri;
|
||||||
|
|
||||||
namespace Android {
|
namespace Android;
|
||||||
[Activity(
|
|
||||||
Label = "@string/app_name",
|
|
||||||
MainLauncher = true,
|
|
||||||
Icon = "@drawable/icon",
|
|
||||||
AlwaysRetainTaskState = true,
|
|
||||||
LaunchMode = LaunchMode.SingleInstance,
|
|
||||||
ScreenOrientation = ScreenOrientation.UserPortrait,
|
|
||||||
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize
|
|
||||||
)]
|
|
||||||
public class Activity1 : AndroidGameActivity {
|
|
||||||
|
|
||||||
private GameImpl game;
|
[Activity(
|
||||||
private AndroidPlatform platform;
|
Label = "@string/app_name",
|
||||||
private LinearLayout mainView;
|
MainLauncher = true,
|
||||||
|
Icon = "@drawable/icon",
|
||||||
|
AlwaysRetainTaskState = true,
|
||||||
|
LaunchMode = LaunchMode.SingleInstance,
|
||||||
|
ScreenOrientation = ScreenOrientation.UserPortrait,
|
||||||
|
ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize
|
||||||
|
)]
|
||||||
|
public class Activity1 : AndroidGameActivity {
|
||||||
|
|
||||||
protected override void OnCreate(Bundle bundle) {
|
private GameImpl game;
|
||||||
base.OnCreate(bundle);
|
private AndroidPlatform platform;
|
||||||
|
private LinearLayout mainView;
|
||||||
|
|
||||||
// ad layout
|
protected override void OnCreate(Bundle bundle) {
|
||||||
var adLayout = new LinearLayout(this) {Orientation = Orientation.Vertical};
|
base.OnCreate(bundle);
|
||||||
adLayout.SetGravity(GravityFlags.Bottom);
|
|
||||||
|
|
||||||
// set up the game
|
// ad layout
|
||||||
MlemPlatform.Current = new MlemPlatform.Mobile(KeyboardInput.Show, l => this.StartActivity(new Intent(Intent.ActionView, Uri.Parse(l))));
|
var adLayout = new LinearLayout(this) {Orientation = Orientation.Vertical};
|
||||||
this.platform = new AndroidPlatform(this, adLayout);
|
adLayout.SetGravity(GravityFlags.Bottom);
|
||||||
this.game = new GameImpl(this.platform);
|
|
||||||
this.game.GraphicsDeviceManager.ResetWidthAndHeight(this.game.Window);
|
|
||||||
this.game.GraphicsDeviceManager.IsFullScreen = true;
|
|
||||||
this.game.OnLoadContent += game => game.InputHandler.HandleMouse = false;
|
|
||||||
|
|
||||||
var gameView = this.game.Services.GetService(typeof(View)) as View;
|
// set up the game
|
||||||
gameView.LayoutChange += (o, args) => {
|
MlemPlatform.Current = new MlemPlatform.Mobile(KeyboardInput.Show, l => this.StartActivity(new Intent(Intent.ActionView, Uri.Parse(l))));
|
||||||
// force the game size to update when the ad size changes
|
this.platform = new AndroidPlatform(this, adLayout);
|
||||||
this.game.GraphicsDeviceManager.PreferredBackBufferWidth = args.Right - args.Left;
|
this.game = new GameImpl(this.platform);
|
||||||
this.game.GraphicsDeviceManager.PreferredBackBufferHeight = args.Bottom - args.Top;
|
this.game.GraphicsDeviceManager.ResetWidthAndHeight(this.game.Window);
|
||||||
this.game.GraphicsDeviceManager.ApplyChanges();
|
this.game.GraphicsDeviceManager.IsFullScreen = true;
|
||||||
};
|
this.game.OnLoadContent += game => game.InputHandler.HandleMouse = false;
|
||||||
|
|
||||||
// don't render under notches
|
var gameView = this.game.Services.GetService(typeof(View)) as View;
|
||||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
|
gameView.LayoutChange += (_, args) => {
|
||||||
this.Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.Never;
|
// force the game size to update when the ad size changes
|
||||||
|
this.game.GraphicsDeviceManager.PreferredBackBufferWidth = args.Right - args.Left;
|
||||||
|
this.game.GraphicsDeviceManager.PreferredBackBufferHeight = args.Bottom - args.Top;
|
||||||
|
this.game.GraphicsDeviceManager.ApplyChanges();
|
||||||
|
};
|
||||||
|
|
||||||
// total layout that is displayed
|
// don't render under notches
|
||||||
this.mainView = new LinearLayout(this) {Orientation = Orientation.Vertical};
|
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
|
||||||
this.mainView.LayoutParameters = new LinearLayout.LayoutParams(MatchParent, MatchParent);
|
this.Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.Never;
|
||||||
this.mainView.AddView(gameView);
|
|
||||||
// height of 0 but high weight causes this element so scale based on the ad's height
|
|
||||||
gameView.LayoutParameters = new LinearLayout.LayoutParams(MatchParent, 0, 1);
|
|
||||||
this.mainView.AddView(adLayout);
|
|
||||||
adLayout.LayoutParameters = new LinearLayout.LayoutParams(MatchParent, WrapContent);
|
|
||||||
this.SetContentView(this.mainView);
|
|
||||||
|
|
||||||
this.game.Run();
|
// total layout that is displayed
|
||||||
}
|
this.mainView = new LinearLayout(this) {Orientation = Orientation.Vertical};
|
||||||
|
this.mainView.LayoutParameters = new LinearLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
|
||||||
protected override void OnActivityResult(int requestCode, Result result, Intent data) {
|
this.mainView.AddView(gameView);
|
||||||
base.OnActivityResult(requestCode, result, data);
|
// height of 0 but high weight causes this element so scale based on the ad's height
|
||||||
// Connect again after logging in to Google Play game services, but only if we haven't tried yet
|
gameView.LayoutParameters = new LinearLayout.LayoutParams(LayoutParams.MatchParent, 0, 1);
|
||||||
try {
|
this.mainView.AddView(adLayout);
|
||||||
if (requestCode == AndroidPlatform.GooglePlayLoginRequest && (int) result != GamesActivityResultCodes.ResultSignInFailed)
|
adLayout.LayoutParameters = new LinearLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.WrapContent);
|
||||||
this.platform.GoogleApi.Connect();
|
this.SetContentView(this.mainView);
|
||||||
} catch (Exception e) {
|
|
||||||
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "OnActivityResult " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnWindowFocusChanged(bool hasFocus) {
|
|
||||||
base.OnWindowFocusChanged(hasFocus);
|
|
||||||
// hide the status bar
|
|
||||||
if (hasFocus)
|
|
||||||
this.Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (ImmersiveSticky | LayoutStable | LayoutHideNavigation | LayoutFullscreen | HideNavigation | Fullscreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.game.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnActivityResult(int requestCode, Result result, Intent data) {
|
||||||
|
base.OnActivityResult(requestCode, result, data);
|
||||||
|
// Connect again after logging in to Google Play game services, but only if we haven't tried yet
|
||||||
|
try {
|
||||||
|
if (requestCode == AndroidPlatform.GooglePlayLoginRequest && (int) result != GamesActivityResultCodes.ResultSignInFailed)
|
||||||
|
this.platform.GoogleApi.Connect();
|
||||||
|
} catch (Exception e) {
|
||||||
|
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "OnActivityResult " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnWindowFocusChanged(bool hasFocus) {
|
||||||
|
base.OnWindowFocusChanged(hasFocus);
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
// hide the status bar
|
||||||
|
if (hasFocus)
|
||||||
|
this.Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (SystemUiFlags.ImmersiveSticky | SystemUiFlags.LayoutStable | SystemUiFlags.LayoutHideNavigation | SystemUiFlags.LayoutFullscreen | SystemUiFlags.HideNavigation | SystemUiFlags.Fullscreen);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,94 +1,31 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFramework>net6.0-android</TargetFramework>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<SupportedOSPlatformVersion>31</SupportedOSPlatformVersion>
|
||||||
<ProductVersion>8.0.30703</ProductVersion>
|
<OutputType>Exe</OutputType>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<ApplicationId>de.ellpeck.touchytickets</ApplicationId>
|
||||||
<ProjectGuid>{410C0262-131C-4D0E-910D-D01B4F7143E0}</ProjectGuid>
|
<ApplicationVersion>1.2.1</ApplicationVersion>
|
||||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>Android</RootNamespace>
|
|
||||||
<AssemblyName>Android</AssemblyName>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<AndroidApplication>true</AndroidApplication>
|
|
||||||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
|
|
||||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
|
||||||
<AndroidStoreUncompressedFileExtensions>.m4a</AndroidStoreUncompressedFileExtensions>
|
|
||||||
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
|
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
|
||||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
|
||||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
|
||||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
|
||||||
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
|
|
||||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE;ANDROID</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
|
|
||||||
<AndroidLinkMode>None</AndroidLinkMode>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\</OutputPath>
|
|
||||||
<DefineConstants>TRACE;ANDROID</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
|
|
||||||
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
|
|
||||||
<AotAssemblies>false</AotAssemblies>
|
|
||||||
<EnableLLVM>false</EnableLLVM>
|
|
||||||
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
|
|
||||||
<BundleAssemblies>false</BundleAssemblies>
|
|
||||||
<MandroidI18n />
|
|
||||||
<AndroidPackageFormat>aab</AndroidPackageFormat>
|
|
||||||
<AndroidUseAapt2>true</AndroidUseAapt2>
|
|
||||||
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<ProjectReference Include="..\TouchyTickets\TouchyTickets.csproj"/>
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml" />
|
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303"/>
|
||||||
<Reference Include="Mono.Android" />
|
<PackageReference Include="MonoGame.Framework.Android" Version="3.8.1.303"/>
|
||||||
|
<PackageReference Include="Contentless" Version="3.0.7"/>
|
||||||
|
<PackageReference Include="GameAnalytics.Xamarin.SDK" Version="5.2.5"/>
|
||||||
|
<PackageReference Include="Xamarin.GooglePlayServices.Games" Version="123.1.0.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Activity1.cs" />
|
<MonoGameContentReference Include="..\TouchyTickets\Content\Content.mgcb"/>
|
||||||
<Compile Include="AndroidPlatform.cs" />
|
<None Include="..\TouchyTickets\Content\*\**">
|
||||||
<Compile Include="Resources\Resource.Designer.cs" />
|
<Link>Content/%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\Drawable\Icon.png" />
|
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
|
||||||
<AndroidResource Include="Resources\Values\Strings.xml" />
|
<Message Text="Restoring dotnet tools" Importance="High"/>
|
||||||
</ItemGroup>
|
<Exec Command="dotnet tool restore"/>
|
||||||
<ItemGroup>
|
</Target>
|
||||||
<None Include="Properties\AndroidManifest.xml" />
|
|
||||||
<None Include="..\TouchyTickets\Content\*\**" />
|
|
||||||
<MonoGameContentReference Include="..\TouchyTickets\Content\Content.mgcb">
|
|
||||||
<Link>Content\Content.mgcb</Link>
|
|
||||||
</MonoGameContentReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Contentless" Version="3.0.6" />
|
|
||||||
<PackageReference Include="GameAnalytics.Xamarin.SDK" Version="5.2.3" />
|
|
||||||
<PackageReference Include="MonoGame.Content.Builder" Version="3.7.0.9" />
|
|
||||||
<PackageReference Include="MonoGame.Framework.Android" Version="3.8.0.1641" />
|
|
||||||
<PackageReference Include="Xamarin.GooglePlayServices.Games" Version="121.0.0.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\TouchyTickets\TouchyTickets.csproj">
|
|
||||||
<Project>{3df7ae69-f3f0-461a-be98-f31eb576b5e2}</Project>
|
|
||||||
<Name>TouchyTickets</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
|
||||||
</Project>
|
</Project>
|
|
@ -1,9 +1,10 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.ellpeck.touchytickets" android:installLocation="auto"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.ellpeck.touchytickets"
|
||||||
android:versionCode="121" android:versionName="1.2.1">
|
android:installLocation="auto" android:versionCode="121" android:versionName="1.2.1">
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
|
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="31"/>
|
||||||
|
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
|
||||||
<application android:label="Touchy Tickets" android:resizeableActivity="true">
|
<application android:label="Touchy Tickets" android:resizeableActivity="true">
|
||||||
<meta-data android:name="com.google.android.gms.games.APP_ID" android:value="\u003169609944700" />
|
<meta-data android:name="com.google.android.gms.games.APP_ID" android:value="\u003169609944700"/>
|
||||||
</application>
|
</application>
|
||||||
<permission android:name="ACCESS_NETWORK_STATE"/>
|
<permission android:name="ACCESS_NETWORK_STATE"/>
|
||||||
<permission android:name="INTERNET"/>
|
<permission android:name="INTERNET"/>
|
|
@ -1,149 +1,145 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Android.App;
|
using Android.App;
|
||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Gms.Common;
|
|
||||||
using Android.Gms.Common.Apis;
|
using Android.Gms.Common.Apis;
|
||||||
using Android.Gms.Extensions;
|
|
||||||
using Android.Gms.Games;
|
using Android.Gms.Games;
|
||||||
using Android.Gms.Games.Achievement;
|
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Coroutine;
|
|
||||||
using GameAnalyticsSDK;
|
using GameAnalyticsSDK;
|
||||||
using GameAnalyticsSDK.Utilities;
|
using GameAnalyticsSDK.Utilities;
|
||||||
|
using Java.Lang;
|
||||||
using TouchyTickets;
|
using TouchyTickets;
|
||||||
using Achievement = TouchyTickets.Achievement;
|
using Achievement = TouchyTickets.Achievement;
|
||||||
using Uri = Android.Net.Uri;
|
using Uri = Android.Net.Uri;
|
||||||
|
|
||||||
namespace Android {
|
namespace Android;
|
||||||
public class AndroidPlatform : Platform {
|
|
||||||
|
|
||||||
public const int GooglePlayLoginRequest = 9001;
|
public class AndroidPlatform : Platform {
|
||||||
public const int ShowAchievementsRequest = 9002;
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, string> AchievementIds = new Dictionary<string, string> {
|
public const int GooglePlayLoginRequest = 9001;
|
||||||
{"1Stars", "CgkI_Lyp7PcEEAIQAw"},
|
public const int ShowAchievementsRequest = 9002;
|
||||||
{"10Stars", "CgkI_Lyp7PcEEAIQBA"},
|
|
||||||
{"100Stars", "CgkI_Lyp7PcEEAIQBQ"},
|
|
||||||
{"FullMap", "CgkI_Lyp7PcEEAIQBg"},
|
|
||||||
{"OnlySmallRides", "CgkI_Lyp7PcEEAIQBw"},
|
|
||||||
{"OnlyRelaxedRides", "CgkI_Lyp7PcEEAIQCA"},
|
|
||||||
{"OnlyWalkingRides", "CgkI_Lyp7PcEEAIQCQ"},
|
|
||||||
{"OnlyNonTechnologyRides", "CgkI_Lyp7PcEEAIQCg"},
|
|
||||||
{"100Modifiers", "CgkI_Lyp7PcEEAIQCw"},
|
|
||||||
{"500Modifiers", "CgkI_Lyp7PcEEAIQDA"},
|
|
||||||
{"1000Modifiers", "CgkI_Lyp7PcEEAIQDQ"},
|
|
||||||
{"5000Modifiers", "CgkI_Lyp7PcEEAIQDg"},
|
|
||||||
{"1ExpTickets", "CgkI_Lyp7PcEEAIQDw"},
|
|
||||||
{"2ExpTickets", "CgkI_Lyp7PcEEAIQEA"},
|
|
||||||
{"3ExpTickets", "CgkI_Lyp7PcEEAIQEQ"},
|
|
||||||
{"4ExpTickets", "CgkI_Lyp7PcEEAIQEg"},
|
|
||||||
{"5ExpTickets", "CgkI_Lyp7PcEEAIQEw"},
|
|
||||||
{"6ExpTickets", "CgkI_Lyp7PcEEAIQFA"},
|
|
||||||
{"7ExpTickets", "CgkI_Lyp7PcEEAIQFQ"},
|
|
||||||
{"8ExpTickets", "CgkI_Lyp7PcEEAIQFg"},
|
|
||||||
{"9ExpTickets", "CgkI_Lyp7PcEEAIQFw"},
|
|
||||||
{"10ExpTickets", "CgkI_Lyp7PcEEAIQGA"}
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly Activity activity;
|
private static readonly Dictionary<string, string> AchievementIds = new() {
|
||||||
private readonly LinearLayout adLayout;
|
{"1Stars", "CgkI_Lyp7PcEEAIQAw"},
|
||||||
public GoogleApiClient GoogleApi { get; private set; }
|
{"10Stars", "CgkI_Lyp7PcEEAIQBA"},
|
||||||
|
{"100Stars", "CgkI_Lyp7PcEEAIQBQ"},
|
||||||
|
{"FullMap", "CgkI_Lyp7PcEEAIQBg"},
|
||||||
|
{"OnlySmallRides", "CgkI_Lyp7PcEEAIQBw"},
|
||||||
|
{"OnlyRelaxedRides", "CgkI_Lyp7PcEEAIQCA"},
|
||||||
|
{"OnlyWalkingRides", "CgkI_Lyp7PcEEAIQCQ"},
|
||||||
|
{"OnlyNonTechnologyRides", "CgkI_Lyp7PcEEAIQCg"},
|
||||||
|
{"100Modifiers", "CgkI_Lyp7PcEEAIQCw"},
|
||||||
|
{"500Modifiers", "CgkI_Lyp7PcEEAIQDA"},
|
||||||
|
{"1000Modifiers", "CgkI_Lyp7PcEEAIQDQ"},
|
||||||
|
{"5000Modifiers", "CgkI_Lyp7PcEEAIQDg"},
|
||||||
|
{"1ExpTickets", "CgkI_Lyp7PcEEAIQDw"},
|
||||||
|
{"2ExpTickets", "CgkI_Lyp7PcEEAIQEA"},
|
||||||
|
{"3ExpTickets", "CgkI_Lyp7PcEEAIQEQ"},
|
||||||
|
{"4ExpTickets", "CgkI_Lyp7PcEEAIQEg"},
|
||||||
|
{"5ExpTickets", "CgkI_Lyp7PcEEAIQEw"},
|
||||||
|
{"6ExpTickets", "CgkI_Lyp7PcEEAIQFA"},
|
||||||
|
{"7ExpTickets", "CgkI_Lyp7PcEEAIQFQ"},
|
||||||
|
{"8ExpTickets", "CgkI_Lyp7PcEEAIQFg"},
|
||||||
|
{"9ExpTickets", "CgkI_Lyp7PcEEAIQFw"},
|
||||||
|
{"10ExpTickets", "CgkI_Lyp7PcEEAIQGA"}
|
||||||
|
};
|
||||||
|
|
||||||
public AndroidPlatform(Activity activity, LinearLayout adLayout) {
|
private readonly Activity activity;
|
||||||
this.activity = activity;
|
private readonly LinearLayout adLayout;
|
||||||
this.adLayout = adLayout;
|
public GoogleApiClient GoogleApi { get; private set; }
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetupOnlineInteractions(Dictionary<string, object> analyticsJson) {
|
|
||||||
// Analytics
|
|
||||||
GameAnalytics.SetAutoDetectAppVersion(true);
|
|
||||||
GameAnalytics.Initialize(this.activity, GA_MiniJSON.Serialize(new Hashtable(analyticsJson)));
|
|
||||||
AndroidEnvironment.UnhandledExceptionRaiser += (o, args) => GameAnalytics.NewErrorEvent(GAErrorSeverity.Critical, args.Exception.ToString());
|
|
||||||
|
|
||||||
// TODO fix ads
|
|
||||||
// Ads
|
|
||||||
/*try {
|
|
||||||
var ad = new AdView(this.activity) {
|
|
||||||
AdUnitId = "ca-app-pub-5754829579653773/7841535920",
|
|
||||||
AdSize = AdSize.SmartBanner
|
|
||||||
};
|
|
||||||
ad.LoadAd(new AdRequest.Builder()
|
|
||||||
.AddTestDevice("14B965C6457E17D2808061ADF7E34923")
|
|
||||||
.Build());
|
|
||||||
this.adLayout.AddView(ad);
|
|
||||||
} catch (Exception e) {
|
|
||||||
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "Ads " + e);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// TODO fix google play game services
|
|
||||||
/*// Google Play game services
|
|
||||||
try {
|
|
||||||
this.GoogleApi = new GoogleApiClient.Builder(this.activity)
|
|
||||||
.AddApi(GamesClass.API)
|
|
||||||
.AddScope(GamesClass.ScopeGames)
|
|
||||||
.AddOnConnectionFailedListener(res => {
|
|
||||||
if (res.HasResolution) {
|
|
||||||
res.StartResolutionForResult(this.activity, GooglePlayLoginRequest);
|
|
||||||
} else {
|
|
||||||
throw new GoogleApiClientConnectionException(res);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.Build();
|
|
||||||
this.GoogleApi.Connect();
|
|
||||||
} catch (Exception e) {
|
|
||||||
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "GoogleApiClient " + e);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
// Sanity check to ensure that all achievements are mapped
|
|
||||||
foreach (var achievement in Achievement.Achievements.Values) {
|
|
||||||
var _ = AchievementIds[achievement.Name];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId) {
|
|
||||||
GameAnalytics.NewResourceEvent(sink ? GAResourceFlowType.Sink : GAResourceFlowType.Source, currency, amount, itemType, itemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetKeepScreenOn(bool keep) {
|
|
||||||
if (keep) {
|
|
||||||
this.activity.Window.AddFlags(WindowManagerFlags.KeepScreenOn);
|
|
||||||
} else {
|
|
||||||
this.activity.Window.ClearFlags(WindowManagerFlags.KeepScreenOn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OpenRateLink() {
|
|
||||||
this.activity.StartActivity(new Intent(Intent.ActionView, Uri.Parse("https://play.google.com/store/apps/details?id=de.ellpeck.touchytickets")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool GainAchievement(Achievement achievement) {
|
|
||||||
try {
|
|
||||||
if (this.GoogleApi != null && this.GoogleApi.IsConnected) {
|
|
||||||
GamesClass.Achievements.Unlock(this.GoogleApi, AchievementIds[achievement.Name]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "GainAchievement " + e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ShowAchievements() {
|
|
||||||
try {
|
|
||||||
if (this.GoogleApi == null || !this.GoogleApi.IsConnected)
|
|
||||||
return;
|
|
||||||
var intent = GamesClass.Achievements.GetAchievementsIntent(this.GoogleApi);
|
|
||||||
this.activity.StartActivityForResult(intent, ShowAchievementsRequest);
|
|
||||||
} catch (Exception e) {
|
|
||||||
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "ShowAchievements " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public AndroidPlatform(Activity activity, LinearLayout adLayout) {
|
||||||
|
this.activity = activity;
|
||||||
|
this.adLayout = adLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetupOnlineInteractions(Dictionary<string, object> analyticsJson) {
|
||||||
|
// Analytics
|
||||||
|
GameAnalytics.SetAutoDetectAppVersion(true);
|
||||||
|
GameAnalytics.Initialize(this.activity, GA_MiniJSON.Serialize(new Hashtable(analyticsJson)));
|
||||||
|
AndroidEnvironment.UnhandledExceptionRaiser += (_, args) => GameAnalytics.NewErrorEvent(GAErrorSeverity.Critical, args.Exception.ToString());
|
||||||
|
|
||||||
|
// TODO fix ads
|
||||||
|
// Ads
|
||||||
|
/*try {
|
||||||
|
var ad = new AdView(this.activity) {
|
||||||
|
AdUnitId = "ca-app-pub-5754829579653773/7841535920",
|
||||||
|
AdSize = AdSize.SmartBanner
|
||||||
|
};
|
||||||
|
ad.LoadAd(new AdRequest.Builder()
|
||||||
|
.AddTestDevice("14B965C6457E17D2808061ADF7E34923")
|
||||||
|
.Build());
|
||||||
|
this.adLayout.AddView(ad);
|
||||||
|
} catch (Exception e) {
|
||||||
|
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "Ads " + e);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// TODO fix google play game services
|
||||||
|
/*// Google Play game services
|
||||||
|
try {
|
||||||
|
this.GoogleApi = new GoogleApiClient.Builder(this.activity)
|
||||||
|
.AddApi(GamesClass.API)
|
||||||
|
.AddScope(GamesClass.ScopeGames)
|
||||||
|
.AddOnConnectionFailedListener(res => {
|
||||||
|
if (res.HasResolution) {
|
||||||
|
res.StartResolutionForResult(this.activity, GooglePlayLoginRequest);
|
||||||
|
} else {
|
||||||
|
throw new GoogleApiClientConnectionException(res);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.Build();
|
||||||
|
this.GoogleApi.Connect();
|
||||||
|
} catch (Exception e) {
|
||||||
|
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "GoogleApiClient " + e);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
// Sanity check to ensure that all achievements are mapped
|
||||||
|
foreach (var achievement in Achievement.Achievements.Values) {
|
||||||
|
var _ = AndroidPlatform.AchievementIds[achievement.Name];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId) {
|
||||||
|
GameAnalytics.NewResourceEvent(sink ? GAResourceFlowType.Sink : GAResourceFlowType.Source, currency, amount, itemType, itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetKeepScreenOn(bool keep) {
|
||||||
|
if (keep) {
|
||||||
|
this.activity.Window.AddFlags(WindowManagerFlags.KeepScreenOn);
|
||||||
|
} else {
|
||||||
|
this.activity.Window.ClearFlags(WindowManagerFlags.KeepScreenOn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OpenRateLink() {
|
||||||
|
this.activity.StartActivity(new Intent(Intent.ActionView, Uri.Parse("https://play.google.com/store/apps/details?id=de.ellpeck.touchytickets")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool GainAchievement(Achievement achievement) {
|
||||||
|
try {
|
||||||
|
if (this.GoogleApi != null && this.GoogleApi.IsConnected) {
|
||||||
|
GamesClass.Achievements.Unlock(this.GoogleApi, AndroidPlatform.AchievementIds[achievement.Name]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "GainAchievement " + e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ShowAchievements() {
|
||||||
|
try {
|
||||||
|
if (this.GoogleApi == null || !this.GoogleApi.IsConnected)
|
||||||
|
return;
|
||||||
|
var intent = GamesClass.Achievements.GetAchievementsIntent(this.GoogleApi);
|
||||||
|
this.activity.StartActivityForResult(intent, AndroidPlatform.ShowAchievementsRequest);
|
||||||
|
} catch (Exception e) {
|
||||||
|
GameAnalytics.NewErrorEvent(GAErrorSeverity.Error, "ShowAchievements " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Android.App;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Touchy Tickets")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Touchy Tickets")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
1037
Android/Resources/Resource.Designer.cs
generated
1037
Android/Resources/Resource.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Touchy Tickets</string>
|
<string name="app_name">Touchy Tickets</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -4,8 +4,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchyTickets", "TouchyTick
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "Android\Android.csproj", "{410C0262-131C-4D0E-910D-D01B4F7143E0}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "Android\Android.csproj", "{410C0262-131C-4D0E-910D-D01B4F7143E0}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "iOS\iOS.csproj", "{CA7AB65C-57DE-412C-AF42-E7E6EDDF2D5F}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -20,9 +18,5 @@ Global
|
||||||
{410C0262-131C-4D0E-910D-D01B4F7143E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{410C0262-131C-4D0E-910D-D01B4F7143E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{410C0262-131C-4D0E-910D-D01B4F7143E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{410C0262-131C-4D0E-910D-D01B4F7143E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{410C0262-131C-4D0E-910D-D01B4F7143E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{410C0262-131C-4D0E-910D-D01B4F7143E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{CA7AB65C-57DE-412C-AF42-E7E6EDDF2D5F}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{CA7AB65C-57DE-412C-AF42-E7E6EDDF2D5F}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{CA7AB65C-57DE-412C-AF42-E7E6EDDF2D5F}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator
|
|
||||||
{CA7AB65C-57DE-412C-AF42-E7E6EDDF2D5F}.Release|Any CPU.Build.0 = Release|iPhoneSimulator
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -5,56 +5,56 @@ using System.Numerics;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using TouchyTickets.Attractions;
|
using TouchyTickets.Attractions;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public class Achievement {
|
|
||||||
|
|
||||||
public static readonly Dictionary<string, Achievement> Achievements = new Dictionary<string, Achievement>();
|
public class Achievement {
|
||||||
|
|
||||||
static Achievement() {
|
public static readonly Dictionary<string, Achievement> Achievements = new();
|
||||||
foreach (var amount in new[] {1, 10, 100})
|
|
||||||
Register(new Achievement($"{amount}Stars", g => g.Stars >= amount));
|
static Achievement() {
|
||||||
Register(new Achievement("FullMap", g => {
|
foreach (var amount in new[] {1, 10, 100})
|
||||||
for (var x = 0; x < g.Map.Width; x++) {
|
Achievement.Register(new Achievement($"{amount}Stars", g => g.Stars >= amount));
|
||||||
for (var y = 0; y < g.Map.Height; y++) {
|
Achievement.Register(new Achievement("FullMap", g => {
|
||||||
if (g.Map.GetAttractionAt(new Point(x, y)) == null)
|
for (var x = 0; x < g.Map.Width; x++) {
|
||||||
return false;
|
for (var y = 0; y < g.Map.Height; y++) {
|
||||||
}
|
if (g.Map.GetAttractionAt(new Point(x, y)) == null)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}));
|
|
||||||
foreach (var flag in new[] {AttractionFlags.Small, AttractionFlags.Relaxed, AttractionFlags.Walking, AttractionFlags.NonTechnology})
|
|
||||||
Register(new Achievement($"Only{flag}Rides", g => g.Map.GetAttractionAmount(null) >= 100 && g.Map.GetAttractions().All(a => a.Item2.Type.Flags.HasFlag(flag))));
|
|
||||||
foreach (var amount in new[] {100, 500, 1000, 5000})
|
|
||||||
Register(new Achievement($"{amount}Modifiers", g => g.Map.GetAttractionAmount(null) > 0 && g.Map.GetAttractions().All(a => a.Item2.GetModifierAmount(null) >= amount)));
|
|
||||||
for (var i = 1; i <= 10; i++) {
|
|
||||||
var amount = BigInteger.Pow(1000, i + 1);
|
|
||||||
Register(new Achievement($"{i}ExpTickets", g => g.Tickets >= amount));
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
foreach (var flag in new[] {AttractionFlags.Small, AttractionFlags.Relaxed, AttractionFlags.Walking, AttractionFlags.NonTechnology})
|
||||||
|
Achievement.Register(new Achievement($"Only{flag}Rides", g => g.Map.GetAttractionAmount(null) >= 100 && g.Map.GetAttractions().All(a => a.Item2.Type.Flags.HasFlag(flag))));
|
||||||
|
foreach (var amount in new[] {100, 500, 1000, 5000})
|
||||||
|
Achievement.Register(new Achievement($"{amount}Modifiers", g => g.Map.GetAttractionAmount(null) > 0 && g.Map.GetAttractions().All(a => a.Item2.GetModifierAmount(null) >= amount)));
|
||||||
|
for (var i = 1; i <= 10; i++) {
|
||||||
|
var amount = BigInteger.Pow(1000, i + 1);
|
||||||
|
Achievement.Register(new Achievement($"{i}ExpTickets", g => g.Tickets >= amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly string Name;
|
|
||||||
private readonly Func<GameImpl, bool> condition;
|
|
||||||
// this value doesn't save between game runs, since achievements
|
|
||||||
// are only displayed inside of the respective stores anyway
|
|
||||||
private bool unlocked;
|
|
||||||
|
|
||||||
public Achievement(string name, Func<GameImpl, bool> condition) {
|
|
||||||
this.Name = name;
|
|
||||||
this.condition = condition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update() {
|
|
||||||
if (this.unlocked)
|
|
||||||
return;
|
|
||||||
if (!this.condition.Invoke(GameImpl.Instance))
|
|
||||||
return;
|
|
||||||
if (GameImpl.Instance.Platform.GainAchievement(this))
|
|
||||||
this.unlocked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Register(Achievement achievement) {
|
|
||||||
Achievements.Add(achievement.Name, achievement);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly string Name;
|
||||||
|
private readonly Func<GameImpl, bool> condition;
|
||||||
|
// this value doesn't save between game runs, since achievements
|
||||||
|
// are only displayed inside of the respective stores anyway
|
||||||
|
private bool unlocked;
|
||||||
|
|
||||||
|
public Achievement(string name, Func<GameImpl, bool> condition) {
|
||||||
|
this.Name = name;
|
||||||
|
this.condition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update() {
|
||||||
|
if (this.unlocked)
|
||||||
|
return;
|
||||||
|
if (!this.condition.Invoke(GameImpl.Instance))
|
||||||
|
return;
|
||||||
|
if (GameImpl.Instance.Platform.GainAchievement(this))
|
||||||
|
this.unlocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Register(Achievement achievement) {
|
||||||
|
Achievement.Achievements.Add(achievement.Name, achievement);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,34 +5,34 @@ using MLEM.Font;
|
||||||
using MLEM.Startup;
|
using MLEM.Startup;
|
||||||
using MLEM.Textures;
|
using MLEM.Textures;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public static class Assets {
|
|
||||||
|
|
||||||
public static UniformTextureAtlas TilesTexture { get; private set; }
|
public static class Assets {
|
||||||
public static UniformTextureAtlas AttractionTexture { get; private set; }
|
|
||||||
public static UniformTextureAtlas UiTexture { get; private set; }
|
|
||||||
|
|
||||||
public static SoundEffect ClickSound { get; private set; }
|
public static UniformTextureAtlas TilesTexture { get; private set; }
|
||||||
public static SoundEffect PlaceSound { get; private set; }
|
public static UniformTextureAtlas AttractionTexture { get; private set; }
|
||||||
public static SoundEffect BuySound { get; private set; }
|
public static UniformTextureAtlas UiTexture { get; private set; }
|
||||||
|
|
||||||
public static Vector2 TileSize { get; private set; }
|
public static SoundEffect ClickSound { get; private set; }
|
||||||
public static GenericFont Font { get; private set; }
|
public static SoundEffect PlaceSound { get; private set; }
|
||||||
public static GenericFont MonospacedFont { get; private set; }
|
public static SoundEffect BuySound { get; private set; }
|
||||||
|
|
||||||
public static void Load() {
|
public static Vector2 TileSize { get; private set; }
|
||||||
TilesTexture = new UniformTextureAtlas(MlemGame.LoadContent<Texture2D>("Textures/Tiles"), 16, 16);
|
public static GenericFont Font { get; private set; }
|
||||||
AttractionTexture = new UniformTextureAtlas(MlemGame.LoadContent<Texture2D>("Textures/Attractions"), 16, 16);
|
public static GenericFont MonospacedFont { get; private set; }
|
||||||
UiTexture = new UniformTextureAtlas(MlemGame.LoadContent<Texture2D>("Textures/Ui"), 16, 16);
|
|
||||||
|
|
||||||
ClickSound = MlemGame.LoadContent<SoundEffect>("Sounds/Click");
|
public static void Load() {
|
||||||
PlaceSound = MlemGame.LoadContent<SoundEffect>("Sounds/Place");
|
Assets.TilesTexture = new UniformTextureAtlas(MlemGame.LoadContent<Texture2D>("Textures/Tiles"), 16, 16);
|
||||||
BuySound = MlemGame.LoadContent<SoundEffect>("Sounds/StarBuy");
|
Assets.AttractionTexture = new UniformTextureAtlas(MlemGame.LoadContent<Texture2D>("Textures/Attractions"), 16, 16);
|
||||||
|
Assets.UiTexture = new UniformTextureAtlas(MlemGame.LoadContent<Texture2D>("Textures/Ui"), 16, 16);
|
||||||
|
|
||||||
TileSize = new Vector2(AttractionTexture.RegionWidth, AttractionTexture.RegionHeight);
|
Assets.ClickSound = MlemGame.LoadContent<SoundEffect>("Sounds/Click");
|
||||||
Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/" + Localization.Get("Font")));
|
Assets.PlaceSound = MlemGame.LoadContent<SoundEffect>("Sounds/Place");
|
||||||
MonospacedFont = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/Monospaced"));
|
Assets.BuySound = MlemGame.LoadContent<SoundEffect>("Sounds/StarBuy");
|
||||||
}
|
|
||||||
|
|
||||||
|
Assets.TileSize = new Vector2(Assets.AttractionTexture.RegionWidth, Assets.AttractionTexture.RegionHeight);
|
||||||
|
Assets.Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/" + Localization.Get("Font")));
|
||||||
|
Assets.MonospacedFont = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/Monospaced"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,107 +5,104 @@ using System.Numerics;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using MLEM.Extensions;
|
|
||||||
using MLEM.Misc;
|
using MLEM.Misc;
|
||||||
using MLEM.Startup;
|
|
||||||
using MLEM.Textures;
|
using MLEM.Textures;
|
||||||
using TouchyTickets.Upgrades;
|
using TouchyTickets.Upgrades;
|
||||||
using static TouchyTickets.Attractions.AttractionFlags;
|
using Vector2 = Microsoft.Xna.Framework.Vector2;
|
||||||
using static TouchyTickets.Attractions.AttractionType;
|
|
||||||
|
|
||||||
namespace TouchyTickets.Attractions {
|
namespace TouchyTickets.Attractions;
|
||||||
[DataContract]
|
|
||||||
public class Attraction {
|
|
||||||
|
|
||||||
[DataMember]
|
[DataContract]
|
||||||
public readonly List<ActiveModifier> Modifiers = new List<ActiveModifier>();
|
public class Attraction {
|
||||||
[DataMember]
|
|
||||||
public readonly AttractionType Type;
|
|
||||||
[DataMember]
|
|
||||||
private double ticketPercentage;
|
|
||||||
private float animationSizeModifier;
|
|
||||||
|
|
||||||
public Attraction(AttractionType type) {
|
[DataMember]
|
||||||
this.Type = type;
|
public readonly List<ActiveModifier> Modifiers = new();
|
||||||
}
|
[DataMember]
|
||||||
|
public readonly AttractionType Type;
|
||||||
public double Update(TimeSpan passed, ParkMap map, Point position) {
|
[DataMember]
|
||||||
var genRate = this.GetGenerationRate(map, position);
|
private double ticketPercentage;
|
||||||
// apply generation rate to ticket amount
|
private float animationSizeModifier;
|
||||||
this.ticketPercentage += genRate * passed.TotalSeconds;
|
|
||||||
var total = (BigInteger) this.ticketPercentage;
|
|
||||||
if (total > 0) {
|
|
||||||
GameImpl.Instance.Tickets += total;
|
|
||||||
this.ticketPercentage -= (double) total;
|
|
||||||
}
|
|
||||||
|
|
||||||
// animation stuff
|
|
||||||
if (this.animationSizeModifier > 0)
|
|
||||||
this.animationSizeModifier = Math.Max(this.animationSizeModifier - 0.2F, 0);
|
|
||||||
|
|
||||||
// return the generation rate per second
|
|
||||||
return genRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw(SpriteBatch batch, Vector2 position, float alpha, float scale) {
|
|
||||||
var drawScale = scale;
|
|
||||||
if (this.animationSizeModifier > 0)
|
|
||||||
drawScale += (float) Math.Sin(this.animationSizeModifier) * 0.05F;
|
|
||||||
var tex = Assets.AttractionTexture[this.Type.TextureRegion];
|
|
||||||
var center = tex.Size.ToVector2() / 2;
|
|
||||||
batch.Draw(tex, position + center * scale, Color.White * alpha, 0, center, drawScale, SpriteEffects.None, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double GetGenerationRate(ParkMap map, Point position) {
|
|
||||||
var genRate = this.Type.GetGenerationRate();
|
|
||||||
|
|
||||||
// apply attraction modifiers
|
|
||||||
var mod = 1D;
|
|
||||||
foreach (var modifier in this.Modifiers)
|
|
||||||
mod += Math.Pow(modifier.Modifier.Multiplier, modifier.Amount) - 1;
|
|
||||||
genRate *= mod;
|
|
||||||
|
|
||||||
// apply star upgrades
|
|
||||||
foreach (var upgrade in Upgrade.Upgrades.Values.OfType<NeighborModifierUpgrade>())
|
|
||||||
genRate *= upgrade.GetCurrentMultiplier(this, map, position);
|
|
||||||
|
|
||||||
return genRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ApplyModifier(AttractionModifier modifier) {
|
|
||||||
// increase the amount of existing modifiers
|
|
||||||
foreach (var mod in this.Modifiers) {
|
|
||||||
if (mod.Modifier == modifier) {
|
|
||||||
mod.Amount++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// or add a new modifier
|
|
||||||
this.Modifiers.Add(new ActiveModifier(modifier, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetModifierAmount(AttractionModifier modifier) {
|
|
||||||
return this.Modifiers.Where(m => modifier == null || m.Modifier == modifier).Sum(m => m.Amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger GetModifierPrice(AttractionModifier modifier) {
|
|
||||||
var amount = this.GetModifierAmount(modifier);
|
|
||||||
return (BigInteger) Math.Ceiling(modifier.InitialPrice * Math.Pow(1 + 0.45F, amount));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Wobble() {
|
|
||||||
this.animationSizeModifier = MathHelper.Pi;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Attraction> GetSurrounding(ParkMap map, Point position, AttractionType type) {
|
|
||||||
foreach (var tile in this.Type.GetCoveredTiles()) {
|
|
||||||
foreach (var dir in Direction2Helper.Adjacent) {
|
|
||||||
var other = map.GetAttractionAt(position + tile + dir.Offset());
|
|
||||||
if (other != null && other != this && other.Type == type)
|
|
||||||
yield return other;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public Attraction(AttractionType type) {
|
||||||
|
this.Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double Update(TimeSpan passed, ParkMap map, Point position) {
|
||||||
|
var genRate = this.GetGenerationRate(map, position);
|
||||||
|
// apply generation rate to ticket amount
|
||||||
|
this.ticketPercentage += genRate * passed.TotalSeconds;
|
||||||
|
var total = (BigInteger) this.ticketPercentage;
|
||||||
|
if (total > 0) {
|
||||||
|
GameImpl.Instance.Tickets += total;
|
||||||
|
this.ticketPercentage -= (double) total;
|
||||||
|
}
|
||||||
|
|
||||||
|
// animation stuff
|
||||||
|
if (this.animationSizeModifier > 0)
|
||||||
|
this.animationSizeModifier = Math.Max(this.animationSizeModifier - 0.2F, 0);
|
||||||
|
|
||||||
|
// return the generation rate per second
|
||||||
|
return genRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch batch, Vector2 position, float alpha, float scale) {
|
||||||
|
var drawScale = scale;
|
||||||
|
if (this.animationSizeModifier > 0)
|
||||||
|
drawScale += (float) Math.Sin(this.animationSizeModifier) * 0.05F;
|
||||||
|
var tex = Assets.AttractionTexture[this.Type.TextureRegion];
|
||||||
|
var center = tex.Size.ToVector2() / 2;
|
||||||
|
batch.Draw(tex, position + center * scale, Color.White * alpha, 0, center, drawScale, SpriteEffects.None, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetGenerationRate(ParkMap map, Point position) {
|
||||||
|
var genRate = this.Type.GetGenerationRate();
|
||||||
|
|
||||||
|
// apply attraction modifiers
|
||||||
|
var mod = 1D;
|
||||||
|
foreach (var modifier in this.Modifiers)
|
||||||
|
mod += Math.Pow(modifier.Modifier.Multiplier, modifier.Amount) - 1;
|
||||||
|
genRate *= mod;
|
||||||
|
|
||||||
|
// apply star upgrades
|
||||||
|
foreach (var upgrade in Upgrade.Upgrades.Values.OfType<NeighborModifierUpgrade>())
|
||||||
|
genRate *= upgrade.GetCurrentMultiplier(this, map, position);
|
||||||
|
|
||||||
|
return genRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyModifier(AttractionModifier modifier) {
|
||||||
|
// increase the amount of existing modifiers
|
||||||
|
foreach (var mod in this.Modifiers) {
|
||||||
|
if (mod.Modifier == modifier) {
|
||||||
|
mod.Amount++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// or add a new modifier
|
||||||
|
this.Modifiers.Add(new ActiveModifier(modifier, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetModifierAmount(AttractionModifier modifier) {
|
||||||
|
return this.Modifiers.Where(m => modifier == null || m.Modifier == modifier).Sum(m => m.Amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger GetModifierPrice(AttractionModifier modifier) {
|
||||||
|
var amount = this.GetModifierAmount(modifier);
|
||||||
|
return (BigInteger) Math.Ceiling(modifier.InitialPrice * Math.Pow(1 + 0.45F, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Wobble() {
|
||||||
|
this.animationSizeModifier = MathHelper.Pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Attraction> GetSurrounding(ParkMap map, Point position, AttractionType type) {
|
||||||
|
foreach (var tile in this.Type.GetCoveredTiles()) {
|
||||||
|
foreach (var dir in Direction2Helper.Adjacent) {
|
||||||
|
var other = map.GetAttractionAt(position + tile + dir.Offset());
|
||||||
|
if (other != null && other != this && other.Type == type)
|
||||||
|
yield return other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,18 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace TouchyTickets.Attractions {
|
namespace TouchyTickets.Attractions;
|
||||||
[Flags]
|
|
||||||
public enum AttractionFlags {
|
|
||||||
|
|
||||||
// base flags
|
[Flags]
|
||||||
None = 0,
|
public enum AttractionFlags {
|
||||||
Relaxed = 1,
|
|
||||||
Cars = 2,
|
// base flags
|
||||||
Walking = 4,
|
None = 0,
|
||||||
FastCars = 8,
|
Relaxed = 1,
|
||||||
NonTechnology = 16,
|
Cars = 2,
|
||||||
Small = 32,
|
Walking = 4,
|
||||||
All = ~0
|
FastCars = 8,
|
||||||
|
NonTechnology = 16,
|
||||||
|
Small = 32,
|
||||||
|
All = ~0
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -2,85 +2,84 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using MLEM.Textures;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using static TouchyTickets.Attractions.AttractionFlags;
|
using static TouchyTickets.Attractions.AttractionFlags;
|
||||||
|
|
||||||
namespace TouchyTickets.Attractions {
|
namespace TouchyTickets.Attractions;
|
||||||
[JsonConverter(typeof(Converter))]
|
|
||||||
public class AttractionModifier {
|
|
||||||
|
|
||||||
public static readonly Dictionary<string, AttractionModifier> Modifiers = new Dictionary<string, AttractionModifier>();
|
[JsonConverter(typeof(Converter))]
|
||||||
|
public class AttractionModifier {
|
||||||
|
|
||||||
static AttractionModifier() {
|
public static readonly Dictionary<string, AttractionModifier> Modifiers = new();
|
||||||
Register(new AttractionModifier("Lubricant", 200, Cars | FastCars, 1.02F, new Point(0, 4)));
|
|
||||||
Register(new AttractionModifier("LouderMusic", 500, Relaxed, 1.03F, new Point(2, 4)));
|
static AttractionModifier() {
|
||||||
Register(new AttractionModifier("SmallAds", 800, Small, 1.35F, new Point(5, 4)));
|
AttractionModifier.Register(new AttractionModifier("Lubricant", 200, AttractionFlags.Cars | AttractionFlags.FastCars, 1.02F, new Point(0, 4)));
|
||||||
Register(new AttractionModifier("LongerQueue", 1000, All, 1.06F, new Point(1, 4)));
|
AttractionModifier.Register(new AttractionModifier("LouderMusic", 500, AttractionFlags.Relaxed, 1.03F, new Point(2, 4)));
|
||||||
Register(new AttractionModifier("Bouncer", 1500, Walking, 1.2F, new Point(3, 4)));
|
AttractionModifier.Register(new AttractionModifier("SmallAds", 800, AttractionFlags.Small, 1.35F, new Point(5, 4)));
|
||||||
Register(new AttractionModifier("OnRideCameras", 2500, FastCars, 1.1F, new Point(4, 4)));
|
AttractionModifier.Register(new AttractionModifier("LongerQueue", 1000, AttractionFlags.All, 1.06F, new Point(1, 4)));
|
||||||
|
AttractionModifier.Register(new AttractionModifier("Bouncer", 1500, AttractionFlags.Walking, 1.2F, new Point(3, 4)));
|
||||||
|
AttractionModifier.Register(new AttractionModifier("OnRideCameras", 2500, AttractionFlags.FastCars, 1.1F, new Point(4, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly string Name;
|
||||||
|
public readonly long InitialPrice;
|
||||||
|
public readonly Point Texture;
|
||||||
|
public readonly float Multiplier;
|
||||||
|
private readonly AttractionFlags affectedFlags;
|
||||||
|
|
||||||
|
public AttractionModifier(string name, long initialPrice, AttractionFlags affectedFlags, float multiplier, Point texture) {
|
||||||
|
this.Name = name;
|
||||||
|
this.InitialPrice = initialPrice;
|
||||||
|
this.affectedFlags = affectedFlags;
|
||||||
|
this.Texture = texture;
|
||||||
|
this.Multiplier = multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAffected(Attraction attraction) {
|
||||||
|
return (attraction.Type.Flags & this.affectedFlags) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Buy(Attraction attraction) {
|
||||||
|
var price = attraction.GetModifierPrice(this);
|
||||||
|
if (GameImpl.Instance.Tickets < price)
|
||||||
|
return false;
|
||||||
|
GameImpl.Instance.Tickets -= price;
|
||||||
|
GameImpl.Instance.Platform.AddResourceEvent(true, "Tickets", (float) price, "Modifier", this.Name);
|
||||||
|
attraction.ApplyModifier(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AttractionModifier Register(AttractionModifier type) {
|
||||||
|
AttractionModifier.Modifiers.Add(type.Name, type);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Converter : JsonConverter<AttractionModifier> {
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, AttractionModifier value, JsonSerializer serializer) {
|
||||||
|
if (value != null)
|
||||||
|
writer.WriteValue(value.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly string Name;
|
public override AttractionModifier ReadJson(JsonReader reader, Type objectType, AttractionModifier existingValue, bool hasExistingValue, JsonSerializer serializer) {
|
||||||
public readonly long InitialPrice;
|
return reader.Value != null ? AttractionModifier.Modifiers[reader.Value.ToString()] : null;
|
||||||
public readonly Point Texture;
|
|
||||||
public readonly float Multiplier;
|
|
||||||
private readonly AttractionFlags affectedFlags;
|
|
||||||
|
|
||||||
public AttractionModifier(string name, long initialPrice, AttractionFlags affectedFlags, float multiplier, Point texture) {
|
|
||||||
this.Name = name;
|
|
||||||
this.InitialPrice = initialPrice;
|
|
||||||
this.affectedFlags = affectedFlags;
|
|
||||||
this.Texture = texture;
|
|
||||||
this.Multiplier = multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAffected(Attraction attraction) {
|
|
||||||
return (attraction.Type.Flags & this.affectedFlags) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Buy(Attraction attraction) {
|
|
||||||
var price = attraction.GetModifierPrice(this);
|
|
||||||
if (GameImpl.Instance.Tickets < price)
|
|
||||||
return false;
|
|
||||||
GameImpl.Instance.Tickets -= price;
|
|
||||||
GameImpl.Instance.Platform.AddResourceEvent(true, "Tickets", (float) price, "Modifier", this.Name);
|
|
||||||
attraction.ApplyModifier(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AttractionModifier Register(AttractionModifier type) {
|
|
||||||
Modifiers.Add(type.Name, type);
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Converter : JsonConverter<AttractionModifier> {
|
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, AttractionModifier value, JsonSerializer serializer) {
|
|
||||||
if (value != null)
|
|
||||||
writer.WriteValue(value.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override AttractionModifier ReadJson(JsonReader reader, Type objectType, AttractionModifier existingValue, bool hasExistingValue, JsonSerializer serializer) {
|
|
||||||
return reader.Value != null ? Modifiers[reader.Value.ToString()] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataContract]
|
}
|
||||||
public class ActiveModifier {
|
|
||||||
|
[DataContract]
|
||||||
[DataMember]
|
public class ActiveModifier {
|
||||||
public readonly AttractionModifier Modifier;
|
|
||||||
[DataMember]
|
[DataMember]
|
||||||
public int Amount;
|
public readonly AttractionModifier Modifier;
|
||||||
|
[DataMember]
|
||||||
public ActiveModifier(AttractionModifier modifier, int amount) {
|
public int Amount;
|
||||||
this.Modifier = modifier;
|
|
||||||
this.Amount = amount;
|
public ActiveModifier(AttractionModifier modifier, int amount) {
|
||||||
}
|
this.Modifier = modifier;
|
||||||
|
this.Amount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,98 +2,97 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using MLEM.Textures;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using TouchyTickets.Upgrades;
|
using TouchyTickets.Upgrades;
|
||||||
using static TouchyTickets.Attractions.AttractionFlags;
|
using static TouchyTickets.Attractions.AttractionFlags;
|
||||||
|
|
||||||
namespace TouchyTickets.Attractions {
|
namespace TouchyTickets.Attractions;
|
||||||
[JsonConverter(typeof(Converter))]
|
|
||||||
public class AttractionType {
|
|
||||||
|
|
||||||
public static readonly Dictionary<string, AttractionType> Attractions = new Dictionary<string, AttractionType>();
|
[JsonConverter(typeof(Converter))]
|
||||||
public static readonly AttractionType Carousel = Register(new AttractionType("Carousel", RectArea(1, 1), new Rectangle(0, 0, 1, 1), 0.5F, 50, Relaxed | Cars | Small));
|
public class AttractionType {
|
||||||
public static readonly AttractionType MirrorHouse = Register(new AttractionType("MirrorHouse", RectArea(1, 1), new Rectangle(3, 0, 1, 1), 1, 150, Relaxed | Walking | NonTechnology | Small));
|
|
||||||
public static readonly AttractionType FoodCourt = Register(new AttractionType("FoodCourt", RectArea(2, 1), new Rectangle(1, 0, 2, 1), 2F, 300, None));
|
|
||||||
public static readonly AttractionType SpiralSlide = Register(new AttractionType("SpiralSlide", RectArea(1, 2), new Rectangle(5, 0, 1, 2), 4, 1200, Relaxed | Walking));
|
|
||||||
public static readonly AttractionType HedgeMaze = Register(new AttractionType("HedgeMaze", RectArea(2, 2), new Rectangle(3, 3, 2, 2), 8, 2500, Relaxed | Walking | NonTechnology));
|
|
||||||
public static readonly AttractionType FerrisWheel = Register(new AttractionType("FerrisWheel", RectArea(2, 2), new Rectangle(0, 1, 2, 2), 12, 4000, Relaxed | Cars));
|
|
||||||
public static readonly AttractionType FreefallCoaster = Register(new AttractionType("FreefallCoaster", new[,] {{true, false, true}, {true, true, true}}, new Rectangle(6, 0, 3, 2), 24, 8000, FastCars));
|
|
||||||
public static readonly AttractionType HauntedHouse = Register(new AttractionType("HauntedHouse", RectArea(2, 2), new Rectangle(3, 5, 2, 2), 30, 12000, FastCars));
|
|
||||||
public static readonly AttractionType GoKarts = Register(new AttractionType("GoKarts", RectArea(2, 2), new Rectangle(5, 2, 2, 2), 50, 24000, Cars | Relaxed));
|
|
||||||
public static readonly AttractionType MiniGolf = Register(new AttractionType("MiniGolf", RectArea(2, 3), new Rectangle(9, 0, 2, 3), 75, 35000, Relaxed | Walking | NonTechnology));
|
|
||||||
public static readonly AttractionType WildMouse = Register(new AttractionType("WildMouse", RectArea(3, 2), new Rectangle(2, 1, 3, 2), 100, 60000, FastCars));
|
|
||||||
public static readonly AttractionType LogFlume = Register(new AttractionType("LogFlume", new[,] {{true, true, false}, {true, true, true}}, new Rectangle(0, 3, 3, 2), 160, 90000, FastCars));
|
|
||||||
public static readonly AttractionType HeartlineTwister = Register(new AttractionType("HeartlineTwister", RectArea(4, 2), new Rectangle(5, 4, 4, 2), 250, 150000, FastCars));
|
|
||||||
public static readonly AttractionType WoodCoaster = Register(new AttractionType("WoodCoaster", RectArea(3, 3), new Rectangle(0, 5, 3, 3), 300, 215000, FastCars));
|
|
||||||
public static readonly AttractionType SafariZone = Register(new AttractionType("SafariZone", RectArea(5, 3), new Rectangle(11, 0, 5, 3), 600, 750000, Relaxed | Walking | NonTechnology));
|
|
||||||
|
|
||||||
public readonly string Name;
|
public static readonly Dictionary<string, AttractionType> Attractions = new();
|
||||||
public readonly bool[,] Area;
|
public static readonly AttractionType Carousel = AttractionType.Register(new AttractionType("Carousel", AttractionType.RectArea(1, 1), new Rectangle(0, 0, 1, 1), 0.5F, 50, AttractionFlags.Relaxed | AttractionFlags.Cars | AttractionFlags.Small));
|
||||||
public int Width => this.Area.GetLength(1);
|
public static readonly AttractionType MirrorHouse = AttractionType.Register(new AttractionType("MirrorHouse", AttractionType.RectArea(1, 1), new Rectangle(3, 0, 1, 1), 1, 150, AttractionFlags.Relaxed | AttractionFlags.Walking | AttractionFlags.NonTechnology | AttractionFlags.Small));
|
||||||
public int Height => this.Area.GetLength(0);
|
public static readonly AttractionType FoodCourt = AttractionType.Register(new AttractionType("FoodCourt", AttractionType.RectArea(2, 1), new Rectangle(1, 0, 2, 1), 2F, 300, AttractionFlags.None));
|
||||||
public readonly Rectangle TextureRegion;
|
public static readonly AttractionType SpiralSlide = AttractionType.Register(new AttractionType("SpiralSlide", AttractionType.RectArea(1, 2), new Rectangle(5, 0, 1, 2), 4, 1200, AttractionFlags.Relaxed | AttractionFlags.Walking));
|
||||||
private readonly float generationPerSecond;
|
public static readonly AttractionType HedgeMaze = AttractionType.Register(new AttractionType("HedgeMaze", AttractionType.RectArea(2, 2), new Rectangle(3, 3, 2, 2), 8, 2500, AttractionFlags.Relaxed | AttractionFlags.Walking | AttractionFlags.NonTechnology));
|
||||||
public readonly long InitialPrice;
|
public static readonly AttractionType FerrisWheel = AttractionType.Register(new AttractionType("FerrisWheel", AttractionType.RectArea(2, 2), new Rectangle(0, 1, 2, 2), 12, 4000, AttractionFlags.Relaxed | AttractionFlags.Cars));
|
||||||
public readonly AttractionFlags Flags;
|
public static readonly AttractionType FreefallCoaster = AttractionType.Register(new AttractionType("FreefallCoaster", new[,] {{true, false, true}, {true, true, true}}, new Rectangle(6, 0, 3, 2), 24, 8000, AttractionFlags.FastCars));
|
||||||
|
public static readonly AttractionType HauntedHouse = AttractionType.Register(new AttractionType("HauntedHouse", AttractionType.RectArea(2, 2), new Rectangle(3, 5, 2, 2), 30, 12000, AttractionFlags.FastCars));
|
||||||
|
public static readonly AttractionType GoKarts = AttractionType.Register(new AttractionType("GoKarts", AttractionType.RectArea(2, 2), new Rectangle(5, 2, 2, 2), 50, 24000, AttractionFlags.Cars | AttractionFlags.Relaxed));
|
||||||
|
public static readonly AttractionType MiniGolf = AttractionType.Register(new AttractionType("MiniGolf", AttractionType.RectArea(2, 3), new Rectangle(9, 0, 2, 3), 75, 35000, AttractionFlags.Relaxed | AttractionFlags.Walking | AttractionFlags.NonTechnology));
|
||||||
|
public static readonly AttractionType WildMouse = AttractionType.Register(new AttractionType("WildMouse", AttractionType.RectArea(3, 2), new Rectangle(2, 1, 3, 2), 100, 60000, AttractionFlags.FastCars));
|
||||||
|
public static readonly AttractionType LogFlume = AttractionType.Register(new AttractionType("LogFlume", new[,] {{true, true, false}, {true, true, true}}, new Rectangle(0, 3, 3, 2), 160, 90000, AttractionFlags.FastCars));
|
||||||
|
public static readonly AttractionType HeartlineTwister = AttractionType.Register(new AttractionType("HeartlineTwister", AttractionType.RectArea(4, 2), new Rectangle(5, 4, 4, 2), 250, 150000, AttractionFlags.FastCars));
|
||||||
|
public static readonly AttractionType WoodCoaster = AttractionType.Register(new AttractionType("WoodCoaster", AttractionType.RectArea(3, 3), new Rectangle(0, 5, 3, 3), 300, 215000, AttractionFlags.FastCars));
|
||||||
|
public static readonly AttractionType SafariZone = AttractionType.Register(new AttractionType("SafariZone", AttractionType.RectArea(5, 3), new Rectangle(11, 0, 5, 3), 600, 750000, AttractionFlags.Relaxed | AttractionFlags.Walking | AttractionFlags.NonTechnology));
|
||||||
|
|
||||||
public AttractionType(string name, bool[,] area, Rectangle textureRegion, float generationPerSecond, long initialPrice, AttractionFlags flags) {
|
public readonly string Name;
|
||||||
this.Name = name;
|
public readonly bool[,] Area;
|
||||||
this.Area = area;
|
public int Width => this.Area.GetLength(1);
|
||||||
this.TextureRegion = textureRegion;
|
public int Height => this.Area.GetLength(0);
|
||||||
this.generationPerSecond = generationPerSecond;
|
public readonly Rectangle TextureRegion;
|
||||||
this.InitialPrice = initialPrice;
|
private readonly float generationPerSecond;
|
||||||
this.Flags = flags;
|
public readonly long InitialPrice;
|
||||||
}
|
public readonly AttractionFlags Flags;
|
||||||
|
|
||||||
public Attraction Create() {
|
public AttractionType(string name, bool[,] area, Rectangle textureRegion, float generationPerSecond, long initialPrice, AttractionFlags flags) {
|
||||||
return new Attraction(this);
|
this.Name = name;
|
||||||
}
|
this.Area = area;
|
||||||
|
this.TextureRegion = textureRegion;
|
||||||
|
this.generationPerSecond = generationPerSecond;
|
||||||
|
this.InitialPrice = initialPrice;
|
||||||
|
this.Flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
public double GetGenerationRate() {
|
public Attraction Create() {
|
||||||
var genRate = this.generationPerSecond;
|
return new Attraction(this);
|
||||||
foreach (var upgrade in Upgrade.Upgrades.Values.OfType<ModifierUpgrade>())
|
}
|
||||||
genRate *= upgrade.GetCurrentMultiplier(this);
|
|
||||||
return genRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Point> GetCoveredTiles() {
|
public double GetGenerationRate() {
|
||||||
for (var x = 0; x < this.Width; x++) {
|
var genRate = this.generationPerSecond;
|
||||||
for (var y = 0; y < this.Height; y++) {
|
foreach (var upgrade in Upgrade.Upgrades.Values.OfType<ModifierUpgrade>())
|
||||||
if (this.Area[y, x])
|
genRate *= upgrade.GetCurrentMultiplier(this);
|
||||||
yield return new Point(x, y);
|
return genRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Point> GetCoveredTiles() {
|
||||||
|
for (var x = 0; x < this.Width; x++) {
|
||||||
|
for (var y = 0; y < this.Height; y++) {
|
||||||
|
if (this.Area[y, x])
|
||||||
|
yield return new Point(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static AttractionType Register(AttractionType type) {
|
private static AttractionType Register(AttractionType type) {
|
||||||
Attractions.Add(type.Name, type);
|
AttractionType.Attractions.Add(type.Name, type);
|
||||||
return type;
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool[,] RectArea(int width, int height) {
|
||||||
|
var ret = new bool[height, width];
|
||||||
|
for (var x = 0; x < width; x++) {
|
||||||
|
for (var y = 0; y < height; y++)
|
||||||
|
ret[y, x] = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate Attraction Constructor(AttractionType type);
|
||||||
|
|
||||||
|
public class Converter : JsonConverter<AttractionType> {
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, AttractionType value, JsonSerializer serializer) {
|
||||||
|
if (value != null)
|
||||||
|
writer.WriteValue(value.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool[,] RectArea(int width, int height) {
|
public override AttractionType ReadJson(JsonReader reader, Type objectType, AttractionType existingValue, bool hasExistingValue, JsonSerializer serializer) {
|
||||||
var ret = new bool[height, width];
|
return reader.Value != null ? AttractionType.Attractions[reader.Value.ToString()] : null;
|
||||||
for (var x = 0; x < width; x++) {
|
|
||||||
for (var y = 0; y < height; y++)
|
|
||||||
ret[y, x] = true;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public delegate Attraction Constructor(AttractionType type);
|
|
||||||
|
|
||||||
public class Converter : JsonConverter<AttractionType> {
|
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, AttractionType value, JsonSerializer serializer) {
|
|
||||||
if (value != null)
|
|
||||||
writer.WriteValue(value.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override AttractionType ReadJson(JsonReader reader, Type objectType, AttractionType existingValue, bool hasExistingValue, JsonSerializer serializer) {
|
|
||||||
return reader.Value != null ? Attractions[reader.Value.ToString()] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"obj/",
|
"obj/",
|
||||||
"bin/",
|
"bin/",
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"README"
|
"README"
|
||||||
],
|
],
|
||||||
"overrides": {
|
"overrides": {
|
||||||
".json": {
|
".json": {
|
||||||
"copy": true
|
"copy": true
|
||||||
},
|
},
|
||||||
"Sounds/": {
|
"Sounds/": {
|
||||||
"processor": "SoundEffectProcessor"
|
"processor": "SoundEffectProcessor"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -7,141 +7,143 @@ using Microsoft.Xna.Framework.Graphics;
|
||||||
using MLEM.Cameras;
|
using MLEM.Cameras;
|
||||||
using MLEM.Startup;
|
using MLEM.Startup;
|
||||||
using TouchyTickets.Upgrades;
|
using TouchyTickets.Upgrades;
|
||||||
|
using Vector2 = Microsoft.Xna.Framework.Vector2;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public class GameImpl : MlemGame {
|
|
||||||
|
|
||||||
public static GameImpl Instance { get; private set; }
|
public class GameImpl : MlemGame {
|
||||||
public readonly ISet<Upgrade> AppliedUpgrades = new HashSet<Upgrade>();
|
|
||||||
public readonly Platform Platform;
|
|
||||||
public BigInteger Tickets;
|
|
||||||
public int TimesRestarted;
|
|
||||||
public int Stars;
|
|
||||||
public ParkMap Map;
|
|
||||||
public Tutorial Tutorial { get; private set; }
|
|
||||||
public Camera Camera { get; private set; }
|
|
||||||
public Ui Ui { get; private set; }
|
|
||||||
public bool DrawMap;
|
|
||||||
public DateTime LastUpdate;
|
|
||||||
public TimeSpan PlayTime;
|
|
||||||
private double saveCounter;
|
|
||||||
private double achievementCounter;
|
|
||||||
|
|
||||||
public GameImpl(Platform platform) {
|
public static GameImpl Instance { get; private set; }
|
||||||
this.Platform = platform;
|
public readonly ISet<Upgrade> AppliedUpgrades = new HashSet<Upgrade>();
|
||||||
Instance = this;
|
public readonly Platform Platform;
|
||||||
}
|
public BigInteger Tickets;
|
||||||
|
public int TimesRestarted;
|
||||||
protected override void LoadContent() {
|
public int Stars;
|
||||||
base.LoadContent();
|
public ParkMap Map;
|
||||||
Assets.Load();
|
public Tutorial Tutorial { get; private set; }
|
||||||
Options.Load();
|
public Camera Camera { get; private set; }
|
||||||
|
public Ui Ui { get; private set; }
|
||||||
// start the load sequence
|
public bool DrawMap;
|
||||||
Ui.SetupUiSystem(this.UiSystem);
|
public DateTime LastUpdate;
|
||||||
CoroutineHandler.Start(Ui.DisplaySplash(this.LoadGame));
|
public TimeSpan PlayTime;
|
||||||
}
|
private double saveCounter;
|
||||||
|
private double achievementCounter;
|
||||||
private void LoadGame() {
|
|
||||||
// set up online stuff
|
|
||||||
var analytics = new Dictionary<string, object>();
|
|
||||||
analytics["InfoLog"] = true;
|
|
||||||
analytics["VerboseLog"] = true;
|
|
||||||
analytics["ResourceCurrencies"] = new[] {"Tickets", "Stars"};
|
|
||||||
analytics["ResourceItemTypes"] = new[] {"Attraction", "Restart", "Upgrade", "Modifier"};
|
|
||||||
// ios comes first, then android. For now they're the same
|
|
||||||
analytics["GameKey"] = new[] {"cc18de06eebbc5d5e987c384fcd28000", "cc18de06eebbc5d5e987c384fcd28000"};
|
|
||||||
analytics["SecretKey"] = new[] {"82ca1a930ee38e2383ffb02db7631e16033b511d", "82ca1a930ee38e2383ffb02db7631e16033b511d"};
|
|
||||||
this.Platform.SetupOnlineInteractions(analytics);
|
|
||||||
|
|
||||||
this.Tutorial = new Tutorial();
|
|
||||||
|
|
||||||
if (!SaveHandler.Load(this))
|
|
||||||
this.Map = new ParkMap(20, 20);
|
|
||||||
|
|
||||||
// load other stuff
|
|
||||||
this.Ui = new Ui(this.UiSystem);
|
|
||||||
this.Camera = new Camera(this.GraphicsDevice) {
|
|
||||||
Scale = 4,
|
|
||||||
AutoScaleWithScreen = true,
|
|
||||||
AutoScaleReferenceSize = new Point(720, 1280),
|
|
||||||
MaxScale = 24,
|
|
||||||
MinScale = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
// update the map once to make sure that catching up happens during loading
|
|
||||||
this.UpdateMapOnce();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DoUpdate(GameTime gameTime) {
|
|
||||||
base.DoUpdate(gameTime);
|
|
||||||
|
|
||||||
if (this.Map != null) {
|
|
||||||
// update the map
|
|
||||||
this.UpdateMapOnce();
|
|
||||||
|
|
||||||
// achievements
|
|
||||||
this.achievementCounter += gameTime.ElapsedGameTime.TotalSeconds;
|
|
||||||
if (this.achievementCounter >= 5) {
|
|
||||||
this.achievementCounter = 0;
|
|
||||||
foreach (var achievement in Achievement.Achievements.Values)
|
|
||||||
achievement.Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
// save every 3 seconds
|
|
||||||
this.saveCounter += gameTime.ElapsedGameTime.TotalSeconds;
|
|
||||||
if (this.saveCounter >= 3) {
|
|
||||||
this.saveCounter = 0;
|
|
||||||
SaveHandler.Save(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// play time stuff
|
|
||||||
var lastTime = this.PlayTime;
|
|
||||||
this.PlayTime += gameTime.ElapsedGameTime;
|
|
||||||
if (lastTime.TotalHours >= 1 != this.PlayTime.TotalHours >= 1)
|
|
||||||
Ui.DisplayRatePlease();
|
|
||||||
|
|
||||||
this.Ui?.Update(gameTime);
|
|
||||||
this.Tutorial?.Update(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DoDraw(GameTime gameTime) {
|
|
||||||
this.GraphicsDevice.Clear(Color.Black);
|
|
||||||
if (this.DrawMap) {
|
|
||||||
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: this.Camera.ViewMatrix);
|
|
||||||
this.Map.Draw(gameTime, this.SpriteBatch, Vector2.Zero, 1, 1, true, this.Camera.GetVisibleRectangle());
|
|
||||||
this.SpriteBatch.End();
|
|
||||||
}
|
|
||||||
base.DoDraw(gameTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger GetStarPrice() {
|
|
||||||
return 1000000000 * BigInteger.Pow(100, this.TimesRestarted);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetBuyableStars() {
|
|
||||||
#if DEBUG
|
|
||||||
return 3;
|
|
||||||
#endif
|
|
||||||
return (int) BigInteger.Min(3, this.Tickets / this.GetStarPrice());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateMapOnce() {
|
|
||||||
var now = DateTime.Now;
|
|
||||||
if (this.LastUpdate != default) {
|
|
||||||
var lastTickets = this.Tickets;
|
|
||||||
var lastTps = this.Map.TicketsPerSecond;
|
|
||||||
|
|
||||||
var passed = now - this.LastUpdate;
|
|
||||||
this.Map.Update(passed, passed.TotalSeconds >= 1);
|
|
||||||
|
|
||||||
// if 10 or more seconds passed, we display a message
|
|
||||||
if (Options.Instance.WhileYouWereAwayMessage && passed.TotalSeconds >= 10)
|
|
||||||
Ui.DisplayWhileYouWereAway(passed, this.Tickets - lastTickets, this.Map.TicketsPerSecond - lastTps);
|
|
||||||
}
|
|
||||||
this.LastUpdate = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public GameImpl(Platform platform) {
|
||||||
|
this.Platform = platform;
|
||||||
|
GameImpl.Instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadContent() {
|
||||||
|
base.LoadContent();
|
||||||
|
Assets.Load();
|
||||||
|
Options.Load();
|
||||||
|
|
||||||
|
// start the load sequence
|
||||||
|
Ui.SetupUiSystem(this.UiSystem);
|
||||||
|
CoroutineHandler.Start(Ui.DisplaySplash(this.LoadGame));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadGame() {
|
||||||
|
// set up online stuff
|
||||||
|
var analytics = new Dictionary<string, object>();
|
||||||
|
analytics["InfoLog"] = true;
|
||||||
|
analytics["VerboseLog"] = true;
|
||||||
|
analytics["ResourceCurrencies"] = new[] {"Tickets", "Stars"};
|
||||||
|
analytics["ResourceItemTypes"] = new[] {"Attraction", "Restart", "Upgrade", "Modifier"};
|
||||||
|
// ios comes first, then android. For now they're the same
|
||||||
|
analytics["GameKey"] = new[] {"cc18de06eebbc5d5e987c384fcd28000", "cc18de06eebbc5d5e987c384fcd28000"};
|
||||||
|
analytics["SecretKey"] = new[] {"82ca1a930ee38e2383ffb02db7631e16033b511d", "82ca1a930ee38e2383ffb02db7631e16033b511d"};
|
||||||
|
this.Platform.SetupOnlineInteractions(analytics);
|
||||||
|
|
||||||
|
this.Tutorial = new Tutorial();
|
||||||
|
|
||||||
|
if (!SaveHandler.Load(this))
|
||||||
|
this.Map = new ParkMap(20, 20);
|
||||||
|
|
||||||
|
// load other stuff
|
||||||
|
this.Ui = new Ui(this.UiSystem);
|
||||||
|
this.Camera = new Camera(this.GraphicsDevice) {
|
||||||
|
Scale = 4,
|
||||||
|
AutoScaleWithScreen = true,
|
||||||
|
AutoScaleReferenceSize = new Point(720, 1280),
|
||||||
|
MaxScale = 24,
|
||||||
|
MinScale = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// update the map once to make sure that catching up happens during loading
|
||||||
|
this.UpdateMapOnce();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DoUpdate(GameTime gameTime) {
|
||||||
|
base.DoUpdate(gameTime);
|
||||||
|
|
||||||
|
if (this.Map != null) {
|
||||||
|
// update the map
|
||||||
|
this.UpdateMapOnce();
|
||||||
|
|
||||||
|
// achievements
|
||||||
|
this.achievementCounter += gameTime.ElapsedGameTime.TotalSeconds;
|
||||||
|
if (this.achievementCounter >= 5) {
|
||||||
|
this.achievementCounter = 0;
|
||||||
|
foreach (var achievement in Achievement.Achievements.Values)
|
||||||
|
achievement.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// save every 3 seconds
|
||||||
|
this.saveCounter += gameTime.ElapsedGameTime.TotalSeconds;
|
||||||
|
if (this.saveCounter >= 3) {
|
||||||
|
this.saveCounter = 0;
|
||||||
|
SaveHandler.Save(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// play time stuff
|
||||||
|
var lastTime = this.PlayTime;
|
||||||
|
this.PlayTime += gameTime.ElapsedGameTime;
|
||||||
|
if (lastTime.TotalHours >= 1 != this.PlayTime.TotalHours >= 1)
|
||||||
|
Ui.DisplayRatePlease();
|
||||||
|
|
||||||
|
this.Ui?.Update(gameTime);
|
||||||
|
this.Tutorial?.Update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DoDraw(GameTime gameTime) {
|
||||||
|
this.GraphicsDevice.Clear(Color.Black);
|
||||||
|
if (this.DrawMap) {
|
||||||
|
this.SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, transformMatrix: this.Camera.ViewMatrix);
|
||||||
|
this.Map.Draw(gameTime, this.SpriteBatch, Vector2.Zero, 1, 1, true, this.Camera.GetVisibleRectangle());
|
||||||
|
this.SpriteBatch.End();
|
||||||
|
}
|
||||||
|
base.DoDraw(gameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger GetStarPrice() {
|
||||||
|
return 1000000000 * BigInteger.Pow(100, this.TimesRestarted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetBuyableStars() {
|
||||||
|
#if DEBUG
|
||||||
|
return 3;
|
||||||
|
#else
|
||||||
|
return (int) BigInteger.Min(3, this.Tickets / this.GetStarPrice());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateMapOnce() {
|
||||||
|
var now = DateTime.Now;
|
||||||
|
if (this.LastUpdate != default) {
|
||||||
|
var lastTickets = this.Tickets;
|
||||||
|
var lastTps = this.Map.TicketsPerSecond;
|
||||||
|
|
||||||
|
var passed = now - this.LastUpdate;
|
||||||
|
this.Map.Update(passed, passed.TotalSeconds >= 1);
|
||||||
|
|
||||||
|
// if 10 or more seconds passed, we display a message
|
||||||
|
if (Options.Instance.WhileYouWereAwayMessage && passed.TotalSeconds >= 10)
|
||||||
|
Ui.DisplayWhileYouWereAway(passed, this.Tickets - lastTickets, this.Map.TicketsPerSecond - lastTps);
|
||||||
|
}
|
||||||
|
this.LastUpdate = now;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,47 +4,46 @@ using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Content;
|
using Microsoft.Xna.Framework.Content;
|
||||||
using MLEM.Startup;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public static class Localization {
|
|
||||||
|
|
||||||
public static readonly List<string> NumberFormat = LoadLocalized<List<string>>("NumberFormat", "json5");
|
public static class Localization {
|
||||||
private static readonly Dictionary<string, string> Strings = LoadLocalized<Dictionary<string, string>>("Localization");
|
|
||||||
private static readonly Dictionary<string, string> FallbackStrings = Load<Dictionary<string, string>>("Localization");
|
|
||||||
private static readonly List<string> News = LoadLocalized<List<string>>("News");
|
|
||||||
private static readonly Random Random = new Random();
|
|
||||||
|
|
||||||
public static string Get(string key) {
|
public static readonly List<string> NumberFormat = Localization.LoadLocalized<List<string>>("NumberFormat", "json5");
|
||||||
if (Strings.TryGetValue(key, out var val))
|
private static readonly Dictionary<string, string> Strings = Localization.LoadLocalized<Dictionary<string, string>>("Localization");
|
||||||
return val;
|
private static readonly Dictionary<string, string> FallbackStrings = Localization.Load<Dictionary<string, string>>("Localization");
|
||||||
if (FallbackStrings.TryGetValue(key, out var fallback))
|
private static readonly List<string> News = Localization.LoadLocalized<List<string>>("News");
|
||||||
return fallback;
|
private static readonly Random Random = new();
|
||||||
return $"?{key}?";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetRandomNews() {
|
|
||||||
return News[Random.Next(News.Count)];
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T LoadLocalized<T>(string name, string extension = "json") {
|
|
||||||
var culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
|
|
||||||
foreach (var path in new[] {$"{name}.{culture}", name}) {
|
|
||||||
try {
|
|
||||||
return Load<T>(path, extension);
|
|
||||||
} catch (Exception) {
|
|
||||||
// move on to the next path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new ContentLoadException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T Load<T>(string name, string extension = "json") {
|
|
||||||
var path = $"{GameImpl.Instance.Content.RootDirectory}/Localization/{name}.{extension}";
|
|
||||||
using (var reader = new JsonTextReader(new StreamReader(TitleContainer.OpenStream(path))))
|
|
||||||
return SaveHandler.Serializer.Deserialize<T>(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public static string Get(string key) {
|
||||||
|
if (Localization.Strings.TryGetValue(key, out var val))
|
||||||
|
return val;
|
||||||
|
if (Localization.FallbackStrings.TryGetValue(key, out var fallback))
|
||||||
|
return fallback;
|
||||||
|
return $"?{key}?";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetRandomNews() {
|
||||||
|
return Localization.News[Localization.Random.Next(Localization.News.Count)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T LoadLocalized<T>(string name, string extension = "json") {
|
||||||
|
var culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
|
||||||
|
foreach (var path in new[] {$"{name}.{culture}", name}) {
|
||||||
|
try {
|
||||||
|
return Localization.Load<T>(path, extension);
|
||||||
|
} catch (Exception) {
|
||||||
|
// move on to the next path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ContentLoadException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T Load<T>(string name, string extension = "json") {
|
||||||
|
var path = $"{GameImpl.Instance.Content.RootDirectory}/Localization/{name}.{extension}";
|
||||||
|
using var reader = new JsonTextReader(new StreamReader(TitleContainer.OpenStream(path)));
|
||||||
|
return SaveHandler.Serializer.Deserialize<T>(reader);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,58 +3,58 @@ using System.Runtime.Serialization;
|
||||||
using Microsoft.Xna.Framework.Audio;
|
using Microsoft.Xna.Framework.Audio;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
[DataContract]
|
|
||||||
public class Options {
|
|
||||||
|
|
||||||
public static Options Instance { get; private set; }
|
[DataContract]
|
||||||
|
public class Options {
|
||||||
|
|
||||||
[DataMember]
|
public static Options Instance { get; private set; }
|
||||||
public int RainingTicketLimit = 300;
|
|
||||||
[DataMember]
|
[DataMember]
|
||||||
public float SoundVolume {
|
public int RainingTicketLimit = 300;
|
||||||
get => this.soundVolume;
|
[DataMember]
|
||||||
set {
|
public float SoundVolume {
|
||||||
this.soundVolume = value;
|
get => this.soundVolume;
|
||||||
SoundEffect.MasterVolume = value;
|
set {
|
||||||
}
|
this.soundVolume = value;
|
||||||
|
SoundEffect.MasterVolume = value;
|
||||||
}
|
}
|
||||||
private float soundVolume = 1;
|
|
||||||
[DataMember]
|
|
||||||
public bool WhileYouWereAwayMessage = true;
|
|
||||||
[DataMember]
|
|
||||||
public bool KeepScreenOn {
|
|
||||||
get => this.keepScreenOn;
|
|
||||||
set {
|
|
||||||
this.keepScreenOn = value;
|
|
||||||
GameImpl.Instance.Platform.SetKeepScreenOn(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool keepScreenOn;
|
|
||||||
[DataMember]
|
|
||||||
public bool AutoBuyEnabled = true;
|
|
||||||
[DataMember]
|
|
||||||
public int MinTicketsForAutoBuy = 50000;
|
|
||||||
|
|
||||||
public static void Save() {
|
|
||||||
var file = GetOptionsFile(true);
|
|
||||||
using (var stream = new JsonTextWriter(file.CreateText()))
|
|
||||||
SaveHandler.Serializer.Serialize(stream, Instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Load() {
|
|
||||||
var file = GetOptionsFile(false);
|
|
||||||
if (file.Exists) {
|
|
||||||
using (var stream = new JsonTextReader(file.OpenText()))
|
|
||||||
Instance = SaveHandler.Serializer.Deserialize<Options>(stream);
|
|
||||||
} else {
|
|
||||||
Instance = new Options();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FileInfo GetOptionsFile(bool create) {
|
|
||||||
return new FileInfo(Path.Combine(SaveHandler.GetGameDirectory(create).FullName, "Options"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
private float soundVolume = 1;
|
||||||
|
[DataMember]
|
||||||
|
public bool WhileYouWereAwayMessage = true;
|
||||||
|
[DataMember]
|
||||||
|
public bool KeepScreenOn {
|
||||||
|
get => this.keepScreenOn;
|
||||||
|
set {
|
||||||
|
this.keepScreenOn = value;
|
||||||
|
GameImpl.Instance.Platform.SetKeepScreenOn(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool keepScreenOn;
|
||||||
|
[DataMember]
|
||||||
|
public bool AutoBuyEnabled = true;
|
||||||
|
[DataMember]
|
||||||
|
public int MinTicketsForAutoBuy = 50000;
|
||||||
|
|
||||||
|
public static void Save() {
|
||||||
|
var file = Options.GetOptionsFile(true);
|
||||||
|
using var stream = new JsonTextWriter(file.CreateText());
|
||||||
|
SaveHandler.Serializer.Serialize(stream, Options.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Load() {
|
||||||
|
var file = Options.GetOptionsFile(false);
|
||||||
|
if (file.Exists) {
|
||||||
|
using var stream = new JsonTextReader(file.OpenText());
|
||||||
|
Options.Instance = SaveHandler.Serializer.Deserialize<Options>(stream);
|
||||||
|
} else {
|
||||||
|
Options.Instance = new Options();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FileInfo GetOptionsFile(bool create) {
|
||||||
|
return new FileInfo(Path.Combine(SaveHandler.GetGameDirectory(create).FullName, "Options"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -12,273 +12,273 @@ using MLEM.Textures;
|
||||||
using TouchyTickets.Attractions;
|
using TouchyTickets.Attractions;
|
||||||
using TouchyTickets.Upgrades;
|
using TouchyTickets.Upgrades;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
[DataContract]
|
|
||||||
public class ParkMap {
|
|
||||||
|
|
||||||
private const int AdditionalRadius = 15;
|
[DataContract]
|
||||||
private const int AutoBuyIntervalSecs = 30;
|
public class ParkMap {
|
||||||
|
|
||||||
[DataMember]
|
private const int AdditionalRadius = 15;
|
||||||
public readonly int Width;
|
private const int AutoBuyIntervalSecs = 30;
|
||||||
[DataMember]
|
|
||||||
public readonly int Height;
|
|
||||||
[DataMember]
|
|
||||||
private readonly List<(Point, Attraction)> attractions = new List<(Point, Attraction)>();
|
|
||||||
private readonly Dictionary<Point, int> treePositions = new Dictionary<Point, int>();
|
|
||||||
private readonly Dictionary<Point, int> fencePositions = new Dictionary<Point, int>();
|
|
||||||
private readonly Attraction[,] attractionGrid;
|
|
||||||
|
|
||||||
[DataMember]
|
[DataMember]
|
||||||
public double TicketsPerSecond { get; private set; }
|
public readonly int Width;
|
||||||
public Attraction PlacingAttraction;
|
[DataMember]
|
||||||
public AttractionModifier PlacingModifier;
|
public readonly int Height;
|
||||||
public Point PlacingPosition;
|
[DataMember]
|
||||||
public Point? SelectedPosition;
|
private readonly List<(Point, Attraction)> attractions = new();
|
||||||
private bool draggingAttraction;
|
private readonly Dictionary<Point, int> treePositions = new();
|
||||||
private double autoBuyCounter;
|
private readonly Dictionary<Point, int> fencePositions = new();
|
||||||
|
private readonly Attraction[,] attractionGrid;
|
||||||
|
|
||||||
public ParkMap(int width, int height) {
|
[DataMember]
|
||||||
this.Width = width;
|
public double TicketsPerSecond { get; private set; }
|
||||||
this.Height = height;
|
public Attraction PlacingAttraction;
|
||||||
this.attractionGrid = new Attraction[width, height];
|
public AttractionModifier PlacingModifier;
|
||||||
|
public Point PlacingPosition;
|
||||||
|
public Point? SelectedPosition;
|
||||||
|
private bool draggingAttraction;
|
||||||
|
private double autoBuyCounter;
|
||||||
|
|
||||||
// set up trees
|
public ParkMap(int width, int height) {
|
||||||
var random = new Random();
|
this.Width = width;
|
||||||
for (var x = -AdditionalRadius; x < this.Width + AdditionalRadius; x++) {
|
this.Height = height;
|
||||||
for (var y = -AdditionalRadius; y < this.Height + AdditionalRadius; y++) {
|
this.attractionGrid = new Attraction[width, height];
|
||||||
var pos = new Point(x, y);
|
|
||||||
if (this.IsInBounds(pos))
|
|
||||||
continue;
|
|
||||||
if (random.Next(15) != 0)
|
|
||||||
continue;
|
|
||||||
var type = random.Next(3);
|
|
||||||
this.treePositions[pos] = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set up fences
|
// set up trees
|
||||||
this.fencePositions[new Point(-1, -1)] = 2;
|
var random = new Random();
|
||||||
this.fencePositions[new Point(this.Width, -1)] = 3;
|
for (var x = -ParkMap.AdditionalRadius; x < this.Width + ParkMap.AdditionalRadius; x++) {
|
||||||
this.fencePositions[new Point(-1, this.Height)] = 4;
|
for (var y = -ParkMap.AdditionalRadius; y < this.Height + ParkMap.AdditionalRadius; y++) {
|
||||||
this.fencePositions[new Point(this.Width, this.Height)] = 5;
|
var pos = new Point(x, y);
|
||||||
for (var x = 0; x < this.Width; x++) {
|
if (this.IsInBounds(pos))
|
||||||
this.fencePositions[new Point(x, -1)] = 0;
|
continue;
|
||||||
this.fencePositions[new Point(x, this.Height)] = 0;
|
if (random.Next(15) != 0)
|
||||||
}
|
continue;
|
||||||
for (var y = 0; y < this.Height; y++) {
|
var type = random.Next(3);
|
||||||
this.fencePositions[new Point(-1, y)] = 1;
|
this.treePositions[pos] = type;
|
||||||
this.fencePositions[new Point(this.Width, y)] = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(TimeSpan passed, bool wasAway) {
|
// set up fences
|
||||||
var toSimulate = wasAway ? new TimeSpan(passed.Ticks / 2) : passed;
|
this.fencePositions[new Point(-1, -1)] = 2;
|
||||||
|
this.fencePositions[new Point(this.Width, -1)] = 3;
|
||||||
// handle auto-buying
|
this.fencePositions[new Point(-1, this.Height)] = 4;
|
||||||
this.autoBuyCounter += toSimulate.TotalSeconds;
|
this.fencePositions[new Point(this.Width, this.Height)] = 5;
|
||||||
this.TryAutoBuy();
|
for (var x = 0; x < this.Width; x++) {
|
||||||
var autoBuysPerAttraction = ((float) this.autoBuyCounter / AutoBuyIntervalSecs / this.attractions.Count).Ceil();
|
this.fencePositions[new Point(x, -1)] = 0;
|
||||||
|
this.fencePositions[new Point(x, this.Height)] = 0;
|
||||||
// update tickets
|
|
||||||
this.TicketsPerSecond = 0;
|
|
||||||
foreach (var (pos, attraction) in this.attractions) {
|
|
||||||
var genPerSecond = attraction.Update(toSimulate, this, pos);
|
|
||||||
this.TicketsPerSecond += genPerSecond;
|
|
||||||
|
|
||||||
// if we were away, we have to catch up with auto-buys while also taking into account
|
|
||||||
// the amount of tickets that each ride generates. The easiest way we can do this is
|
|
||||||
// to progress, between updating each ride, by a percentage of the total update amount
|
|
||||||
if (wasAway) {
|
|
||||||
for (var i = autoBuysPerAttraction; i > 0; i--) {
|
|
||||||
if (!this.TryAutoBuy())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// map movement
|
|
||||||
if (GameImpl.Instance.DrawMap && GameImpl.Instance.UiSystem.Controls.HandleTouch) {
|
|
||||||
var camera = GameImpl.Instance.Camera;
|
|
||||||
if (MlemGame.Input.GetGesture(GestureType.Pinch, out var pinch)) {
|
|
||||||
// pinch zoom
|
|
||||||
var center = (pinch.Position + pinch.Position2) / 2;
|
|
||||||
var newDist = Vector2.Distance(pinch.Position + pinch.Delta, pinch.Position2 + pinch.Delta2);
|
|
||||||
var oldDist = Vector2.Distance(pinch.Position, pinch.Position2);
|
|
||||||
var newScale = newDist / oldDist * camera.Scale;
|
|
||||||
camera.Zoom(newScale - camera.Scale, center);
|
|
||||||
} else if (MlemGame.Input.GetGesture(GestureType.FreeDrag, out var drag)) {
|
|
||||||
if (this.draggingAttraction) {
|
|
||||||
// move the current placing position
|
|
||||||
var nextPos = (camera.ToWorldPos(drag.Position + drag.Delta) / Assets.TileSize).ToPoint();
|
|
||||||
// drag the center of the attraction
|
|
||||||
nextPos -= new Point(this.PlacingAttraction.Type.Width / 2, this.PlacingAttraction.Type.Height / 2);
|
|
||||||
if (this.PlacingAttraction.Type.GetCoveredTiles().Select(p => nextPos + p).All(this.IsInBounds))
|
|
||||||
this.PlacingPosition = nextPos;
|
|
||||||
} else {
|
|
||||||
// move the camera
|
|
||||||
camera.Position -= drag.Delta / camera.ActualScale;
|
|
||||||
}
|
|
||||||
} else if (this.PlacingAttraction != null) {
|
|
||||||
foreach (var touch in MlemGame.Input.TouchState) {
|
|
||||||
if (touch.State != TouchLocationState.Pressed)
|
|
||||||
continue;
|
|
||||||
// when first pressing down, go into attraction drag mode if we're touching the place location
|
|
||||||
var offset = (camera.ToWorldPos(touch.Position) / Assets.TileSize).ToPoint();
|
|
||||||
this.draggingAttraction = this.PlacingAttraction.Type.GetCoveredTiles()
|
|
||||||
.Any(p => this.PlacingPosition + p == offset);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we're not placing an attraction, so we're in remove and move mode
|
|
||||||
if (MlemGame.Input.GetGesture(GestureType.Tap, out var tap) && GameImpl.Instance.UiSystem.Controls.GetElementUnderPos(tap.Position) == null) {
|
|
||||||
var pos = (camera.ToWorldPos(tap.Position) / Assets.TileSize).ToPoint();
|
|
||||||
var attraction = this.GetAttractionAt(pos);
|
|
||||||
if (attraction != null && (this.PlacingModifier == null || this.PlacingModifier.IsAffected(attraction))) {
|
|
||||||
// actually select the top left for easy usage later
|
|
||||||
this.SelectedPosition = this.attractions.First(kv => kv.Item2 == attraction).Item1;
|
|
||||||
} else {
|
|
||||||
this.SelectedPosition = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
camera.ConstrainWorldBounds(new Vector2(-AdditionalRadius) * Assets.TileSize, new Vector2(this.Width + AdditionalRadius, this.Height + AdditionalRadius) * Assets.TileSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for (var y = 0; y < this.Height; y++) {
|
||||||
public void Draw(GameTime time, SpriteBatch batch, Vector2 position, float scale, float alpha, bool showSurroundings, RectangleF visibleArea) {
|
this.fencePositions[new Point(-1, y)] = 1;
|
||||||
var tileSize = Assets.TileSize * scale;
|
this.fencePositions[new Point(this.Width, y)] = 1;
|
||||||
// draw ground
|
|
||||||
var additionalRadius = showSurroundings ? AdditionalRadius : 0;
|
|
||||||
var minX = Math.Max(-additionalRadius, visibleArea.Left / tileSize.X).Floor();
|
|
||||||
var minY = Math.Max(-additionalRadius, visibleArea.Top / tileSize.Y).Floor();
|
|
||||||
var maxX = Math.Min(this.Width + additionalRadius, visibleArea.Right / tileSize.X).Ceil();
|
|
||||||
var maxY = Math.Min(this.Height + additionalRadius, visibleArea.Bottom / tileSize.Y).Ceil();
|
|
||||||
for (var x = minX; x < maxX; x++) {
|
|
||||||
for (var y = minY; y < maxY; y++) {
|
|
||||||
var pos = new Vector2(x, y);
|
|
||||||
var drawPos = position + pos * tileSize;
|
|
||||||
batch.Draw(Assets.TilesTexture[0, 0], drawPos, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
|
|
||||||
|
|
||||||
if (this.fencePositions.TryGetValue(pos.ToPoint(), out var fenceType)) {
|
|
||||||
batch.Draw(Assets.TilesTexture[fenceType, 1], drawPos, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
|
|
||||||
} else if (this.treePositions.TryGetValue(pos.ToPoint(), out var treeType)) {
|
|
||||||
batch.Draw(Assets.TilesTexture[1 + treeType, 0], drawPos, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// selected attraction
|
|
||||||
if (this.SelectedPosition != null) {
|
|
||||||
var selected = this.SelectedPosition.Value;
|
|
||||||
var attr = this.GetAttractionAt(selected);
|
|
||||||
foreach (var pos in attr.Type.GetCoveredTiles())
|
|
||||||
batch.Draw(batch.GetBlankTexture(), new RectangleF(position + (selected + pos).ToVector2() * tileSize, tileSize), Color.Black * 0.25F * alpha);
|
|
||||||
}
|
|
||||||
// draw attractions
|
|
||||||
foreach (var (pos, attraction) in this.attractions) {
|
|
||||||
if (this.PlacingModifier != null && this.PlacingModifier.IsAffected(attraction)) {
|
|
||||||
var color = GameImpl.Instance.Tickets >= attraction.GetModifierPrice(this.PlacingModifier) ? Color.Yellow : Color.Red;
|
|
||||||
foreach (var offset in attraction.Type.GetCoveredTiles())
|
|
||||||
batch.Draw(batch.GetBlankTexture(), new RectangleF(position + (pos + offset).ToVector2() * tileSize, tileSize), color * 0.25F * alpha);
|
|
||||||
}
|
|
||||||
attraction.Draw(batch, position + pos.ToVector2() * tileSize, alpha, scale);
|
|
||||||
}
|
|
||||||
// placing attraction
|
|
||||||
if (this.PlacingAttraction != null) {
|
|
||||||
var placingPos = position + this.PlacingPosition.ToVector2() * tileSize;
|
|
||||||
var color = this.CanPlace(this.PlacingPosition, this.PlacingAttraction) ? Color.Yellow : Color.Red;
|
|
||||||
foreach (var pos in this.PlacingAttraction.Type.GetCoveredTiles())
|
|
||||||
batch.Draw(batch.GetBlankTexture(), new RectangleF(placingPos + pos.ToVector2() * tileSize, tileSize), color * 0.25F * alpha);
|
|
||||||
this.PlacingAttraction.Draw(batch, placingPos, alpha * 0.5F, scale);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanPlace(Point position, Attraction attraction) {
|
|
||||||
foreach (var offset in attraction.Type.GetCoveredTiles()) {
|
|
||||||
if (!this.IsInBounds(position + offset))
|
|
||||||
return false;
|
|
||||||
if (this.GetAttractionAt(position + offset) != null)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Place(Point position, Attraction attraction) {
|
|
||||||
foreach (var (x, y) in attraction.Type.GetCoveredTiles())
|
|
||||||
this.attractionGrid[position.X + x, position.Y + y] = attraction;
|
|
||||||
this.attractions.Add((position, attraction));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Attraction Remove(Point position) {
|
|
||||||
var attraction = this.GetAttractionAt(position);
|
|
||||||
if (attraction != null) {
|
|
||||||
foreach (var (x, y) in attraction.Type.GetCoveredTiles())
|
|
||||||
this.attractionGrid[position.X + x, position.Y + y] = null;
|
|
||||||
this.attractions.Remove((position, attraction));
|
|
||||||
}
|
|
||||||
return attraction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Attraction GetAttractionAt(Point position) {
|
|
||||||
return !this.IsInBounds(position) ? null : this.attractionGrid[position.X, position.Y];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetAttractionAmount(AttractionType type) {
|
|
||||||
return this.attractions.Count(a => type == null || a.Item2.Type == type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetModifierAmount(AttractionModifier modifier) {
|
|
||||||
return this.attractions.Sum(a => a.Item2.GetModifierAmount(modifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAnyAttractionAffected(AttractionModifier modifier) {
|
|
||||||
return this.attractions.Any(a => modifier.IsAffected(a.Item2));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<(Point, Attraction)> GetAttractions() {
|
|
||||||
foreach (var attraction in this.attractions)
|
|
||||||
yield return attraction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInBounds(Point pos) {
|
|
||||||
return pos.X >= 0 && pos.Y >= 0 && pos.X < this.Width && pos.Y < this.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ParkMap Copy(int? newWidth = null, int? newHeight = null) {
|
|
||||||
var newMap = new ParkMap(newWidth ?? this.Width, newHeight ?? this.Height);
|
|
||||||
foreach (var (pos, attraction) in this.attractions) {
|
|
||||||
if (newMap.CanPlace(pos, attraction))
|
|
||||||
newMap.Place(pos, attraction);
|
|
||||||
}
|
|
||||||
newMap.TicketsPerSecond = this.TicketsPerSecond;
|
|
||||||
return newMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryAutoBuy() {
|
|
||||||
if (!Options.Instance.AutoBuyEnabled)
|
|
||||||
return false;
|
|
||||||
if (GameImpl.Instance.Tickets < Options.Instance.MinTicketsForAutoBuy)
|
|
||||||
return false;
|
|
||||||
if (this.autoBuyCounter < AutoBuyIntervalSecs)
|
|
||||||
return false;
|
|
||||||
this.autoBuyCounter -= AutoBuyIntervalSecs;
|
|
||||||
|
|
||||||
var success = false;
|
|
||||||
// auto-buy modifiers
|
|
||||||
if (Upgrade.AutoPlaceModifiers[0].IsActive()) {
|
|
||||||
// loop through all attractions, but look at attractions with fewer applied modifiers first
|
|
||||||
foreach (var attraction in this.attractions.Select(kv => kv.Item2).OrderBy(a => a.GetModifierAmount(null))) {
|
|
||||||
var match = AttractionModifier.Modifiers.Values.Where(m => m.IsAffected(attraction));
|
|
||||||
// if we don't have level 2, we only want to increase existing modifiers
|
|
||||||
if (!Upgrade.AutoPlaceModifiers[1].IsActive())
|
|
||||||
match = match.Where(m => attraction.GetModifierAmount(m) > 0);
|
|
||||||
// we want to apply the least applied modifier on this attraction
|
|
||||||
var modifier = match.OrderBy(m => attraction.GetModifierAmount(m)).FirstOrDefault();
|
|
||||||
if (modifier != null && modifier.Buy(attraction))
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Update(TimeSpan passed, bool wasAway) {
|
||||||
|
var toSimulate = wasAway ? new TimeSpan(passed.Ticks / 2) : passed;
|
||||||
|
|
||||||
|
// handle auto-buying
|
||||||
|
this.autoBuyCounter += toSimulate.TotalSeconds;
|
||||||
|
this.TryAutoBuy();
|
||||||
|
var autoBuysPerAttraction = ((float) this.autoBuyCounter / ParkMap.AutoBuyIntervalSecs / this.attractions.Count).Ceil();
|
||||||
|
|
||||||
|
// update tickets
|
||||||
|
this.TicketsPerSecond = 0;
|
||||||
|
foreach (var (pos, attraction) in this.attractions) {
|
||||||
|
var genPerSecond = attraction.Update(toSimulate, this, pos);
|
||||||
|
this.TicketsPerSecond += genPerSecond;
|
||||||
|
|
||||||
|
// if we were away, we have to catch up with auto-buys while also taking into account
|
||||||
|
// the amount of tickets that each ride generates. The easiest way we can do this is
|
||||||
|
// to progress, between updating each ride, by a percentage of the total update amount
|
||||||
|
if (wasAway) {
|
||||||
|
for (var i = autoBuysPerAttraction; i > 0; i--) {
|
||||||
|
if (!this.TryAutoBuy())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// map movement
|
||||||
|
if (GameImpl.Instance.DrawMap && GameImpl.Instance.UiSystem.Controls.HandleTouch) {
|
||||||
|
var camera = GameImpl.Instance.Camera;
|
||||||
|
if (MlemGame.Input.GetGesture(GestureType.Pinch, out var pinch)) {
|
||||||
|
// pinch zoom
|
||||||
|
var center = (pinch.Position + pinch.Position2) / 2;
|
||||||
|
var newDist = Vector2.Distance(pinch.Position + pinch.Delta, pinch.Position2 + pinch.Delta2);
|
||||||
|
var oldDist = Vector2.Distance(pinch.Position, pinch.Position2);
|
||||||
|
var newScale = newDist / oldDist * camera.Scale;
|
||||||
|
camera.Zoom(newScale - camera.Scale, center);
|
||||||
|
} else if (MlemGame.Input.GetGesture(GestureType.FreeDrag, out var drag)) {
|
||||||
|
if (this.draggingAttraction) {
|
||||||
|
// move the current placing position
|
||||||
|
var nextPos = (camera.ToWorldPos(drag.Position + drag.Delta) / Assets.TileSize).ToPoint();
|
||||||
|
// drag the center of the attraction
|
||||||
|
nextPos -= new Point(this.PlacingAttraction.Type.Width / 2, this.PlacingAttraction.Type.Height / 2);
|
||||||
|
if (this.PlacingAttraction.Type.GetCoveredTiles().Select(p => nextPos + p).All(this.IsInBounds))
|
||||||
|
this.PlacingPosition = nextPos;
|
||||||
|
} else {
|
||||||
|
// move the camera
|
||||||
|
camera.Position -= drag.Delta / camera.ActualScale;
|
||||||
|
}
|
||||||
|
} else if (this.PlacingAttraction != null) {
|
||||||
|
foreach (var touch in MlemGame.Input.TouchState) {
|
||||||
|
if (touch.State != TouchLocationState.Pressed)
|
||||||
|
continue;
|
||||||
|
// when first pressing down, go into attraction drag mode if we're touching the place location
|
||||||
|
var offset = (camera.ToWorldPos(touch.Position) / Assets.TileSize).ToPoint();
|
||||||
|
this.draggingAttraction = this.PlacingAttraction.Type.GetCoveredTiles()
|
||||||
|
.Any(p => this.PlacingPosition + p == offset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we're not placing an attraction, so we're in remove and move mode
|
||||||
|
if (MlemGame.Input.GetGesture(GestureType.Tap, out var tap) && GameImpl.Instance.UiSystem.Controls.GetElementUnderPos(tap.Position) == null) {
|
||||||
|
var pos = (camera.ToWorldPos(tap.Position) / Assets.TileSize).ToPoint();
|
||||||
|
var attraction = this.GetAttractionAt(pos);
|
||||||
|
if (attraction != null && (this.PlacingModifier == null || this.PlacingModifier.IsAffected(attraction))) {
|
||||||
|
// actually select the top left for easy usage later
|
||||||
|
this.SelectedPosition = this.attractions.First(kv => kv.Item2 == attraction).Item1;
|
||||||
|
} else {
|
||||||
|
this.SelectedPosition = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
camera.ConstrainWorldBounds(new Vector2(-ParkMap.AdditionalRadius) * Assets.TileSize, new Vector2(this.Width + ParkMap.AdditionalRadius, this.Height + ParkMap.AdditionalRadius) * Assets.TileSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(GameTime time, SpriteBatch batch, Vector2 position, float scale, float alpha, bool showSurroundings, RectangleF visibleArea) {
|
||||||
|
var tileSize = Assets.TileSize * scale;
|
||||||
|
// draw ground
|
||||||
|
var additionalRadius = showSurroundings ? ParkMap.AdditionalRadius : 0;
|
||||||
|
var minX = Math.Max(-additionalRadius, visibleArea.Left / tileSize.X).Floor();
|
||||||
|
var minY = Math.Max(-additionalRadius, visibleArea.Top / tileSize.Y).Floor();
|
||||||
|
var maxX = Math.Min(this.Width + additionalRadius, visibleArea.Right / tileSize.X).Ceil();
|
||||||
|
var maxY = Math.Min(this.Height + additionalRadius, visibleArea.Bottom / tileSize.Y).Ceil();
|
||||||
|
for (var x = minX; x < maxX; x++) {
|
||||||
|
for (var y = minY; y < maxY; y++) {
|
||||||
|
var pos = new Vector2(x, y);
|
||||||
|
var drawPos = position + pos * tileSize;
|
||||||
|
batch.Draw(Assets.TilesTexture[0, 0], drawPos, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
|
||||||
|
|
||||||
|
if (this.fencePositions.TryGetValue(pos.ToPoint(), out var fenceType)) {
|
||||||
|
batch.Draw(Assets.TilesTexture[fenceType, 1], drawPos, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
|
||||||
|
} else if (this.treePositions.TryGetValue(pos.ToPoint(), out var treeType)) {
|
||||||
|
batch.Draw(Assets.TilesTexture[1 + treeType, 0], drawPos, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// selected attraction
|
||||||
|
if (this.SelectedPosition != null) {
|
||||||
|
var selected = this.SelectedPosition.Value;
|
||||||
|
var attr = this.GetAttractionAt(selected);
|
||||||
|
foreach (var pos in attr.Type.GetCoveredTiles())
|
||||||
|
batch.Draw(batch.GetBlankTexture(), new RectangleF(position + (selected + pos).ToVector2() * tileSize, tileSize), Color.Black * 0.25F * alpha);
|
||||||
|
}
|
||||||
|
// draw attractions
|
||||||
|
foreach (var (pos, attraction) in this.attractions) {
|
||||||
|
if (this.PlacingModifier != null && this.PlacingModifier.IsAffected(attraction)) {
|
||||||
|
var color = GameImpl.Instance.Tickets >= attraction.GetModifierPrice(this.PlacingModifier) ? Color.Yellow : Color.Red;
|
||||||
|
foreach (var offset in attraction.Type.GetCoveredTiles())
|
||||||
|
batch.Draw(batch.GetBlankTexture(), new RectangleF(position + (pos + offset).ToVector2() * tileSize, tileSize), color * 0.25F * alpha);
|
||||||
|
}
|
||||||
|
attraction.Draw(batch, position + pos.ToVector2() * tileSize, alpha, scale);
|
||||||
|
}
|
||||||
|
// placing attraction
|
||||||
|
if (this.PlacingAttraction != null) {
|
||||||
|
var placingPos = position + this.PlacingPosition.ToVector2() * tileSize;
|
||||||
|
var color = this.CanPlace(this.PlacingPosition, this.PlacingAttraction) ? Color.Yellow : Color.Red;
|
||||||
|
foreach (var pos in this.PlacingAttraction.Type.GetCoveredTiles())
|
||||||
|
batch.Draw(batch.GetBlankTexture(), new RectangleF(placingPos + pos.ToVector2() * tileSize, tileSize), color * 0.25F * alpha);
|
||||||
|
this.PlacingAttraction.Draw(batch, placingPos, alpha * 0.5F, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanPlace(Point position, Attraction attraction) {
|
||||||
|
foreach (var offset in attraction.Type.GetCoveredTiles()) {
|
||||||
|
if (!this.IsInBounds(position + offset))
|
||||||
|
return false;
|
||||||
|
if (this.GetAttractionAt(position + offset) != null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Place(Point position, Attraction attraction) {
|
||||||
|
foreach (var (x, y) in attraction.Type.GetCoveredTiles())
|
||||||
|
this.attractionGrid[position.X + x, position.Y + y] = attraction;
|
||||||
|
this.attractions.Add((position, attraction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Attraction Remove(Point position) {
|
||||||
|
var attraction = this.GetAttractionAt(position);
|
||||||
|
if (attraction != null) {
|
||||||
|
foreach (var (x, y) in attraction.Type.GetCoveredTiles())
|
||||||
|
this.attractionGrid[position.X + x, position.Y + y] = null;
|
||||||
|
this.attractions.Remove((position, attraction));
|
||||||
|
}
|
||||||
|
return attraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Attraction GetAttractionAt(Point position) {
|
||||||
|
return !this.IsInBounds(position) ? null : this.attractionGrid[position.X, position.Y];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetAttractionAmount(AttractionType type) {
|
||||||
|
return this.attractions.Count(a => type == null || a.Item2.Type == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetModifierAmount(AttractionModifier modifier) {
|
||||||
|
return this.attractions.Sum(a => a.Item2.GetModifierAmount(modifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAnyAttractionAffected(AttractionModifier modifier) {
|
||||||
|
return this.attractions.Any(a => modifier.IsAffected(a.Item2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(Point, Attraction)> GetAttractions() {
|
||||||
|
foreach (var attraction in this.attractions)
|
||||||
|
yield return attraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInBounds(Point pos) {
|
||||||
|
return pos.X >= 0 && pos.Y >= 0 && pos.X < this.Width && pos.Y < this.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParkMap Copy(int? newWidth = null, int? newHeight = null) {
|
||||||
|
var newMap = new ParkMap(newWidth ?? this.Width, newHeight ?? this.Height);
|
||||||
|
foreach (var (pos, attraction) in this.attractions) {
|
||||||
|
if (newMap.CanPlace(pos, attraction))
|
||||||
|
newMap.Place(pos, attraction);
|
||||||
|
}
|
||||||
|
newMap.TicketsPerSecond = this.TicketsPerSecond;
|
||||||
|
return newMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryAutoBuy() {
|
||||||
|
if (!Options.Instance.AutoBuyEnabled)
|
||||||
|
return false;
|
||||||
|
if (GameImpl.Instance.Tickets < Options.Instance.MinTicketsForAutoBuy)
|
||||||
|
return false;
|
||||||
|
if (this.autoBuyCounter < ParkMap.AutoBuyIntervalSecs)
|
||||||
|
return false;
|
||||||
|
this.autoBuyCounter -= ParkMap.AutoBuyIntervalSecs;
|
||||||
|
|
||||||
|
var success = false;
|
||||||
|
// auto-buy modifiers
|
||||||
|
if (Upgrade.AutoPlaceModifiers[0].IsActive()) {
|
||||||
|
// loop through all attractions, but look at attractions with fewer applied modifiers first
|
||||||
|
foreach (var attraction in this.attractions.Select(kv => kv.Item2).OrderBy(a => a.GetModifierAmount(null))) {
|
||||||
|
var match = AttractionModifier.Modifiers.Values.Where(m => m.IsAffected(attraction));
|
||||||
|
// if we don't have level 2, we only want to increase existing modifiers
|
||||||
|
if (!Upgrade.AutoPlaceModifiers[1].IsActive())
|
||||||
|
match = match.Where(m => attraction.GetModifierAmount(m) > 0);
|
||||||
|
// we want to apply the least applied modifier on this attraction
|
||||||
|
var modifier = match.OrderBy(m => attraction.GetModifierAmount(m)).FirstOrDefault();
|
||||||
|
if (modifier != null && modifier.Buy(attraction))
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,19 +1,19 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public abstract class Platform {
|
|
||||||
|
|
||||||
public abstract void SetupOnlineInteractions(Dictionary<string, object> analyticsJson);
|
public abstract class Platform {
|
||||||
|
|
||||||
public abstract void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId);
|
public abstract void SetupOnlineInteractions(Dictionary<string, object> analyticsJson);
|
||||||
|
|
||||||
public abstract void SetKeepScreenOn(bool keep);
|
public abstract void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId);
|
||||||
|
|
||||||
public abstract void OpenRateLink();
|
public abstract void SetKeepScreenOn(bool keep);
|
||||||
|
|
||||||
public abstract bool GainAchievement(Achievement achievement);
|
public abstract void OpenRateLink();
|
||||||
|
|
||||||
public abstract void ShowAchievements();
|
public abstract bool GainAchievement(Achievement achievement);
|
||||||
|
|
||||||
|
public abstract void ShowAchievements();
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -2,34 +2,33 @@ using System;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using MLEM.Extensions;
|
using MLEM.Extensions;
|
||||||
using MLEM.Misc;
|
|
||||||
using MLEM.Textures;
|
using MLEM.Textures;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public class RainingTicket {
|
|
||||||
|
|
||||||
private static readonly Random Random = new Random();
|
public class RainingTicket {
|
||||||
private readonly Vector2 speed;
|
|
||||||
private readonly float rotationSpeed;
|
|
||||||
private float rotation;
|
|
||||||
private Vector2 position;
|
|
||||||
|
|
||||||
public RainingTicket() {
|
private static readonly Random Random = new();
|
||||||
this.position = new Vector2((float) Random.NextDouble(), -0.15F);
|
private readonly Vector2 speed;
|
||||||
this.speed = new Vector2((float) Random.NextDouble() * 0.0005F - 0.00025F, 0.005F + (float) Random.NextDouble() * 0.01F);
|
private readonly float rotationSpeed;
|
||||||
this.rotationSpeed = MathHelper.ToRadians((float) Random.NextDouble() * 5);
|
private float rotation;
|
||||||
}
|
private Vector2 position;
|
||||||
|
|
||||||
public bool Update() {
|
|
||||||
this.rotation += this.rotationSpeed;
|
|
||||||
this.position += this.speed;
|
|
||||||
return this.position.Y >= 1.15F;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw(SpriteBatch batch, Vector2 viewport, float scale, Color color) {
|
|
||||||
var tex = Assets.UiTexture[2, 0];
|
|
||||||
batch.Draw(tex, this.position * viewport, color, this.rotation, tex.Size.ToVector2() / 2, scale, SpriteEffects.None, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public RainingTicket() {
|
||||||
|
this.position = new Vector2(RainingTicket.Random.NextSingle(), -0.15F);
|
||||||
|
this.speed = new Vector2(RainingTicket.Random.NextSingle() * 0.0005F - 0.00025F, 0.005F + RainingTicket.Random.NextSingle() * 0.01F);
|
||||||
|
this.rotationSpeed = MathHelper.ToRadians(RainingTicket.Random.NextSingle() * 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Update() {
|
||||||
|
this.rotation += this.rotationSpeed;
|
||||||
|
this.position += this.speed;
|
||||||
|
return this.position.Y >= 1.15F;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch batch, Vector2 viewport, float scale, Color color) {
|
||||||
|
var tex = Assets.UiTexture[2, 0];
|
||||||
|
batch.Draw(tex, this.position * viewport, color, this.rotation, tex.Size.ToVector2() / 2, scale, SpriteEffects.None, 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -6,92 +6,91 @@ using System.Numerics;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using TouchyTickets.Upgrades;
|
using TouchyTickets.Upgrades;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public static class SaveHandler {
|
|
||||||
|
|
||||||
public static readonly JsonSerializer Serializer = JsonSerializer.Create(new JsonSerializerSettings {
|
public static class SaveHandler {
|
||||||
TypeNameHandling = TypeNameHandling.Auto,
|
|
||||||
Formatting = Formatting.Indented
|
|
||||||
});
|
|
||||||
private const int SaveVersion = 3;
|
|
||||||
|
|
||||||
public static void Save(GameImpl game) {
|
public static readonly JsonSerializer Serializer = JsonSerializer.Create(new JsonSerializerSettings {
|
||||||
var file = GetSaveFile(true);
|
TypeNameHandling = TypeNameHandling.Auto,
|
||||||
using (var stream = new JsonTextWriter(file.CreateText())) {
|
Formatting = Formatting.Indented
|
||||||
var data = new SaveData {
|
});
|
||||||
SaveVersion = SaveVersion,
|
private const int SaveVersion = 3;
|
||||||
Tickets = game.Tickets,
|
|
||||||
LastUpdate = game.LastUpdate,
|
|
||||||
Map = game.Map,
|
|
||||||
Stars = game.Stars,
|
|
||||||
TimesRestarted = game.TimesRestarted,
|
|
||||||
Upgrades = game.AppliedUpgrades.Select(u => u.Name).ToList(),
|
|
||||||
TutorialStep = game.Tutorial.CurrentStep,
|
|
||||||
PlayTime = game.PlayTime
|
|
||||||
};
|
|
||||||
Serializer.Serialize(stream, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Load(GameImpl game) {
|
|
||||||
var file = GetSaveFile(false);
|
|
||||||
if (!file.Exists)
|
|
||||||
return false;
|
|
||||||
SaveData data;
|
|
||||||
using (var stream = new JsonTextReader(file.OpenText()))
|
|
||||||
data = Serializer.Deserialize<SaveData>(stream);
|
|
||||||
|
|
||||||
game.Tickets = data.Tickets;
|
|
||||||
game.LastUpdate = data.LastUpdate;
|
|
||||||
game.Map = data.Map.Copy();
|
|
||||||
game.Stars = data.Stars;
|
|
||||||
game.TimesRestarted = data.TimesRestarted;
|
|
||||||
game.AppliedUpgrades.Clear();
|
|
||||||
foreach (var name in data.Upgrades)
|
|
||||||
game.AppliedUpgrades.Add(Upgrade.Upgrades[name]);
|
|
||||||
game.Tutorial.CurrentStep = data.TutorialStep;
|
|
||||||
game.PlayTime = data.PlayTime;
|
|
||||||
|
|
||||||
// version 1 had smaller maps
|
|
||||||
if (data.SaveVersion <= 1) {
|
|
||||||
game.Map = game.Map.Copy(20, 20);
|
|
||||||
foreach (var upgrade in game.AppliedUpgrades.Intersect(Upgrade.MapSize))
|
|
||||||
upgrade.OnApplied();
|
|
||||||
}
|
|
||||||
// new tutorial additions need to be forced
|
|
||||||
if (data.SaveVersion <= 2) {
|
|
||||||
if (game.Tutorial.CurrentStep > 4)
|
|
||||||
game.Tutorial.CurrentStep = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DirectoryInfo GetGameDirectory(bool create) {
|
|
||||||
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
|
||||||
var dir = new DirectoryInfo(Path.Combine(path, "TouchyTickets"));
|
|
||||||
if (!dir.Exists && create)
|
|
||||||
dir.Create();
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FileInfo GetSaveFile(bool create) {
|
|
||||||
return new FileInfo(Path.Combine(GetGameDirectory(create).FullName, "Save"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public static void Save(GameImpl game) {
|
||||||
|
var file = SaveHandler.GetSaveFile(true);
|
||||||
|
using var stream = new JsonTextWriter(file.CreateText());
|
||||||
|
var data = new SaveData {
|
||||||
|
SaveVersion = SaveHandler.SaveVersion,
|
||||||
|
Tickets = game.Tickets,
|
||||||
|
LastUpdate = game.LastUpdate,
|
||||||
|
Map = game.Map,
|
||||||
|
Stars = game.Stars,
|
||||||
|
TimesRestarted = game.TimesRestarted,
|
||||||
|
Upgrades = game.AppliedUpgrades.Select(u => u.Name).ToList(),
|
||||||
|
TutorialStep = game.Tutorial.CurrentStep,
|
||||||
|
PlayTime = game.PlayTime
|
||||||
|
};
|
||||||
|
SaveHandler.Serializer.Serialize(stream, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SaveData {
|
public static bool Load(GameImpl game) {
|
||||||
|
var file = SaveHandler.GetSaveFile(false);
|
||||||
|
if (!file.Exists)
|
||||||
|
return false;
|
||||||
|
SaveData data;
|
||||||
|
using (var stream = new JsonTextReader(file.OpenText()))
|
||||||
|
data = SaveHandler.Serializer.Deserialize<SaveData>(stream);
|
||||||
|
|
||||||
public int SaveVersion;
|
game.Tickets = data.Tickets;
|
||||||
public BigInteger Tickets;
|
game.LastUpdate = data.LastUpdate;
|
||||||
public DateTime LastUpdate;
|
game.Map = data.Map.Copy();
|
||||||
public ParkMap Map;
|
game.Stars = data.Stars;
|
||||||
public int Stars;
|
game.TimesRestarted = data.TimesRestarted;
|
||||||
public int TimesRestarted;
|
game.AppliedUpgrades.Clear();
|
||||||
public List<string> Upgrades;
|
foreach (var name in data.Upgrades)
|
||||||
public int TutorialStep;
|
game.AppliedUpgrades.Add(Upgrade.Upgrades[name]);
|
||||||
public TimeSpan PlayTime;
|
game.Tutorial.CurrentStep = data.TutorialStep;
|
||||||
|
game.PlayTime = data.PlayTime;
|
||||||
|
|
||||||
|
// version 1 had smaller maps
|
||||||
|
if (data.SaveVersion <= 1) {
|
||||||
|
game.Map = game.Map.Copy(20, 20);
|
||||||
|
foreach (var upgrade in game.AppliedUpgrades.Intersect(Upgrade.MapSize))
|
||||||
|
upgrade.OnApplied();
|
||||||
|
}
|
||||||
|
// new tutorial additions need to be forced
|
||||||
|
if (data.SaveVersion <= 2) {
|
||||||
|
if (game.Tutorial.CurrentStep > 4)
|
||||||
|
game.Tutorial.CurrentStep = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DirectoryInfo GetGameDirectory(bool create) {
|
||||||
|
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||||
|
var dir = new DirectoryInfo(Path.Combine(path, "TouchyTickets"));
|
||||||
|
if (!dir.Exists && create)
|
||||||
|
dir.Create();
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FileInfo GetSaveFile(bool create) {
|
||||||
|
return new FileInfo(Path.Combine(SaveHandler.GetGameDirectory(create).FullName, "Save"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SaveData {
|
||||||
|
|
||||||
|
public int SaveVersion;
|
||||||
|
public BigInteger Tickets;
|
||||||
|
public DateTime LastUpdate;
|
||||||
|
public ParkMap Map;
|
||||||
|
public int Stars;
|
||||||
|
public int TimesRestarted;
|
||||||
|
public List<string> Upgrades;
|
||||||
|
public int TutorialStep;
|
||||||
|
public TimeSpan PlayTime;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Coroutine" Version="2.1.3" />
|
<PackageReference Include="Coroutine" Version="2.1.4"/>
|
||||||
<PackageReference Include="MLEM.Startup" Version="5.3.0-365" />
|
<PackageReference Include="MLEM.Startup" Version="6.1.0"/>
|
||||||
<PackageReference Include="MonoGame.Framework.Portable" Version="3.7.1.189">
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.2"/>
|
||||||
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
|
@ -4,68 +4,68 @@ using MLEM.Ui;
|
||||||
using MLEM.Ui.Elements;
|
using MLEM.Ui.Elements;
|
||||||
using TouchyTickets.Attractions;
|
using TouchyTickets.Attractions;
|
||||||
|
|
||||||
namespace TouchyTickets {
|
namespace TouchyTickets;
|
||||||
public class Tutorial {
|
|
||||||
|
|
||||||
private static readonly Step[] Steps = {
|
public class Tutorial {
|
||||||
// introduction
|
|
||||||
new Step(g => true, "Tutorial1"),
|
|
||||||
new Step(g => g.Tickets >= AttractionType.Carousel.InitialPrice, "Tutorial2"),
|
|
||||||
new Step(g => g.DrawMap && g.Map.PlacingAttraction?.Type == AttractionType.Carousel, "Tutorial3"),
|
|
||||||
new Step(g => g.Map.GetAttractionAmount(AttractionType.Carousel) > 0, "Tutorial4", "Tutorial5", "Tutorial6"),
|
|
||||||
// modifier tutorial
|
|
||||||
new Step(g => g.Map.GetAttractionAmount(null) >= 3, "Tutorial11"),
|
|
||||||
new Step(g => g.Map.PlacingModifier != null, "Tutorial12"),
|
|
||||||
new Step(g => g.Map.GetModifierAmount(null) > 0, "Tutorial13"),
|
|
||||||
// star tutorial
|
|
||||||
new Step(g => g.Tickets >= g.GetStarPrice(), "Tutorial7", "Tutorial8"),
|
|
||||||
new Step(g => g.Stars > 0, "Tutorial9", "Tutorial10")
|
|
||||||
};
|
|
||||||
public int CurrentStep;
|
|
||||||
private int currentStepMessage;
|
|
||||||
|
|
||||||
public void Update(GameImpl game) {
|
private static readonly Step[] Steps = {
|
||||||
// stop if the tutorial is finished
|
// introduction
|
||||||
if (this.CurrentStep >= Steps.Length)
|
new(_ => true, "Tutorial1"),
|
||||||
return;
|
new(g => g.Tickets >= AttractionType.Carousel.InitialPrice, "Tutorial2"),
|
||||||
// don't do anything while a tutorial box is already displaying
|
new(g => g.DrawMap && g.Map.PlacingAttraction?.Type == AttractionType.Carousel, "Tutorial3"),
|
||||||
if (game.UiSystem.Get("TutorialBox") != null)
|
new(g => g.Map.GetAttractionAmount(AttractionType.Carousel) > 0, "Tutorial4", "Tutorial5", "Tutorial6"),
|
||||||
return;
|
// modifier tutorial
|
||||||
|
new(g => g.Map.GetAttractionAmount(null) >= 3, "Tutorial11"),
|
||||||
|
new(g => g.Map.PlacingModifier != null, "Tutorial12"),
|
||||||
|
new(g => g.Map.GetModifierAmount(null) > 0, "Tutorial13"),
|
||||||
|
// star tutorial
|
||||||
|
new(g => g.Tickets >= g.GetStarPrice(), "Tutorial7", "Tutorial8"),
|
||||||
|
new(g => g.Stars > 0, "Tutorial9", "Tutorial10")
|
||||||
|
};
|
||||||
|
public int CurrentStep;
|
||||||
|
private int currentStepMessage;
|
||||||
|
|
||||||
var step = Steps[this.CurrentStep];
|
public void Update(GameImpl game) {
|
||||||
if (step.ShouldContinue(game)) {
|
// stop if the tutorial is finished
|
||||||
var infoBox = new Group(Anchor.TopLeft, Vector2.One, false) {
|
if (this.CurrentStep >= Tutorial.Steps.Length)
|
||||||
OnDrawn = (e2, time, batch, alpha) => batch.Draw(batch.GetBlankTexture(), e2.DisplayArea, Color.Black * 0.35F)
|
return;
|
||||||
};
|
// don't do anything while a tutorial box is already displaying
|
||||||
var panel = infoBox.AddChild(new Panel(Anchor.Center, new Vector2(0.8F), Vector2.Zero, true));
|
if (game.UiSystem.Get("TutorialBox") != null)
|
||||||
panel.AddChild(new Paragraph(Anchor.AutoLeft, 1, Localization.Get(step.Content[this.currentStepMessage])));
|
return;
|
||||||
panel.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 30), Localization.Get("Okay")) {
|
|
||||||
OnPressed = e2 => {
|
var step = Tutorial.Steps[this.CurrentStep];
|
||||||
game.UiSystem.Remove(e2.Root.Name);
|
if (step.ShouldContinue(game)) {
|
||||||
this.currentStepMessage++;
|
var infoBox = new Group(Anchor.TopLeft, Vector2.One, false) {
|
||||||
if (this.currentStepMessage >= step.Content.Length) {
|
OnDrawn = (e2, _, batch, _) => batch.Draw(batch.GetBlankTexture(), e2.DisplayArea, Color.Black * 0.35F)
|
||||||
this.currentStepMessage = 0;
|
};
|
||||||
this.CurrentStep++;
|
var panel = infoBox.AddChild(new Panel(Anchor.Center, new Vector2(0.8F), Vector2.Zero, true));
|
||||||
}
|
panel.AddChild(new Paragraph(Anchor.AutoLeft, 1, Localization.Get(step.Content[this.currentStepMessage])));
|
||||||
|
panel.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 30), Localization.Get("Okay")) {
|
||||||
|
OnPressed = e2 => {
|
||||||
|
game.UiSystem.Remove(e2.Root.Name);
|
||||||
|
this.currentStepMessage++;
|
||||||
|
if (this.currentStepMessage >= step.Content.Length) {
|
||||||
|
this.currentStepMessage = 0;
|
||||||
|
this.CurrentStep++;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
game.UiSystem.Add("TutorialBox", infoBox);
|
});
|
||||||
}
|
game.UiSystem.Add("TutorialBox", infoBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Step {
|
||||||
|
|
||||||
|
public readonly ContinueDelegate ShouldContinue;
|
||||||
|
public readonly string[] Content;
|
||||||
|
|
||||||
|
public Step(ContinueDelegate shouldContinue, params string[] content) {
|
||||||
|
this.ShouldContinue = shouldContinue;
|
||||||
|
this.Content = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Step {
|
public delegate bool ContinueDelegate(GameImpl game);
|
||||||
|
|
||||||
public readonly ContinueDelegate ShouldContinue;
|
|
||||||
public readonly string[] Content;
|
|
||||||
|
|
||||||
public Step(ContinueDelegate shouldContinue, params string[] content) {
|
|
||||||
this.ShouldContinue = shouldContinue;
|
|
||||||
this.Content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public delegate bool ContinueDelegate(GameImpl game);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
1368
TouchyTickets/Ui.cs
1368
TouchyTickets/Ui.cs
File diff suppressed because it is too large
Load diff
|
@ -1,23 +1,23 @@
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using TouchyTickets.Attractions;
|
using TouchyTickets.Attractions;
|
||||||
|
|
||||||
namespace TouchyTickets.Upgrades {
|
namespace TouchyTickets.Upgrades;
|
||||||
public class ModifierUpgrade : Upgrade {
|
|
||||||
|
|
||||||
private readonly AttractionFlags requiredFlag;
|
public class ModifierUpgrade : Upgrade {
|
||||||
private readonly float modifier;
|
|
||||||
|
|
||||||
public ModifierUpgrade(string name, int price, Point texture, AttractionFlags requiredFlag, float modifier, params Upgrade[] dependencies) :
|
private readonly AttractionFlags requiredFlag;
|
||||||
base(name, price, texture, dependencies) {
|
private readonly float modifier;
|
||||||
this.requiredFlag = requiredFlag;
|
|
||||||
this.modifier = modifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float GetCurrentMultiplier(AttractionType attraction) {
|
|
||||||
if (this.IsActive() && attraction.Flags.HasFlag(this.requiredFlag))
|
|
||||||
return this.modifier;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public ModifierUpgrade(string name, int price, Point texture, AttractionFlags requiredFlag, float modifier, params Upgrade[] dependencies) :
|
||||||
|
base(name, price, texture, dependencies) {
|
||||||
|
this.requiredFlag = requiredFlag;
|
||||||
|
this.modifier = modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float GetCurrentMultiplier(AttractionType attraction) {
|
||||||
|
if (this.IsActive() && attraction.Flags.HasFlag(this.requiredFlag))
|
||||||
|
return this.modifier;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,25 +2,25 @@ using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using TouchyTickets.Attractions;
|
using TouchyTickets.Attractions;
|
||||||
|
|
||||||
namespace TouchyTickets.Upgrades {
|
namespace TouchyTickets.Upgrades;
|
||||||
public class NeighborModifierUpgrade : Upgrade {
|
|
||||||
|
|
||||||
private readonly AttractionType requiredNeighbor;
|
public class NeighborModifierUpgrade : Upgrade {
|
||||||
private readonly AttractionFlags requiredFlag;
|
|
||||||
private readonly float modifier;
|
|
||||||
|
|
||||||
public NeighborModifierUpgrade(string name, int price, Point texture, AttractionType requiredNeighbor, float modifier, AttractionFlags requiredFlag = AttractionFlags.None, params Upgrade[] dependencies) :
|
private readonly AttractionType requiredNeighbor;
|
||||||
base(name, price, texture, dependencies) {
|
private readonly AttractionFlags requiredFlag;
|
||||||
this.requiredNeighbor = requiredNeighbor;
|
private readonly float modifier;
|
||||||
this.requiredFlag = requiredFlag;
|
|
||||||
this.modifier = modifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float GetCurrentMultiplier(Attraction attraction, ParkMap map, Point position) {
|
|
||||||
if (this.IsActive() && attraction.Type.Flags.HasFlag(this.requiredFlag) && attraction.GetSurrounding(map, position, this.requiredNeighbor).Any())
|
|
||||||
return this.modifier;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public NeighborModifierUpgrade(string name, int price, Point texture, AttractionType requiredNeighbor, float modifier, AttractionFlags requiredFlag = AttractionFlags.None, params Upgrade[] dependencies) :
|
||||||
|
base(name, price, texture, dependencies) {
|
||||||
|
this.requiredNeighbor = requiredNeighbor;
|
||||||
|
this.requiredFlag = requiredFlag;
|
||||||
|
this.modifier = modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float GetCurrentMultiplier(Attraction attraction, ParkMap map, Point position) {
|
||||||
|
if (this.IsActive() && attraction.Type.Flags.HasFlag(this.requiredFlag) && attraction.GetSurrounding(map, position, this.requiredNeighbor).Any())
|
||||||
|
return this.modifier;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,64 +3,65 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using MLEM.Extensions;
|
using MLEM.Extensions;
|
||||||
|
using TouchyTickets.Attractions;
|
||||||
using static TouchyTickets.Attractions.AttractionFlags;
|
using static TouchyTickets.Attractions.AttractionFlags;
|
||||||
using static TouchyTickets.Attractions.AttractionType;
|
using static TouchyTickets.Attractions.AttractionType;
|
||||||
|
|
||||||
namespace TouchyTickets.Upgrades {
|
namespace TouchyTickets.Upgrades;
|
||||||
public class Upgrade {
|
|
||||||
|
|
||||||
public static readonly Dictionary<string, Upgrade> Upgrades = new Dictionary<string, Upgrade>();
|
public class Upgrade {
|
||||||
public static readonly Upgrade[] MapSize = RegisterTiers("MapSize", 5, 1, 1, new Point(0, 3));
|
|
||||||
public static readonly Upgrade[] TapIncrease = RegisterTiers("TapIncrease", 3, 1, 0.5F, new Point(6, 3));
|
|
||||||
public static readonly Upgrade[] ModifierIncrease = RegisterTiers("ModifierIncrease", 3, 1, 1.5F, new Point(9, 3));
|
|
||||||
public static readonly Upgrade[] AutoPlaceModifiers = RegisterTiers("AutoPlaceModifiers", 2, 6, 1, new Point(10, 3));
|
|
||||||
public static readonly Upgrade FerrisWheelModifier = Register(new NeighborModifierUpgrade("FerrisWheelModifier", 1, new Point(2, 3), FerrisWheel, 2));
|
|
||||||
public static readonly Upgrade NatureModifier = Register(new ModifierUpgrade("NatureModifier", 1, new Point(8, 3), NonTechnology, 2));
|
|
||||||
public static readonly Upgrade FoodCourtModifier = Register(new NeighborModifierUpgrade("FoodCourtModifier", 2, new Point(1, 3), FoodCourt, 2));
|
|
||||||
public static readonly Upgrade RollerCoasterModifier = Register(new ModifierUpgrade("RollerCoasterModifier", 2, new Point(3, 3), FastCars, 2));
|
|
||||||
public static readonly Upgrade ManualRideModifier = Register(new ModifierUpgrade("ManualRideModifier", 2, new Point(4, 3), Walking, 3));
|
|
||||||
public static readonly Upgrade SpiralSlideModifier = Register(new NeighborModifierUpgrade("SpiralSlideModifier", 2, new Point(5, 3), SpiralSlide, 2));
|
|
||||||
public static readonly Upgrade HauntedHouseModifier = Register(new NeighborModifierUpgrade("HauntedHouseModifier", 2, new Point(7, 3), HauntedHouse, 3, Relaxed));
|
|
||||||
|
|
||||||
public readonly string Name;
|
public static readonly Dictionary<string, Upgrade> Upgrades = new();
|
||||||
public readonly int Price;
|
public static readonly Upgrade[] MapSize = Upgrade.RegisterTiers("MapSize", 5, 1, 1, new Point(0, 3));
|
||||||
public readonly Point Texture;
|
public static readonly Upgrade[] TapIncrease = Upgrade.RegisterTiers("TapIncrease", 3, 1, 0.5F, new Point(6, 3));
|
||||||
public readonly Upgrade[] Dependencies;
|
public static readonly Upgrade[] ModifierIncrease = Upgrade.RegisterTiers("ModifierIncrease", 3, 1, 1.5F, new Point(9, 3));
|
||||||
|
public static readonly Upgrade[] AutoPlaceModifiers = Upgrade.RegisterTiers("AutoPlaceModifiers", 2, 6, 1, new Point(10, 3));
|
||||||
|
public static readonly Upgrade FerrisWheelModifier = Upgrade.Register(new NeighborModifierUpgrade("FerrisWheelModifier", 1, new Point(2, 3), AttractionType.FerrisWheel, 2));
|
||||||
|
public static readonly Upgrade NatureModifier = Upgrade.Register(new ModifierUpgrade("NatureModifier", 1, new Point(8, 3), AttractionFlags.NonTechnology, 2));
|
||||||
|
public static readonly Upgrade FoodCourtModifier = Upgrade.Register(new NeighborModifierUpgrade("FoodCourtModifier", 2, new Point(1, 3), AttractionType.FoodCourt, 2));
|
||||||
|
public static readonly Upgrade RollerCoasterModifier = Upgrade.Register(new ModifierUpgrade("RollerCoasterModifier", 2, new Point(3, 3), AttractionFlags.FastCars, 2));
|
||||||
|
public static readonly Upgrade ManualRideModifier = Upgrade.Register(new ModifierUpgrade("ManualRideModifier", 2, new Point(4, 3), AttractionFlags.Walking, 3));
|
||||||
|
public static readonly Upgrade SpiralSlideModifier = Upgrade.Register(new NeighborModifierUpgrade("SpiralSlideModifier", 2, new Point(5, 3), AttractionType.SpiralSlide, 2));
|
||||||
|
public static readonly Upgrade HauntedHouseModifier = Upgrade.Register(new NeighborModifierUpgrade("HauntedHouseModifier", 2, new Point(7, 3), AttractionType.HauntedHouse, 3, AttractionFlags.Relaxed));
|
||||||
|
|
||||||
public Upgrade(string name, int price, Point texture, params Upgrade[] dependencies) {
|
public readonly string Name;
|
||||||
this.Name = name;
|
public readonly int Price;
|
||||||
this.Price = price;
|
public readonly Point Texture;
|
||||||
this.Texture = texture;
|
public readonly Upgrade[] Dependencies;
|
||||||
this.Dependencies = dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnApplied() {
|
|
||||||
// map size upgrades
|
|
||||||
if (MapSize.Contains(this)) {
|
|
||||||
var oldMap = GameImpl.Instance.Map;
|
|
||||||
GameImpl.Instance.Map = oldMap.Copy(oldMap.Width + 10, oldMap.Height + 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsActive() {
|
|
||||||
return GameImpl.Instance.AppliedUpgrades.Contains(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Upgrade Register(Upgrade upgrade) {
|
|
||||||
Upgrades.Add(upgrade.Name, upgrade);
|
|
||||||
return upgrade;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Upgrade[] RegisterTiers(string name, int amount, int startPrice, float priceIncrease, Point texture) {
|
|
||||||
var ret = new Upgrade[amount];
|
|
||||||
for (var i = 0; i < amount; i++) {
|
|
||||||
// every tier except first depends on last tier
|
|
||||||
var deps = i == 0 ? Array.Empty<Upgrade>() : new[] {ret[i - 1]};
|
|
||||||
var price = (startPrice * (1 + i * priceIncrease)).Floor();
|
|
||||||
Register(ret[i] = new Upgrade(name + (i + 1), price, texture, deps));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public Upgrade(string name, int price, Point texture, params Upgrade[] dependencies) {
|
||||||
|
this.Name = name;
|
||||||
|
this.Price = price;
|
||||||
|
this.Texture = texture;
|
||||||
|
this.Dependencies = dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnApplied() {
|
||||||
|
// map size upgrades
|
||||||
|
if (Upgrade.MapSize.Contains(this)) {
|
||||||
|
var oldMap = GameImpl.Instance.Map;
|
||||||
|
GameImpl.Instance.Map = oldMap.Copy(oldMap.Width + 10, oldMap.Height + 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsActive() {
|
||||||
|
return GameImpl.Instance.AppliedUpgrades.Contains(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Upgrade Register(Upgrade upgrade) {
|
||||||
|
Upgrade.Upgrades.Add(upgrade.Name, upgrade);
|
||||||
|
return upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Upgrade[] RegisterTiers(string name, int amount, int startPrice, float priceIncrease, Point texture) {
|
||||||
|
var ret = new Upgrade[amount];
|
||||||
|
for (var i = 0; i < amount; i++) {
|
||||||
|
// every tier except first depends on last tier
|
||||||
|
var deps = i == 0 ? Array.Empty<Upgrade>() : new[] {ret[i - 1]};
|
||||||
|
var price = (startPrice * (1 + i * priceIncrease)).Floor();
|
||||||
|
Upgrade.Register(ret[i] = new Upgrade(name + (i + 1), price, texture, deps));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
BIN
iOS/Default.png
BIN
iOS/Default.png
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
Binary file not shown.
Before Width: | Height: | Size: 729 B |
|
@ -1,37 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>0.1.0</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>Touchy Tickets</string>
|
|
||||||
<key>CFBundleIconFiles</key>
|
|
||||||
<array>
|
|
||||||
<string>GameThumbnail.png</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>Ellpeck.TouchyTickets</string>
|
|
||||||
<key>MinimumOSVersion</key>
|
|
||||||
<string>7.0</string>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>TouchyTickets</string>
|
|
||||||
<key>UIRequiresFullScreen</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIStatusBarHidden</key>
|
|
||||||
<true/>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
|
||||||
<string>LaunchScreen</string>
|
|
||||||
<!-- Allow running on iPhones (1) and iPads (2) -->
|
|
||||||
<key>UIDeviceFamily</key>
|
|
||||||
<array>
|
|
||||||
<integer>1</integer>
|
|
||||||
<integer>2</integer>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
|
@ -1,32 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using TouchyTickets;
|
|
||||||
|
|
||||||
namespace iOS {
|
|
||||||
public class IosPlatform : Platform {
|
|
||||||
|
|
||||||
public override void SetupOnlineInteractions(Dictionary<string, object> analyticsJson) {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddResourceEvent(bool sink, string currency, float amount, string itemType, string itemId) {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetKeepScreenOn(bool keep) {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OpenRateLink() {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool GainAchievement(Achievement achievement) {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ShowAchievements() {
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
|
|
||||||
<dependencies>
|
|
||||||
<deployment identifier="iOS" />
|
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530" />
|
|
||||||
</dependencies>
|
|
||||||
<scenes>
|
|
||||||
<!--View Controller-->
|
|
||||||
<scene sceneID="EHf-IW-A2E">
|
|
||||||
<objects>
|
|
||||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
|
||||||
<layoutGuides>
|
|
||||||
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb" />
|
|
||||||
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok" />
|
|
||||||
</layoutGuides>
|
|
||||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600" />
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" />
|
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite" />
|
|
||||||
</view>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder" />
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="53" y="375" />
|
|
||||||
</scene>
|
|
||||||
</scenes>
|
|
||||||
</document>
|
|
|
@ -1,30 +0,0 @@
|
||||||
using Foundation;
|
|
||||||
using MLEM.Misc;
|
|
||||||
using TouchyTickets;
|
|
||||||
using UIKit;
|
|
||||||
|
|
||||||
namespace iOS {
|
|
||||||
[Register("AppDelegate")]
|
|
||||||
internal class Program : UIApplicationDelegate {
|
|
||||||
|
|
||||||
private static GameImpl game;
|
|
||||||
|
|
||||||
private static void RunGame() {
|
|
||||||
TextInputWrapper.Current = new TextInputWrapper.Mobile();
|
|
||||||
game = new GameImpl(new IosPlatform());
|
|
||||||
game.Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The main entry point for the application.
|
|
||||||
/// </summary>
|
|
||||||
private static void Main(string[] args) {
|
|
||||||
UIApplication.Main(args, null, "AppDelegate");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void FinishedLaunching(UIApplication app) {
|
|
||||||
RunGame();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Touchy Tickets")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Touchy Tickets")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following attributes are used to specify the signing key for the assembly,
|
|
||||||
// if desired. See the Mono documentation for more information about signing.
|
|
||||||
|
|
||||||
//[assembly: AssemblyDelaySign(false)]
|
|
||||||
//[assembly: AssemblyKeyFile("")]
|
|
146
iOS/iOS.csproj
146
iOS/iOS.csproj
|
@ -1,146 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Common.props')" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
|
|
||||||
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<ProjectGuid>{CA7AB65C-57DE-412C-AF42-E7E6EDDF2D5F}</ProjectGuid>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<RootNamespace>iOS</RootNamespace>
|
|
||||||
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
|
|
||||||
<AssemblyName>iOS</AssemblyName>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>false</ConsolePause>
|
|
||||||
<MtouchArch>i386, x86_64</MtouchArch>
|
|
||||||
<MtouchLink>None</MtouchLink>
|
|
||||||
<MtouchUseRefCounting>true</MtouchUseRefCounting>
|
|
||||||
<MtouchUseSGen>true</MtouchUseSGen>
|
|
||||||
<MtouchFastDev>true</MtouchFastDev>
|
|
||||||
<MtouchDebug>true</MtouchDebug>
|
|
||||||
<MtouchProfiling>true</MtouchProfiling>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
|
|
||||||
<DebugType>none</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>false</ConsolePause>
|
|
||||||
<MtouchArch>i386, x86_64</MtouchArch>
|
|
||||||
<MtouchLink>None</MtouchLink>
|
|
||||||
<MtouchUseRefCounting>true</MtouchUseRefCounting>
|
|
||||||
<MtouchUseSGen>true</MtouchUseSGen>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>false</ConsolePause>
|
|
||||||
<MtouchArch>ARMv7, ARMv7s, ARM64</MtouchArch>
|
|
||||||
<DeviceSpecificBuild>true</DeviceSpecificBuild>
|
|
||||||
<MtouchDebug>true</MtouchDebug>
|
|
||||||
<MtouchUseSGen>true</MtouchUseSGen>
|
|
||||||
<MtouchUseRefCounting>true</MtouchUseRefCounting>
|
|
||||||
<MtouchProfiling>true</MtouchProfiling>
|
|
||||||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
|
||||||
<CodesignKey>iPhone Developer</CodesignKey>
|
|
||||||
<MtouchLink>None</MtouchLink>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
|
|
||||||
<DebugType>none</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>false</ConsolePause>
|
|
||||||
<MtouchArch>ARMv7, ARMv7s, ARM64</MtouchArch>
|
|
||||||
<MtouchUseSGen>true</MtouchUseSGen>
|
|
||||||
<MtouchUseRefCounting>true</MtouchUseRefCounting>
|
|
||||||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
|
||||||
<CodesignKey>iPhone Developer</CodesignKey>
|
|
||||||
<MtouchLink>None</MtouchLink>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
|
|
||||||
<DebugType>none</DebugType>
|
|
||||||
<Optimize>True</Optimize>
|
|
||||||
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>False</ConsolePause>
|
|
||||||
<MtouchArch>ARMv7, ARMv7s, ARM64</MtouchArch>
|
|
||||||
<MtouchUseRefCounting>true</MtouchUseRefCounting>
|
|
||||||
<MtouchUseSGen>true</MtouchUseSGen>
|
|
||||||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
|
||||||
<BuildIpa>True</BuildIpa>
|
|
||||||
<CodesignProvision>Automatic:AdHoc</CodesignProvision>
|
|
||||||
<CodesignKey>iPhone Distribution</CodesignKey>
|
|
||||||
<MtouchLink>None</MtouchLink>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' ">
|
|
||||||
<DebugType>none</DebugType>
|
|
||||||
<Optimize>True</Optimize>
|
|
||||||
<OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>False</ConsolePause>
|
|
||||||
<MtouchArch>ARMv7, ARMv7s, ARM64</MtouchArch>
|
|
||||||
<MtouchUseSGen>true</MtouchUseSGen>
|
|
||||||
<MtouchUseRefCounting>true</MtouchUseRefCounting>
|
|
||||||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
|
||||||
<CodesignProvision>Automatic:AppStore</CodesignProvision>
|
|
||||||
<CodesignKey>iPhone Distribution</CodesignKey>
|
|
||||||
<MtouchLink>None</MtouchLink>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="Xamarin.iOS" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="IosPlatform.cs" />
|
|
||||||
<Compile Include="Program.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Entitlements.plist" />
|
|
||||||
<None Include="Info.plist" />
|
|
||||||
<None Include="..\TouchyTickets\Content\*\**" />
|
|
||||||
<MonoGameContentReference Include="..\TouchyTickets\Content\Content.mgcb">
|
|
||||||
<Link>Content\Content.mgcb</Link>
|
|
||||||
</MonoGameContentReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<BundleResource Include="Default.png" />
|
|
||||||
<BundleResource Include="GameThumbnail.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<InterfaceDefinition Include="LaunchScreen.storyboard" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Contentless" Version="3.0.6" />
|
|
||||||
<PackageReference Include="GameAnalytics.Xamarin.SDK" Version="5.2.3" />
|
|
||||||
<PackageReference Include="MonoGame.Content.Builder" Version="3.7.0.9" />
|
|
||||||
<PackageReference Include="MonoGame.Framework.iOS" Version="3.8.0.1641" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\TouchyTickets\TouchyTickets.csproj">
|
|
||||||
<Project>{3df7ae69-f3f0-461a-be98-f31eb576b5e2}</Project>
|
|
||||||
<Name>TouchyTickets</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
|
||||||
</Project>
|
|
Loading…
Reference in a new issue