tModLoader Official tModLoader Help Thread

Is it possible to make an item Channel on right click, but not channel on left click? And/or vice versa?
Right now, there is no standard way to do this. Player.channel will always be set to false in Player.ItemCheck_Inner() if Player.controlUseItem is false. Though, ModItem.HoldItem() is called after this is done, and ModItem.CanUseItem() is called before an item is used.

Though, if you are willing, you can easily add the ability to modify the condition of which the player is allowed to channel under.
In Player.ItemCheck_Inner(), this is what decides whether or not the player is allowed to continue channeling:
C#:
bool allowChannel = this.controlUseItem;
if(this.mount.Active && this.mount.Type == MountID.Drill)
{
    allowChannel = this.controlUseItem || this.controlUseTile;
}
if(allowChanneling)
    this.channel = false;
By adding a function call, we give ourselves an easy to change allowChannel to whatever we want!
C#:
bool allowChannel = this.controlUseItem;
MyLoadingClass.ModifyAllowChannel(this, currentHeldItem, ref allowChannel); // We "insert" in this statement!
if(this.mount.Active && this.mount.Type == MountID.Drill)
{
    allowChannel = this.controlUseItem || this.controlUseTile;
}
if(allowChanneling)
    this.channel = false;

The way we would make this modification would be like this:
C#:
public override void Load()
{
    IL_Player.ItemCheck_Inner += IL_Player_ItemCheck_Inner;
}

public static void IL_Player_ItemCheck_Inner(ILContext il)
{
    ILCursor cur = new ILCursor(il);
 
    // moves to after the "bool allowChannel = this.controlUseItem" statement
    cur.GotoNext(MoveType.After,
        // Matches to "this"
        i => i.MatchLdarg0(),
        // Matches to ".controlUseItem"
        i => i.MatchLdfld<Player>("controlUseItem")
        // Matches to "allowChannel = "
        i => i.MatchStloc(6)
    );
 
    // Pushes "this"
    cur.EmitLdarg0();
    // Pushes "currentHeldItem" (an already existing local variable in
    //   Player.ItemCheck_Inner() that stores the palyer's held item)
    cur.EmitLdloc1();
    // Pushes "ref allowChannel"
    cur.EmitLdloca(6);
    // Calls MyLoadingClass.ModifyAllowChannel() with the last 3 things pushed/on_the_stack as the arguments
    cur.EmitCall(typeof(MyLoadingClass).GetMethod("ModifyAllowChannel"));
}

public static void ModifyAllowChannel(PLayer player, Item heldItem, ref bool allowChannel)
{
    // add your own conditions for channeling here!
}

In your case where you want enable or disable channeling for primary and secondary fire, you may have a ModifyAllowChannel() that looks like this:
C#:
public static void ModifyAllowChannel(PLayer player, Item heldItem, ref bool allowChannel)
{
    if(heldItem.type == ModContent.ItemType<MyChannelItem>())
    {
        // Disable channeling for left click:
        if(player.altFunctionUse == 0)
            allowChannel = false;
     
        // Enable channeling for right click:
        if(player.altFunctionUse != 0)
            allowChannel = player.controlUseTile;
    }
}

Something to note is that player.controlUseItem keeps track if the player is left clicking, and player.controlUseTile keep track of right clicking. This means that whatever the MountID.Drill is, it's an example of channeling with right click. Also note that, even without this modification, it is still to possible to channel with right click if the player begins holding left click at the perfect moment!
 
Last edited:
Hi Guys,

I'm new to modding. Trying something simple at first and it's already giving me grief. Please help!

All I'm trying to do is make different slimes drop different items (green - copper sword, blue - copper axe, purple - copper pickaxe). But they ALL ALWAYS drop the loot assigned for Blue Slimes! No matter what. And if I remove Blue Slimes from the code, - nothing drops from any other slimes! Could you please help me understand why???


public override void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) {
// Check the type of the NPC that was killed
if (npc.type == NPCID.GreenSlime) {
// Clear any existing generic slime drops if desired (optional)
// npcLoot.RemoveWhere(rule => rule is CommonDrop);

// Add a new drop rule for the Blue Slime
// ItemDropRule.Common(ItemID, chanceDenominator, minimumAmount, maximumAmount)
// This makes the Blue Slime drop a Copper Shortsword with 100% chance (1/1)
npcLoot.Add(ItemDropRule.Common(ItemID.CopperShortsword, 1, 1, 1));
}
else if (npc.type == NPCID.BlueSlime) {
// Add a new drop rule for the Green Slime
// This makes the Green Slime drop a Copper Axe with 100% chance (1/1)
npcLoot.Add(ItemDropRule.Common(ItemID.CopperAxe, 1, 1, 1));
}
else if (npc.type == NPCID.PurpleSlime) {
// Add a new drop rule for the Purple Slime
// This makes the Purple Slime drop a Copper Pickaxe with 100% chance (1/1)
npcLoot.Add(ItemDropRule.Common(ItemID.CopperPickaxe, 1, 1, 1));
}
}
 
