Skip to content

1: Creating modded game objects

Miron Alexandru edited this page Dec 24, 2021 · 2 revisions

The process

You can create modded game objects (such as items and enemies) using Create methods from the Mod class.

These methods return an Entry that allows you to configure the modded object's properties.

Some creation methods take a string parameter that represents the Mod ID of that object. The Mod ID must be unique between objects of the same type and created by the same mod!

It is important that you configure your items before exiting Mod.Load(). Changing the entries after your mod loads is now allowed, and will cause an exception.

Creating Objects

Audio

AudioEntry audio = CreateAudio();

audio.AddMusic("TestMod", "Intro", "Clash", "DeafSilence");
audio.AddMusic("TestModStuff", "Ripped", "Destiny");

You can create at most one audio entry per mod.

GrindScript uses preset wave bank and sound bank names to load audio data. Depending on what you do, you will need the following wave banks in the "Sound" folder:

  • {Mod.NameID}Effects.xwb - The wave bank used for effects
  • {Mod.NameID}Effects.xsb - The sound bank used for effects
  • {Mod.NameID}.xwb - The universal music wave bank. These stay loaded until you exit the game, or reload your mods
  • {Mod.NameID}Music.xsb - The sound bank used for music
  • Region wave banks - each represents a distinct region of the game, and are loaded / unloaded as needed.

In the list above, {Mod.NameID} is the NameID property of your mod class.

Commands

CommandEntry commands = CreateCommands();

commands.SetCommand("HelloWorld", (args, connection) =>
{
    if (args.Length >= 2 && args[0] == "TheFirstParam" && args[1] == "SecondAndSoOn")
    {
        CAS.AddChatMessage("Hello World from GrindScript!");
    }
});

After defining your commands, you can call them by typing in chat /<Mod's NameID>:<Command> [args...}.

If you don't remember what commands you have defined, calling /GrindScript:Help <NameID> will show them in a list. Alternatively, you can call /<NameID>:Help.

You can also write a custom "Help" command that will take place of the implicit command list shown by /<NameID>:Help.

You can create at most one command entry per mod.

Curses (Arcade)

CurseEntry curse01 = CreateCurse("MyUniqueCurseIDHere");

curse01.Name = "Spooky Curse";
curse01.Description = "Very cursed stuff!";
curse01.IsCurse = true;
curse01.ScoreModifier = 0.4f;
curse01.TexturePath = this.AssetPath + "RogueLike/SpookyCurseIcon.xnb";

Treats and Curses are the same thing internally, the only difference is the shop that they appear in.

Enemies

EnemyEntry enemy = CreateEnemy("MyUniqueEnemyIDHere");

enemy.Name = "Modded Slime";
enemy.BaseHealth = 1600;
enemy.Constructor = ModSlimeAI.InstanceBuilder;  // Instantiates the slime
enemy.DifficultyScaler = ModSlimeAI.DifficultyScaler;  // Scales its stats based on difficulty
enemy.EliteScaler = null;  // If not null, the slime can be elite; the method scales the stats
enemy.Category = EnemyDescription.Category.Regular;
enemy.CardDropChance = 75.0f;  // 75%
enemy.CardInfo = "Boosts your bamboozling by 420%";

enemy.LootTable.Add(new EnemyEntry.Drop(100f, ItemCodex.ItemTypes._Misc_GiftBox_Consumable));
enemy.LootTable.Add(new EnemyEntry.Drop(75f, ItemCodex.ItemTypes._Misc_GiftBox_Consumable));
enemy.LootTable.Add(new EnemyEntry.Drop(50f, ItemCodex.ItemTypes._Misc_GiftBox_Consumable));
enemy.LootTable.Add(new EnemyEntry.Drop(25f, ItemCodex.ItemTypes._Misc_GiftBox_Consumable));

// Do animation setup, etc.

Equipment Effects

Coming SoonTM.

Items

ItemEntry item = CreateItem("MyUniqueItemIDHere");

item.Name = "Shield Example";
item.Description = "This is a custom shield!";
item.EquipType = EquipmentType.Shield;
item.IconPath = this.AssetPath + "Items/ModShield/Icon";
item.EquipResourcePath = this.AssetPath + "Items/ModShield";
item.ShldHP = 250;

Levels

Coming SoonTM.

Networking

NetworkEntry network = CreateNetwork();

// Process packets of ID 0 on client
network.SetClientSideParser(0, (BinaryReader x) =>
{
    string message = x.ReadString();
    CAS.AddChatMessage("Mod Message from Server: " + message);
});

// Process packets of ID 0 on server
network.SetServerSideParser(0, (BinaryReader x, long connectionID) =>
{
    PlayerView view = Globals.Game.dixPlayers[connectionID];
    string message = x.ReadString();
    CAS.AddChatMessage($"Mod Message from Client {view.sNetworkNickname}: " + message);
});

You can create at most one network entry per mod.

The packet IDs are separate for each mod. You can choose any IDs that you want in the range 0-65535.

Perks (Arcade)

PerkEntry perk01 = CreatePerk("MyUniquePerkIDHere");

perk01.Name = "Soul Booster";
perk01.Description = "Gain 10 extra EP.";
perk01.EssenceCost = 15;
perk01.RunStartActivator = (player) =>
{
    player.xEntity.xBaseStats.iMaxEP += 10;
    player.xEntity.xBaseStats._ichkBaseMaxEP += 10 * 2;
};
perk01.TexturePath = this.AssetPath + "RogueLike/SoulBooster";

Pins

PinEntry pin;

pin = CreatePin("MYUniquePinIDHere");

pin.Description = "Gain 150 bonus Shield HP with all shields.";
pin.PinSymbol = PinEntry.Symbol.Shield;
pin.PinShape = PinEntry.Shape.Circle;
pin.PinColor = PinEntry.Color.BilobaFlower;
pin.EquipAction = (PlayerView view) =>
{
    view.xEntity.xBaseStats.iShieldMaxHP += 150;
};
pin.UnequipAction = (PlayerView view) =>
{
    view.xEntity.xBaseStats.iShieldMaxHP -= 150;
};

Quests

Coming SoonTM.

Spells

Coming SoonTM.

Status Effects

StatusEffectEntry status01, status02, status03;

status01 = CreateStatusEffect("DrainDebuff_ASPD");
status02 = CreateStatusEffect("DrainDebuff_CSPD");
status03 = CreateStatusEffect("DrainDebuff_EPReg");

World Regions

Coming SoonTM.

Clone this wiki locally