tModLoader Shop Expander

This mod is breaking the Vending Machines mod. Attempting to sell anything to a vending machine will fail, the item panels will flash and the item I tried to sell is immediately sent back to my inventory.
The Vending Machines mod seems to bypass NPC.SetupShop, so making fully work with Shop Expander is gonna be kinda difficult... The sell feature is only broken if you are trying to sell to a vending machine without opening a regular NPC shop first after a mod reload. So if you start the game, open a world, open an NPC shop, close it, then open a vending machine it should work. Items wont show up for buyback though.
I'll look into some better way to check if there is an open expanded shop and avoid issues like this.
 
The Vending Machines mod seems to bypass NPC.SetupShop, so making fully work with Shop Expander is gonna be kinda difficult... The sell feature is only broken if you are trying to sell to a vending machine without opening a regular NPC shop first after a mod reload. So if you start the game, open a world, open an NPC shop, close it, then open a vending machine it should work. Items wont show up for buyback though.
I'll look into some better way to check if there is an open expanded shop and avoid issues like this.

As an alternative to making it work, perhaps the vending machines could be "blacklisted" somehow, so that they are left unmodified by the mod. In the meantime though, I'll leave a message on the mod's thread and see if its something JPAN can fix on their end.

EDIT: Link to my post on the vending machines thread: tModLoader - Vending Machines
 
Hm. Bit of an odd one here, but the Merchant doesn't appear to sell the Old Shovel from the mod Box of Gadgets like he's supposed to, if Shop Expander is installed. Other modded items appear correctly in his inventory, but that one in particular just doesn't want to show up. I've also posted there in case it's an issue on their end.
 
Another issue, I'm afraid. Pretty certain it is on this mod's end because of how it alters shops. Untested in singleplayer as of yet, but on our Dedicated Server, accessories such as the Discount Card and Ring of Greed don't apply their discounts to any shop.
 
Another issue, I'm afraid. Pretty certain it is on this mod's end because of how it alters shops. Untested in singleplayer as of yet, but on our Dedicated Server, accessories such as the Discount Card and Ring of Greed don't apply their discounts to any shop.
Oops. Yeah, I'll just add that to the list of things I missed. :p Luckily this one isn't too difficult to deal with, I just have to manually apply the discount after setting setting up shops.
I kind of expected that there would be many things to fix with this mod after release. It's pretty difficult to foresee all the different ways in which mods might use SetupShop.
 
Oops. Yeah, I'll just add that to the list of things I missed. :p Luckily this one isn't too difficult to deal with, I just have to manually apply the discount after setting setting up shops.
I kind of expected that there would be many things to fix with this mod after release. It's pretty difficult to foresee all the different ways in which mods might use SetupShop.
Hey, I get that. And I applaud you taking the effort to make this! I only hope more mods begin to adopt its usage natively. In particular, mods such as the multiple Alchemist NPC mods which always need to have a bunch of shops switched through a dialogue option... Since unfortunately they currently aren't affected by this because they already split things into seperate shops.
 
Hey, I get that. And I applaud you taking the effort to make this! I only hope more mods begin to adopt its usage natively. In particular, mods such as the multiple Alchemist NPC mods which always need to have a bunch of shops switched through a dialogue option... Since unfortunately they currently aren't affected by this because they already split things into seperate shops.
Yeah, that would be pretty cool. I am working on a few changes that should allow mod creators more control over shop pages. So, you could have separate pages for different item categories, and choose the layout of the items manually.
 
Yeah, that would be pretty cool. I am working on a few changes that should allow mod creators more control over shop pages. So, you could have separate pages for different item categories, and choose the layout of the items manually.
Not sure if it's possible, but it would be cool if pages could be labelled too, like just a text between your inventory and the shop inventory, and when hovering over the Next/Previous page buttons to show which page is next/previous/etc. Ideally, the buttons wouldn't take inventory slots either, or show empty slots when no other pages are in place, but that's not a big deal.
 
you might wanna fix this bug here, seem like you don't fully unload some of the stuff (reported on tmodloader 64bit)
unknown.png
 
Hello. I am receiving a bit of an issue with Fargo's Mutant Mod. I am using a rather large mod pack on Tml 64 and whenever I open the Mutant's item shop, I get a shop expander has failed to load error. With that NPC, I am unable to scroll through the shop. All other NPCs are fine and the first page of the shop is fine too but I can't access other pages. I will attach my mods list and the error log.
 

Attachments

  • client.log
    159.9 KB · Views: 132
  • enabled.json
    1.5 KB · Views: 127
you might wanna fix this bug here, seem like you don't fully unload some of the stuff (reported on tmodloader 64bit)
unknown.png
I've already fixed that actually. It's just not in the latest release yet.

