private static void RegisterDMEvents() { NWNXEvents.SubscribeEvent(NWNXEventType.DMAppearBefore, "dm_appear"); NWNXEvents.SubscribeEvent(NWNXEventType.DMChangeDifficultyBefore, "dm_change_diff"); NWNXEvents.SubscribeEvent(NWNXEventType.DMDisableTrapBefore, "dm_disab_trap"); NWNXEvents.SubscribeEvent(NWNXEventType.DMDisappearBefore, "dm_disappear"); NWNXEvents.SubscribeEvent(NWNXEventType.DMForceRestBefore, "dm_force_rest"); NWNXEvents.SubscribeEvent(NWNXEventType.DMGetVariableBefore, "dm_get_var"); NWNXEvents.SubscribeEvent(NWNXEventType.DMGiveGoldBefore, "dm_give_gold"); NWNXEvents.SubscribeEvent(NWNXEventType.DMGiveItemAfter, "dm_give_item"); NWNXEvents.SubscribeEvent(NWNXEventType.DMGiveLevelBefore, "dm_give_level"); NWNXEvents.SubscribeEvent(NWNXEventType.DMGiveXPBefore, "dm_give_xp"); NWNXEvents.SubscribeEvent(NWNXEventType.DMHealBefore, "dm_heal"); NWNXEvents.SubscribeEvent(NWNXEventType.DMJumpBefore, "dm_jump"); NWNXEvents.SubscribeEvent(NWNXEventType.DMJumpAllPlayersToPointBefore, "dm_jump_all"); NWNXEvents.SubscribeEvent(NWNXEventType.DMJumpTargetToPointBefore, "dm_jump_target"); NWNXEvents.SubscribeEvent(NWNXEventType.DMKillBefore, "dm_kill"); NWNXEvents.SubscribeEvent(NWNXEventType.DMLimboBefore, "dm_limbo"); NWNXEvents.SubscribeEvent(NWNXEventType.DMPossessBefore, "dm_possess"); NWNXEvents.SubscribeEvent(NWNXEventType.DMSetDateBefore, "dm_set_date"); NWNXEvents.SubscribeEvent(NWNXEventType.DMSetStatBefore, "dm_set_stat"); NWNXEvents.SubscribeEvent(NWNXEventType.DMSetTimeBefore, "dm_set_time"); NWNXEvents.SubscribeEvent(NWNXEventType.DMSetVariableBefore, "dm_set_var"); NWNXEvents.SubscribeEvent(NWNXEventType.DMSpawnObjectAfter, "dm_spawn"); NWNXEvents.SubscribeEvent(NWNXEventType.DMTakeItemBefore, "dm_take_item"); NWNXEvents.SubscribeEvent(NWNXEventType.DMToggleImmortalBefore, "dm_togg_immo"); NWNXEvents.SubscribeEvent(NWNXEventType.DMToggleInvulnerabilityBefore, "dm_togg_invuln"); NWNXEvents.SubscribeEvent(NWNXEventType.DMToggleAIBefore, "dm_toggle_ai"); NWNXEvents.SubscribeEvent(NWNXEventType.DMToggleLockBefore, "dm_toggle_lock"); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var difficulty = NWNXEvents.OnDMChangeDifficulty_GetDifficultySetting(); WriteLog(dm, "Change Difficulty", "New Setting: " + difficulty); }
private static void OnModuleUseFeat() { NWPlayer pc = _.OBJECT_SELF; int featID = Convert.ToInt32(NWNXEvents.GetEventData("FEAT_ID")); if (featID != (int)Feat.ChatCommandTargeter) { return; } var target = _.StringToObject(NWNXEvents.GetEventData("TARGET_OBJECT_ID")); var targetPositionX = (float)Convert.ToDouble(NWNXEvents.GetEventData("TARGET_POSITION_X")); var targetPositionY = (float)Convert.ToDouble(NWNXEvents.GetEventData("TARGET_POSITION_Y")); var targetPositionZ = (float)Convert.ToDouble(NWNXEvents.GetEventData("TARGET_POSITION_Z")); var targetPosition = Vector3(targetPositionX, targetPositionY, targetPositionZ); var targetArea = _.StringToObject(NWNXEvents.GetEventData("AREA_OBJECT_ID")); var targetLocation = Location(targetArea, targetPosition, 0.0f); string command = pc.GetLocalString("CHAT_COMMAND"); string args = pc.GetLocalString("CHAT_COMMAND_ARGS"); if (string.IsNullOrWhiteSpace(command)) { pc.SendMessage("Please enter a chat command and then use this feat. Type /help to learn more about the available chat commands."); return; } IChatCommand chatCommand = GetChatCommandHandler(command); ProcessChatCommand(chatCommand, pc, target, targetLocation, args); pc.DeleteLocalString("CHAT_COMMAND"); pc.DeleteLocalString("CHAT_COMMAND_ARGS"); }
private static void OnModuleUseFeat() { NWPlayer pc = Object.OBJECT_SELF; int featID = NWNXEvents.OnFeatUsed_GetFeatID(); if (featID != (int)CustomFeatType.RenameCraftedItem) { return; } pc.ClearAllActions(); bool isSetting = pc.GetLocalInt("CRAFT_RENAMING_ITEM") == TRUE; NWItem renameItem = NWNXEvents.OnFeatUsed_GetTarget().Object; if (isSetting) { pc.SendMessage("You are no longer naming an item."); pc.DeleteLocalInt("CRAFT_RENAMING_ITEM"); pc.DeleteLocalObject("CRAFT_RENAMING_ITEM_OBJECT"); return; } string crafterPlayerID = renameItem.GetLocalString("CRAFTER_PLAYER_ID"); if (string.IsNullOrWhiteSpace(crafterPlayerID) || new Guid(crafterPlayerID) != pc.GlobalID) { pc.SendMessage("You may only rename items which you have personally crafted."); return; } pc.SetLocalInt("CRAFT_RENAMING_ITEM", TRUE); pc.SetLocalObject("CRAFT_RENAMING_ITEM_OBJECT", renameItem); pc.SendMessage("Please enter in a name for this item. Length should be between 3 and 64 characters. Use this feat again to cancel this procedure."); }
private static void OnModuleUseFeat() { NWPlayer pc = Object.OBJECT_SELF; int featID = NWNXEvents.OnFeatUsed_GetFeatID(); if (featID != (int)CustomFeatType.ChatCommandTargeter) { return; } var target = NWNXEvents.OnFeatUsed_GetTarget(); var targetLocation = NWNXEvents.OnFeatUsed_GetTargetLocation(); string command = pc.GetLocalString("CHAT_COMMAND"); string args = pc.GetLocalString("CHAT_COMMAND_ARGS"); if (string.IsNullOrWhiteSpace(command)) { pc.SendMessage("Please enter a chat command and then use this feat. Type /help to learn more about the available chat commands."); return; } IChatCommand chatCommand = GetChatCommandHandler(command); ProcessChatCommand(chatCommand, pc, target, targetLocation, args); pc.DeleteLocalString("CHAT_COMMAND"); pc.DeleteLocalString("CHAT_COMMAND_ARGS"); }
private static void OnModuleUseFeat() { NWPlayer pc = _.OBJECT_SELF; int featID = Convert.ToInt32(NWNXEvents.GetEventData("FEAT_ID")); if (featID != (int)Feat.RenameCraftedItem) { return; } pc.ClearAllActions(); bool isSetting = GetLocalBool(pc, "CRAFT_RENAMING_ITEM") == true; NWItem renameItem = NWNXObject.StringToObject(NWNXEvents.GetEventData("TARGET_OBJECT_ID")); if (isSetting) { pc.SendMessage("You are no longer naming an item."); pc.DeleteLocalInt("CRAFT_RENAMING_ITEM"); pc.DeleteLocalObject("CRAFT_RENAMING_ITEM_OBJECT"); return; } string crafterPlayerID = renameItem.GetLocalString("CRAFTER_PLAYER_ID"); if (string.IsNullOrWhiteSpace(crafterPlayerID) || new Guid(crafterPlayerID) != pc.GlobalID) { pc.SendMessage("You may only rename items which you have personally crafted."); return; } SetLocalBool(pc, "CRAFT_RENAMING_ITEM", true); pc.SetLocalObject("CRAFT_RENAMING_ITEM_OBJECT", renameItem); pc.SendMessage("Please enter in a name for this item. Length should be between 3 and 64 characters. Use this feat again to cancel this procedure."); }
public static void Main() { var player = NWNXEvents.OnInventoryAddItem_GetPlayer(); var playerID = GetGlobalID(player); var key = BuildKey(playerID); AddItem(key); }
// ReSharper disable once UnusedMember.Local public static void Main() { var obj = NWNXEvents.OnDMSpawnObject_GetObject(); MessageHub.Instance.Publish(new ObjectCreated(obj)); Script.RunScriptEvents(_.GetModule(), DMScriptPrefix.OnSpawnObject); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var target = NWNXEvents.OnDMPossess_GetTarget(); var targetName = GetName(target); WriteLog(dm, "Toggle Lock", $"Target: {targetName}"); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var trap = NWNXEvents.OnDMDisableTrap_GetTrap(); var trapName = GetName(trap); WriteLog(dm, "Disable Trap", trapName); }
/// <summary> /// Registers all of the NWNX event scripts. /// </summary> private static void RegisterNWNXEvents() { NWNXEvents.SubscribeEvent(NWNXEventType.StartCombatRoundBefore, "mod_on_attack"); NWNXEvents.SubscribeEvent(NWNXEventType.ExamineObjectBefore, "mod_on_examine"); NWNXEvents.SubscribeEvent(NWNXEventType.UseFeatBefore, "mod_on_usefeat"); NWNXEvents.SubscribeEvent(NWNXEventType.UseItemBefore, "mod_on_useitem"); NWNXEvents.SubscribeEvent(NWNXEventType.ItemEquipBefore, "mod_nwnx_equip"); NWNXEvents.SubscribeEvent(NWNXEventType.ItemUnequipBefore, "mod_nwnx_unequip"); NWNXChat.RegisterChatScript("mod_on_nwnxchat"); }
/// <summary> /// Processes all feats which are linked to perks. /// </summary> private static void OnModuleUseFeat() { // Activator is the creature who used the feat. // Target is who the activator selected to use this feat on. NWCreature activator = _.OBJECT_SELF; NWCreature target = NWNXObject.StringToObject(NWNXEvents.GetEventData("TARGET_OBJECT_ID")); var featID = (Feat)Convert.ToInt32(NWNXEvents.GetEventData("FEAT_ID")); // Ensure this perk feat can be activated. if (!CanUsePerkFeat(activator, target, featID)) { return; } // Retrieve information necessary for activation of perk feat. var perkFeat = DataService.PerkFeat.GetByFeatID((int)featID); Data.Entity.Perk perk = DataService.Perk.GetByID(perkFeat.PerkID); int creaturePerkLevel = PerkService.GetCreaturePerkLevel(activator, perk.ID); var handler = PerkService.GetPerkHandler(perkFeat.PerkID); SendAOEMessage(activator, activator.Name + " readies " + perk.Name + "."); // Force Abilities (aka Spells) if (perk.ExecutionTypeID == PerkExecutionType.ForceAbility) { target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_FORCE); ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.ForceAbility, perkFeat.PerkLevelUnlocked); } // Combat Abilities else if (perk.ExecutionTypeID == PerkExecutionType.CombatAbility) { target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_PHYSICAL); ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.CombatAbility, perkFeat.PerkLevelUnlocked); } // Queued Weapon Skills else if (perk.ExecutionTypeID == PerkExecutionType.QueuedWeaponSkill) { target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_PHYSICAL); HandleQueueWeaponSkill(activator, perk, handler, featID); } // Stances else if (perk.ExecutionTypeID == PerkExecutionType.Stance) { target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_COMBATABILITY); ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.Stance, perkFeat.PerkLevelUnlocked); } // Concentration Abilities else if (perk.ExecutionTypeID == PerkExecutionType.ConcentrationAbility) { target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_FORCE); ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.ConcentrationAbility, perkFeat.PerkLevelUnlocked); } }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var amount = NWNXEvents.OnDMGiveLevels_GetAmount(); var target = NWNXEvents.OnDMGiveLevels_GetTarget(); var targetName = _.GetName(target); string log = $"Amount = {amount}, target = {targetName}"; WriteLog(dm, "Give Level", log); }
private static void OnModuleUseFeat() { NWPlayer pc = (OBJECT_SELF); int featID = Convert.ToInt32(NWNXEvents.GetEventData("FEAT_ID")); if (featID != (int)Feat.OpenRestMenu) { return; } pc.ClearAllActions(); DialogService.StartConversation(pc, pc, "RestMenu"); }
private static void OnModuleUseFeat() { NWPlayer pc = (Object.OBJECT_SELF); int featID = NWNXEvents.OnFeatUsed_GetFeatID(); if (featID != (int)CustomFeatType.OpenRestMenu) { return; } pc.ClearAllActions(); DialogService.StartConversation(pc, pc, "RestMenu"); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var item = NWNXEvents.OnDMGiveItem_GetItem(); var itemName = GetName(item); var target = NWNXEvents.OnDMGiveItem_GetTarget(); var targetName = GetName(target); string log = $"Item = {itemName}, target = {targetName}"; WriteLog(dm, "Give Item", log); }
// ReSharper disable once UnusedMember.Local public static void Main() { // Breaking the rules for the examine event because the result of the services is used in the following // service call. We still signal an event for this, but in general all of the logic should go into this method. using (new Profiler(nameof(mod_on_examine))) { NWPlayer examiner = (_.OBJECT_SELF); NWObject examinedObject = NWNXObject.StringToObject(NWNXEvents.GetEventData("EXAMINEE_OBJECT_ID")); if (ExaminationService.OnModuleExamine(examiner, examinedObject)) { MessageHub.Instance.Publish(new OnModuleExamine()); return; } string description; if (_.GetIsPC(examinedObject.Object) == true) { // https://github.com/zunath/SWLOR_NWN/issues/853 // safest probably to get the modified (non-original) description only for players // may want to always get the modified description for later flexibility? description = _.GetDescription(examinedObject.Object, false) + "\n\n"; } else { description = _.GetDescription(examinedObject.Object, true) + "\n\n"; } if (examinedObject.IsCreature) { var racialID = Convert.ToInt32(_.Get2DAString("racialtypes", "Name", (int)_.GetRacialType(examinedObject))); string racialtype = _.GetStringByStrRef(racialID); if (!description.Contains(ColorTokenService.Green("Racial Type: ") + racialtype)) { description += ColorTokenService.Green("Racial Type: ") + racialtype; } } description = ModService.OnModuleExamine(description, examiner, examinedObject); description = ItemService.OnModuleExamine(description, examinedObject); description = DurabilityService.OnModuleExamine(description, examinedObject); if (!string.IsNullOrWhiteSpace(description)) { _.SetDescription(examinedObject.Object, description, false); _.SetDescription(examinedObject.Object, description); } } MessageHub.Instance.Publish(new OnModuleExamine()); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var area = NWNXEvents.OnDMSpawnObject_GetArea(); var areaName = GetName(area); var obj = NWNXEvents.OnDMSpawnObject_GetObject(); var objName = GetName(obj); var type = NWNXEvents.OnDMSpawnObject_GetObjectType(); var x = NWNXEvents.OnDMSpawnObject_GetPositionX(); var y = NWNXEvents.OnDMSpawnObject_GetPositionY(); var z = NWNXEvents.OnDMSpawnObject_GetPositionZ(); WriteLog(dm, "Spawn Object", $"{areaName} - {objName} - {type} - ({x}, {y}, {z})"); }
public static void Main() { var player = NWGameObject.OBJECT_SELF; if (!GetIsPlayer(player)) { return; } var item = NWNXEvents.OnEquipItem_GetItem(); // Didn't find the item property. Add it now. SafeAddItemProperty(item, ItemPropertyOnHitCastSpell(IPConst.Onhit_CastSpell_FFOSystem, 40), 0.0f, AddItemPropertyPolicy.ReplaceExisting, true, true); }
protected static void RunAudit(string @event) { var dm = NWGameObject.OBJECT_SELF; var targets = NWNXEvents.DMEvents_GetTargetList(); var details = "Target List: "; foreach (var target in targets) { var name = GetName(target); details += "(" + name + ") "; } WriteLog(dm, @event, details); }
// ReSharper disable once UnusedMember.Local private static void Main() { NWItem item = NWGameObject.OBJECT_SELF; // We ignore any decrements to shurikens, darts, and throwing axes. if (item.BaseItemType == _.BASE_ITEM_SHURIKEN || item.BaseItemType == _.BASE_ITEM_DART || item.BaseItemType == _.BASE_ITEM_THROWINGAXE) { NWNXEvents.SkipEvent(); } MessageHub.Instance.Publish(new OnItemDecrementStack()); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var position = Vector( NWNXEvents.OnDMJumpToPoint_GetX(), NWNXEvents.OnDMJumpToPoint_GetY(), NWNXEvents.OnDMJumpToPoint_GetZ()); var area = NWNXEvents.OnDMJumpToPoint_GetArea(); var areaName = GetName(area); var log = $"{areaName} - {position.X}, {position.Y}, {position.Z}"; WriteLog(dm, "Jump All Players to Point", log); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var target = NWNXEvents.OnDMPossess_GetTarget(); var targetName = GetName(target); if (GetIsObjectValid(target)) { WriteLog(dm, "Possess", $"Target: {targetName}"); } else { WriteLog(dm, "Unpossess"); } }
// ReSharper disable once UnusedMember.Local public static void Main() { NWItem item = _.OBJECT_SELF; if (!item.IsValid) return; // We ignore any decrements to shurikens, darts, and throwing axes. if(item.BaseItemType == BaseItem.Shuriken || item.BaseItemType == BaseItem.Dart || item.BaseItemType == BaseItem.ThrowingAxe) { NWNXEvents.SkipEvent(); } MessageHub.Instance.Publish(new OnItemDecrementStack(), false); }
/// <summary> /// Retrieves feat user stats. Data is retrieved differently based on whether user is a player or NPC. /// </summary> /// <returns>The stats of the user</returns> private static UserStats GetUserStats(NWGameObject user, NWGameObject target, Feat feat) { var ability = AbilityRegistry.Get(feat); var targetLocation = GetIsObjectValid(target) ? GetLocation(target) : NWNXEvents.OnFeatUsed_GetTargetLocation(); var stats = new UserStats { User = user, AbilityDefinition = ability, Target = target, TargetLocation = targetLocation, CastingPosition = GetPosition(user), MPCost = ability.MP(user), Feat = feat }; // Players - retrieve from DB if (GetIsPlayer(user)) { var playerID = GetGlobalID(user); var player = PlayerRepo.Get(playerID); var cooldown = CooldownRepo.Get(playerID, feat); stats.MP = player.MP; stats.CooldownUnlock = cooldown.DateUnlocked; } // NPCs - retrieve from local variables else if (GetIsNPC(user)) { stats.MP = GetLocalInt(user, "MP_CURRENT"); var cooldown = GetLocalString(user, $"ABILITY_COOLDOWN_{feat}"); if (string.IsNullOrWhiteSpace(cooldown)) { stats.CooldownUnlock = DateTime.UtcNow; } else { stats.CooldownUnlock = DateTime.ParseExact(cooldown, "yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture); } } stats.Now = DateTime.UtcNow; return(stats); }
private static string ProcessEventAndBuildDetails(int eventID) { string details = string.Empty; NWObject target; int amount; switch (eventID) { case 1: // Spawn Creature var area = _.StringToObject(NWNXEvents.GetEventData("AREA")); string areaName = GetName(area); NWCreature creature = _.StringToObject(NWNXEvents.GetEventData("OBJECT")); int objectTypeID = Convert.ToInt32(NWNXEvents.GetEventData("OBJECT_TYPE")); float x = (float)Convert.ToDouble(NWNXEvents.GetEventData("POS_X")); float y = (float)Convert.ToDouble(NWNXEvents.GetEventData("POS_Y")); float z = (float)Convert.ToDouble(NWNXEvents.GetEventData("POS_Z")); SetLocalBool(creature, "DM_SPAWNED", true); details = areaName + "," + creature.Name + "," + objectTypeID + "," + x + "," + y + "," + z; break; case 22: // Give XP amount = Convert.ToInt32(NWNXEvents.GetEventData("AMOUNT")); target = _.StringToObject(NWNXEvents.GetEventData("OBJECT")); details = amount + "," + target.Name; break; case 23: // Give Level amount = Convert.ToInt32(NWNXEvents.GetEventData("AMOUNT")); target = _.StringToObject(NWNXEvents.GetEventData("OBJECT")); details = amount + "," + target.Name; break; case 24: // Give Gold amount = Convert.ToInt32(NWNXEvents.GetEventData("AMOUNT")); target = _.StringToObject(NWNXEvents.GetEventData("OBJECT")); details = amount + "," + target.Name; break; } return(details); }
private static string ProcessEventAndBuildDetails(int eventID) { string details = string.Empty; NWObject target; int amount; switch (eventID) { case 1: // Spawn Creature string areaName = NWNXEvents.OnDMSpawnObject_GetArea().Name; NWCreature creature = NWNXEvents.OnDMSpawnObject_GetObject().Object; int objectTypeID = NWNXEvents.OnDMSpawnObject_GetObjectType(); float x = NWNXEvents.OnDMSpawnObject_GetPositionX(); float y = NWNXEvents.OnDMSpawnObject_GetPositionY(); float z = NWNXEvents.OnDMSpawnObject_GetPositionZ(); creature.SetLocalInt("DM_SPAWNED", _.TRUE); details = areaName + "," + creature.Name + "," + objectTypeID + "," + x + "," + y + "," + z; break; case 22: // Give XP amount = NWNXEvents.OnDMGiveXP_GetAmount(); target = NWNXEvents.OnDMGiveXP_GetTarget(); details = amount + "," + target.Name; break; case 23: // Give Level amount = NWNXEvents.OnDMGiveLevels_GetAmount(); target = NWNXEvents.OnDMGiveLevels_GetTarget(); details = amount + "," + target.Name; break; case 24: // Give Gold amount = NWNXEvents.OnDMGiveGold_GetAmount(); target = NWNXEvents.OnDMGiveGold_GetTarget(); details = amount + "," + target.Name; break; } return(details); }
public static void Main() { // Ignore any unregistered feats. var feat = NWNXEvents.OnFeatUsed_GetFeat(); if (!AbilityRegistry.IsRegistered(feat)) { return; } var target = NWNXEvents.OnFeatUsed_GetTarget(); // Retrieve stats and validate the use of this ability. var stats = GetUserStats(NWGameObject.OBJECT_SELF, target, feat); if (!ValidateFeatUse(stats)) { return; } // Begin the casting process StartCasting(stats); }
public static void Main() { var dm = NWGameObject.OBJECT_SELF; var position = Vector( NWNXEvents.OnDMJumpToPoint_GetX(), NWNXEvents.OnDMJumpToPoint_GetY(), NWNXEvents.OnDMJumpToPoint_GetZ()); var area = NWNXEvents.OnDMJumpToPoint_GetArea(); var targets = NWNXEvents.DMEvents_GetTargetList(); var areaName = GetName(area); var targetNames = string.Empty; foreach (var target in targets) { var targetName = GetName(target); targetNames += "(" + targetName + ") "; } var log = $"{areaName} - {position.X}, {position.Y}, {position.Z} - [{targetNames}]"; WriteLog(dm, "Jump Target to Point", log); }
// ReSharper disable once UnusedMember.Local private static void Main() { // Breaking the rules for the examine event because the result of the services is used in the following // service call. We still signal an event for this, but in general all of the logic should go into this method. using (new Profiler(nameof(mod_on_examine))) { NWPlayer examiner = (Object.OBJECT_SELF); NWObject examinedObject = NWNXEvents.OnExamineObject_GetTarget(); if (ExaminationService.OnModuleExamine(examiner, examinedObject)) { MessageHub.Instance.Publish(new OnModuleExamine()); return; } string description = _.GetDescription(examinedObject.Object, _.TRUE) + "\n\n"; if (examinedObject.IsCreature) { int racialID = Convert.ToInt32(_.Get2DAString("racialtypes", "Name", _.GetRacialType(examinedObject))); string racialtype = _.GetStringByStrRef(racialID); description += ColorTokenService.Green("Racial Type: ") + racialtype; } description = ModService.OnModuleExamine(description, examiner, examinedObject); description = ItemService.OnModuleExamine(description, examiner, examinedObject); description = DurabilityService.OnModuleExamine(description, examinedObject); description = FarmingService.OnModuleExamine(description, examinedObject); if (!string.IsNullOrWhiteSpace(description)) { _.SetDescription(examinedObject.Object, description, _.FALSE); _.SetDescription(examinedObject.Object, description); } } MessageHub.Instance.Publish(new OnModuleExamine()); }