Usable campaign items tutorial
This is how to make a usable item (such as a sword or a helmet) that is also vital to the plot.
The problem with regular Plot items is that they're really just tokens that can't be used for anything.
Item Template
Set the item variable ITEM_SEND_ACQUIRED_EVENT to 1.
Module Script
The item variable we just set will trigger a module event when the player acquires the item.
At minimum, we probably want to stop the player destroying the item, so the module event script will include
case EVENT_TYPE_CAMPAIGN_ITEM_ACQUIRED: { object oAcquirer = GetEventCreator(ev); object oItem = GetEventObject(ev, 0); string sItem = GetTag(oItem); // Make item indestructible SetItemIndestructible(oItem, TRUE); // Set plot flags if required (sItem tells us which item has been acquired) break; }
Merchants
We probably don't want to allow the player to sell campaign items.
NOTE: The solution adopted here assumes that event handling is not possible while a merchant is open. It has recently been reported that ToggleGamePause(FALSE) enables event handling, so there might be an easier way.
Here, a custom version of the "open store" plot script is used to store the campaign items in a temporary placeable.
Returning the items to the player is delayed until the next AI update, which happens after the store closes (there's no explicit event for this).
case COC_GENERAL_OPEN_STORE: { object oPlayer = GetHero(); object oStore = GetObjectByTag("store_" + GetTag(oConversationOwner)); object oBin; object [] oItemTable; object oItem; int nItemCount; int nGetItemsOption = GET_ITEMS_OPTION_BACKPACK; int i = -1; if (!IsObjectValid(oStore)) { Log_Trace(LOG_CHANNEL_SYSTEMS, GetCurrentScriptName(), "INVALID STORE OBJECT"); break; } // Hide campaign items (so they can't be sold). oBin = CreateObject(OBJECT_TYPE_PLACEABLE, R"cocip_bin.utp", GetLocation(GetHero())); // Almost any placeable template will do SetTag(oBin, "cocip_campaign_items"); oItemTable = GetItemsInInventory(oPlayer, nGetItemsOption); nItemCount = GetArraySize(oItemTable); while (++i < nItemCount) { oItem = oItemTable[i]; if (GetLocalInt(oItem, ITEM_SEND_ACQUIRED_EVENT)) MoveItem(oPlayer, oBin, oItem); } // Schedule an event to return campaign items to the player at the next AI update DelayEvent(0.0, oPlayer, Event(EVENT_TYPE_INVALID), "coc_restore_campaign_items"); // Open store ScaleStoreItems(oStore); OpenStore(oStore); break; }
The delayed script coc_restore_campaign_items looks like this:
// Restore campaign items to the player // // Campaign items were removed from inventory while the player was trading with a merchant. // Now they are returned. // // Proleric 08-Dec-2010 // #include "log_h" #include "utility_h" #include "wrappers_h" #include "plot_h" void main() { object oPlayer = GetHero(); object oBin = GetObjectByTag("cocip_campaign_items"); object [] oItemTable; object oItem; int nItemCount; int nGetItemsOption = GET_ITEMS_OPTION_BACKPACK; int i = -1; if (IsObjectValid(oBin)) { oItemTable = GetItemsInInventory(oBin, nGetItemsOption); nItemCount = GetArraySize(oItemTable); while (++i < nItemCount) { oItem = oItemTable[i]; MoveItem(oBin, oPlayer, oItem); } WR_DestroyObject(oBin); } }
Lost Items
If your campaign allows items to be lost by other means (such as a camp storage chest), you may want to set the ITEM_SEND_LOST_EVENT variable on the item. This can be intercepted in the EVENT_TYPE_CAMPAIGN_ITEM_LOST module event to control what happens.
Dismissed Followers
If your campaign allows the player to dismiss followers without being able to get them back easily, you might want to check if the follower being fired has a campaign item equipped. Either notify the player, or move it to the shared inventory space automatically.