Skip to content

Patch Documentation

Robert Jordan edited this page Oct 7, 2017 · 7 revisions

Patch Documentation

Below is all of the information on how functions are injected into the Terraria executable. Click on The Original or Replacement text to view the function. Local variable names referenced in the Replacement functions should be changed to the name the local variable has in the Original decompiled function. Functions in bold are the original Terraria functions and the functions below are what gets injected into the original Terraria functions.

tModLoader: Code replaced by Terraria Rupee Replacer is, for the most part, completely untouched by tModLoader, so it's relatively easy to patch. The major differences are changes to the index of local variables and occasionally the OpCodes used to interact with local variables.

Recommended Tool: dnSpy


Coin Pickup Text

static void ItemText.NewText(Item newItem, int stack, bool noStack, bool longText)

Vector2 OnCoinPickupText(Item, int)

Original
for (int i = 0; i < 20; i++) {
    if (Main.itemText[i].active && (Main.itemText[i].name == newItem.AffixName() || (flag && Main.itemText[i].coinText)) && !Main.itemText[i].NoStack && !noStack) {
        //[...]
        if (flag && Main.itemText[i].coinText) {
            int num = 0;
            if (newItem.type == 71) {
                num += newItem.stack;
            }
            else if (newItem.type == 72) {
                num += 100 * newItem.stack;
            }
            else if (newItem.type == 73) {
                num += 10000 * newItem.stack;
            }
            else if (newItem.type == 74) {
                num += 1000000 * newItem.stack;
            }
            Main.itemText[i].coinValue += num;
            text = ItemText.ValueToName(Main.itemText[i].coinValue);
            vector = Main.fontMouseText.MeasureString(text);
            Main.itemText[i].name = text;
            if (Main.itemText[i].coinValue >= 1000000) {
                if (Main.itemText[i].lifeTime < 300) {
                    Main.itemText[i].lifeTime = 300;
                }
                Main.itemText[i].color = new Color(220, 220, 198);
            }
            else if (Main.itemText[i].coinValue >= 10000) {
                if (Main.itemText[i].lifeTime < 240) {
                    Main.itemText[i].lifeTime = 240;
                }
                Main.itemText[i].color = new Color(224, 201, 92);
            }
            else if (Main.itemText[i].coinValue >= 100) {
                if (Main.itemText[i].lifeTime < 180) {
                    Main.itemText[i].lifeTime = 180;
                }
                Main.itemText[i].color = new Color(181, 192, 193);
            }
            else if (Main.itemText[i].coinValue >= 1) {
                if (Main.itemText[i].lifeTime < 120) {
                    Main.itemText[i].lifeTime = 120;
                }
                Main.itemText[i].color = new Color(246, 138, 96);
            }
        }
        //[...]
Replacement
for (int i = 0; i < 20; i++) {
    if (Main.itemText[i].active && (Main.itemText[i].name == newItem.AffixName() || (flag && Main.itemText[i].coinText)) && !Main.itemText[i].NoStack && !noStack) {
        //[...]
        if (flag && Main.itemText[i].coinText) {
            vector = CoinReplacer.OnCoinPickupText(newItem, i)
        }
        //[...]

void OnCoinPickupText2(Item, int)

Original
if (num2 >= 0) {
    //[...]
    if (Main.itemText[num2].coinText) {
        if (newItem.type == 71) {
            Main.itemText[num2].coinValue += Main.itemText[num2].stack;
        }
        else if (newItem.type == 72) {
            Main.itemText[num2].coinValue += 100 * Main.itemText[num2].stack;
        }
        else if (newItem.type == 73) {
            Main.itemText[num2].coinValue += 10000 * Main.itemText[num2].stack;
        }
        else if (newItem.type == 74) {
            Main.itemText[num2].coinValue += 1000000 * Main.itemText[num2].stack;
        }
        Main.itemText[num2].ValueToName();
        Main.itemText[num2].stack = 1;
        int num4 = num2;
        if (Main.itemText[num4].coinValue >= 1000000) {
            if (Main.itemText[num4].lifeTime < 300) {
                Main.itemText[num4].lifeTime = 300;
            }
            Main.itemText[num4].color = new Color(220, 220, 198);
            return;
        }
        if (Main.itemText[num4].coinValue >= 10000) {
            if (Main.itemText[num4].lifeTime < 240) {
                Main.itemText[num4].lifeTime = 240;
            }
            Main.itemText[num4].color = new Color(224, 201, 92);
            return;
        }
        if (Main.itemText[num4].coinValue >= 100) {
            if (Main.itemText[num4].lifeTime < 180) {
                Main.itemText[num4].lifeTime = 180;
            }
            Main.itemText[num4].color = new Color(181, 192, 193);
            return;
        }
        if (Main.itemText[num4].coinValue >= 1) {
            if (Main.itemText[num4].lifeTime < 120) {
                Main.itemText[num4].lifeTime = 120;
            }
            Main.itemText[num4].color = new Color(246, 138, 96);
        }
    }
    return;
Replacement
if (num2 >= 0) {
    //[...]
    if (Main.itemText[num2].coinText) {
        CoinReplacer.OnCoinPickupText2(newItem, num2)
    }
    return;

Technically this function is never used when overriding ItemText.NewText however it's safer to modify it in case it's needed in the future.

void ItemText.ValueToName()

void OnValueToName(ItemText)

Original
//[Entire function]
Replacement
CoinReplacer.OnValueToName(this);

NPC Shop Price Text

void Main.MouseText_DrawItemTooltip(int rare, byte diff, int X, int Y)

Color OnNPCShopPrice(Color, int, string[], int)

This function contains differences between Vanilla and tModLoader.

Original
if (Main.npcShop > 0) {
    int storeValue = Main.HoverItem.GetStoreValue();
    //[...]
    else if (Main.HoverItem.GetStoreValue() > 0) {
        string text = "";
        int num26 = 0;
        int num27 = 0;
        int num28 = 0;
        int num29 = 0;
        int num30 = storeValue * Main.HoverItem.stack;
        if (!Main.HoverItem.buy) {
            num30 = storeValue / 5;
            if (num30 < 1) {
                num30 = 1;
            }
            num30 *= Main.HoverItem.stack;
        }
        if (num30 < 1) {
            num30 = 1;
        }
        if (num30 >= 1000000) {
            num26 = num30 / 1000000;
            num30 -= num26 * 1000000;
        }
        if (num30 >= 10000) {
            num27 = num30 / 10000;
            num30 -= num27 * 10000;
        }
        if (num30 >= 100) {
            num28 = num30 / 100;
            num30 -= num28 * 100;
        }
        if (num30 >= 1) {
            num29 = num30;
        }
        if (num26 > 0) {
            text = string.Concat(new object[] {
                text,
                num26,
                " ",
                Lang.inter[15].Value,
                " "
            });
        }
        if (num27 > 0) {
            text = string.Concat(new object[] {
                text,
                num27,
                " ",
                Lang.inter[16].Value,
                " "
            });
        }
        if (num28 > 0) {
            text = string.Concat(new object[] {
                text,
                num28,
                " ",
                Lang.inter[17].Value,
                " "
            });
        }
        if (num29 > 0) {
            text = string.Concat(new object[] {
                text,
                num29,
                " ",
                Lang.inter[18].Value,
                " "
            });
        }
        if (!Main.HoverItem.buy) {
            array[num4] = Lang.tip[49].Value + " " + text;
        }
        else {
            array[num4] = Lang.tip[50].Value + " " + text;
        }
        #if TMOD
        // tModLoader-specific code
        array4[num4] = "Price";
        #endif
        num4++;
        if (num26 > 0) {
            color = new Color((int)((byte)(220f * num25)), (int)((byte)(220f * num25)), (int)((byte)(198f * num25)), a);
        }
        else if (num27 > 0) {
            color = new Color((int)((byte)(224f * num25)), (int)((byte)(201f * num25)), (int)((byte)(92f * num25)), a);
        }
        else if (num28 > 0) {
            color = new Color((int)((byte)(181f * num25)), (int)((byte)(192f * num25)), (int)((byte)(193f * num25)), a);
        }
        else if (num29 > 0) {
            color = new Color((int)((byte)(246f * num25)), (int)((byte)(138f * num25)), (int)((byte)(96f * num25)), a);
        }
    }
    //[...]
Replacement
if (Main.npcShop > 0) {
    int storeValue = Main.HoverItem.GetStoreValue();
    //[...]
    else if (Main.HoverItem.GetStoreValue() > 0) {
        color = CoinReplacer.OnNPCShopPrice(color, num4, array, storeValue);
        #if TMOD
        // tModLoader-specific code
        array4[num4] = "Price";
        #endif
        num4++;
    }
    //[...]

Reforge Cost Text

void Main.DrawInventory()

string OnReforgeCost(int)

Original
if (Main.InReforgeMenu) {
    //[...]
    if (Main.player[Main.myPlayer].chest != -1 || Main.npcShop != 0 || Main.player[Main.myPlayer].talkNPC == -1 || Main.InGuideCraftMenu) {
        //[...]
    }
    else {
        int num58 = 50;
        int num59 = 270;
        string text2 = Lang.inter[46].Value + ": ";
        if (Main.reforgeItem.type > 0) {
            int num60 = Main.reforgeItem.value;
            if (Main.player[Main.myPlayer].discount) {
                num60 = (int)((double)num60 * 0.8);
            }
            num60 /= 3;
            string text3 = "";
            int num61 = 0;
            int num62 = 0;
            int num63 = 0;
            int num64 = 0;
            int num65 = num60;
            if (num65 < 1) {
                num65 = 1;
            }
            if (num65 >= 1000000) {
                num61 = num65 / 1000000;
                num65 -= num61 * 1000000;
            }
            if (num65 >= 10000) {
                num62 = num65 / 10000;
                num65 -= num62 * 10000;
            }
            if (num65 >= 100) {
                num63 = num65 / 100;
                num65 -= num63 * 100;
            }
            if (num65 >= 1) {
                num64 = num65;
            }
            if (num61 > 0) {
                text3 = string.Concat(new object[] {
                    text3,
                    "[c/",
                    Colors.AlphaDarken(Colors.CoinPlatinum).Hex3(),
                    ":",
                    num61,
                    " ",
                    Lang.inter[15].Value,
                    "] "
                });
            }
            if (num62 > 0) {
                text3 = string.Concat(new object[] {
                    text3,
                    "[c/",
                    Colors.AlphaDarken(Colors.CoinGold).Hex3(),
                    ":",
                    num62,
                    " ",
                    Lang.inter[16].Value,
                    "] "
                });
            }
            if (num63 > 0) {
                text3 = string.Concat(new object[] {
                    text3,
                    "[c/",
                    Colors.AlphaDarken(Colors.CoinSilver).Hex3(),
                    ":",
                    num63,
                    " ",
                    Lang.inter[17].Value,
                    "] "
                });
            }
            if (num64 > 0) {
                text3 = string.Concat(new object[] {
                    text3,
                    "[c/",
                    Colors.AlphaDarken(Colors.CoinCopper).Hex3(),
                    ":",
                    num64,
                    " ",
                    Lang.inter[18].Value,
                    "] "
                });
            }
            ItemSlot.DrawSavings(Main.spriteBatch, (float)(num58 + 130), (float)this.invBottom, true);
            ChatManager.DrawColorCodedStringWithShadow(Main.spriteBatch, Main.fontMouseText, text3, new Vector2((float)(num58 + 50) + Main.fontMouseText.MeasureString(text2).X, (float)num59), Color.White, 0f, Vector2.Zero, Vector2.One, -1f, 2f);
            //[...]
Replacement
if (Main.InReforgeMenu) {
    //[...]
    if (Main.player[Main.myPlayer].chest != -1 || Main.npcShop != 0 || Main.player[Main.myPlayer].talkNPC == -1 || Main.InGuideCraftMenu) {
        //[...]
    }
    else {
        int num58 = 50;
        int num59 = 270;
        string text2 = Lang.inter[46].Value + ": ";
        if (Main.reforgeItem.type > 0) {
            int num60 = Main.reforgeItem.value;
            if (Main.player[Main.myPlayer].discount) {
                num60 = (int)((double)num60 * 0.8);
            }
            num60 /= 3;
            string text3;
            text3 = CoinReplacer.OnReforgeCost(num60);
            ItemSlot.DrawSavings(Main.spriteBatch, (float)(num58 + 130), (float)this.invBottom, true);
            ChatManager.DrawColorCodedStringWithShadow(Main.spriteBatch, Main.fontMouseText, text3, new Vector2((float)(num58 + 50) + Main.fontMouseText.MeasureString(text2).X, (float)num59), Color.White, 0f, Vector2.Zero, Vector2.One, -1f, 2f);
            //[...]

Nurse and Tax Collector Text

void Main.GUIChatDrawInner()

void OnTaxCollect(ref string, ref Color, ref int)

Original
else if (Main.npc[Main.player[Main.myPlayer].talkNPC].type == 441) {
    if (Main.player[Main.myPlayer].taxMoney <= 0) {
        focusText = Lang.inter[89].Value;
    }
    else {
        string text = "";
        int num8 = 0;
        int num9 = 0;
        int num10 = 0;
        int num11 = 0;
        int num12 = Main.player[Main.myPlayer].taxMoney;
        if (num12 < 0) {
            num12 = 0;
        }
        num6 = num12;
        if (num12 >= 1000000) {
            num8 = num12 / 1000000;
            num12 -= num8 * 1000000;
        }
        if (num12 >= 10000) {
            num9 = num12 / 10000;
            num12 -= num9 * 10000;
        }
        if (num12 >= 100) {
            num10 = num12 / 100;
            num12 -= num10 * 100;
        }
        if (num12 >= 1) {
            num11 = num12;
        }
        if (num8 > 0) {
            text = string.Concat(new object[] {
                text,
                num8,
                " ",
                Lang.inter[15].Value,
                " "
            });
        }
        if (num9 > 0) {
            text = string.Concat(new object[] {
                text,
                num9,
                " ",
                Lang.inter[16].Value,
                " "
            });
        }
        if (num10 > 0) {
            text = string.Concat(new object[] {
                text,
                num10,
                " ",
                Lang.inter[17].Value,
                " "
            });
        }
        if (num11 > 0) {
            text = string.Concat(new object[] {
                text,
                num11,
                " ",
                Lang.inter[18].Value,
                " "
            });
        }
        float num13 = (float)Main.mouseTextColor / 255f;
        if (num8 > 0) {
            color2 = new Color((int)((byte)(220f * num13)), (int)((byte)(220f * num13)), (int)((byte)(198f * num13)), (int)Main.mouseTextColor);
        }
        else if (num9 > 0) {
            color2 = new Color((int)((byte)(224f * num13)), (int)((byte)(201f * num13)), (int)((byte)(92f * num13)), (int)Main.mouseTextColor);
        }
        else if (num10 > 0) {
            color2 = new Color((int)((byte)(181f * num13)), (int)((byte)(192f * num13)), (int)((byte)(193f * num13)), (int)Main.mouseTextColor);
        }
        else if (num11 > 0) {
            color2 = new Color((int)((byte)(246f * num13)), (int)((byte)(138f * num13)), (int)((byte)(96f * num13)), (int)Main.mouseTextColor);
        }
        if (text == "") {
            focusText = Lang.inter[89].Value;
        }
        else {
            text = text.Substring(0, text.Length - 1);
            focusText = Lang.inter[89].Value + " (" + text + ")";
        }
    }
}
else if (Main.npc[Main.player[Main.myPlayer].talkNPC].type == 18) {
Replacement
else if (Main.npc[Main.player[Main.myPlayer].talkNPC].type == 441) {
    if (Main.player[Main.myPlayer].taxMoney <= 0) {
        focusText = Lang.inter[89].Value;
    }
    else {
        CoinReplacer.OnTaxCollect(ref focusText, ref color2, ref num6);
    }
}
else if (Main.npc[Main.player[Main.myPlayer].talkNPC].type == 18) {

void OnNurseHeal(ref string, ref Color, ref int)

Original
else if (Main.npc[Main.player[Main.myPlayer].talkNPC].type == 18) {
    string text2 = "";
    int num14 = 0;
    int num15 = 0;
    int num16 = 0;
    int num17 = 0;
    int num18 = num6;
    if (num18 > 0) {
        num18 = (int)((double)num18 * 0.75);
        if (num18 < 1) {
            num18 = 1;
        }
    }
    if (num18 < 0) {
        num18 = 0;
    }
    num6 = num18;
    if (num18 >= 1000000) {
        num14 = num18 / 1000000;
        num18 -= num14 * 1000000;
    }
    if (num18 >= 10000) {
        num15 = num18 / 10000;
        num18 -= num15 * 10000;
    }
    if (num18 >= 100) {
        num16 = num18 / 100;
        num18 -= num16 * 100;
    }
    if (num18 >= 1) {
        num17 = num18;
    }
    if (num14 > 0) {
        text2 = string.Concat(new object[] {
            text2,
            num14,
            " ",
            Lang.inter[15].Value,
            " "
        });
    }
    if (num15 > 0) {
        text2 = string.Concat(new object[] {
            text2,
            num15,
            " ",
            Lang.inter[16].Value,
            " "
        });
    }
    if (num16 > 0) {
        text2 = string.Concat(new object[] {
            text2,
            num16,
            " ",
            Lang.inter[17].Value,
            " "
        });
    }
    if (num17 > 0) {
        text2 = string.Concat(new object[] {
            text2,
            num17,
            " ",
            Lang.inter[18].Value,
            " "
        });
    }
    float num19 = (float)Main.mouseTextColor / 255f;
    if (num14 > 0) {
        color2 = new Color((int)((byte)(220f * num19)), (int)((byte)(220f * num19)), (int)((byte)(198f * num19)), (int)Main.mouseTextColor);
    }
    else if (num15 > 0) {
        color2 = new Color((int)((byte)(224f * num19)), (int)((byte)(201f * num19)), (int)((byte)(92f * num19)), (int)Main.mouseTextColor);
    }
    else if (num16 > 0) {
        color2 = new Color((int)((byte)(181f * num19)), (int)((byte)(192f * num19)), (int)((byte)(193f * num19)), (int)Main.mouseTextColor);
    }
    else if (num17 > 0) {
        color2 = new Color((int)((byte)(246f * num19)), (int)((byte)(138f * num19)), (int)((byte)(96f * num19)), (int)Main.mouseTextColor);
    }
    if (text2 == "") {
        focusText = Lang.inter[54].Value;
    }
    else {
        text2 = text2.Substring(0, text2.Length - 1);
        focusText = Lang.inter[54].Value + " (" + text2 + ")";
    }
}
if (!flag) {
Replacement
else if (Main.npc[Main.player[Main.myPlayer].talkNPC].type == 18) {
    CoinReplacer.OnNurseHeal(ref focusText, ref color2, ref num6);
}
if (!flag) {

Death Dropped Coins Text

static string Main.ValueToCoins(int value)

string OnValueToCoins(int)

Original
//[Entire function]
Replacement
return CoinReplacer.OnValueToCoins(value);

Coin Movement Glow

static void Dust.UpdateDust()

void OnCoinGlow(Dust)

Original
for (int i = 0; i < 6000; i++) {
    Dust dust = Main.dust[i];
    if (i < Main.maxDustToDraw) {
        if (dust.active) {
            //[...]
            else if (dust.type >= 244 && dust.type <= 247) {
                dust.rotation += 0.1f * dust.scale;
                Color color = Lighting.GetColor((int)(dust.position.X / 16f), (int)(dust.position.Y / 16f));
                byte b = (color.R + color.G + color.B) / 3;
                float num78 = ((float)b / 270f + 1f) / 2f;
                float num79 = ((float)b / 270f + 1f) / 2f;
                float num80 = ((float)b / 270f + 1f) / 2f;
                num78 *= dust.scale * 0.9f;
                num79 *= dust.scale * 0.9f;
                num80 *= dust.scale * 0.9f;
                if (dust.alpha < 255) {
                    dust.scale += 0.09f;
                    if (dust.scale >= 1f) {
                        dust.scale = 1f;
                        dust.alpha = 255;
                    }
                }
                else {
                    if ((double)dust.scale < 0.8) {
                        dust.scale -= 0.01f;
                    }
                    if ((double)dust.scale < 0.5) {
                        dust.scale -= 0.01f;
                    }
                }
                float num81 = 1f;
                if (dust.type == 244) {
                    num78 *= 0.8862745f;
                    num79 *= 0.4627451f;
                    num80 *= 0.298039228f;
                    num81 = 0.9f;
                }
                else if (dust.type == 245) {
                    num78 *= 0.5137255f;
                    num79 *= 0.6745098f;
                    num80 *= 0.6784314f;
                    num81 = 1f;
                }
                else if (dust.type == 246) {
                    num78 *= 0.8f;
                    num79 *= 0.709803939f;
                    num80 *= 0.282352954f;
                    num81 = 1.1f;
                }
                else if (dust.type == 247) {
                    num78 *= 0.6f;
                    num79 *= 0.6745098f;
                    num80 *= 0.7254902f;
                    num81 = 1.2f;
                }
                num78 *= num81;
                num79 *= num81;
                num80 *= num81;
                Lighting.AddLight((int)(dust.position.X / 16f), (int)(dust.position.Y / 16f), num78, num79, num80);
            }
            else if (dust.type == 43) {
               //[...]
Replacement
for (int i = 0; i < 6000; i++) {
    Dust dust = Main.dust[i];
    if (i < Main.maxDustToDraw) {
        if (dust.active) {
            //[...]
            else if (dust.type >= 244 && dust.type <= 247) {
                CoinReplacer.OnCoinGlow(dust);
            }
            else if (dust.type == 43) {
               //[...]

Localization Injection

void LanguageManager.LoadLanguage(GameCulture culture)

void OnLoadLocalizations(GameCulture culture)

Original
this.LoadFilesForCulture(culture);
if (this.OnLanguageChanging != null) {
    this.OnLanguageChanging(this);
}
this.ProcessCopyCommandsInTexts();
Replacement
this.LoadFilesForCulture(culture);
CoinReplacer.OnLoadLocalizations(culture);
if (this.OnLanguageChanging != null) {
    this.OnLanguageChanging(this);
}
this.ProcessCopyCommandsInTexts();
Clone this wiki locally