using System; using System.Collections.Generic; using System.IO; using System.Linq; using CustomNPCFramework.Framework.Enums; using CustomNPCFramework.Framework.ModularNpcs; using CustomNPCFramework.Framework.ModularNpcs.CharacterAnimationBases; using CustomNPCFramework.Framework.ModularNpcs.ColorCollections; using CustomNPCFramework.Framework.ModularNpcs.ModularRenderers; using CustomNPCFramework.Framework.NPCS; using StardewValley; namespace CustomNPCFramework.Framework.Graphics { /// Used to hold a collection of strings. public class NamePairings { public string leftString; public string rightString; public string upString; public string downString; public NamePairings(string LeftString, string RightString, string UpString, string DownString) { this.leftString = LeftString; this.rightString = RightString; this.upString = UpString; this.downString = DownString; } } /// Used to contain all of the asset managers. public class AssetPool { /// A dictionary holding all of the asset managers. (Name, AssetManager) public Dictionary assetPool; /// Construct an instance. public AssetPool() { this.assetPool = new Dictionary(); } /// Adds an asset manager to the asset pool. /// A key value pair with the convention being (Manager Name, Asset Manager) public void addAssetManager(KeyValuePair pair) { this.assetPool.Add(pair.Key, pair.Value); } /// Adds an asset manager to the asset pool. /// The name of the asset manager to be added. /// The asset manager object to be added to the asset pool. public void addAssetManager(string assetManagerName, AssetManager assetManager) { this.assetPool.Add(assetManagerName, assetManager); } /// Get an asset manager from the asset pool from a name. /// The name of the asset manager to return. public AssetManager getAssetManager(string name) { this.assetPool.TryGetValue(name, out AssetManager asset); return asset; } /// Remove an asset manager from the asset pool. /// The name of the asset manager to remove. public void removeAssetManager(string key) { this.assetPool.Remove(key); } /// Go through all of the asset managers and load assets according to their respective paths. public void loadAllAssets() { foreach (KeyValuePair assetManager in this.assetPool) assetManager.Value.loadAssets(); } /// Creates an extended animated sprite object given the asset name in the asset manager. /// The asset name. public AnimatedSpriteExtended getAnimatedSpriteFromAsset(string name) { this.assetPool.TryGetValue(name, out AssetManager asset); var assetSheet = asset.getAssetByName(name); return new AnimatedSpriteExtended(assetSheet.path.Clone().ToString(), assetSheet.index, (int)assetSheet.assetInfo.assetSize.X, (int)assetSheet.assetInfo.assetSize.Y); } /// Generates a new AnimatedSpriteCollection object from the data held in an asset sheet. /// An asset sheet that holds the data for textures. /// The type of asset to get from the sheet. Hair, eyes, shoes, etc. public AnimatedSpriteCollection getSpriteCollectionFromSheet(AssetSheet assetSheet, AnimationType type) { var left = new AnimatedSpriteExtended(assetSheet.clone().getTexture(Direction.left, type), assetSheet); var right = new AnimatedSpriteExtended(assetSheet.clone().getTexture(Direction.right, type), assetSheet); var up = new AnimatedSpriteExtended(assetSheet.clone().getTexture(Direction.up, type), assetSheet); var down = new AnimatedSpriteExtended(assetSheet.clone().getTexture(Direction.down, type), assetSheet); return new AnimatedSpriteCollection(left, right, up, down, Direction.down); } /// Gets an animated sprite collection (ie a hair style facing all four directions) from a list of asset names. /// The name of the asset for the left facing sprite. /// The name of the asset for the right facing sprite. /// The name of the asset for the up facing sprite. /// The name of the asset for the down facing sprite. /// The sprite's starting direction. public AnimatedSpriteCollection getAnimatedSpriteCollectionFromAssets(string left, string right, string up, string down, Direction startingDirection = Direction.down) { var leftSprite = this.getAnimatedSpriteFromAsset(left); var rightSprite = this.getAnimatedSpriteFromAsset(right); var upSprite = this.getAnimatedSpriteFromAsset(up); var downSprite = this.getAnimatedSpriteFromAsset(down); return new AnimatedSpriteCollection(leftSprite, rightSprite, upSprite, downSprite, startingDirection); } /// Get an AnimatedSpriteCollection from a name pairing. /// A collection of strings that hold information on directional textures. /// The direction in which the sprite should face. public AnimatedSpriteCollection getAnimatedSpriteCollectionFromAssets(NamePairings pair, Direction startingDirection = Direction.down) { return this.getAnimatedSpriteCollectionFromAssets(pair.leftString, pair.rightString, pair.upString, pair.downString); } /// Get a collection of sprites to generate a collective animated sprite. /// The collection of sprites to be used for the boyd of the npc. /// The collection of sprites to be used for the eye of the npc. /// The collection of sprites to be used for the hair of the npc. /// The collection of sprites to be used for the shirts of the npc. /// The collection of sprites to be used for the pants of the npc. /// The collection of sprites to be used for the shoes of the npc. /// The collection of sprites to be used for the accessories of the npc. /// The collection of collors to be used for chaing the color of an individual asset. public StandardCharacterAnimation GetStandardCharacterAnimation(NamePairings BodySprites, NamePairings EyeSprites, NamePairings HairSprites, NamePairings ShirtsSprites, NamePairings PantsSprites, NamePairings ShoesSprites, List AccessoriesSprites, StandardColorCollection DrawColors = null) { var body = this.getAnimatedSpriteCollectionFromAssets(BodySprites); var eyes = this.getAnimatedSpriteCollectionFromAssets(EyeSprites); var hair = this.getAnimatedSpriteCollectionFromAssets(HairSprites); var shirts = this.getAnimatedSpriteCollectionFromAssets(ShirtsSprites); var pants = this.getAnimatedSpriteCollectionFromAssets(PantsSprites); var shoes = this.getAnimatedSpriteCollectionFromAssets(ShoesSprites); List accessories = new List(); foreach (var v in AccessoriesSprites) accessories.Add(this.getAnimatedSpriteCollectionFromAssets(v)); if (DrawColors == null) DrawColors = new StandardColorCollection(); return new StandardCharacterAnimation(body, eyes, hair, shirts, pants, shoes, accessories, DrawColors); } /// Get a list of parts that can apply for this criteria. /// The name of the asset manager. /// The gender critera. /// The season critera. /// The part type critera. public List getListOfApplicableBodyParts(string assetManagerName, Genders gender, Seasons season, PartType type) { var parts = this.getAssetManager(assetManagerName).getListOfAssetsThatMatchThisCriteria(gender, season, type); return parts; } /// Generate a basic NPC based on the NPC data here. /// The NPC gender. /// The minimum number of accessories to generate. /// The maximum number of accessories to generate. /// The colors for the NPC's different assets. public ExtendedNpc generateNPC(Genders gender, int minNumOfAccessories, int maxNumOfAccessories, StandardColorCollection drawColors = null) { Seasons myseason = Seasons.spring; if (Game1.currentSeason == "spring") myseason = Seasons.spring; if (Game1.currentSeason == "summer") myseason = Seasons.summer; if (Game1.currentSeason == "fall") myseason = Seasons.fall; if (Game1.currentSeason == "winter") myseason = Seasons.winter; List bodyList = new List(); List eyesList = new List(); List hairList = new List(); List shirtList = new List(); List shoesList = new List(); List pantsList = new List(); List accessoryList = new List(); //Get all applicable parts from this current asset manager foreach (var assetManager in this.assetPool) { var body = this.getListOfApplicableBodyParts(assetManager.Key, gender, myseason, PartType.body); foreach (var piece in body) bodyList.Add(piece); var eyes = this.getListOfApplicableBodyParts(assetManager.Key, gender, myseason, PartType.eyes); foreach (var piece in eyes) eyesList.Add(piece); var hair = this.getListOfApplicableBodyParts(assetManager.Key, gender, myseason, PartType.hair); foreach (var piece in hair) hairList.Add(piece); var shirt = this.getListOfApplicableBodyParts(assetManager.Key, gender, myseason, PartType.shirt); foreach (var piece in shirt) shirtList.Add(piece); var pants = this.getListOfApplicableBodyParts(assetManager.Key, gender, myseason, PartType.pants); foreach (var piece in pants) pantsList.Add(piece); var shoes = this.getListOfApplicableBodyParts(assetManager.Key, gender, myseason, PartType.shoes); foreach (var piece in shoes) shoesList.Add(piece); var accessory = this.getListOfApplicableBodyParts(assetManager.Key, gender, myseason, PartType.accessory); foreach (var piece in accessory) accessoryList.Add(piece); } Random r = new Random(DateTime.Now.Millisecond); int amount = r.Next(minNumOfAccessories, maxNumOfAccessories + 1); int bodyIndex; int eyesIndex; int hairIndex; int shirtIndex; int pantsIndex; int shoesIndex; if (bodyList.Count != 0) bodyIndex = r.Next(0, bodyList.Count - 1); else { Class1.ModMonitor.Log("Error: Not enough body templates to generate an npc. Aborting", StardewModdingAPI.LogLevel.Error); return null; } if (eyesList.Count != 0) eyesIndex = r.Next(0, eyesList.Count - 1); else { Class1.ModMonitor.Log("Error: Not enough eyes templates to generate an npc. Aborting", StardewModdingAPI.LogLevel.Error); return null; } if (hairList.Count != 0) hairIndex = r.Next(0, hairList.Count - 1); else { Class1.ModMonitor.Log("Error: Not enough hair templates to generate an npc. Aborting", StardewModdingAPI.LogLevel.Error); return null; } if (shirtList.Count != 0) shirtIndex = r.Next(0, shirtList.Count - 1); else { Class1.ModMonitor.Log("Error: Not enough shirt templates to generate an npc. Aborting", StardewModdingAPI.LogLevel.Error); return null; } if (pantsList.Count != 0) pantsIndex = r.Next(0, pantsList.Count - 1); else { Class1.ModMonitor.Log("Error: Not enough pants templates to generate an npc. Aborting", StardewModdingAPI.LogLevel.Error); return null; } if (shoesList.Count != 0) shoesIndex = r.Next(0, shoesList.Count - 1); else { Class1.ModMonitor.Log("Error: Not enough shoes templates to generate an npc. Aborting", StardewModdingAPI.LogLevel.Error); return null; } List accIntList = new List(); if (accessoryList.Count != 0) { for (int i = 0; i < amount; i++) { int acc = r.Next(0, accessoryList.Count - 1); accIntList.Add(acc); } } //Get a single sheet to pull from. AssetSheet bodySheet = bodyList.ElementAt(bodyIndex); AssetSheet eyesSheet = eyesList.ElementAt(eyesIndex); AssetSheet hairSheet = hairList.ElementAt(hairIndex); AssetSheet shirtSheet = shirtList.ElementAt(shirtIndex); AssetSheet pantsSheet = pantsList.ElementAt(pantsIndex); AssetSheet shoesSheet = shoesList.ElementAt(shoesIndex); List accessorySheet = new List(); foreach (int v in accIntList) accessorySheet.Add(accessoryList.ElementAt(v)); if (drawColors == null) drawColors = new StandardColorCollection(); var render = this.generateBasicRenderer(bodySheet, eyesSheet, hairSheet, shirtSheet, pantsSheet, shoesSheet, accessorySheet, drawColors); return new ExtendedNpc(new Sprite(this.getDefaultSpriteImage(bodySheet)), render, new Microsoft.Xna.Framework.Vector2(0, 0) * Game1.tileSize, 2, NpcNames.getRandomNpcName(gender)); } /// Creates a character renderer (a collection of textures) from a bunch of different asset sheets. /// The textures for the NPC's body. /// The textures for the NPC's eyes. /// The textures for the NPC's hair. /// The textures for the NPC's shirt. /// The textures for the NPC's pants. /// The textures for the NPC's shoes. /// The textures for the NPC's accessories. /// The colors for the NPC's different assets. public virtual BasicRenderer generateBasicRenderer(AssetSheet bodySheet, AssetSheet eyesSheet, AssetSheet hairSheet, AssetSheet shirtSheet, AssetSheet pantsSheet, AssetSheet shoesSheet, List accessorySheet, StandardColorCollection drawColors = null) { if (drawColors == null) drawColors = new StandardColorCollection(); // Get all of the appropriate animations. StandardCharacterAnimation standingAnimation = this.generateCharacterAnimation(bodySheet, eyesSheet, hairSheet, shirtSheet, pantsSheet, shoesSheet, accessorySheet, AnimationType.standing, drawColors); StandardCharacterAnimation movingAnimation = this.generateCharacterAnimation(bodySheet, eyesSheet, hairSheet, shirtSheet, pantsSheet, shoesSheet, accessorySheet, AnimationType.walking, drawColors); StandardCharacterAnimation swimmingAnimation = this.generateCharacterAnimation(bodySheet, eyesSheet, hairSheet, shirtSheet, pantsSheet, shoesSheet, accessorySheet, AnimationType.swimming, drawColors); return new BasicRenderer(standingAnimation, movingAnimation, swimmingAnimation); } /// Generate a Standard Character Animation from some asset sheets. (collection of textures to animations) /// The textures for the NPC's body. /// The textures for the NPC's eyes. /// The textures for the NPC's hair. /// The textures for the NPC's shirt. /// The textures for the NPC's pants. /// The textures for the NPC's shoes. /// The textures for the NPC's accessories. /// The animation type to generate. /// The colors for the NPC's different assets. public virtual StandardCharacterAnimation generateCharacterAnimation(AssetSheet body, AssetSheet eyes, AssetSheet hair, AssetSheet shirt, AssetSheet pants, AssetSheet shoes, List accessories, AnimationType animationType, StandardColorCollection drawColors = null) { AnimatedSpriteCollection bodySprite = this.getSpriteCollectionFromSheet(body, animationType); AnimatedSpriteCollection eyesSprite = this.getSpriteCollectionFromSheet(eyes, animationType); AnimatedSpriteCollection hairSprite = this.getSpriteCollectionFromSheet(hair, animationType); AnimatedSpriteCollection shirtSprite = this.getSpriteCollectionFromSheet(shirt, animationType); AnimatedSpriteCollection pantsSprite = this.getSpriteCollectionFromSheet(pants, animationType); AnimatedSpriteCollection shoesSprite = this.getSpriteCollectionFromSheet(shoes, animationType); List accessoryCollection = new List(); foreach (var v in accessories) { AnimatedSpriteCollection acc = this.getSpriteCollectionFromSheet(v, AnimationType.standing); accessoryCollection.Add(acc); } if (drawColors == null) drawColors = new StandardColorCollection(); return new StandardCharacterAnimation(bodySprite, eyesSprite, hairSprite, shirtSprite, pantsSprite, shoesSprite, accessoryCollection, drawColors); } /// Get the relative path for the standard character sprite to be used from this asset sheet. /// The standard asset sheet to be used. public virtual string getDefaultSpriteImage(AssetSheet imageGraphics) { return Class1.getRelativeDirectory(Path.Combine(imageGraphics.path, imageGraphics.assetInfo.standingAssetPaths.downString)); } } }