Hi Guys,

I'm new to modding. Trying something simple at first and it's already giving me grief. Please help!

All I'm trying to do is make different slimes drop different items (green - copper sword, blue - copper axe, purple - copper pickaxe). But they ALL ALWAYS drop the loot assigned for Blue Slimes! No matter what. And if I remove Blue Slimes from the code, - nothing drops from any other slimes! Could you please help me understand why???


public override void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) {
// Check the type of the NPC that was killed
if (npc.type == NPCID.GreenSlime) {
// Clear any existing generic slime drops if desired (optional)
// npcLoot.RemoveWhere(rule => rule is CommonDrop);

// Add a new drop rule for the Blue Slime
// ItemDropRule.Common(ItemID, chanceDenominator, minimumAmount, maximumAmount)
// This makes the Blue Slime drop a Copper Shortsword with 100% chance (1/1)
npcLoot.Add(ItemDropRule.Common(ItemID.CopperShortsword, 1, 1, 1));
}
else if (npc.type == NPCID.BlueSlime) {
// Add a new drop rule for the Green Slime
// This makes the Green Slime drop a Copper Axe with 100% chance (1/1)
npcLoot.Add(ItemDropRule.Common(ItemID.CopperAxe, 1, 1, 1));
}
else if (npc.type == NPCID.PurpleSlime) {
// Add a new drop rule for the Purple Slime
// This makes the Purple Slime drop a Copper Pickaxe with 100% chance (1/1)
npcLoot.Add(ItemDropRule.Common(ItemID.CopperPickaxe, 1, 1, 1));
}
}
Most of the slimes share the same "type", with most of their NPCID values being negative (except for the blue slime's who has a value of 1). When NPC.SetDefaults() is called with a negative type, a special, extra "SetDefaults" is called that sets the NPC's type to a positive value before modifying the stats a bit.

Try using NPC.netID instead of NPC.type when trying to distinguish between the different colored slimes. You would still use NPCID
 
Most of the slimes share the same "type", with most of their NPCID values being negative (except for the blue slime's who has a value of 1). When NPC.SetDefaults() is called with a negative type, a special, extra "SetDefaults" is called that sets the NPC's type to a positive value before modifying the stats a bit.

Try using NPC.netID instead of NPC.type when trying to distinguish between the different colored slimes. You would still use NPCID
It worked, thank you! Though I still don't fully understand your explanation. Probably need more exposure to code and practice. Thank you again!


EDIT: One last thing is left to complete my mod, and it seems to be really challenging even for AI. I'm trying to make blue slimes spill water when killed. But it seems that both the WorldGen and Main.tile options aren't allowed anymore?
When trying to use the tile manipulation approach:
//Read the tile into a local variable first
Tile tile = Main.tile[tileX, tileY];
// Set the tile to be a liquid tile, and trigger a liquid update
// The amount of liquid is set to 255 (max amount)
tile.LiquidType = (byte)liquidType;
tile.LiquidAmount = 255;
//Write the modified local variable back to Main.tile
Main.tile[tileX, tileY] = tile;

I get a CS0200 error (Tilemap.this - read only)

And when I use WorldGen approach:

WorldGen.PlaceLiquidInWorld(tileX, tileY, liquidType, 255);

I get error CS0117 : 'WorldGen' doesn't contain a definition for 'PlaceLiquidInWorld'

So, is there a new method of spawning water?
 
Last edited:
It worked, thank you! Though I still don't fully understand your explanation. Probably need more exposure to code and practice. Thank you again!


EDIT: One last thing is left to complete my mod, and it seems to be really challenging even for AI. I'm trying to make blue slimes spill water when killed. But it seems that both the WorldGen and Main.tile options aren't allowed anymore?
When trying to use the tile manipulation approach:
//Read the tile into a local variable first
Tile tile = Main.tile[tileX, tileY];
// Set the tile to be a liquid tile, and trigger a liquid update
// The amount of liquid is set to 255 (max amount)
tile.LiquidType = (byte)liquidType;
tile.LiquidAmount = 255;
//Write the modified local variable back to Main.tile
Main.tile[tileX, tileY] = tile;

I get a CS0200 error (Tilemap.this - read only)

And when I use WorldGen approach:

WorldGen.PlaceLiquidInWorld(tileX, tileY, liquidType, 255);

I get error CS0117 : 'WorldGen' doesn't contain a definition for 'PlaceLiquidInWorld'

So, is there a new method of spawning water?
You can use this function from the WorldGen class to add liquid to a single tile:
C#:
public static bool WorldGen.PlaceLiquid(int x, int y, byte liquidType, byte amount);
 
You can use this function from the WorldGen class to add liquid to a single tile:
C#:
public static bool WorldGen.PlaceLiquid(int x, int y, byte liquidType, byte amount);
Thank you! I ended up using this (needed multiple tiles)
WorldGen.SquareTileFrame(i, j, true);
if (Main.netMode == NetmodeID.Server)
{
NetMessage.SendTileSquare(-1, i, j, 1);
}
 
Back
Top Bottom