Does this fix AlchemistNPC making Pumpkin Seeds disappear from the Dryad's shop?
Currently Shop Expander makes it pretty much impossible for regular SetupShop methods to remove items from a shop. So, it probably does fix that. Although in the next version I am planning to facilitate this sort of item removal, since some mods might want to do it intentionally.

Hello. I am receiving a bit of an issue with Fargo's Mutant Mod. I am using a rather large mod pack on Tml 64 and whenever I open the Mutant's item shop, I get a shop expander has failed to load error. With that NPC, I am unable to scroll through the shop. All other NPCs are fine and the first page of the shop is fine too but I can't access other pages. I will attach my mods list and the error log.
So, to clarify, a "Next page" button shows up in the last slot, but clicking on it does nothing? Could you also send me a world where this happens? Manually Setting up all the flags to make all the items show up is really tedious...

The exception itself most likely happens due to the mod trying to add more items than there are slots in the shop inventory. Shop Expander provides a fake empty shop for each ModNPC/GlobalNPC, but the size of that shop is still just 40 slots, for compatibility reasons. There is a pretty simple way to override that though using mod.Call(). So, this will need fixing on @Fargowilta's end.
 
Currently Shop Expander makes it pretty much impossible for regular SetupShop methods to remove items from a shop. So, it probably does fix that. Although in the next version I am planning to facilitate this sort of item removal, since some mods might want to do it intentionally.

Actually, it's a bug caused by one of the items in AlchemistNPC, but the modder himself doesn't seem to even bother with that.

EDIT: Tested, and it works. You got yourself a new client.
 
I've already fixed that actually. It's just not in the latest release yet.


Currently Shop Expander makes it pretty much impossible for regular SetupShop methods to remove items from a shop. So, it probably does fix that. Although in the next version I am planning to facilitate this sort of item removal, since some mods might want to do it intentionally.


So, to clarify, a "Next page" button shows up in the last slot, but clicking on it does nothing? Could you also send me a world where this happens? Manually Setting up all the flags to make all the items show up is really tedious...

The exception itself most likely happens due to the mod trying to add more items than there are slots in the shop inventory. Shop Expander provides a fake empty shop for each ModNPC/GlobalNPC, but the size of that shop is still just 40 slots, for compatibility reasons. There is a pretty simple way to override that though using mod.Call(). So, this will need fixing on @Fargowilta's end.

Yeah, sure. I will attach my world and character to this message. As for the issue, there simply is no next page icon in the shop. It is entirely gone. The last slot of the shop is left blank for it but it will not appear in that NPC's shop.
 

Attachments

  • Train Player.zip
    26.7 KB · Views: 130
  • DeatYT Ultimate World.zip
    10.7 MB · Views: 114
Yeah, sure. I will attach my world and character to this message. As for the issue, there simply is no next page icon in the shop. It is entirely gone. The last slot of the shop is left blank for it but it will not appear in that NPC's shop.
Yeah, it's what I expected. I just got confused, because normally if you run out of indexes, the shop would have 40 items, so you'd have a second page with 2 items. But it turns out with your setup there are two items that Fargo's tries to add, but they don't exist, so they just turn into air. So the 38 total items is actually correct.

I am planning to add some sort of easy way to convert the Fargo's/Alchemist NPC style multi-page shops into a multi-page Shop Expander shop. So, once that's done I'll contact @Fargowilta, and we'll try to work this out.

Actually, it's a bug caused by one of the items in AlchemistNPC, but the modder himself doesn't seem to even bother with that.

EDIT: Tested, and it works. You got yourself a new client.
Well, like I said, this could un-fix itself sometime in the future. I might not do the removal support in the next update then, since I don't really know of many mods that remove items intentionally. And it seems it would actually be a bit messy to implement anyways, after looking into it... But, you know, just saying, it would be best to resolve this with the original author, cause I may still add this later.
 
I'm trying to add more slots on my basic cheat npc mod. but when i click next page. there are only 2 other items there. and this shows up Errormessagefromexpander.PNG even though i have more items in the shop added in the script.

here's the script btw

using System.Linq;
using Terraria;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.Utilities;

