public static bool IsHarvestableBush(Bush bush) { return(bush != null && !bush.townBush.Value && bush.inBloom(Game1.GetSeasonForLocation(bush.currentLocation), Game1.dayOfMonth) && bush.size.Value != Bush.greenTeaBush && bush.size.Value != Bush.walnutBush); }
internal static void ShakeBush(Bush bush, Vector2?tileLocation = null) { bush.performUseAction(tileLocation ?? Game1.player.getTileLocation() + new Vector2(0, -2), Game1.player.currentLocation); }
public static Color GetColor(Bush b) => Color.Lerp(Color.LightGreen, Color.DarkGreen, b.BerryFraction);
/// <summary>SMAPI console command. Creates a new bush with the specified size.</summary> /// <param name="command">The console command's name.</param> /// <param name="args">The space-delimited arguments entered with the command.</param> public static void AddBush(string command, string[] args) { if (!Context.IsWorldReady) //if the player is not currently in a loaded game { return; //do nothing } if (args.Length <= 0) //"add_bush" (invalid) { ModEntry.Instance.Monitor.Log($"Invalid number of arguments. Please include a bush size, e.g. \"{command} {Bush.largeBush}\". Type \"help {command}\" for formatting information.", LogLevel.Info); return; } else if (args.Length == 2) //"add_bush <size> [x]" (invalid) { ModEntry.Instance.Monitor.Log($"Invalid number of arguments. Please include both X and Y, e.g. \"{command} {Bush.largeBush} 64 19\". Type \"help {command}\" for formatting information.", LogLevel.Info); return; } int?size = ParseBushSize(args[0]); //attempt to parse the size argument if (size == null) //if parsing failed { ModEntry.Instance.Monitor.Log($"\"{args[0]}\" is not a recognized bush size. Type \"help {command}\" for formatting information.", LogLevel.Info); return; } int x; int y; if (args.Length >= 3) //if x y arguments were provided { if (int.TryParse(args[1], out x) == false) //try to parse the x argument; if it fails, { ModEntry.Instance.Monitor.Log($"\"{args[1]}\" could not be parsed as an integer (x). Type \"help {command}\" for formatting information.", LogLevel.Info); return; } else if (int.TryParse(args[2], out y) == false) //try to parse the y argument; if it fails, { ModEntry.Instance.Monitor.Log($"\"{args[2]}\" could not be parsed as an integer (y). Type \"help {command}\" for formatting information.", LogLevel.Info); return; } } else //if x y arguments were NOT provided { //get the player's current tile position x = Game1.player.getTileX(); y = Game1.player.getTileY(); } GameLocation location; if (args.Length >= 4) //if a location argument was provided { //combine the remaining arguments into a single string string locationName = args[3]; //get the first location argument for (int count = 4; count < args.Length; count++) //for each argument after args[3] { locationName += " " + args[count]; //add this argument to the location name, separated by a space } location = Game1.getLocationFromName(locationName); //attempt to get a location with the combined name if (location == null) //if no location matched the name { ModEntry.Instance.Monitor.Log($"No location named \"{locationName}\" could be found. Type \"help {command}\" for formatting information.", LogLevel.Info); return; } } else { location = Game1.player.currentLocation; //use the player's current location if (location == null) //if the player's location was null { return; //do nothing } } //all necessary information has been parsed Bush bush = new Bush(new Vector2(x, y), size.Value, location); //create the new bush Rectangle playerBox = Game1.player.GetBoundingBox(); while (playerBox.Intersects(bush.getBoundingBox())) //while this bush is colliding with the player { switch (Game1.player.FacingDirection) //based on which direction the player is facing { default: //unknown facing position (should be unreachable) case 0: //up bush.tilePosition.Value = new Vector2(bush.tilePosition.X, bush.tilePosition.Y - 1); //move bush up 1 tile break; case 1: //right bush.tilePosition.Value = new Vector2(bush.tilePosition.X + 1, bush.tilePosition.Y); //move bush right 1 tile break; case 2: //down bush.tilePosition.Value = new Vector2(bush.tilePosition.X, bush.tilePosition.Y + 1); //move bush down 1 tile break; case 3: //left bush.tilePosition.Value = new Vector2(bush.tilePosition.X - 1, bush.tilePosition.Y); //move bush left 1 tile break; } } location.largeTerrainFeatures.Add(bush); //add the bush to the location }
/********* ** Private methods *********/ /// <summary>Get whether the given bush produces berries.</summary> /// <param name="bush">The berry busy.</param> private bool IsBerryBush(Bush bush) { return(bush.size.Value == Bush.mediumBush && !bush.townBush.Value); }
static void Main(string[] args) { string[] inputs; Strategy.myTeam = int.Parse(Console.ReadLine()); int bushAndSpawnPointCount = int.Parse(Console.ReadLine()); // useful from wood1, represents the number of bushes and the number of places where neutral units can spawn for (int i = 0; i < bushAndSpawnPointCount; i++) { inputs = Console.ReadLine().Split(' '); string entityType = inputs[0]; // BUSH, from wood1 it can also be SPAWN int x = int.Parse(inputs[1]); int y = int.Parse(inputs[2]); int radius = int.Parse(inputs[3]); if (entityType == "BUSH") { Bush newBush = new Bush(); newBush.pos = new Vector(x, y, 0); newBush.attackRange = radius; Strategy.bushes.Add(newBush); } } int itemCount = int.Parse(Console.ReadLine()); // useful from wood2 for (int i = 0; i < itemCount; i++) { inputs = Console.ReadLine().Split(' '); string itemName = inputs[0]; // contains keywords such as BRONZE, SILVER and BLADE, BOOTS connected by "_" to help you sort easier int itemCost = int.Parse(inputs[1]); // BRONZE items have lowest cost, the most expensive items are LEGENDARY int damage = int.Parse(inputs[2]); // keyword BLADE is present if the most important item stat is damage int health = int.Parse(inputs[3]); int maxHealth = int.Parse(inputs[4]); int mana = int.Parse(inputs[5]); int maxMana = int.Parse(inputs[6]); int moveSpeed = int.Parse(inputs[7]); // keyword BOOTS is present if the most important item stat is moveSpeed int manaRegeneration = int.Parse(inputs[8]); int isPotion = int.Parse(inputs[9]); // 0 if it's not instantly consumed Item newItem = new Item { name = itemName, cost = itemCost, damage = damage, health = health, maxHealth = maxHealth, mana = mana, maxMana = maxMana, speed = moveSpeed, manaRegen = manaRegeneration, isPotion = isPotion == 1, }; Strategy.items.Add(itemName, newItem); newItem.CalculateItemValue(); newItem.PrintStats(); } // game loop while (true) { Game.NewRound(); Strategy.myGold = int.Parse(Console.ReadLine()); Strategy.enemyGold = int.Parse(Console.ReadLine()); int roundType = int.Parse(Console.ReadLine()); // a positive value will show the number of heroes that await a command int entityCount = int.Parse(Console.ReadLine()); for (int i = 0; i < entityCount; i++) { inputs = Console.ReadLine().Split(' '); int unitId = int.Parse(inputs[0]); int team = int.Parse(inputs[1]); string unitType = inputs[2]; // UNIT, HERO, TOWER, can also be GROOT from wood1 int x = int.Parse(inputs[3]); int y = int.Parse(inputs[4]); int attackRange = int.Parse(inputs[5]); int health = int.Parse(inputs[6]); int maxHealth = int.Parse(inputs[7]); int shield = int.Parse(inputs[8]); // useful in bronze int attackDamage = int.Parse(inputs[9]); int movementSpeed = int.Parse(inputs[10]); int stunDuration = int.Parse(inputs[11]); // useful in bronze int goldValue = int.Parse(inputs[12]); int countDown1 = int.Parse(inputs[13]); // all countDown and mana variables are useful starting in bronze int countDown2 = int.Parse(inputs[14]); int countDown3 = int.Parse(inputs[15]); int mana = int.Parse(inputs[16]); int maxMana = int.Parse(inputs[17]); int manaRegeneration = int.Parse(inputs[18]); string heroType = inputs[19]; // DEADPOOL, VALKYRIE, DOCTOR_STRANGE, HULK, IRONMAN int isVisible = int.Parse(inputs[20]); // 0 if it isn't int itemsOwned = int.Parse(inputs[21]); // useful from wood1 Entity newUnit; //UNIT, HERO, TOWER if (unitType == "TOWER") { newUnit = new Tower(); } else if (unitType == "GROOT") { newUnit = new Groot(); } else if (unitType == "HERO") { newUnit = new Hero(); Hero newHero = newUnit as Hero; newHero.cooldowns[0] = countDown1; newHero.cooldowns[1] = countDown2; newHero.cooldowns[2] = countDown3; foreach (HeroType type in Enum.GetValues(typeof(HeroType))) { if (type.ToString() == heroType) { newHero.heroType = type; break; } } newHero.InitSpells(); } else { newUnit = new Unit(); } newUnit.id = unitId; newUnit.pos = new Vector(x, y, 0); newUnit.team = Strategy.myTeam == team ? Team.Ally : Team.Enemy; newUnit.attackRange = attackRange; newUnit.health = health; newUnit.maxHealth = maxHealth; newUnit.shield = shield; newUnit.damage = attackDamage; newUnit.speed = movementSpeed; newUnit.stunDuration = stunDuration; newUnit.goldValue = goldValue; //countdown newUnit.mana = mana; newUnit.maxMana = maxMana; newUnit.manaRegen = manaRegeneration; newUnit.isVisible = isVisible == 1; newUnit.itemsOwned = itemsOwned; newUnit.isAlly = Strategy.myTeam == team && team != -1; newUnit.isEnemy = Strategy.myTeam != team && team != -1; newUnit.isNeutral = team == -1; Strategy.allUnits.Add(newUnit.id, newUnit); if (newUnit is Hero) { Strategy.allHeros.Add(newUnit as Hero); } if (newUnit.isAlly) { Strategy.allyUnits.Add(newUnit.id, newUnit); if (newUnit is Hero) { Hero myHero = newUnit as Hero; Strategy.myHeros.Add(myHero); myHero.InitStrategy(); } else if (newUnit is Tower) { Strategy.myTower = newUnit as Tower; } else if (newUnit is Unit) { Strategy.allyMinions.Add(newUnit); } } else if (newUnit.isEnemy) { Strategy.enemyUnits.Add(newUnit.id, newUnit); if (newUnit is Hero) { Hero hero = newUnit as Hero; Strategy.enemyHeros.Add(hero); } else if (newUnit is Tower) { Strategy.enemyTower = newUnit as Tower; } else if (newUnit is Unit) { Strategy.enemyMinions.Add(newUnit); } } else { Strategy.neutralUnits.Add(newUnit.id, newUnit); } } Game.MakeMove(roundType); } }
/// <summary>If this bush was destroyed, this adds it to this mod's "destroyed bushes" list. It also drops an amount of wood designated by this mod's config.json file settings.</summary> /// <param name="t">The <see cref="Tool"/> used on this bush.</param> /// <param name="tileLocation">The tile on which the tool is being used.</param> /// <param name="location">The location of the bush and tool.</param> /// <param name="__instance">The <see cref="Bush"/> on which a tool is being used.</param> /// <param name="__result">True if this bush was destroyed."/></param> public static void performToolAction_Postfix(Tool t, Vector2 tileLocation, GameLocation location, Bush __instance, bool __result) { try { if (__result) //if this bush was destroyed { int amountOfWood; //the amount of wood this bush should drop bool shouldRegrow = false; //whether this bush should eventually be respawned switch (__instance.size.Value) //based on the bush's size, set the amount of wood { case Bush.smallBush: amountOfWood = ModEntry.Config?.AmountOfWoodDropped?.SmallBushes ?? 0; shouldRegrow = true; break; case Bush.mediumBush: amountOfWood = ModEntry.Config?.AmountOfWoodDropped?.MediumBushes ?? 0; shouldRegrow = true; break; case Bush.largeBush: amountOfWood = ModEntry.Config?.AmountOfWoodDropped?.LargeBushes ?? 0; shouldRegrow = true; break; case Bush.greenTeaBush: amountOfWood = ModEntry.Config?.AmountOfWoodDropped?.GreenTeaBushes ?? 0; break; default: amountOfWood = 0; break; } if (shouldRegrow) //if this bush should eventually be respawned { ModData.DestroyedBush destroyed = new ModData.DestroyedBush(location?.Name, __instance.tilePosition.Value, __instance.size.Value); //create a record of this bush if (Context.IsMainPlayer) //if this code is run by the main player { ModEntry.Data.DestroyedBushes.Add(destroyed); //add the record to the list of destroyed bushes } else //if this code is run by a multiplayer farmhand { ModEntry.Instance.Helper.Multiplayer.SendMessage //send the record to the main player ( message: destroyed, messageType: "DestroyedBush", modIDs: new[] { ModEntry.Instance.ModManifest.UniqueID }, playerIDs: new[] { Game1.serverHost.Value.UniqueMultiplayerID } ); } } if (amountOfWood > 0) //if this bush should drop any wood { if (t?.getLastFarmerToUse() is Farmer farmer && farmer.professions.Contains(12)) //if the player destroying this bush has the "Forester" profession { double multipliedWood = 1.25 * amountOfWood; //increase wood by 25% amountOfWood = (int)Math.Floor(multipliedWood); //update the amount of wood (round down) if (multipliedWood > amountOfWood) //if the multiplied wood had a decimal { multipliedWood -= amountOfWood; //get the decimal amount of wood if (Game1.random.NextDouble() < multipliedWood) //use the decimal as a random chance { amountOfWood++; //add 1 wood } } } //drop the amount of wood at this bush's location Game1.createRadialDebris(location, 12, (int)tileLocation.X, (int)tileLocation.Y, amountOfWood, true, -1, false, -1); } } } catch (Exception ex) { ModEntry.Instance.Monitor.LogOnce($"Harmony patch \"{nameof(performToolAction_Postfix)}\" has encountered an error:\n{ex.ToString()}", LogLevel.Error); } }
/// <summary>Apply the tool to the given tile.</summary> /// <param name="tile">The tile to modify.</param> /// <param name="tileObj">The object on the tile.</param> /// <param name="tileFeature">The feature on the tile.</param> /// <param name="player">The current player.</param> /// <param name="tool">The tool selected by the player (if any).</param> /// <param name="item">The item selected by the player (if any).</param> /// <param name="location">The current location.</param> public override bool Apply(Vector2 tile, SObject tileObj, TerrainFeature tileFeature, Farmer player, Tool tool, Item item, GameLocation location) { // spawned forage if (this.TryHarvestForage(tileObj, location, tile, player)) { return(true); } // crop or indoor pot if (this.TryGetHoeDirt(tileFeature, tileObj, out HoeDirt dirt, out bool dirtCoveredByObj, out IndoorPot pot)) { // crop or spring onion (if an object like a scarecrow isn't placed on top of it) if (!dirtCoveredByObj && this.TryHarvestCrop(dirt, location, tile, player, tool)) { return(true); } // indoor pot bush if (this.TryHarvestBush(pot?.bush.Value, location)) { return(true); } } // machine if (this.TryHarvestMachine(tileObj)) { return(true); } // fruit tree if (this.TryHarvestFruitTree(tileFeature as FruitTree, location, tile)) { return(true); } // grass if (this.TryHarvestGrass(tileFeature as Grass, location, tile, tool)) { return(true); } // weeds if (this.TryHarvestWeeds(tileObj, location, tile, player, tool)) { return(true); } // bush Rectangle tileArea = this.GetAbsoluteTileArea(tile); if (this.Config.HarvestForage) { Bush bush = tileFeature as Bush ?? location.largeTerrainFeatures.FirstOrDefault(p => p.getBoundingBox(p.tilePosition.Value).Intersects(tileArea)) as Bush; if (this.TryHarvestBush(bush, location)) { return(true); } } return(false); }
/********* ** Private methods *********/ /// <summary>Build a subject.</summary> /// <param name="bush">The entity to look up.</param> private ISubject BuildSubject(Bush bush) { return(new BushSubject(this.GameHelper, bush, this.Reflection)); }
/// <summary>Get whether a given bush should be chopped.</summary> /// <param name="bush">The bush to check.</param> private bool ShouldCut(Bush bush) { var config = this.Config; return(config.CutBushes); }