Started work on custom npcs. Can load in new npcs from graphics. They don't do anything but stand there...
This commit is contained in:
parent
534eda1414
commit
1fc38b964c
|
@ -0,0 +1,84 @@
|
|||
using CustomNPCFramework.Framework.Graphics;
|
||||
using CustomNPCFramework.Framework.NPCS;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using StardewModdingAPI;
|
||||
using StardewValley;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CustomNPCFramework
|
||||
{
|
||||
public class Class1 : Mod
|
||||
{
|
||||
public static IModHelper ModHelper;
|
||||
public static IMonitor ModMonitor;
|
||||
public static AssetManager assetManager;
|
||||
public override void Entry(IModHelper helper)
|
||||
{
|
||||
ModHelper = this.Helper;
|
||||
ModMonitor = this.Monitor;
|
||||
assetManager = new AssetManager();
|
||||
initializeExamples();
|
||||
assetManager.loadAssets();
|
||||
StardewModdingAPI.Events.SaveEvents.AfterLoad += SaveEvents_LoadChar;
|
||||
StardewModdingAPI.Events.LocationEvents.CurrentLocationChanged += LocationEvents_CurrentLocationChanged;
|
||||
StardewModdingAPI.Events.GameEvents.UpdateTick += GameEvents_UpdateTick;
|
||||
}
|
||||
|
||||
private void GameEvents_UpdateTick(object sender, EventArgs e)
|
||||
{
|
||||
if (Game1.player.currentLocation == null) return;
|
||||
foreach (var v in Game1.player.currentLocation.characters)
|
||||
{
|
||||
v.speed = 5;
|
||||
v.MovePosition(Game1.currentGameTime, Game1.viewport, Game1.player.currentLocation);
|
||||
ModMonitor.Log(v.name);
|
||||
}
|
||||
}
|
||||
|
||||
private void LocationEvents_CurrentLocationChanged(object sender, StardewModdingAPI.Events.EventArgsCurrentLocationChanged e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void SaveEvents_LoadChar(object sender, EventArgs e)
|
||||
{
|
||||
string path = Path.Combine(ModHelper.DirectoryPath, "Content", "Graphics", "NPCS", "Characters", "RainMan");
|
||||
assetManager.addPathCreateDirectory(new KeyValuePair<string, string>("characters", path));
|
||||
Texture2D tex=ModHelper.Content.Load<Texture2D>(Path.Combine(getShortenedDirectory(path).Remove(0,1), "character.png"));
|
||||
ExtendedNPC myNpc3 = new ExtendedNPC(new StardewValley.AnimatedSprite(tex, 0, 16, 32), new Vector2(14, 14)*Game1.tileSize, 2, "b2");
|
||||
Game1.getLocationFromName("BusStop").addCharacter(myNpc3);
|
||||
myNpc3.SetMovingDown(true);
|
||||
}
|
||||
|
||||
public void initializeExamples()
|
||||
{
|
||||
string dirPath = Path.Combine(ModHelper.DirectoryPath, "Content", "Templates");
|
||||
assetManager.addPathCreateDirectory(new KeyValuePair<string, string>("templates", dirPath));
|
||||
string filePath =Path.Combine(dirPath, "Example.json");
|
||||
if (File.Exists(filePath)) return;
|
||||
string getRelativePath = getShortenedDirectory(filePath);
|
||||
ModMonitor.Log("THIS IS THE PATH::: " + getRelativePath);
|
||||
AssetInfo info = new AssetInfo("Example", new Vector2(16, 16), false);
|
||||
info.writeToJson(filePath);
|
||||
}
|
||||
|
||||
public static string getShortenedDirectory(string path)
|
||||
{
|
||||
|
||||
string[] spliter = path.Split(new string[] { ModHelper.DirectoryPath },StringSplitOptions.None);
|
||||
return spliter[1];
|
||||
}
|
||||
|
||||
public static string getRelativeDirectory(string path)
|
||||
{
|
||||
string s = getShortenedDirectory(path);
|
||||
return s.Remove(0, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{89C7DF45-8AE5-49AC-ADA9-6312E9590829}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CustomNPCFramework</RootNamespace>
|
||||
<AssemblyName>CustomNPCFramework</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Class1.cs" />
|
||||
<Compile Include="Framework\Graphics\AssetInfo.cs" />
|
||||
<Compile Include="Framework\Graphics\AssetManager.cs" />
|
||||
<Compile Include="Framework\Graphics\AssetSheet.cs" />
|
||||
<Compile Include="Framework\NPCS\ExtendedNPC.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\Pathoschild.Stardew.ModBuildConfig.2.0.2\build\Pathoschild.Stardew.ModBuildConfig.targets" Condition="Exists('..\packages\Pathoschild.Stardew.ModBuildConfig.2.0.2\build\Pathoschild.Stardew.ModBuildConfig.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Pathoschild.Stardew.ModBuildConfig.2.0.2\build\Pathoschild.Stardew.ModBuildConfig.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Pathoschild.Stardew.ModBuildConfig.2.0.2\build\Pathoschild.Stardew.ModBuildConfig.targets'))" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,47 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CustomNPCFramework.Framework.Graphics
|
||||
{
|
||||
public class AssetInfo
|
||||
{
|
||||
public string name;
|
||||
public Vector2 assetSize;
|
||||
public bool randomizeUponLoad;
|
||||
/// <summary>
|
||||
/// A constructor use to create asset info which can then be used to create asset sheets.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the texture sheet. Can be different than the actual file name.</param>
|
||||
/// <param name="assetSize">The size of the individual sprites on the texture sheet. Ex 16x16 pixels.</param>
|
||||
/// <param name="randomizeUponLoad">If true, the index for the asset will be randomized. Good for getting variation from a texture.</param>
|
||||
public AssetInfo(string name, Vector2 assetSize, bool randomizeUponLoad)
|
||||
{
|
||||
this.name = name;
|
||||
this.assetSize = assetSize;
|
||||
this.randomizeUponLoad = randomizeUponLoad;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the json to a certain location.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public void writeToJson(string path)
|
||||
{
|
||||
Class1.ModHelper.WriteJsonFile<AssetInfo>(path, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the json from a certain location.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static AssetInfo readFromJson(string path)
|
||||
{
|
||||
return Class1.ModHelper.ReadJsonFile<AssetInfo>(path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CustomNPCFramework.Framework.Graphics
|
||||
{
|
||||
public class AssetManager
|
||||
{
|
||||
public List<AssetSheet> assets;
|
||||
public Dictionary<string,string> paths;
|
||||
|
||||
/// <summary>
|
||||
/// Basic constructor.
|
||||
/// </summary>
|
||||
public AssetManager()
|
||||
{
|
||||
this.assets = new List<AssetSheet>();
|
||||
this.paths = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default loading function from paths.
|
||||
/// </summary>
|
||||
public void loadAssets()
|
||||
{
|
||||
foreach(var path in this.paths)
|
||||
{
|
||||
string[] files= Directory.GetFiles(path.Value, "*.json");
|
||||
foreach(var file in files)
|
||||
{
|
||||
AssetInfo info = AssetInfo.readFromJson(file);
|
||||
AssetSheet sheet = new AssetSheet(info,path.Value);
|
||||
this.assets.Add(sheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an asset to be handled from the asset manager.
|
||||
/// </summary>
|
||||
/// <param name="asset"></param>
|
||||
public void addAsset(AssetSheet asset)
|
||||
{
|
||||
this.assets.Add(asset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an individual asset by its name.
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
public AssetSheet getAssetByName(string s)
|
||||
{
|
||||
foreach(var v in assets)
|
||||
{
|
||||
if (v.assetInfo.name == s) return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new path to the asset manager and create the directory for it.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public void addPathCreateDirectory(KeyValuePair<string,string> path)
|
||||
{
|
||||
this.addPath(path);
|
||||
string dir = Path.Combine(Class1.ModHelper.DirectoryPath, path.Value);
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(Class1.ModHelper.DirectoryPath, path.Value));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a path to the dictionary.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
private void addPath(KeyValuePair<string,string> path)
|
||||
{
|
||||
this.paths.Add(path.Key, path.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create appropriate directories for the path.
|
||||
/// </summary>
|
||||
private void createDirectoriesFromPaths()
|
||||
{
|
||||
foreach(var v in paths)
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(Class1.ModHelper.DirectoryPath,v.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CustomNPCFramework.Framework.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to handle loading different textures and handling opperations on those textures.
|
||||
/// </summary>
|
||||
public class AssetSheet
|
||||
{
|
||||
public Texture2D texture;
|
||||
public AssetInfo assetInfo;
|
||||
public string path;
|
||||
|
||||
public int index;
|
||||
|
||||
private int widthIndex;
|
||||
private int heightIndex;
|
||||
private int widthIndexMax;
|
||||
private int heightIndexMax;
|
||||
|
||||
public Rectangle currentAsset;
|
||||
|
||||
public AssetSheet(AssetInfo info,string path)
|
||||
{
|
||||
this.assetInfo = info;
|
||||
this.texture = Class1.ModHelper.Content.Load<Texture2D>(Class1.getShortenedDirectory(Path.Combine(path,info.name+".png")).Remove(0,1));
|
||||
|
||||
this.widthIndexMax = this.texture.Width / (int)this.assetInfo.assetSize.X;
|
||||
this.heightIndexMax = this.texture.Width / (int)this.assetInfo.assetSize.Y;
|
||||
this.index = 0;
|
||||
if (this.assetInfo.randomizeUponLoad == false)
|
||||
{
|
||||
this.widthIndex = 0;
|
||||
this.heightIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
getRandomAssetIndicies();
|
||||
setIndex();
|
||||
}
|
||||
this.currentAsset = new Rectangle(widthIndex * (int)this.assetInfo.assetSize.X, heightIndex * (int)this.assetInfo.assetSize.Y, (int)this.assetInfo.assetSize.X, (int)this.assetInfo.assetSize.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the next graphic from the texture.
|
||||
/// </summary>
|
||||
public void getNext()
|
||||
{
|
||||
//If I can still iterate through my list but my width is maxed, increment height.
|
||||
if (this.widthIndex == this.widthIndexMax - 1 && this.heightIndex != this.heightIndexMax)
|
||||
{
|
||||
this.widthIndex -= 0;
|
||||
this.heightIndex++;
|
||||
}
|
||||
//If I reached the end of my image loop to 0;
|
||||
else if (this.heightIndex == this.heightIndexMax && this.widthIndex == this.widthIndexMax - 1)
|
||||
{
|
||||
this.heightIndex = 0;
|
||||
this.widthIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If I can still iterate through my list do so.
|
||||
widthIndex++;
|
||||
}
|
||||
this.setIndex();
|
||||
this.setAsset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the last graphic from my texture.
|
||||
/// </summary>
|
||||
public void getPrevious()
|
||||
{
|
||||
//If my width index is 0 and my height index isn't decrement my height index and set the width index to the far right.
|
||||
if (this.widthIndex == 0 && this.heightIndex != 0)
|
||||
{
|
||||
this.heightIndex--;
|
||||
this.widthIndex = this.widthIndexMax - 1;
|
||||
}
|
||||
//If both my height and width indicies are 0, loop to the bottom right of the texture.
|
||||
else if (this.widthIndex == 0 && this.heightIndex == 0)
|
||||
{
|
||||
this.widthIndex = this.widthIndexMax - 1;
|
||||
this.heightIndex = this.heightIndexMax - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Just decrement my width index by 1.
|
||||
this.widthIndex--;
|
||||
}
|
||||
this.setIndex();
|
||||
this.setAsset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sets the current positioning for the rectangle index;
|
||||
/// </summary>
|
||||
private void setAsset()
|
||||
{
|
||||
this.currentAsset.X = widthIndex * (int)this.assetInfo.assetSize.X;
|
||||
this.currentAsset.Y = heightIndex * (int)this.assetInfo.assetSize.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used mainly for display purposes and length purposes.
|
||||
/// </summary>
|
||||
public void setIndex()
|
||||
{
|
||||
this.index = heightIndex * widthIndexMax + widthIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the asset index to a random value.
|
||||
/// </summary>
|
||||
public void getRandomAssetIndicies()
|
||||
{
|
||||
Random r = new Random(DateTime.Now.Millisecond);
|
||||
this.widthIndex = r.Next(0, this.widthIndexMax);
|
||||
this.widthIndex = r.Next(0, this.heightIndexMax);
|
||||
setIndex();
|
||||
setAsset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used just to get a copy of this asset sheet.
|
||||
/// </summary>
|
||||
public void clone()
|
||||
{
|
||||
var asset = new AssetSheet(this.assetInfo,(string)this.path.Clone());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,341 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using StardewValley;
|
||||
using StardewValley.Characters;
|
||||
using StardewValley.Locations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using xTile.Dimensions;
|
||||
using xTile.ObjectModel;
|
||||
using xTile.Tiles;
|
||||
|
||||
namespace CustomNPCFramework.Framework.NPCS
|
||||
{
|
||||
class ExtendedNPC :StardewValley.NPC
|
||||
{
|
||||
public ExtendedNPC() :base()
|
||||
{
|
||||
|
||||
}
|
||||
public ExtendedNPC(StardewValley.AnimatedSprite sprite,Vector2 position,int facingDirection,string name): base(sprite, position, facingDirection, name, null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override void MovePosition(GameTime time, xTile.Dimensions.Rectangle viewport, GameLocation currentLocation)
|
||||
{
|
||||
if (this.GetType() == typeof(FarmAnimal))
|
||||
this.willDestroyObjectsUnderfoot = false;
|
||||
if ((double)this.xVelocity != 0.0 || (double)this.yVelocity != 0.0)
|
||||
{
|
||||
Microsoft.Xna.Framework.Rectangle boundingBox = this.GetBoundingBox();
|
||||
boundingBox.X += (int)this.xVelocity;
|
||||
boundingBox.Y -= (int)this.yVelocity;
|
||||
if (currentLocation == null || !currentLocation.isCollidingPosition(boundingBox, viewport, false, 0, false, this))
|
||||
{
|
||||
this.position.X += this.xVelocity;
|
||||
this.position.Y -= this.yVelocity;
|
||||
}
|
||||
this.xVelocity = (float)(int)((double)this.xVelocity - (double)this.xVelocity / 2.0);
|
||||
this.yVelocity = (float)(int)((double)this.yVelocity - (double)this.yVelocity / 2.0);
|
||||
}
|
||||
else if (this.moveUp)
|
||||
{
|
||||
if (currentLocation == null || !currentLocation.isCollidingPosition(this.nextPosition(0), viewport, false, 0, false, this) || this.isCharging)
|
||||
{
|
||||
this.position.Y -= (float)(this.speed + this.addedSpeed);
|
||||
if (!this.ignoreMovementAnimation)
|
||||
{
|
||||
this.sprite.AnimateUp(time, (this.speed - 2 + this.addedSpeed) * -25, Utility.isOnScreen(this.getTileLocationPoint(), 1, currentLocation) ? "Cowboy_Footstep" : "");
|
||||
this.faceDirection(0);
|
||||
}
|
||||
}
|
||||
else if (!currentLocation.isTilePassable(this.nextPosition(0), viewport) || !this.willDestroyObjectsUnderfoot)
|
||||
this.Halt();
|
||||
else if (this.willDestroyObjectsUnderfoot)
|
||||
{
|
||||
Vector2 vector2 = new Vector2((float)(this.getStandingX() / Game1.tileSize), (float)(this.getStandingY() / Game1.tileSize - 1));
|
||||
if (currentLocation.characterDestroyObjectWithinRectangle(this.nextPosition(0), true))
|
||||
{
|
||||
this.doEmote(12, true);
|
||||
this.position.Y -= (float)(this.speed + this.addedSpeed);
|
||||
}
|
||||
else
|
||||
this.blockedInterval = this.blockedInterval + time.ElapsedGameTime.Milliseconds;
|
||||
}
|
||||
}
|
||||
else if (this.moveRight)
|
||||
{
|
||||
if (currentLocation == null || !currentLocation.isCollidingPosition(this.nextPosition(1), viewport, false, 0, false, this) || this.isCharging)
|
||||
{
|
||||
this.position.X += (float)(this.speed + this.addedSpeed);
|
||||
if (!this.ignoreMovementAnimation)
|
||||
{
|
||||
this.sprite.AnimateRight(time, (this.speed - 2 + this.addedSpeed) * -25, Utility.isOnScreen(this.getTileLocationPoint(), 1, currentLocation) ? "Cowboy_Footstep" : "");
|
||||
this.faceDirection(1);
|
||||
}
|
||||
}
|
||||
else if (!currentLocation.isTilePassable(this.nextPosition(1), viewport) || !this.willDestroyObjectsUnderfoot)
|
||||
this.Halt();
|
||||
else if (this.willDestroyObjectsUnderfoot)
|
||||
{
|
||||
Vector2 vector2 = new Vector2((float)(this.getStandingX() / Game1.tileSize + 1), (float)(this.getStandingY() / Game1.tileSize));
|
||||
if (currentLocation.characterDestroyObjectWithinRectangle(this.nextPosition(1), true))
|
||||
{
|
||||
this.doEmote(12, true);
|
||||
this.position.X += (float)(this.speed + this.addedSpeed);
|
||||
}
|
||||
else
|
||||
this.blockedInterval = this.blockedInterval + time.ElapsedGameTime.Milliseconds;
|
||||
}
|
||||
}
|
||||
else if (this.moveDown)
|
||||
{
|
||||
if (currentLocation == null || !currentLocation.isCollidingPosition(this.nextPosition(2), viewport, false, 0, false, this) || this.isCharging)
|
||||
{
|
||||
this.position.Y += (float)(this.speed + this.addedSpeed);
|
||||
if (!this.ignoreMovementAnimation)
|
||||
{
|
||||
this.sprite.AnimateDown(time, (this.speed - 2 + this.addedSpeed) * -25, Utility.isOnScreen(this.getTileLocationPoint(), 1, currentLocation) ? "Cowboy_Footstep" : "");
|
||||
this.faceDirection(2);
|
||||
}
|
||||
}
|
||||
else if (!currentLocation.isTilePassable(this.nextPosition(2), viewport) || !this.willDestroyObjectsUnderfoot)
|
||||
this.Halt();
|
||||
else if (this.willDestroyObjectsUnderfoot)
|
||||
{
|
||||
Vector2 vector2 = new Vector2((float)(this.getStandingX() / Game1.tileSize), (float)(this.getStandingY() / Game1.tileSize + 1));
|
||||
if (currentLocation.characterDestroyObjectWithinRectangle(this.nextPosition(2), true))
|
||||
{
|
||||
this.doEmote(12, true);
|
||||
this.position.Y += (float)(this.speed + this.addedSpeed);
|
||||
}
|
||||
else
|
||||
this.blockedInterval = this.blockedInterval + time.ElapsedGameTime.Milliseconds;
|
||||
}
|
||||
}
|
||||
else if (this.moveLeft)
|
||||
{
|
||||
if (currentLocation == null || !currentLocation.isCollidingPosition(this.nextPosition(3), viewport, false, 0, false, this) || this.isCharging)
|
||||
{
|
||||
this.position.X -= (float)(this.speed + this.addedSpeed);
|
||||
if (!this.ignoreMovementAnimation)
|
||||
{
|
||||
this.sprite.AnimateLeft(time, (this.speed - 2 + this.addedSpeed) * -25, Utility.isOnScreen(this.getTileLocationPoint(), 1, currentLocation) ? "Cowboy_Footstep" : "");
|
||||
this.faceDirection(3);
|
||||
}
|
||||
}
|
||||
else if (!currentLocation.isTilePassable(this.nextPosition(3), viewport) || !this.willDestroyObjectsUnderfoot)
|
||||
this.Halt();
|
||||
else if (this.willDestroyObjectsUnderfoot)
|
||||
{
|
||||
Vector2 vector2 = new Vector2((float)(this.getStandingX() / Game1.tileSize - 1), (float)(this.getStandingY() / Game1.tileSize));
|
||||
if (currentLocation.characterDestroyObjectWithinRectangle(this.nextPosition(3), true))
|
||||
{
|
||||
this.doEmote(12, true);
|
||||
this.position.X -= (float)(this.speed + this.addedSpeed);
|
||||
}
|
||||
else
|
||||
this.blockedInterval = this.blockedInterval + time.ElapsedGameTime.Milliseconds;
|
||||
}
|
||||
}
|
||||
if (this.blockedInterval >= 3000 && (double)this.blockedInterval <= 3750.0 && !Game1.eventUp)
|
||||
{
|
||||
this.doEmote(Game1.random.NextDouble() < 0.5 ? 8 : 40, true);
|
||||
this.blockedInterval = 3750;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.blockedInterval < 5000)
|
||||
return;
|
||||
this.speed = 4;
|
||||
this.isCharging = true;
|
||||
this.blockedInterval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override void draw(SpriteBatch b, float alpha = 1f)
|
||||
{
|
||||
if (this.sprite == null || this.isInvisible || !Utility.isOnScreen(this.position, 2 * Game1.tileSize))
|
||||
return;
|
||||
//Checks if the npc is swimming. If not draw it's default graphic. Do characters aside from Farmer and Penny Swim???
|
||||
if (this.swimming)
|
||||
{
|
||||
b.Draw(this.Sprite.Texture, this.getLocalPosition(Game1.viewport) + new Vector2((float)(Game1.tileSize / 2), (float)(Game1.tileSize + Game1.tileSize / 4 + this.yJumpOffset * 2)) + (this.shakeTimer > 0 ? new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)) : Vector2.Zero) - new Vector2(0.0f, this.yOffset), new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(this.sprite.SourceRect.X, this.sprite.SourceRect.Y, this.sprite.SourceRect.Width, this.sprite.SourceRect.Height / 2 - (int)((double)this.yOffset / (double)Game1.pixelZoom))), Color.White, this.rotation, new Vector2((float)(Game1.tileSize / 2), (float)(Game1.tileSize * 3 / 2)) / 4f, Math.Max(0.2f, this.scale) * (float)Game1.pixelZoom, this.flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None, Math.Max(0.0f, this.drawOnTop ? 0.991f : (float)this.getStandingY() / 10000f));
|
||||
Vector2 localPosition = this.getLocalPosition(Game1.viewport);
|
||||
b.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle((int)localPosition.X + (int)this.yOffset + Game1.pixelZoom * 2, (int)localPosition.Y - 32 * Game1.pixelZoom + this.sprite.SourceRect.Height * Game1.pixelZoom + Game1.tileSize * 3 / 4 + this.yJumpOffset * 2 - (int)this.yOffset, this.sprite.SourceRect.Width * Game1.pixelZoom - (int)this.yOffset * 2 - Game1.pixelZoom * 4, Game1.pixelZoom), new Microsoft.Xna.Framework.Rectangle?(Game1.staminaRect.Bounds), Color.White * 0.75f, 0.0f, Vector2.Zero, SpriteEffects.None, (float)((double)this.getStandingY() / 10000.0 + 1.0 / 1000.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
b.Draw(this.Sprite.Texture, this.getLocalPosition(Game1.viewport) + new Vector2((float)(this.sprite.spriteWidth * Game1.pixelZoom / 2), (float)(this.GetBoundingBox().Height / 2)) + (this.shakeTimer > 0 ? new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)) : Vector2.Zero), new Microsoft.Xna.Framework.Rectangle?(this.Sprite.SourceRect), Color.White * alpha, this.rotation, new Vector2((float)(this.sprite.spriteWidth / 2), (float)((double)this.sprite.spriteHeight * 3.0 / 4.0)), Math.Max(0.2f, this.scale) * (float)Game1.pixelZoom, this.flip || this.sprite.currentAnimation != null && this.sprite.currentAnimation[this.sprite.currentAnimationIndex].flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None, Math.Max(0.0f, this.drawOnTop ? 0.991f : (float)this.getStandingY() / 10000f));
|
||||
}
|
||||
//If the npc breathes then this code is ran.
|
||||
if (this.breather && this.shakeTimer <= 0 && (!this.swimming && this.sprite.CurrentFrame < 16) && !this.farmerPassesThrough)
|
||||
{
|
||||
Microsoft.Xna.Framework.Rectangle sourceRect = this.sprite.SourceRect;
|
||||
sourceRect.Y += this.sprite.spriteHeight / 2 + this.sprite.spriteHeight / 32;
|
||||
sourceRect.Height = this.sprite.spriteHeight / 4;
|
||||
sourceRect.X += this.sprite.spriteWidth / 4;
|
||||
sourceRect.Width = this.sprite.spriteWidth / 2;
|
||||
Vector2 vector2 = new Vector2((float)(this.sprite.spriteWidth * Game1.pixelZoom / 2), (float)(Game1.tileSize / 8));
|
||||
if (this.age == 2)
|
||||
{
|
||||
sourceRect.Y += this.sprite.spriteHeight / 6 + 1;
|
||||
sourceRect.Height /= 2;
|
||||
vector2.Y += (float)(this.sprite.spriteHeight / 8 * Game1.pixelZoom);
|
||||
}
|
||||
else if (this.gender == 1)
|
||||
{
|
||||
++sourceRect.Y;
|
||||
vector2.Y -= (float)Game1.pixelZoom;
|
||||
sourceRect.Height /= 2;
|
||||
}
|
||||
float num = Math.Max(0.0f, (float)(Math.Ceiling(Math.Sin(Game1.currentGameTime.TotalGameTime.TotalMilliseconds / 600.0 + (double)this.DefaultPosition.X * 20.0)) / 4.0));
|
||||
b.Draw(this.Sprite.Texture, this.getLocalPosition(Game1.viewport) + vector2 + (this.shakeTimer > 0 ? new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)) : Vector2.Zero), new Microsoft.Xna.Framework.Rectangle?(sourceRect), Color.White * alpha, this.rotation, new Vector2((float)(sourceRect.Width / 2), (float)(sourceRect.Height / 2 + 1)), Math.Max(0.2f, this.scale) * (float)Game1.pixelZoom + num, this.flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None, Math.Max(0.0f, this.drawOnTop ? 0.992f : (float)((double)this.getStandingY() / 10000.0 + 1.0 / 1000.0)));
|
||||
}
|
||||
|
||||
//Checks if the npc is glowing.
|
||||
if (this.isGlowing)
|
||||
b.Draw(this.Sprite.Texture, this.getLocalPosition(Game1.viewport) + new Vector2((float)(this.sprite.spriteWidth * Game1.pixelZoom / 2), (float)(this.GetBoundingBox().Height / 2)) + (this.shakeTimer > 0 ? new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)) : Vector2.Zero), new Microsoft.Xna.Framework.Rectangle?(this.Sprite.SourceRect), this.glowingColor * this.glowingTransparency, this.rotation, new Vector2((float)(this.sprite.spriteWidth / 2), (float)((double)this.sprite.spriteHeight * 3.0 / 4.0)), Math.Max(0.2f, this.scale) * 4f, this.flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None, Math.Max(0.0f, this.drawOnTop ? 0.99f : (float)((double)this.getStandingY() / 10000.0 + 1.0 / 1000.0)));
|
||||
|
||||
//This code runs if the npc is emoting.
|
||||
if (!this.IsEmoting || Game1.eventUp)
|
||||
return;
|
||||
Vector2 localPosition1 = this.getLocalPosition(Game1.viewport);
|
||||
localPosition1.Y -= (float)(Game1.tileSize / 2 + this.sprite.spriteHeight * Game1.pixelZoom);
|
||||
b.Draw(Game1.emoteSpriteSheet, localPosition1, new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(this.CurrentEmoteIndex * 16 % Game1.emoteSpriteSheet.Width, this.CurrentEmoteIndex * 16 / Game1.emoteSpriteSheet.Width * 16, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)Game1.pixelZoom, SpriteEffects.None, (float)this.getStandingY() / 10000f);
|
||||
}
|
||||
|
||||
|
||||
public override void updateMovement(GameLocation location, GameTime time)
|
||||
{
|
||||
this.lastPosition = this.position;
|
||||
if (this.DirectionsToNewLocation != null && !Game1.newDay)
|
||||
{
|
||||
if (this.getStandingX() < -Game1.tileSize || this.getStandingX() > location.map.DisplayWidth + Game1.tileSize || (this.getStandingY() < -Game1.tileSize || this.getStandingY() > location.map.DisplayHeight + Game1.tileSize))
|
||||
{
|
||||
this.IsWalkingInSquare = false;
|
||||
Game1.warpCharacter(this, this.DefaultMap, this.DefaultPosition, true, true);
|
||||
location.characters.Remove(this);
|
||||
}
|
||||
else if (this.IsWalkingInSquare)
|
||||
{
|
||||
this.returnToEndPoint();
|
||||
this.MovePosition(time, Game1.viewport, location);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.followSchedule)
|
||||
return;
|
||||
this.MovePosition(time, Game1.viewport, location);
|
||||
Warp warp = location.isCollidingWithWarp(this.GetBoundingBox());
|
||||
PropertyValue propertyValue = (PropertyValue)null;
|
||||
Tile tile1 = location.map.GetLayer("Buildings").PickTile(this.nextPositionPoint(), Game1.viewport.Size);
|
||||
if (tile1 != null)
|
||||
tile1.Properties.TryGetValue("Action", out propertyValue);
|
||||
string[] strArray1;
|
||||
if (propertyValue != null)
|
||||
strArray1 = propertyValue.ToString().Split(' ');
|
||||
else
|
||||
strArray1 = (string[])null;
|
||||
string[] strArray2 = strArray1;
|
||||
if (warp != null)
|
||||
{
|
||||
if (location is BusStop && warp.TargetName.Equals("Farm"))
|
||||
{
|
||||
Point entryLocation = ((this.isMarried() ? (GameLocation)(this.getHome() as FarmHouse) : Game1.getLocationFromName("FarmHouse")) as FarmHouse).getEntryLocation();
|
||||
warp = new Warp(warp.X, warp.Y, "FarmHouse", entryLocation.X, entryLocation.Y, false);
|
||||
}
|
||||
else if (location is FarmHouse && warp.TargetName.Equals("Farm"))
|
||||
warp = new Warp(warp.X, warp.Y, "BusStop", 0, 23, false);
|
||||
Game1.warpCharacter(this, warp.TargetName, new Vector2((float)(warp.TargetX * Game1.tileSize), (float)(warp.TargetY * Game1.tileSize - this.Sprite.getHeight() / 2 - Game1.tileSize / 4)), false, location.IsOutdoors);
|
||||
location.characters.Remove(this);
|
||||
}
|
||||
else if (strArray2 != null && strArray2.Length >= 1 && strArray2[0].Contains("Warp"))
|
||||
{
|
||||
Game1.warpCharacter(this, strArray2[3], new Vector2((float)Convert.ToInt32(strArray2[1]), (float)Convert.ToInt32(strArray2[2])), false, location.IsOutdoors);
|
||||
if (Game1.currentLocation.name.Equals(location.name) && Utility.isOnScreen(this.getStandingPosition(), Game1.tileSize * 3))
|
||||
Game1.playSound("doorClose");
|
||||
location.characters.Remove(this);
|
||||
}
|
||||
else if (strArray2 != null && strArray2.Length >= 1 && strArray2[0].Contains("Door"))
|
||||
{
|
||||
location.openDoor(new Location(this.nextPositionPoint().X / Game1.tileSize, this.nextPositionPoint().Y / Game1.tileSize), Game1.player.currentLocation.Equals((object)location));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (location.map.GetLayer("Paths") == null)
|
||||
return;
|
||||
Tile tile2 = location.map.GetLayer("Paths").PickTile(new Location(this.getStandingX(), this.getStandingY()), Game1.viewport.Size);
|
||||
Microsoft.Xna.Framework.Rectangle boundingBox = this.GetBoundingBox();
|
||||
boundingBox.Inflate(2, 2);
|
||||
if (tile2 == null || !new Microsoft.Xna.Framework.Rectangle(this.getStandingX() - this.getStandingX() % Game1.tileSize, this.getStandingY() - this.getStandingY() % Game1.tileSize, Game1.tileSize, Game1.tileSize).Contains(boundingBox))
|
||||
return;
|
||||
switch (tile2.TileIndex)
|
||||
{
|
||||
case 0:
|
||||
if (this.getDirection() == 3)
|
||||
{
|
||||
this.SetMovingOnlyUp();
|
||||
break;
|
||||
}
|
||||
if (this.getDirection() != 2)
|
||||
break;
|
||||
this.SetMovingOnlyRight();
|
||||
break;
|
||||
case 1:
|
||||
if (this.getDirection() == 3)
|
||||
{
|
||||
this.SetMovingOnlyDown();
|
||||
break;
|
||||
}
|
||||
if (this.getDirection() != 0)
|
||||
break;
|
||||
this.SetMovingOnlyRight();
|
||||
break;
|
||||
case 2:
|
||||
if (this.getDirection() == 1)
|
||||
{
|
||||
this.SetMovingOnlyDown();
|
||||
break;
|
||||
}
|
||||
if (this.getDirection() != 0)
|
||||
break;
|
||||
this.SetMovingOnlyLeft();
|
||||
break;
|
||||
case 3:
|
||||
if (this.getDirection() == 1)
|
||||
{
|
||||
this.SetMovingOnlyUp();
|
||||
break;
|
||||
}
|
||||
if (this.getDirection() != 2)
|
||||
break;
|
||||
this.SetMovingOnlyLeft();
|
||||
break;
|
||||
case 4:
|
||||
this.changeSchedulePathDirection();
|
||||
this.moveCharacterOnSchedulePath();
|
||||
break;
|
||||
case 7:
|
||||
this.ReachedEndPoint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.IsWalkingInSquare)
|
||||
return;
|
||||
this.randomSquareMovement(time);
|
||||
this.MovePosition(time, Game1.viewport, location);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
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("CustomNPCFramework")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("CustomNPCFramework")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("89c7df45-8ae5-49ac-ada9-6312e9590829")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"Name": "CustomNPCFramework",
|
||||
"Author": "Alpha_Omegasis",
|
||||
"Version": "0.1.0",
|
||||
"Description": "A system to add custom npcs to Stardew.",
|
||||
"UniqueID": "Omegasis.CustomNPCFramework",
|
||||
"EntryDll": "CustomNPCFramework.dll",
|
||||
"MinimumApiVersion": "2.0",
|
||||
"UpdateKeys": [ ]
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Pathoschild.Stardew.ModBuildConfig" version="2.0.2" targetFramework="net45" />
|
||||
</packages>
|
|
@ -82,6 +82,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SundropMapEvents", "Sundrop
|
|||
{BB737337-2D82-4245-AA46-F3B82FC6F228} = {BB737337-2D82-4245-AA46-F3B82FC6F228}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomNPCFramework", "CustomNPCFramework\CustomNPCFramework.csproj", "{89C7DF45-8AE5-49AC-ADA9-6312E9590829}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -188,6 +190,10 @@ Global
|
|||
{29A68F94-B23C-442B-8867-8B8F3502E64F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{29A68F94-B23C-442B-8867-8B8F3502E64F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{29A68F94-B23C-442B-8867-8B8F3502E64F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{89C7DF45-8AE5-49AC-ADA9-6312E9590829}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{89C7DF45-8AE5-49AC-ADA9-6312E9590829}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89C7DF45-8AE5-49AC-ADA9-6312E9590829}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{89C7DF45-8AE5-49AC-ADA9-6312E9590829}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -197,5 +203,6 @@ Global
|
|||
{BB737337-2D82-4245-AA46-F3B82FC6F228} = {3EE26DA0-0337-4991-8B02-BCB8D408008C}
|
||||
{BAAC8F21-C12F-42B0-A51C-0C5F33B52575} = {3EE26DA0-0337-4991-8B02-BCB8D408008C}
|
||||
{29A68F94-B23C-442B-8867-8B8F3502E64F} = {BAAC8F21-C12F-42B0-A51C-0C5F33B52575}
|
||||
{89C7DF45-8AE5-49AC-ADA9-6312E9590829} = {3EE26DA0-0337-4991-8B02-BCB8D408008C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
Loading…
Reference in New Issue