namespace TheCheatNpc.NPCs
{
[AutoloadHead]
public class Kimi : ModNPC
{
public override string Texture
{
get
{
return "TheCheatNpc/NPCs/Kimi";
}
}

public override bool Autoload(ref string name)
{
name = "Kimi";
return mod.Properties.Autoload;
}

public override void SetStaticDefaults()
{
// DisplayName automatically assigned from .lang files, but the commented line below is the normal approach.
// DisplayName.SetDefault("Example Person");
Main.npcFrameCount[npc.type] = 25;
NPCID.Sets.ExtraFramesCount[npc.type] = 9;
NPCID.Sets.AttackFrameCount[npc.type] = 4;
NPCID.Sets.DangerDetectRange[npc.type] = 700;
NPCID.Sets.AttackType[npc.type] = 0;
NPCID.Sets.AttackTime[npc.type] = 90;
NPCID.Sets.AttackAverageChance[npc.type] = 30;
NPCID.Sets.HatOffsetY[npc.type] = 4;
}

public override void SetDefaults()
{
npc.townNPC = true;
npc.friendly = true;
npc.width = 18;
npc.height = 40;
npc.aiStyle = 7;
npc.damage = 10;
npc.defense = 15;
npc.lifeMax = 250;
npc.HitSound = SoundID.NPCHit1;
npc.DeathSound = SoundID.NPCDeath1;
npc.knockBackResist = 0.5f;
animationType = NPCID.DyeTrader;
}

public override void HitEffect(int hitDirection, double damage)
{
int num = npc.life > 0 ? 1 : 5;
for (int k = 0; k < num; k++)
{
Dust.NewDust(npc.position, npc.width, npc.height, mod.DustType("Sparkle"));
}
}

public override bool CanTownNPCSpawn(int numTownNPCs, int money)
{
for (int k = 0; k < 255; k++)
{
Player player = Main.player[k];
if (player.active)
{
for (int j = 0; j < player.inventory.Length; j++)
{
if (player.inventory[j].type == mod.ItemType("EssenceOfMadness"))

{
return true;
}
}
}
}
return false;
}

public override string TownNPCName()
{
switch (WorldGen.genRand.Next(4))
{
case 0:
return "Kimi";
case 1:
return "Kimi";
case 2:
return "Kimi";
default:
return "Kimi";
}
}

public override void FindFrame(int frameHeight)
{
/*npc.frame.Width = 40;
if (((int)Main.time / 10) % 2 == 0)
{
npc.frame.X = 40;
}
else
{
npc.frame.X = 0;
}*/
}

public override string GetChat()
{
int dryad = NPC.FindFirstNPC(NPCID.Dryad);
if (dryad >= 0 && Main.rand.Next(4) == 0)
{
return "Can you please tell " + Main.npc[dryad].GivenName + " that i want some plants for my shelves that i totally have?";
}
switch (Main.rand.Next(3))
{
case 0:
return "Sometimes I feel like I'm different from everyone else here.";
case 1:
return "I'll have Two Number Nines, A number 9 large, A number 6 with extra dip. two number 45s. one with cheese. and a large soda.";
default:
return "Well heres some items i guess.";
}
}

/*
// Consider using this alternate approach to choosing a random thing. Very useful for a variety of use cases.
// The WeightedRandom class needs "using Terraria.Utilities;" to use
public override string GetChat()
{
WeightedRandom<string> chat = new WeightedRandom<string>();

int partyGirl = NPC.FindFirstNPC(NPCID.PartyGirl);
if (partyGirl >= 0 && Main.rand.Next(4) == 0)
{
chat.Add("Can you please tell " + Main.npc[partyGirl].GivenName + " to stop decorating my house with colors?");
}
chat.Add("Sometimes I feel like I'm different from everyone else here.");
chat.Add("What's your favorite color? My favorite colors are white and black.");
chat.Add("What? I don't have any arms or legs? Oh, don't be ridiculous!");
chat.Add("This message has a weight of 5, meaning it appears 5 times more often.", 5.0);
chat.Add("This message has a weight of 0.1, meaning it appears 10 times as rare.", 0.1);
return chat; // chat is implicitly cast to a string. You can also do "return chat.Get();" if that makes you feel better
}
*/

public override void SetChatButtons(ref string button, ref string button2)
{
button = Language.GetTextValue("LegacyInterface.28");
}

public override void OnChatButtonClicked(bool firstButton, ref bool shop)
{
if (firstButton)
{
shop = true;
}
}

public override void SetupShop(Chest shop, ref int nextSlot)
{
shop.item[nextSlot].SetDefaults(ItemID.JungleYoyo);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.DirtBlock);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MudBlock);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.TerraBlade);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MedusaHead);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.HermesBoots);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ArmorBracing);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Bezoar);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.CountercurseMantra);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MedicatedBandage);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Megaphone);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MoonStone);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ObsidianRose);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.PocketMirror);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.RifleScope);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.SharkToothNecklace);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ThePlan);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Vitamins);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.NecromanticScroll);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.HerculesBeetle);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.LuckyCoin);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.GoldRing);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.DiscountCard);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.NaturesGift);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.BandofStarpower);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.BandofRegeneration);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Blindfold);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Muramasa);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Starfury);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Arkhalis);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.IceBlade);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.BladedGlove);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Katana);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.FalconBlade);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.TaxCollectorsStickOfDoom);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.PsychoKnife);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Keybrand);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Spear);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Trident);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.DarkLance);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.IceBoomerang);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Flamarang);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.BloodyMachete);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ChainGuillotines);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ChainKnife);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Anchor);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Marrow);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.IceBow);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Boomstick);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Handgun);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Revolver);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.GrenadeLauncher);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ElectrosphereLauncher);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Sandgun);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Harpoon);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Toxikarp);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MagicMissile);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Flamelash);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Vilethorn);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.CrimsonRod);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.BatScepter);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ClingerStaff);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.FlowerofFrost);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.LaserRifle);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.GoldenShower);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.CrystalStorm);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MagnetSphere);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.WaterBolt);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.DemonScythe);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ToxicFlask);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.ShadowFlameHexDoll);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MagicDagger);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.UnholyTrident);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.SlimeStaff);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.HornetStaff);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.PirateStaff);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.RavenStaff);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Beenade);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.SpikyBall);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Shuriken);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Snowball);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.MolotovCocktail);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Javelin);
nextSlot++;
shop.item[nextSlot].SetDefaults(ItemID.Wood);
nextSlot++;
}
public override void TownNPCAttackStrength(ref int damage, ref float knockback)
{
damage = 20;
knockback = 4f;
}

