User:BinaryDoubts/RelicTutorial: Difference between revisions

From Caves of Qud Wiki
Jump to navigation Jump to search
No edit summary
mNo edit summary
Line 123: Line 123:


== History Spice ==
== History Spice ==
The last step is modifying the game's HistorySpice.json file so that it knows how to name your relic. You can write your own methods to do this, or (recommended) use Tyrir's [[https://steamcommunity.com/workshop/filedetails/?id=3396620647 Hot 'n Spicy History mod]] to achieve the same goal. This tutorial will assume you're using the mod, so make sure you're subscribed to it, that it's enabled in-game, and that it's set as a dependency if your mod is published to the Workshop.
The last step is modifying the game's HistorySpice.json file so that it knows how to name your relic. You can write your own methods to do this, or (recommended) use Tyrir's [https://steamcommunity.com/workshop/filedetails/?id=3396620647 Hot 'n Spicy History mod] to achieve the same goal. This tutorial will assume you're using the mod, so make sure you're subscribed to it, that it's enabled in-game, and that it's set as a dependency if your mod is published to the Workshop.


With the Hot 'n Spicy History mod enabled, all you need to do is create a new file named <code>HistorySpice.json</code> and place it in your mod's root directory. When the game is launched, the contents of your file will be merged with the game's default version, allowing the relic generator to find names for your weapon.
With the Hot 'n Spicy History mod enabled, all you need to do is create a new file named <code>HistorySpice.json</code> and place it in your mod's root directory. When the game is launched, the contents of your file will be merged with the game's default version, allowing the relic generator to find names for your weapon.

Revision as of 20:06, 27 January 2025

This tutorial covers adding new weapon types to the pool of options for relics, allowing them to spawn as historical relics with boosted stats and special relic-only traits. It assumes you have already created a set of weapon blueprints for tiers 0-8 and that the weapon skill is new for your mod. The relic generation functions live in RelicGenerator.cs and can be viewed via ILSpy.

Getting Started

To hook your new weapon type into the generator, you'll need the following:

  • New <populations> entries in PopulationTables.xml for every tier of weapon so the relic generator knows what blueprints to use as the base item to modify
  • New <relictype> and <relictypemapping> entries in Relics.xml to add your weapon type to the pool of options considered by the relic generator
  • Harmony patches to RelicGenerator.GetType(GameObject Object) and RelicGenerator.GetSubtype(string type) so that the generator can correctly understand that your weapons should be treated as such by the generator and be given weapon-only boosts
  • New weapon name synonyms added to HistorySpce.json so the relic generator can give your relic weapon an appropriate name

This tutorial will use the example of a mod called BigSwords that adds the GreatKatana weapon type. Replace BigSwords_GreatKatana with the name used by your new weapon type/skill when copy+pasting code from this page.

XML Edits

The first step is adding some new tags into your mod's XML so that the relic generator knows about your new weapon type and what blueprints to use as the base item when a relic is generated.

PopulationTables.xml

When the game generates a relic, after picking the item's type, it will look for a population containing a set of blueprints that's named in a specific way: BaseRelic_ + WeaponType + tier number. If the weapon has a two-handed variant, the relic can also spawn in a two-handed version, and will look for a population named following the same method but with th added at the end.

Using the BigSwords mod as an example, the populations for a tier 1 weapon would be named BaseRelic_BigSwords_GreatKatana1 or BaseRelic_BigSwords_GreatKatana1th for the two-handed version. The game will always roll (20% chance) to see if a two-handed version is being selected, even if your weapon type doesn't have two-handed variants — if there's no th version of the population table, it will fall back and use the base, non-th population instead. Once the relic generator finds the correct population, it will search the subsidiary Blueprint pick-one group and choose a blueprint as the base item.

If you don't already have it, create a new XML file in your mod's folder named PopulationTables.xml, then fill it with population tables set up as discussed above. For example, here's what our BigSwords mod's tables might look like for tier 1:

<population Name = "BaseRelic_BigSwords_GreatKatana1">
	<group Name = "Blueprint" Style = "pickone">
	    <object Blueprint = "BigSwords_GreatKatana1"/>
	</group>
</population>

<population Name = "BaseRelic_BigSwords_GreatKatana1th">
	<group Name = "Blueprint" Style = "pickone">
	    <object Blueprint = "BigSwords_GreatKatana1th"/>
	</group>
</population>

Adding multiple variants is easy, and they even support weights to make one more likely than the other. Here's an example showing a table with multiple variants:

<population Name = "BaseRelic_BigSwords_GreatKatana1">
	<group Name = "Blueprint" Style = "pickone">
	    <object Blueprint = "BigSwords_GreatKatana1" Weight="20"/>
	    <object Blueprint = "BigSwords_GreatKatana1_FlameBlade" Weight="10"/>
		<object Blueprint = "BigSwords_GreatKatana1_IceBlade" Weight="10"/>
	</group>
</population>
</code>

Relics can spawn from tiers 1-8, so you'll need 8 versions of the table(s), one for each tier. Base (bronze) items cannot spawn as relics so there's no need to create a BaseRelic_BigSwords_GreatKatana (with no number, representing tier 0) population table.

Relics.xml

If you don't already have it, create a new XML file in your mod's folder named Relics.xml. Set up a file that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<relics>
	<relictypes>
	</relictypes>

	<relictypemappings>
	</relictypemappings>
</relics>

The new weapon type needs an entry in the <relictype> table and the <relictypemappings> table. Under relictype, add <relictype Name = "BigSwords_GreatKatana" />. The Name should be exactly the same as your weapon's skill/type name.

Under relictypemappings, add <relictypemapping Name = "great katana" Type = "BigSwords_GreatKatana"/>. The Name field should just be the name of your weapon type in plain lowercase text, while Type should be the name of your weapon type/skill name.

Your final Relics.xml should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<relics>
	<relictypes>
		<relictype Name = "BigSwords_GreatKatana" />
	</relictypes>

	<relictypemappings>
	    <relictypemapping Name = "great katana" Type = "BigSwords_GreatKatana"/>
	</relictypemappings>
</relics>

Harmony Patches

You've set up the infrastructure for your new relic, but the game still needs a little help figuring out if your new relics count as weapons or not. If the game can't figure out an item's type, it will default to treating it like a curio, meaning it won't get any bonuses to damage, to-hit, stats, or other traits that can only roll on weapon relics. You can easily tell if a weapon is set up correctly by checking its effects: if the game thinks it's a curio, the effect will always be either "summon a friendly creature" or "destroy all creatures of a faction."

If you don't already have a C# file for Harmony patches, create a new Patches.cs (name can be anything) file and set it up like this:

using XRL.World;

namespace BigSwords.HarmonyPatches{
	
}

You'll need to patch the RelicGenerator.GetType(GameObject Object)and RelicGenerator.GetSubtype(string type) methods to make sure your weapon type is treated correctly.

GetType

Add a new block of code to the HarmonyPatches namespace:

[HarmonyPatch(typeof(XRL.World.RelicGenerator))]
class BigSwords_RelicGetTypePatch{
	[HarmonyPatch("GetType")]
	[HarmonyPostfix]
	static void Postfix(ref GameObject Object, ref string __result){
		MeleeWeapon wep = Object.GetPart<MeleeWeapon>();
		if (wep != null && wep.Skill == "BigSwords_GreatKatana"){
			__result = "BigSwords_GreatKatana";
		}
	}
}

All we're doing here is using a Harmony patch to access the results of the GetType method. Whenever GetType is run, it looks at the actual created GameObject and returns a string containing the object's Skill name. In this case, we're looking for a weapon that has the skill BigSwords_GreatKatana (since that's what our mod uses) and, if present, return that skill name. If your weapon type is ranged, use GetPart<MissileWeapon>() instead of GetPart<MeleeWeapon>().

GetSubtype

GetSubtype is a simple method that boils down multiple item types to their overarching "class." ShortBlades, LongBlades, Cudgels, and Axes all return "weapon" as their subtype, while Pistols and Rifles return "ranged." All that's needed for this patch is to check if the provided type string matches our new weapon type, and if so, return "weapon" instead of "curio" (the default result if GetSubtype can't figure out the type). Add a new block of code to your HarmonyPatches namespace:

[HarmonyPatch(typeof(XRL.World.RelicGenerator))]
class BigSwords_RelicGetSubtypePatch{
	[HarmonyPatch("GetSubtype")]
	[HarmonyPostfix]
	static void Postfix(ref string type, ref string __result){
		if (type == "BigSwords_GreatKatana"){
			__result = "weapon";
		}
	}
}

If your weapon type is ranged, set __result to "ranged" instead of "weapon".

History Spice

The last step is modifying the game's HistorySpice.json file so that it knows how to name your relic. You can write your own methods to do this, or (recommended) use Tyrir's Hot 'n Spicy History mod to achieve the same goal. This tutorial will assume you're using the mod, so make sure you're subscribed to it, that it's enabled in-game, and that it's set as a dependency if your mod is published to the Workshop.

With the Hot 'n Spicy History mod enabled, all you need to do is create a new file named HistorySpice.json and place it in your mod's root directory. When the game is launched, the contents of your file will be merged with the game's default version, allowing the relic generator to find names for your weapon.

Here's what the file should look like:

{
    "spice": {
        "itemTypes":{
            "BigSwords_GreatKatana": ["ultra-katana", "really big sword", "slicer", "giant razor"]
        }
    }
}

When RelicGenerator tries to name a relic, it picks a random name that corresponds to the relic's type from the itemTypes table. You can have any number of synonyms in the list, although most base-game items only have 4.

Testing

After you've completed all of the above steps, your new weapon type should be fully integrated into the game's relic generation system. To quickly test if you've correctly set it up, load into a new game and use the wish relic to generate a relic of every type. If your type has been added, you should find at least one relic of your new type in the pile of items that spawn. Double-check that it has:

  1. A correct name that includes one of your synonyms from HistorySpice (if it can't find a word, the name will noticeably contain a blank where the word should go).
  2. Weapon bonuses, which could include to-hit, damage, and/or added mutations (if the weapon can summon creatures or wipe out all creatures of a given faction, it has been treated as a curio, not a weapon).

Assuming all is well, that's it. Enjoy your new relics!