Yes, that sums up the problem accurately, with Ghost's script or any other. This is why I indicated the need for an initial all-items scan. Additionally, if you're using object-based banking, rather than resref-based, you would need to scan/replace all the vaults as well. That's possible, but quite a pain. The alternative, a vault wipe, is a very bad idea, as far as player retention goes.
Here's our item updater code. It fires on client enter, and automatically waits until the player hits the first area of the mod where they spend any amount of time, freezing them in place if the need for any updates is detected:
[code=auto:0]
#include "hg_inc"
#include "ac_itemreq_inc"
#include "ac_copycraft_inc"
#include "fky_chat_inc"
#include "inc_draw"
#include "hg_antidupe_inc"
#include "x2_inc_itemprop"
void ArtifactExplode (object oPC) {
int i;
object oItem;
location lCenter = GetLocation(oPC);
effect eImpact, eDamage, eLink;
for (i = 0; i < NUM_INVENTORY_SLOTS; i++) {
oItem = GetItemInSlot(i, oPC);
if (GetLocalInt(oItem, "Artifact")) {
WriteTimestampedLogEntry("ARTIFACT EXPLOSION : " + GetPCPlayerName(oPC) + " : " + GetName(oPC) + " : " + GetName(oItem));
SetItemStackSize(oItem, 1);
SetPlotFlag(oItem, FALSE);
DestroyObject(oItem);
}
}
oItem = GetFirstItemInInventory(oPC);
while (GetIsObjectValid(oItem)) {
if (GetLocalInt(oItem, "Artifact")) {
WriteTimestampedLogEntry("ARTIFACT EXPLOSION : " + GetPCPlayerName(oPC) + " : " + GetName(oPC) + " : " + GetName(oItem));
SetItemStackSize(oItem, 1);
SetPlotFlag(oItem, FALSE);
DestroyObject(oItem);
}
oItem = GetNextItemInInventory(oPC);
}
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SCREEN_SHAKE), lCenter);
DelayCommand(0.25, DrawSphere(1, 249, lCenter, 0.25, 0.0, 30, 0.0, 0.0, 0.0, "z"));
DelayCommand(2.75, DrawSpiral(0, 76, lCenter, 0.0, 23.0, 0.0, 60, 13.0, 0.7, 0.0, "z"));
DelayCommand(2.75, DrawSpiral(0, 469, lCenter, 0.0, 23.0, 0.0, 60, 13.0, 0.7, 0.0, "z"));
DelayCommand(3.00, DrawCircle(0, 22, lCenter, 5.0, 0.0, 10, 1.0, 0.0, 0.0, "z"));
DelayCommand(3.50, DrawCircle(0, 22, lCenter, 11.0, 0.0, 13, 1.0, 0.0, 0.0, "z"));
}
void DestroyOriginalItem (object oItem) {
SetPlotFlag(oItem, FALSE);
DestroyObject(oItem);
}
void ReplaceItem (object oTarget, object oItem, string sRes) {
string sName = GetName(oItem);
string sLog = "UPDATEITEMS : " + GetName(oTarget) + " (" +
GetPCPlayerName(oTarget) + ") : " + sName + " (" +
GetResRef(oItem) + ") [v" + IntToString(GetLocalInt(oItem, "Version")) + "] -> ";
int nCharges = GetItemCharges(oItem);
string sUniqueID = GetLocalString(oItem, "UNIQUE_ID");
if (GetLocalInt(oItem, "Artifact") || GetLocalInt(oItem, "Singleton"))
SetLocalInt(oItem, "NoCopyCrafting", 1);
DeleteLocalInt(oItem, "Artifact");
DeleteLocalInt(oItem, "Singleton");
DeleteLocalString(oItem, "UNIQUE_ID");
int nBaseType = GetBaseItemType(oItem);
if (sRes == GetResRef(oItem) &&
!GetLocalInt(oItem, "NoCopyCrafting") &&
(nBaseType == BASE_ITEM_ARMOR ||
nBaseType == BASE_ITEM_HELMET ||
GetItemIsShield(oItem) ||
GetItemIsWeapon(oItem))) {
AssignCommand(GetModule(), DelayCommand(0.0, DestroyOriginalItem(oItem)));
object oCopy = CreateItemOnObject(sRes, oTarget, 1);
if (!GetLocalInt(oCopy, "Artifact") &&
!GetLocalInt(oCopy, "Singleton") &&
!GetLocalInt(oCopy, "NoCopyCrafting")) {
AssignCommand(GetModule(), DelayCommand(0.0, DestroyOriginalItem(oCopy)));
oCopy = CopyItemCrafting(oItem, oCopy);
}
SetPlotFlag(oItem, FALSE);
SetLocalInt(oItem, "REPLACED", 1);
DestroyObject(oItem);
oItem = oCopy;
} else if (nBaseType == BASE_ITEM_RING && sRes == "multi_signet") {
int i, j;
AssignCommand(GetModule(), DelayCommand(0.0, DestroyOriginalItem(oItem)));
SetPlotFlag(oItem, FALSE);
SetLocalInt(oItem, "REPLACED", 1);
object oRing = CreateItemOnObject(sRes, oTarget, 1);
/* copy the charges from the last Ring of the Planar Traveler */
if (GetResRef(oRing) == GetResRef(oItem)) {
SetLocalInt(oRing, "Charges_", 10);
SetLocalInt(oRing, "Charges_100", 10);
for (i = 1; i <= 4; i++) {
for (j = 1; j <= 9; j++)
SetLocalInt(oRing, "Charges_" + IntToString((100 * i) + 10 + j), 10);
}
}
DestroyObject(oItem);
oItem = oRing;
nCharges = 0;
} else {
if (nBaseType == BASE_ITEM_MAGICWAND && sRes == "wandoftime" && GetLocalInt(oItem, "Version") < 3 && nCharges <= 5) {
if ((nCharges = nCharges * 5) > 50)
nCharges = 50;
}
AssignCommand(GetModule(), DelayCommand(0.0, DestroyOriginalItem(oItem)));
SetPlotFlag(oItem, FALSE);
SetLocalInt(oItem, "REPLACED", 1);
DestroyObject(oItem);
if (GetStringLeft(sRes, 1) == "#") {
GiveGoldToCreature(oTarget, StringToInt(GetSubString(sRes, 1, 10)));
sRes = "DESTROY";
oItem = OBJECT_INVALID;
} else
oItem = CreateItemOnObject(sRes, oTarget, 1);
}
if (GetIsObjectValid(oItem)) {
WriteTimestampedLogEntry(sLog + GetName(oItem) + " (" + sRes + ") [v" +
IntToString(GetLocalInt(oItem, "Version")) + "] : REPLACED" +
(GetItemPossessor(oItem) != oTarget ? " AND DROPPED" : ""));
if (nCharges > 0 && GetItemCharges(oItem) > 0 && !GetLocalInt(oItem, "NoRecharge"))
SetItemCharges(oItem, nCharges);
if (sUniqueID != "")
SetLocalString(oItem, "UNIQUE_ID", sUniqueID);
SetIdentified(oItem, TRUE);
} else if (sRes == "DESTROY")
WriteTimestampedLogEntry(sLog + sRes + " : DESTROYED");
else
WriteTimestampedLogEntry(sLog + sRes + " : FAILED");
if (sRes != "DESTROY" && sRes != "drowdust") {
FloatingTextStringOnCreature("Your " + sName + " has been replaced with a new version.", oTarget, FALSE);
if (GetIsObjectValid(oItem) && GetItemPossessor(oItem) != oTarget)
FloatingTextStringOnCreature(COLOR_RED + "Your new " + sName +
" is on the ground. Please pick it up.</c>", oTarget, FALSE);
}
}
string GetItemUpdate (object oItem) {
if (!GetIsObjectValid(oItem))
return "";
int nVersion = GetLocalInt(oItem, "Version");
int nBaseType = GetBaseItemType(oItem);
string sRes = GetStringLowerCase(GetResRef(oItem));
string sTag = GetStringLowerCase(GetTag(oItem));
DeleteLocalInt(oItem, "ZEP_CR_TEMPITEM");
/* destroy already-replaced items */
if (GetLocalInt(oItem, "REPLACED"))
return "DESTROY";
/* destroy old pet givers */
if (GetStringLeft(sRes, 10) == "custompet0")
return "DESTROY";
/* destroy guild points on relog */
if (sRes == "newguildpoint" && GetTag(GetArea(GetItemPossessor(oItem))) == "DocksofAscension")
return "DESTROY";
/* integrate and destroy guild tokens */
if (GetStringLeft(sTag, 5) == "guild" && GetStringRight(sTag, 5) == "token") {
int nGuild;
string sGuild = GetSubString(sTag, 5, 1);
object oPC = GetItemPossessor(oItem);
if (sGuild == "g")
nGuild = GetLocalInt(oItem, "Guild");
else
nGuild = StringToInt(sGuild);
if (nGuild == GUILD_ETERNAL_ORDER_MERGED_WITH_REDS)
nGuild = GUILD_ETERNAL_REDS;
SetLocalInt(oPC, "Guild", nGuild);
SetPersistentInt(oPC, "Guild", nGuild);
return "DESTROY";
}
/* replace old ammo containers */
if (GetStringLeft(sRes, 3) == "uaq" || GetStringLeft(sRes, 13) == "quiverofendle") {
if (sTag != "ac_rng_uacont")
return sRes;
}
/* replace +6 AC mystic weapons with new versions */
if (GetItemIsMeleeWeapon(oItem) &&
GetStringLeft(sRes, 9) == "scorching" &&
GetItemACValue(oItem) > 0) {
return sRes;
}
/* replace old CEP tridents */
if (nBaseType == 300)
return sRes;
/* replace buggy CEP appearances on armor */
if (nBaseType == BASE_ITEM_ARMOR &&
GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, ITEM_APPR_ARMOR_MODEL_TORSO) == 175) {
SetLocalInt(oItem, "NoCopyCrafting", 1);
return sRes;
}
/* replace old PC Scry tools */
if (sTag == "pclist" && !GetLocalInt(oItem, "New"))
return sRes;
/* set FKY_CHAT_INSTANT on PC Scry, Command Targeter, and DM Voice Thrower */
if (!GetLocalInt(oItem, "FKY_CHAT_INSTANT") &&
(sRes == "pclist" ||
sRes == "autocaster" ||
sRes == "fky_chat_target" ||
sRes == "fky_chat_ventril")) {
if (sRes == "autocaster") {
IPRemoveAllItemProperties(oItem, DURATION_TYPE_PERMANENT);
/* add 'Talk To' and 'Unique Power Self Only' in that order */
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyCastSpell(536, 13), oItem);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyCastSpell(335, 13), oItem);
SetLocalString(oItem, "FKY_CHAT_INSTANT_SCRIPT", "ev_autocaster");
}
SetLocalInt(oItem, "FKY_CHAT_INSTANT", 1);
}
/* set Artifact local on artifacts that don't have it */
if (sTag == "ssith5sstadisben" ||
sTag == "rtyglegendaryhor" ||
sTag == "theeyeofvecna") {
SetLocalInt(oItem, "Artifact", 1);
}
/* return old honed weapons to normal */
if (sTag == "assasswpncrit")
return sRes;
/* integrate the old Greater Dragon Breath with RDDs */
if (sTag == "rddbreath") {
object oRDD = GetItemPossessor(oItem);
int nRDDLevel = GetLocalInt(oItem, "RDD_Level");
SetLocalInt(oRDD, "RDDLevel", nRDDLevel);
SetPersistentInt(oRDD, "RDDLevel", nRDDLevel);
if (GetPersistentInt(oRDD, "RDDLevel") == nRDDLevel)
return "DESTROY";
}
/* ensure all unlimited heal packs require the Beaker */
if (sRes == "unlimitedhealpac")
SetLocalString(oItem, "UnlimitedSourceTag", "bountifulbeaker");
object oMod = GetModule();
/* replace items that swap to new resrefs */
string sNew = HashSetGetLocalString(oMod, "UpdateItemRes", sRes);
if (sNew != "")
return sNew;
/* replace items with new versions */
int nVer = HashSetGetLocalInt(oMod, "UpdateItemVer", sRes);
if (nVer > GetLocalInt(oItem, "Version"))
return sRes;
if (HashSetGetLocalInt(oMod, "UpdateItemSingleton", sRes) && !GetLocalInt(oItem, "Singleton"))
return sRes;
if (HashSetGetLocalInt(oMod, "UpdateItemUndroppable", sRes) && GetItemCursedFlag(oItem)) {
itemproperty ip;
for (ip = GetFirstItemProperty(oItem);
GetIsItemPropertyValid(ip);
ip = GetNextItemProperty(oItem)) {
if (GetItemPropertyType(ip) == ITEM_PROPERTY_INVIS_ADDITIONAL &&
GetItemPropertyCostTableValue(ip) == IP_CONST_ADDITIONAL_UNDROPPABLE)
break;
}
if (!GetIsItemPropertyValid(ip)) {
ip = ItemPropertyInvisAdditional(IP_CONST_ADDITIONAL_UNDROPPABLE);
AddItemProperty(DURATION_TYPE_PERMANENT, ip, oItem);
}
}
/* fix broken random weapons with monster damage */
if (GetStringLeft(sRes, 6) == "randwp" && GetItemHasItemProperty(oItem, ITEM_PROPERTY_MONSTER_DAMAGE))
return sRes;
/* update charges on the Ring of the Planar Traveler */
if (sTag == "multi_signet") {
string sServer = GetLocalString(oMod, "ServerNumber");
if (sServer != "")
SetItemCharges(oItem, 1 + (GetLocalInt(oItem, "Charges_" + sServer) * 2));
}
if (sTag == "hellskull" && !GetItemHasItemProperty(oItem, ITEM_PROPERTY_CAST_SPELL)) {
itemproperty ip = ItemPropertyCastSpell(IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY,
IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE);
AddItemProperty(DURATION_TYPE_PERMANENT, ip, oItem);
}
if (GetLocalString(oItem, "ForgeModifications") != "") {
SetLocalInt(oItem, "Modified", 1);
DeleteLocalString(oItem, "ForgeModifications");
}
int nModified = GetLocalInt(oItem, "Modified");
if (nModified & 2) {
if (nBaseType == BASE_ITEM_ARMOR && !(nModified & 65536))
return sRes;
/* fix full Silence immunity on randomized items */
if (FindSubString(GetLocalString(oItem, "Modifications"), " 2,217,56,0,0,255,0") >= 0) {
WriteTimestampedLogEntry("UPDATEITEMS : " + GetName(GetItemPossessor(oItem)) + " : " + GetName(oItem) + " : fixing full Silence immunity");
string sMods = GetLocalString(oItem, "Modifications");
sMods = ReplaceString(sMods, " 2,217,56,0,0,255,0", " 2,53,0,33,150,255,0", TRUE);
SetLocalString(oItem, "Modifications", sMods);
itemproperty ip;
for (ip = GetFirstItemProperty(oItem); GetIsItemPropertyValid(ip); ip = GetNextItemProperty(oItem)) {
if (GetItemPropertyType(ip) == 217 && GetItemPropertySubType(ip) == 56)
RemoveItemProperty(oItem, ip);
}
ip = ItemPropertySpellImmunitySpecific(150);
AddItemProperty(DURATION_TYPE_PERMANENT, ip, oItem);
}
}
return "";
}
void TagDupes (object oPC, string sUniqueID, int nDupes) {
int i;
object oItem;
for (i = 0; i < NUM_INVENTORY_SLOTS; i++) {
oItem = GetItemInSlot(i, oPC);
if (GetIsObjectValid(oItem) && GetLocalString(oItem, "UNIQUE_ID") == sUniqueID) {
DupeAlert(oPC, oItem);
if (--nDupes < 1)
return;
}
}
oItem = GetFirstItemInInventory(oPC);
while (GetIsObjectValid(oItem)) {
if (GetLocalString(oItem, "UNIQUE_ID") == sUniqueID) {
DupeAlert(oPC, oItem);
if (--nDupes < 1)
return;
}
oItem = GetNextItemInInventory(oPC);
}
}
void main () {
int i, nDupes, nArtifacts = 0, nCount = 0;
int bDay = GetIsDay();
string sRes, sUniqueID;
object oItem, oMod = GetModule(), oArea = GetArea(OBJECT_SELF);
if (!GetIsObjectValid(OBJECT_SELF) || GetIsDM(OBJECT_SELF))
return;
if (!GetIsObjectValid(oArea) || GetTag(oArea) == "voyage") {
DelayCommand(5.0, main());
return;
}
HashSetDestroy(oMod, "DupeID");
HashSetCreate(oMod, "DupeID");
for (i = 0; i < NUM_INVENTORY_SLOTS; i++) {
oItem = GetItemInSlot(i, OBJECT_SELF);
if (GetIsObjectValid(oItem)) {
if (bDay && GetStringLeft(GetTag(oItem), 4) == "asdf")
sRes = "drowdust";
else
sRes = GetItemUpdate(oItem);
if (sRes != "") {
ReplaceItem(OBJECT_SELF, oItem, sRes);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 2.0);
DelayCommand(1.0, main());
return;
}
if ((sUniqueID = GetLocalString(oItem, "UNIQUE_ID")) != "")
HashSetSetLocalInt(oMod, "DupeID", sUniqueID,
HashSetGetLocalInt(oMod, "DupeID", sUniqueID) + 1);
if (GetLocalInt(oItem, "Artifact"))
nArtifacts++;
}
}
oItem = GetFirstItemInInventory(OBJECT_SELF);
while (GetIsObjectValid(oItem)) {
if (!GetItemCursedFlag(oItem) || GetItemIsStackable(oItem))
nCount++;
sRes = GetItemUpdate(oItem);
if (sRes != "") {
ReplaceItem(OBJECT_SELF, oItem, sRes);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 2.0);
DelayCommand(1.0, main());
return;
}
if ((sUniqueID = GetLocalString(oItem, "UNIQUE_ID")) != "")
HashSetSetLocalInt(oMod, "DupeID", sUniqueID,
HashSetGetLocalInt(oMod, "DupeID", sUniqueID) + 1);
if (GetLocalInt(oItem, "Artifact"))
nArtifacts += GetItemStackSize(oItem);
oItem = GetNextItemInInventory(OBJECT_SELF);
}
string sKey = HashSetGetFirstKey(oMod, "DupeID");
while (sKey != "") {
if ((nDupes = HashSetGetLocalInt(oMod, "DupeID", sKey)) > 1)
DelayCommand(0.1, TagDupes(OBJECT_SELF, sKey, nDupes - 1));
sKey = HashSetGetNextKey(oMod, "DupeID");
}
HashSetDestroy(oMod, "DupeID");
if (nArtifacts > 1) {
DelayCommand(0.0, ArtifactExplode(OBJECT_SELF));
return;
}
if (GetTag(oArea) == "DocksofAscension" || GetTag(oArea) == "TownofAscension") {
if (nCount > 150 && !VerifyAdminKey(OBJECT_SELF)) {
location lBurdened = GetLocation(GetWaypointByTag("burdened"));
DelayCommand(3.0, ForceJump(OBJECT_SELF, lBurdened));
return;
}
}
}
[\\code]
Funky
Modifié par FunkySwerve, 16 juin 2011 - 07:12 .