Osiris Tips and Examples
Contents
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 Uses Inside 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 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 a bad guy 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 _Target was never set beforehand, 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.
- Osiris may have issues with databases containing more than 6 columns.
- Inherited types from GUIDSTRING (CHARACTERGUID, ITEMGUID, TRIGGERGUID) need to be declared once in a database, to properly set the type.
Advanced Database Techniques
System Methods
A few system methods hidden from auto-complete exist to extend 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).
Mod Updates
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.
Mod 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.
In a top-level goal (one that will run before all others), enter the following in the KB section:
MyMod__MainScript.txt
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.