Modding Help Invisible bats?

Discussion in 'Mods' started by Hammurabi, Mar 20, 2017.

  1. Hammurabi

    Hammurabi Big Damn Hero

    I'm working on a mod that spawns in monsters similarly to how they are spawned in at the Wilderness Farm (indeed, I based the spawning code directly on decompiled game code), and it's mostly working except for one rather serious issue...

    The bats that the mod spawns are completely invisible. Possibly the serpents, too, but I haven't tested that yet.

    It's not a problem with my installation, because the bats look normal in both the Mines and on the Farm. It's just the ones that my mod is spawning in that aren't visible. It's not a problem with all the monsters being spawned, because it's not affecting the slimes or golems I've tested. I've pored over the decompiled game code, and I'm completely stumped as to why this is happening. Does anybody else have any clues?

    Here's the method that's spawning the bats, if it helps:
    Code:
        public void SpawnFlyingMonster() {
           Vector2 monsterPosition = new Vector2();
           switch (Game1.random.Next(4)) {
             case 0:
               monsterPosition.X = Game1.random.Next(Game1.currentLocation.map.Layers[0].LayerWidth);
               break;
             case 1:
               monsterPosition.X = (Game1.currentLocation.map.Layers[0].LayerWidth - 1);
               monsterPosition.Y = Game1.random.Next(Game1.currentLocation.map.Layers[0].LayerHeight);
               break;
             case 2:
               monsterPosition.Y = (Game1.currentLocation.map.Layers[0].LayerHeight - 1);
               monsterPosition.X = Game1.random.Next(Game1.currentLocation.map.Layers[0].LayerWidth);
               break;
             case 3:
               monsterPosition.Y = Game1.random.Next(Game1.currentLocation.map.Layers[0].LayerHeight);
               break;
           }
           if (Utility.isOnScreen(monsterPosition * Game1.tileSize, Game1.tileSize)) {
             monsterPosition.X -= Game1.viewport.Width;
           }
    
           bool monsterAdded;
           if (Game1.player.CombatLevel >= 10 && Game1.random.NextDouble() < 0.25) {
             Serpent serpent = new Serpent(monsterPosition * Game1.tileSize);
             serpent.focusedOnFarmers = true;
             serpent.wildernessFarmMonster = true;
             Game1.currentLocation.characters.Add(serpent);
             monsterAdded = true;
           }
           else {
             int mineLevel = 1;
             if (Game1.player.CombatLevel >= 8 && Game1.random.NextDouble() < 0.5) { mineLevel = 81; }
             else if (Game1.player.CombatLevel >= 5 && Game1.random.NextDouble() < 0.5) { mineLevel = 41; }
    
             Bat bat = new Bat(monsterPosition * Game1.tileSize, mineLevel);
             bat.focusedOnFarmers = true;
             bat.wildernessFarmMonster = true;
             Game1.currentLocation.characters.Add(bat);
             monsterAdded = true;
           }
    
           if (monsterAdded) {
             foreach (KeyValuePair<Vector2, StardewValley.Object> @object in Game1.currentLocation.objects) {
               if (@object.Value != null && @object.Value.bigCraftable && @object.Value.parentSheetIndex == 83) {
                 @object.Value.shakeTimer = 1000;
                 @object.Value.showNextIndex = true;
                 Game1.currentLightSources.Add(new LightSource(4, @object.Key * Game1.tileSize + new Vector2((Game1.tileSize / 2), 0.0f), 1f, Color.Cyan * 0.75f, (int) (@object.Key.X * 797.0 + @object.Key.Y * 13.0 + 666.0)));
               }
             }
           }
         }
    
     
    • Platonymous

      Platonymous Big Damn Hero


      you have to set Game1.spawnMonstersAtNight = true; otherwise the Bats drawAboveAlllLayers Method isn't called because of this in the Farm class:

      Code:
      public override void drawAboveAlwaysFrontLayer(SpriteBatch b)
          {
            base.drawAboveAlwaysFrontLayer(b);
            if (!Game1.spawnMonstersAtNight)
              return;
            foreach (Character character in this.characters)
            {
              if (character is Monster)
                (character as Monster).drawAboveAllLayers(b);
            }
          }
      
       
        Hammurabi likes this.
      • Hammurabi

        Hammurabi Big Damn Hero

        Ah, okay. That should be a simple enough fix. Thanks!
         
        • Hammurabi

          Hammurabi Big Damn Hero

          Finally had a chance to test this, and it still doesn't work. Upon further research, I found that it's because the Monster.drawAboveAllLayers() method is only called from the Farm and Mine classes (with the exception of the Fly monster class, which calls its own drawAboveAllLayers() method from its drawAboveAlwaysFrontLayer() method, presumably as a workaround due to showing up in the Mutant Bug Lair).

          Well, looks like I'll need to be dropping flyers unless I can find a workaround...
           
          • Hammurabi

            Hammurabi Big Damn Hero

            So, I've been working on this issue a bit since the last post. I've found that I can get the bats and other flying monsters to show up correctly... but only if I use a custom class for each of the flying-monster classes (and for any other monsters that could create them, e.g., Grubs). I'm very leery about actually doing this, though; It's a big compatibility problem, since not only would every one of the classes need to be updated if ConcernedApe changed anything about them, but it also breaks mods like Lookup Anything that are expecting only native classes. Beyond that concern, it's also going to bloat the mod, make it harder to track down bugs, and increase the likelihood of me screwing something up.

            So, any other modders out there: Do you think I should add the custom monster classes so that the monster spawning utility would support flying monsters, or do you think I should nix any feature that requires custom monster classes? This does extend a bit beyond the flying monster issue, as other classes have some hard-coded references to mine levels (e.g., Big Slimes will often spawn the wrong variety of slimes on death if you create them outside of the mine).
             
            • Platonymous

              Platonymous Big Damn Hero

              You don't need a custom monster class. Instead use the OnPreRenderHudEvent to search the current location for monsters and call the drawAboveAllLayers method yourself. Haven't tested it, but should work.
               
                Hammurabi likes this.
              • Hammurabi

                Hammurabi Big Damn Hero

                ...damn, how did I not think of that? Thanks.
                 

                Share This Page