public override void TownNPCAttackCooldown(ref int cooldown, ref int randExtraCooldown)
{
cooldown = 30;
randExtraCooldown = 30;
}

public override void TownNPCAttackProj(ref int projType, ref int attackDelay)
{
projType = mod.ProjectileType("SparklingBall");
attackDelay = 1;
}

public override void TownNPCAttackProjSpeed(ref float multiplier, ref float gravityCorrection, ref float randomOffset)
{
multiplier = 12f;
randomOffset = 2f;
}
}
}
 
Like I said before, Shop Expander only gives 40 slots to every ModNPC/GlobalNPC to work with by default, so that mods that actually rely on the length of the shop don't freak out. You can override this, by doing something like this in your main mod class:
Code:
using TheCheatNpc.NPCs;
...
class TheCheatNpc : Mod
{
...
     public override void PostSetupContent()
     {
          Mod shopExpander = ModLoader.GetMod("ShopExpander");
          if (shopExpander != null)
          {
                shopExpander.Call("SetProvisionSize", GetNPC<Kimi>(), 100);
          }
     }
...
}
Replace "100" with the expected maximum number of slots you'll need. You can find more examples here: DRKV333/ShopExpander
 
Actually, it's a bug caused by one of the items in AlchemistNPC, but the modder himself doesn't seem to even bother with that.

EDIT: Tested, and it works. You got yourself a new client.

By any means, do you recall what the AlchemistNPC item was? Having that same issue myself, but the next/previous buttons in the Fargo shops don't even appear.
 
The mod may have some problem with AlchemistNPC, an error occurred when I talk to the Alchemist.
Here is the log:
Code:
[18:20:46] [1/INFO] [ShopExpander]: --- SHOP EXPANDER ERROR ---
[18:20:46] [1/INFO] [ShopExpander]: Shop Expander failed to load ModNPC from mod AlchemistNPC.
[18:20:46] [1/INFO] [ShopExpander]: System.TypeLoadException: Could not load type 'CalamityMod.World.CalamityWorld' from assembly 'CalamityMod_0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
   at AlchemistNPC.NPCs.Alchemist.get_CalamityModDownedGuardian()
   at AlchemistNPC.NPCs.Alchemist.SetupShop(Chest shop, Int32& nextSlot) in AlchemistNPC\NPCs\Alchemist.cs:line 573
   at ShopExpander.Patches.SetupShopPatch.Prefix(Int32 type, Chest shop)
[18:20:46] [1/INFO] [ShopExpander]: --- END SHOP EXPANDER ERROR ---

[18:20:46] [1/INFO] [ShopExpander]: --- SHOP EXPANDER ERROR ---
[18:20:46] [1/INFO] [ShopExpander]: Shop Expander failed to load GlobalNPC from mod AlchemistNPC.
[18:20:46] [1/INFO] [ShopExpander]: System.TypeLoadException: Could not load type 'CalamityMod.World.CalamityWorld' from assembly 'CalamityMod_0, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
   at AlchemistNPC.NPCs.ModGlobalNPC.get_CalamityModRevengeance()
   at AlchemistNPC.NPCs.ModGlobalNPC.SetupShop(Int32 type, Chest shop, Int32& nextSlot) in AlchemistNPC\NPCs\ModGlobalNPC.cs:line 236
   at ShopExpander.Patches.SetupShopPatch.Prefix(Int32 type, Chest shop)
[18:20:46] [1/INFO] [ShopExpander]: --- END SHOP EXPANDER ERROR ---
 
Back
Top Bottom