Tutorial Old Trader Registration - LaughingLeader-DOS2-Mods/LeaderLib GitHub Wiki
- Registering a Trader
- Level Configuration
- Additional Customization
- Registering Treasure to a Trader
- Trader Registration Example
Registering new traders and treasure with LeaderLib's systems is done purely through procedures that add settings to LeaderLib's databases.
Global characters can be registered as traders, which is a great way to keep their inventory consistent between levels.
LeaderLib_Trader_Register_GlobalTrader((STRING)_TraderID, (CHARACTERGUID)_Trader)
_TraderID
should be a uniquely identifiable string for your trader. Common naming conventions are "MyModPrefix.TraderID".
As an alternative to global characters, a root template can be registered as a trader. Root template traders will spawn in the levels they're registered to, provided a character with that _TraderID
doesn't already exist.
LeaderLib_Trader_Register_TraderTemplate((STRING)_TraderID, (STRING)_Template, (INTEGER)_PlaySpawn)
_PlaySpawn
simply specified whether the spawn animation plays when the trader is created.
For situations where you'd like to turn an existing character in a LeaderLib trader, you can register their CHARACTERGUID to LeaderLib:
LeaderLib_Trader_Register_TraderInstance((STRING)_TraderID, (CHARACTERGUID)_Trader, (STRING)_Level)
If the character is found within the level listed, they'll be added to LeaderLib's "trader spawned" database, and gain the benefits of the trader and treasure systems.
Registered positions are ignored for these kind of traders, since it's assumed that they will already be in position.
Once we have a character registered to an ID, LeaderLib's trader system requires a level and a position to be registered before it can teleport or spawn the trader.
Registering a position will automatically register the associated level for that trader, if not registered previously.
The most basic method is to register an actual position (x, y, z). It's a good idea to consider doing this even as a fallback, as other methods may rely on an object that no longer exists, in which case a position is used.
LeaderLib_Trader_Register_Position((STRING)_TraderID, (STRING)_Level, (REAL)_x, (REAL)_y, (REAL)_z)
Alternatively, a trigger can be registered:
LeaderLib_Trader_Register_PositionTrigger((STRING)_TraderID, (STRING)_Level, (TRIGGERGUID)_Trigger)
Finally, you can register an object as a position for the trader. This can be a character or an item - the trader will be spawned at or teleported to the object, provided it still exists.
LeaderLib_Trader_Register_PositionObject((STRING)_TraderID, (STRING)_Level, (GUIDSTRING)_Object)
The seat a trader should sit in after they've been spawned/teleported can be registered. If no position objects were registered for that level, the seat will be added as such automatically.
LeaderLib_Trader_Register_Seat((STRING)_TraderID, (STRING)_Level, (ITEMGUID)_Seat)
LeaderLib_Trader_Register_Seat((STRING)_TraderID, (STRING)_Level, (ITEMGUID)_Seat, (STRING)_RequirementID)
Note: Your trader will need Sit.charScript
attached to it in order for it to actually sit down. LeaderLib sets the seat variables after the trader is placed next to the seat.
Say you register both a position and an object for the same level. Which one gets used? Positions are prioritized as such:
Priority | Type |
---|---|
2 | Position Object |
1 | Position Trigger |
0 | Position Coordinates |
Position objects are prioritized above all other position types. It's a good idea to register a coordinate position regardless, in case that object no longer exists.
A requirement can be set for each level registered, preventing that trader from spawning/teleporting before the requirement are fulfilled.
LeaderLib_Trader_Register_Level((STRING)_TraderID, (STRING)_Level)
LeaderLib_Trader_Register_Level((STRING)_TraderID, (STRING)_Level, (STRING)_RequirementID)
Note that this procedure is called automatically when registering a position (object/trigger/coordinate/seat). Calling LeaderLib_Trader_Register_Level
afterwards with an _RequirementID
will replace the value registered.
The amount of gold a trader should start with on each level can be configured:
LeaderLib_Trader_Register_StartingGold((STRING)_TraderID, (STRING)_Level, (INTEGER)_Amount)
LeaderLib_Trader_Register_StartingGold((STRING)_TraderID, (STRING)_Level, (INTEGER)_Amount, (STRING)_RequirementID)
This procedure is called after the trader first spawns on each level. If a trader does not meet the requirements, the starting gold will be added later on, when that requirement is unlocked.
Dialog can be registered to a trader, and is set once that trader spawns:
LeaderLib_Trader_Register_Dialog((STRING)_TraderID, (STRING)_Dialog)
Registering a dialog with no level or requirement sets this dialog every time the trader is spawned.
Next, dialogs can be registered to specific levels:
LeaderLib_Trader_Register_Dialog((STRING)_TraderID, (STRING)_Dialog, (STRING)_Level)
Dialog with a level or requirements supersede dialog with none.
Finally, you can specify a _RequirementID
for the dialog, providing finer control over when it should be set:
LeaderLib_Trader_Register_Dialog((STRING)_TraderID, (STRING)_Dialog, (STRING)_Level, (STRING)_RequirementID)
If a valid _RequirementID
is provided, that dialog will be set either when the trader spawns (and the requirement is met), or when the requirement is unlocked.
If a dialog is set and its requirement is locked, the trader's dialog will revert back to the next available registered dialog.
You can specify a story event to call once a trader is finished being spawned by the trader system:
LeaderLib_Trader_Register_CreationEvent((STRING)_TraderID, (STRING)_EventName)
The treasure system is potentially complex enough to warrant its own tutorial, but here's some quick example of registering some treasure to a trader:
First of all, we need to link a _TreasureID
to a _TraderID
:
LeaderLib_Treasure_Register_TreasureToTrader((STRING)_TreasureID, (STRING)_TraderID)
This is all it takes to say "this trader should spawn this treasure". _TreasureID
is of course the string ID of a treasure registered to LeaderLib's treasure system.
Ideally the following would be called once, to register a trader:
PROC
MyMod_RegisterTraderOnce()
AND
NOT DB_MyMod_RegisteredTrader("MyMod.Debug.TestTrader")
THEN
NOT DB_MyMod_RegisteredTrader("MyMod.Debug.TestTrader");
//Trader Setup
LeaderLib_Trader_Register_Trader("MyMod.Debug.TestTrader", "Dwarves_Male_Clothing_b1dd34cb-2a28-46d2-8f72-dfa8171b5aa0", 0);
LeaderLib_Trader_Register_Position("MyMod.Debug.TestTrader", "LeaderLib_TestLevel", 10.0, 0.0, 5.0);
LeaderLib_Trader_Register_PositionObject("MyMod.Debug.TestTrader", "LeaderLib_TestLevel", ITEMGUID_LLLIB_Debug_TestChest_ff6c9edf-aa21-447a-8bb2-2a647a8dae46);
//Trader Config
LeaderLib_Trader_Register_StartingGold("MyMod.Debug.TestTrader", "LeaderLib_TestLevel", 20000);
LeaderLib_Trader_Register_Dialog("MyMod.Debug.TestTrader", "LLLIB_Debug_Trader");
//Trader Treasure
LeaderLib_Treasure_Register_TreasureToTrader("MyMod.Debug.TestTrader.InitialItems", "MyMod.Debug.TestTrader");
LeaderLib_Treasure_Register_TreasureTable("MyMod.Debug.TestTrader.InitialItems", "TEST_Generation", "", 1);
//Generation Type Config
LeaderLib_Treasure_Configure_DefaultGenerationType("MyMod.Debug.TestTrader.InitialItems", "DIALOG_STARTED");
//ItemStat / Rune Example
LeaderLib_Treasure_Register_ItemStat("MyMod.Debug.TestTrader.InitialItems", "WPN_Cheat_Sword_1H_RuneSlot2", 2);
LeaderLib_Treasure_Configure_ItemLevel("MyMod.Debug.TestTrader.InitialItems", "WPN_Cheat_Sword_1H_RuneSlot2", 1); // _UsePartyLevel = True (1)
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Cheat_Sword_1H_RuneSlot2", "Boost_Weapon_Rune_LOOT_Rune_Flame_Giant", 23);
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Cheat_Sword_1H_RuneSlot2", "Boost_Weapon_Rune_LOOT_Rune_Masterwork_Giant", 75);
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Cheat_Sword_1H_RuneSlot2", "Boost_Weapon_Rune_LOOT_Rune_Venom_Large", 61);
LeaderLib_Treasure_Register_ItemTemplate("MyMod.Debug.TestTrader.InitialItems", "LOOT_MagicAmulet_Blue_6de34a88-3046-4fef-8933-b4f634d794ae", 2);
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "LOOT_MagicAmulet_Blue_6de34a88-3046-4fef-8933-b4f634d794ae", "Boost_Armor_Amulet_Rune_LOOT_Rune_Thunder_Small", 75);
LeaderLib_Treasure_Register_ItemTemplate("MyMod.Debug.TestTrader.InitialItems", "EQ_Armor_Chainmail_Upperbody_B_9ffce0ea-5d02-47fe-ae49-63b19b8f6f36", 3);
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "EQ_Armor_Chainmail_Upperbody_B_9ffce0ea-5d02-47fe-ae49-63b19b8f6f36", "Boost_Armor_Amulet_Rune_LOOT_Rune_Masterwork_Giant", 41);
//Item Template / Delta Mod Example
LeaderLib_Treasure_Register_ItemTemplate("MyMod.Debug.TestTrader.InitialItems", "WPN_Common_Spear_2H_A_15b17f97-4354-4f6e-98e9-818f87fe95f7", 4);
LeaderLib_Treasure_Configure_ItemLevel("MyMod.Debug.TestTrader.InitialItems", "WPN_Common_Spear_2H_A_15b17f97-4354-4f6e-98e9-818f87fe95f7", 0, 4, 8); // Will spawn anywhere from level 4 to 8
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Common_Spear_2H_A_15b17f97-4354-4f6e-98e9-818f87fe95f7", "Boost_Weapon_Damage_ArmourPiercing_Small_Spear", 25);
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Common_Spear_2H_A_15b17f97-4354-4f6e-98e9-818f87fe95f7", "Boost_Weapon_Primary_Finesse_Medium", 69);
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Common_Spear_2H_A_15b17f97-4354-4f6e-98e9-818f87fe95f7", "Boost_Weapon_Damage_Bonus_Large", -1);// Guaranteed to be applied
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Common_Spear_2H_A_15b17f97-4354-4f6e-98e9-818f87fe95f7", "Boost_Weapon_LifeSteal_Large_TwoHanded", 47);
LeaderLib_Treasure_Configure_AddDeltaMod("MyMod.Debug.TestTrader.InitialItems", "WPN_Common_Spear_2H_A_15b17f97-4354-4f6e-98e9-818f87fe95f7", "Boost_Weapon_Rune_LOOT_Rune_Masterwork_Small", 82);
//Requirement Example
LeaderLib_Requirements_Add_PartyLevelRequirement("MyMod.Debug.TraderRequirements1", 9); // Unlocked when the party is level 9
LeaderLib_Treasure_Register_ItemTemplate("MyMod.Debug.TestTrader.InitialItems", "LOOT_Source_Orb_106a7107-cf36-4331-b5b5-6de71969f370", 1, "MyMod.Debug.TraderRequirements1");
Note that we use DeltaMods to add new runes. Adding runes specifically can be done, but doing so through a DeltaMod is currently safer, as Larian's ItemInsertRune
call can cause crashes in certain situations: