Difference between revisions of "Osiris Tips and Examples"

From Divinity Engine Wiki
Jump to: navigation, search
(Initial draft)
 
m (Databases Queries for Conditions)
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
The following is a collection of practical examples and tips that will aid in your journey to learn how to power your mod through story script usage.
 +
 
== Rule Flow ==
 
== Rule Flow ==
 
Story scripts run on "rules". Every frame, Osiris will evaluate the rules for every running story goal.
 
Story scripts run on "rules". Every frame, Osiris will evaluate the rules for every running story goal.
Line 25: Line 27:
 
Databases can be used to store specific data (such as characters entering a trigger), or as a way to story settings used in your rules.
 
Databases can be used to store specific data (such as characters entering a trigger), or as a way to story settings used in your rules.
  
=== Database Uses Inside Rules ===
+
=== Database Use Within Rules ===
 +
----
 
Databases may be used in all three rule sections:
 
Databases may be used in all three rule sections:
* Databases used in the event section will run when a new entry is added. It will never run when an entry is removed.
+
;IF
* Databases used in the query section can be used to evaluate if an entry exists, does not exist, or as a way to run subsequent lines on the whole database, or entries that match a particular value.
+
:Databases used in the event section will run when a new entry is added. It will never run when an entry is removed.
* In the call section, new entries are added to databases, or existing entries are removed (i.e. NOT DB_MyDatabase(_VariableA, _VariableB).
+
;AND
 +
:Databases used in the query section can be used to evaluate if an entry exists, does not exist, or as a way to run subsequent lines on the whole database, or entries that match a particular value.
 +
;THEN
 +
:In the call section, new entries are added to databases, or existing entries are removed (i.e. NOT DB_MyDatabase(_VariableA, _VariableB).
 +
 
 +
=== Database Events ===
 +
----
 +
When used as an event, it becomes possible to create rules that run when an entry is added to a database.
 +
 
 +
Say we have a database we use to start a timer, called "DB_ExampleMod_Timers". Additionally, when the timer finishes, we'll add the timer name to a database as a sort of "On Complete" event.
 +
 
 +
<pre>
 +
IF
 +
DB_ExampleMod_Timers(_TimerName, _Time)
 +
THEN
 +
TimerLaunch(_TimerName, _Time);
 +
 
 +
IF
 +
TimerFinished(_TimerName)
 +
AND
 +
DB_ExampleMod_Timers(_TimerName, _Time)
 +
THEN
 +
NOT DB_ExampleMod_Timers(_TimerName, _Time);
 +
DB_ExampleMod_TimerFinished(_TimerName);
 +
</pre>
 +
 
 +
Next we'll trigger the events by pulling a lever, with an additional rule for the "DB_ExampleMod_TimerFinished" database, with our specific timer name in mind:
 +
 
 +
<pre>
 +
IF
 +
CharacterUsedItem(_Player, ITEMGUID_Lever_RunTimer_4289a1de-0d4b-43b0-9c38-0d796dff1d43)
 +
THEN
 +
DB_ExampleMod_Timers("ExampleMod_LeverTimer", 1000);
 +
 
 +
IF
 +
DB_ExampleMod_TimerFinished("ExampleMod_LeverTimer")
 +
THEN
 +
DebugBreak("ExampleMod_LeverTimer finished!");
 +
NOT DB_ExampleMod_TimerFinished("ExampleMod_LeverTimer");
 +
</pre>
 +
 
 +
Since database events only fire when an entry is ''added'', not removed, removing the entry right in the database rule works as expected.
 +
 
 +
=== Database Queries ===
 +
----
 +
Used as a query, databases are powerful ways to retrieve data, or create complex conditions.
 +
==== Databases Queries for Conditions ====
 +
Passing values into Databases is an easy way to create dynamic conditions:
 +
<pre>
 +
IF
 +
CharacterUsedSkillOnTarget(_Santa, (CHARACTERGUID)_Target, "Target_GiveGift", _)
 +
AND
 +
DB_Santa_NaughtyList(_Target)
 +
THEN
 +
DisplayText(_Santa, "Ho ho ho! You're been bad this year! Coal for you!");
 +
ItemTemplateAddTo("QUEST_Coal_df215b50-e18f-4527-a2ac-e7eec6cba576", _Target, 1);
 +
 
 +
IF
 +
CharacterUsedSkillOnTarget(_Santa, (CHARACTERGUID)_Target, "Target_GiveGift", _)
 +
AND
 +
NOT DB_Santa_NaughtyList(_Target)
 +
THEN
 +
DisplayText(_Santa, "Ho ho ho! You've been good this year! Have a present!");
 +
ItemTemplateAddTo("QUEST_Present_29f926ff-bfb3-4c0f-b4a4-e356d6b88cf0", _Target, 1);
 +
</pre>
 +
This example assumes that characters were already added to a database, and uses it to determine which item to give to a target, when Santa casts his skill.
 +
 
 +
==== Databases Queries for Data Retrieval ====
 +
Now we'll use a database to iterate through a number of targets dynamically.
 +
<pre>
 +
IF
 +
SkillCast(_Santa, "Shout_SpreadCheer", _)
 +
AND
 +
DB_Santa_NiceList(_Target)
 +
THEN
 +
ApplyStatus(_Target, "HOLIDAY_CHEER", -1.0);
 +
PlayEffect(_Target, "RS3_FX_Santa_HolidayExplosion_01");
 +
</pre>
 +
Since the value of _Target is not specified in the database query, it acts as an out variable, calling subsequent lines on each entry added to DB_Santa_NiceList.
  
 
=== Database Gotchas ===
 
=== Database Gotchas ===
Databases are a powerful way to create complex logic with Osiris, but there's a few things to look out for when using them.
+
----
 +
While databases are a powerful way to create complex scripting logic, there are a few crucial concepts to keep in mind:
 +
* Unless you take steps to clear it out, database data persists in existing saves, even if you no longer support a particular database in a later version of your mod.
 +
* Consider keeping the number of database columns at a manageable size. Databases can be cross-referenced with other databases if needed.
 +
* Inherited types from GUIDSTRING (CHARACTERGUID, ITEMGUID, TRIGGERGUID) need to be declared once in a database, to properly set the type.
 +
 
 +
=== System Methods ===
 +
----
 +
A few system methods, hidden from auto-complete, exist to enhance database use:
 +
 
 +
;call [[Osiris/API/SysClear|SysClear]]((STRING)_Predicate, (INTEGER)_Arity)
 +
* Predicate is the name of the database ("DB_MyDatabase"), while arity are the number of columns (DB_MyDatabase("Apples", 10) would be 2 arity).
 +
* SysClear provides an ideal way of clearing older saves of old databases from previous version of your mod, or paving the way for a full reset of a database.
 +
;query [[Osiris/API/SysCount|SysCount]]([in](STRING)_Predicate,[in](INTEGER)_Arity,[out](INTEGER)_Count)
 +
* SysCount is a way to count the entries in a database. This is especially useful when creating conditions in reference to a database that is added to dynamically through gameplay (i.e. the number of players inside a trigger, the number of characters who had a particular status applied, and so on).
  
== Mod Updates ==
+
=== Cross-Database Referencing ===
When you use databases as a way to store settings, this information will persist on existing saves unless you purposefully remove it.  
+
----
 +
Using a consistent entry across multiple databases allows you to utilize various databases to dynamically enhance your mod.
 +
 
 +
==== Adventure Mod Example ====
 +
----
 +
 
 +
First, we'll create a few databases to store some settings.
 +
 
 +
INIT:
 +
<pre>
 +
//DB_MyAdventureMod_Triggers(_TriggerName, _TriggerID)
 +
DB_MyAdventureMod_Triggers("MyLevel_FrontDoor", (TRIGGERGUID)TRIGGERGUID_S_MyLevel_DoorEntry_b5ab6a49-b015-4908-8f49-7b152d6c5d30);
 +
DB_MyAdventureMod_Triggers("MyLevel_HallwayAmbush", TRIGGERGUID_S_MyLevel_Ambush1_1d089d37-fc5e-4cc6-807e-51d0535dc0cc);
 +
DB_MyAdventureMod_Triggers("MyLevel_GolemBoss", TRIGGERGUID_S_MyLevel_Boss1_0a009ed0-61f5-4670-9d26-1417ebf02922);
 +
 
 +
//DB_MyAdventureMod_TriggerAtmosphere(_TriggerName, _Atmosphere)
 +
DB_MyAdventureMod_TriggerAtmosphere("MyLevel_FrontDoor", "12f866ca-a2e9-4da2-831c-d7d031638160");
 +
DB_MyAdventureMod_TriggerAtmosphere("MyLevel_HallwayAmbush","12f866ca-a2e9-4da2-831c-d7d031638160");
 +
DB_MyAdventureMod_TriggerAtmosphere("MyLevel_GolemBoss","2052f790-d2d7-4cf7-95f0-4de478e98d28");
 +
 
 +
//DB_MyAdventureMod_TriggerSpawns(_TriggerName, _CharacterTemplate)
 +
DB_MyAdventureMod_TriggerSpawns("MyLevel_HallwayAmbush", "MyMod_SkeletonLeader_584db8ce-8dcf-4906-bc6f-e51eb057de08");
 +
DB_MyAdventureMod_TriggerSpawns("MyLevel_HallwayAmbush", "MyMod_SkeletonMage1_61bf204e-ba2e-412f-ac86-e132a3930105");
 +
DB_MyAdventureMod_TriggerSpawns("MyLevel_HallwayAmbush", "MyMod_SkeletonRanger1_f7bd3244-e1e7-4079-ac95-fef6145a236e");
 +
</pre>
 +
 
 +
By using multiple databases together, we now only need to worry about the TRIGGERGUID in one database, while the others rely on the string name. This is easier to deal with in the long run.
 +
 
 +
Next, we'll look for when a player enters one of these triggers, and store when it first activates.
 +
 
 +
KB:
 +
<pre>
 +
IF
 +
CharacterEnteredTrigger((CHARACTERGUID)_Character, (TRIGGERGUID)_TriggerID)
 +
AND
 +
DB_IsPlayer(_Character)
 +
AND
 +
DB_MyAdventureMod_Triggers(_TriggerName, _TriggerID)
 +
AND
 +
NOT DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID)
 +
THEN
 +
DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID);
 +
</pre>
 +
 
 +
We'll then look for when a trigger is added to the "TriggerActivated" database, and create rules for changing the atmosphere and spawning enemies.
 +
 
 +
KB:
 +
<pre>
 +
IF
 +
DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID)
 +
AND
 +
DB_MyAdventureMod_TriggerAtmosphere(_TriggerName, _Atmosphere)
 +
THEN
 +
TriggerSetAtmosphere(_TriggerID, _Atmosphere);
 +
 
 +
IF
 +
DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID)
 +
AND
 +
DB_MyAdventureMod_TriggerSpawns(_TriggerName, _CharacterTemplate)
 +
AND
 +
GetRandomPositionInTrigger(_TriggerID, _X, _Y, _Z)
 +
AND
 +
CharacterCreateAtPosition(_X, _Y, _Z, _CharacterTemplate, 1, _Enemy)
 +
THEN
 +
DB_MyAdventureMod_SpawnedEnemies(_TriggerName, _Enemy);
 +
</pre>
 +
 
 +
We now have a good basis for changing atmosphere, spawning enemies, and tracking which enemies were spawned. This could easily be extended to support sounds, dialogs that need to start, and more.
 +
 
 +
=== Updating Databases ===
 +
----
 +
When you use databases as a way to store settings, this information will persist on existing saves unless you purposefully remove it.
  
 
As an example, say you have a script like this:
 
As an example, say you have a script like this:
  
 
'''MyMod_ExampleScript.txt'''
 
'''MyMod_ExampleScript.txt'''
 +
 
INIT:
 
INIT:
 
<pre>
 
<pre>
Line 45: Line 212:
 
DB_MyMod_Skill_ItemCreation("Target_MyMod_DiamondTransmutation", "LOOT_Gems_Diamond_A_7e24b009-f2bc-47c0-a635-b776407833aa", 1);
 
DB_MyMod_Skill_ItemCreation("Target_MyMod_DiamondTransmutation", "LOOT_Gems_Diamond_A_7e24b009-f2bc-47c0-a635-b776407833aa", 1);
 
</pre>
 
</pre>
 +
 
KB:
 
KB:
 
<pre>
 
<pre>
Line 56: Line 224:
 
Later, after releasing your mod, you decide that you want "Target_MyMod_DiamondTransmutation" to spawn a different diamond item template. To properly do this, in a way that won't spawn the previous template for an existing save, you need to delete the previous entry from the database.
 
Later, after releasing your mod, you decide that you want "Target_MyMod_DiamondTransmutation" to spawn a different diamond item template. To properly do this, in a way that won't spawn the previous template for an existing save, you need to delete the previous entry from the database.
  
=== Mod Update Example ===
+
==== Database Update Example ====
 
----
 
----
One way to implement internal mod "updates" is by storing a "mod version" in a database, and checking against this version when a save is loaded.
+
One way to implement internal mod "updates" for your databases is by storing a "mod version" in a database, and checking against this version when a save is loaded.
  
In a top-level goal (one that will run before all others), enter the following in the KB section:
+
In a top-level goal (one that will run before all others), enter the following:
  
 
'''MyMod__MainScript.txt'''
 
'''MyMod__MainScript.txt'''
 +
INIT:
 +
<pre>
 +
//The current mod version.
 +
DB_MyMod_Version("1.1.1");
 +
</pre>
 +
 
KB:
 
KB:
 
<pre>
 
<pre>
Line 83: Line 257:
  
 
'''MyMod_ExampleScript.txt'''
 
'''MyMod_ExampleScript.txt'''
 +
 
KB:
 
KB:
 
<pre>
 
<pre>
Line 93: Line 268:
  
 
Now when the main script triggers the update, our second script will also run its own update, clearing out the previous database data and adding our new settings.
 
Now when the main script triggers the update, our second script will also run its own update, clearing out the previous database data and adding our new settings.
 +
 +
=== Updating Mods: Beyond Databases ===
 +
----
 +
Beyond changing databases, updating your mod can be a more extensive ordeal, as there's a variety of factors to keep in mind. More on that here: [[Modding:_Versioning|Modding: Versioning]].
 +
 +
== Further Information ==
 +
More in-depth information on Osiris can be read on the following pages:
 +
* [[Osiris Overview]]
 +
* [[Osiris Design Patterns]]
 +
* [[Osiris Gotchas]]
 +
* [[Your First Story Script]]
 +
* [[:Category:Osiris_APIs|Osiris APIs]]
 +
* [[:Category:Osiris_Calls|Osiris Calls]]
 +
 +
[[Category:Osiris]]

Latest revision as of 21:30, 17 April 2018

The following is a collection of practical examples and tips that will aid in your journey to learn how to power your mod through story script usage.

Rule Flow

Story scripts run on "rules". Every frame, Osiris will evaluate the rules for every running story goal.

The flow of every rule is:

IF
Event
AND
Query
THEN
Call();

Queries between the event and the call section of a rule are optional. You can simply go from event to call if you desire:

IF
Event
THEN
Call();

Queries are both gatekeepers to the call section, and a way to retrieve information.

Databases

Databases can be used to store specific data (such as characters entering a trigger), or as a way to story settings used in your rules.

Database Use Within Rules


Databases may be used in all three rule sections:

IF
Databases used in the event section will run when a new entry is added. It will never run when an entry is removed.
AND
Databases used in the query section can be used to evaluate if an entry exists, does not exist, or as a way to run subsequent lines on the whole database, or entries that match a particular value.
THEN
In the call section, new entries are added to databases, or existing entries are removed (i.e. NOT DB_MyDatabase(_VariableA, _VariableB).

Database Events


When used as an event, it becomes possible to create rules that run when an entry is added to a database.

Say we have a database we use to start a timer, called "DB_ExampleMod_Timers". Additionally, when the timer finishes, we'll add the timer name to a database as a sort of "On Complete" event.

IF
DB_ExampleMod_Timers(_TimerName, _Time)
THEN
TimerLaunch(_TimerName, _Time);

IF
TimerFinished(_TimerName)
AND
DB_ExampleMod_Timers(_TimerName, _Time)
THEN
NOT DB_ExampleMod_Timers(_TimerName, _Time);
DB_ExampleMod_TimerFinished(_TimerName);

Next we'll trigger the events by pulling a lever, with an additional rule for the "DB_ExampleMod_TimerFinished" database, with our specific timer name in mind:

IF
CharacterUsedItem(_Player, ITEMGUID_Lever_RunTimer_4289a1de-0d4b-43b0-9c38-0d796dff1d43)
THEN
DB_ExampleMod_Timers("ExampleMod_LeverTimer", 1000);

IF
DB_ExampleMod_TimerFinished("ExampleMod_LeverTimer")
THEN
DebugBreak("ExampleMod_LeverTimer finished!");
NOT DB_ExampleMod_TimerFinished("ExampleMod_LeverTimer");

Since database events only fire when an entry is added, not removed, removing the entry right in the database rule works as expected.

Database Queries


Used as a query, databases are powerful ways to retrieve data, or create complex conditions.

Databases Queries for Conditions

Passing values into Databases is an easy way to create dynamic conditions:

IF
CharacterUsedSkillOnTarget(_Santa, (CHARACTERGUID)_Target, "Target_GiveGift", _)
AND
DB_Santa_NaughtyList(_Target)
THEN
DisplayText(_Santa, "Ho ho ho! You're been bad this year! Coal for you!");
ItemTemplateAddTo("QUEST_Coal_df215b50-e18f-4527-a2ac-e7eec6cba576", _Target, 1);

IF
CharacterUsedSkillOnTarget(_Santa, (CHARACTERGUID)_Target, "Target_GiveGift", _)
AND
NOT DB_Santa_NaughtyList(_Target)
THEN
DisplayText(_Santa, "Ho ho ho! You've been good this year! Have a present!");
ItemTemplateAddTo("QUEST_Present_29f926ff-bfb3-4c0f-b4a4-e356d6b88cf0", _Target, 1);

This example assumes that characters were already added to a database, and uses it to determine which item to give to a target, when Santa casts his skill.

Databases Queries for Data Retrieval

Now we'll use a database to iterate through a number of targets dynamically.

IF
SkillCast(_Santa, "Shout_SpreadCheer", _)
AND
DB_Santa_NiceList(_Target)
THEN
ApplyStatus(_Target, "HOLIDAY_CHEER", -1.0);
PlayEffect(_Target, "RS3_FX_Santa_HolidayExplosion_01");

Since the value of _Target is not specified in the database query, it acts as an out variable, calling subsequent lines on each entry added to DB_Santa_NiceList.

Database Gotchas


While databases are a powerful way to create complex scripting logic, there are a few crucial concepts to keep in mind:

  • Unless you take steps to clear it out, database data persists in existing saves, even if you no longer support a particular database in a later version of your mod.
  • Consider keeping the number of database columns at a manageable size. Databases can be cross-referenced with other databases if needed.
  • Inherited types from GUIDSTRING (CHARACTERGUID, ITEMGUID, TRIGGERGUID) need to be declared once in a database, to properly set the type.

System Methods


A few system methods, hidden from auto-complete, exist to enhance database use:

call SysClear((STRING)_Predicate, (INTEGER)_Arity)
  • Predicate is the name of the database ("DB_MyDatabase"), while arity are the number of columns (DB_MyDatabase("Apples", 10) would be 2 arity).
  • SysClear provides an ideal way of clearing older saves of old databases from previous version of your mod, or paving the way for a full reset of a database.
query SysCount([in](STRING)_Predicate,[in](INTEGER)_Arity,[out](INTEGER)_Count)
  • SysCount is a way to count the entries in a database. This is especially useful when creating conditions in reference to a database that is added to dynamically through gameplay (i.e. the number of players inside a trigger, the number of characters who had a particular status applied, and so on).

Cross-Database Referencing


Using a consistent entry across multiple databases allows you to utilize various databases to dynamically enhance your mod.

Adventure Mod Example


First, we'll create a few databases to store some settings.

INIT:

//DB_MyAdventureMod_Triggers(_TriggerName, _TriggerID)
DB_MyAdventureMod_Triggers("MyLevel_FrontDoor", (TRIGGERGUID)TRIGGERGUID_S_MyLevel_DoorEntry_b5ab6a49-b015-4908-8f49-7b152d6c5d30);
DB_MyAdventureMod_Triggers("MyLevel_HallwayAmbush", TRIGGERGUID_S_MyLevel_Ambush1_1d089d37-fc5e-4cc6-807e-51d0535dc0cc);
DB_MyAdventureMod_Triggers("MyLevel_GolemBoss", TRIGGERGUID_S_MyLevel_Boss1_0a009ed0-61f5-4670-9d26-1417ebf02922);

//DB_MyAdventureMod_TriggerAtmosphere(_TriggerName, _Atmosphere)
DB_MyAdventureMod_TriggerAtmosphere("MyLevel_FrontDoor", "12f866ca-a2e9-4da2-831c-d7d031638160");
DB_MyAdventureMod_TriggerAtmosphere("MyLevel_HallwayAmbush","12f866ca-a2e9-4da2-831c-d7d031638160");
DB_MyAdventureMod_TriggerAtmosphere("MyLevel_GolemBoss","2052f790-d2d7-4cf7-95f0-4de478e98d28");

//DB_MyAdventureMod_TriggerSpawns(_TriggerName, _CharacterTemplate)
DB_MyAdventureMod_TriggerSpawns("MyLevel_HallwayAmbush", "MyMod_SkeletonLeader_584db8ce-8dcf-4906-bc6f-e51eb057de08");
DB_MyAdventureMod_TriggerSpawns("MyLevel_HallwayAmbush", "MyMod_SkeletonMage1_61bf204e-ba2e-412f-ac86-e132a3930105");
DB_MyAdventureMod_TriggerSpawns("MyLevel_HallwayAmbush", "MyMod_SkeletonRanger1_f7bd3244-e1e7-4079-ac95-fef6145a236e");

By using multiple databases together, we now only need to worry about the TRIGGERGUID in one database, while the others rely on the string name. This is easier to deal with in the long run.

Next, we'll look for when a player enters one of these triggers, and store when it first activates.

KB:

IF
CharacterEnteredTrigger((CHARACTERGUID)_Character, (TRIGGERGUID)_TriggerID)
AND
DB_IsPlayer(_Character)
AND
DB_MyAdventureMod_Triggers(_TriggerName, _TriggerID)
AND
NOT DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID)
THEN
DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID);

We'll then look for when a trigger is added to the "TriggerActivated" database, and create rules for changing the atmosphere and spawning enemies.

KB:

IF
DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID)
AND
DB_MyAdventureMod_TriggerAtmosphere(_TriggerName, _Atmosphere)
THEN
TriggerSetAtmosphere(_TriggerID, _Atmosphere);

IF
DB_MyAdventureMod_TriggerActivated(_TriggerName, _TriggerID)
AND
DB_MyAdventureMod_TriggerSpawns(_TriggerName, _CharacterTemplate)
AND
GetRandomPositionInTrigger(_TriggerID, _X, _Y, _Z)
AND
CharacterCreateAtPosition(_X, _Y, _Z, _CharacterTemplate, 1, _Enemy)
THEN
DB_MyAdventureMod_SpawnedEnemies(_TriggerName, _Enemy);

We now have a good basis for changing atmosphere, spawning enemies, and tracking which enemies were spawned. This could easily be extended to support sounds, dialogs that need to start, and more.

Updating Databases


When you use databases as a way to store settings, this information will persist on existing saves unless you purposefully remove it.

As an example, say you have a script like this:

MyMod_ExampleScript.txt

INIT:

//DB_MyMod_Skill_ItemCreation(_Skill, _ItemTemplate, _Count)
DB_MyMod_Skill_ItemCreation("Target_MyMod_DiamondTransmutation", "LOOT_Gems_Diamond_A_7e24b009-f2bc-47c0-a635-b776407833aa", 1);

KB:

IF
SkillCast(_Character, _Skill, _)
AND
DB_MyMod_Skill_ItemCreation(_Skill, _ItemTemplate, _Count)
THEN
ItemTemplateAddTo(_ItemTemplate, _Character, (INTEGER)_Count, 1);

Later, after releasing your mod, you decide that you want "Target_MyMod_DiamondTransmutation" to spawn a different diamond item template. To properly do this, in a way that won't spawn the previous template for an existing save, you need to delete the previous entry from the database.

Database Update Example


One way to implement internal mod "updates" for your databases is by storing a "mod version" in a database, and checking against this version when a save is loaded.

In a top-level goal (one that will run before all others), enter the following:

MyMod__MainScript.txt INIT:

//The current mod version.
DB_MyMod_Version("1.1.1");

KB:

PROC
MyMod_Update_UpdateDatabases()
THEN
DebugBreak("[MyMod] Mod update detected. Updating databases.");

IF
SavegameLoaded(_,_,_,_)
AND
NOT DB_MyMod_Version("1.1.1")
THEN
MyMod_Update_UpdateDatabases();
SysClear("DB_MyMod_Version", 1); // Clear existing mod versions.
DB_MyMod_Version("1.1.1");

"MyMod_Update_UpdateDatabases()" is a custom PROC we've created to handle updating databases. In the individual goals that we want to update databases for, creating new rules with the same PROC name will run our PROC when the top-level goal's PROC is triggered:

MyMod_ExampleScript.txt

KB:

PROC
MyMod_Update_UpdateDatabases()
THEN
SysClear("DB_MyMod_Skill_ItemCreation", 3);
DB_MyMod_Skill_ItemCreation("Target_MyMod_DiamondTransmutation", "LOOT_Gems_Diamond_B_Black_VW_94933c36-393e-4077-abec-95e04341fc92", 1);

Now when the main script triggers the update, our second script will also run its own update, clearing out the previous database data and adding our new settings.

Updating Mods: Beyond Databases


Beyond changing databases, updating your mod can be a more extensive ordeal, as there's a variety of factors to keep in mind. More on that here: Modding: Versioning.

Further Information

More in-depth information on Osiris can be read on the following pages: