Skip to content

Commit

Permalink
More granularity with regards to notification options, including coll…
Browse files Browse the repository at this point in the history
…ected/uncollected lore and waypoints.
  • Loading branch information
Earthfiredrake committed Jun 27, 2017
1 parent 3d38f88 commit 4502e7c
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 79 deletions.
Binary file modified LoreHound.fla
Binary file not shown.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# TSW-LoreHound
Notifications for lore drops in The Secret World, even if they're not visible.
Mostly compatible with SWL, with limitations on GUI customization.

## Overview
Will detect and attempt to identify lore pickups when they enter or spawn within a 20m radius around the player. Lore pickups have been roughly categorized into four groups.
Expand All @@ -15,7 +16,7 @@ Will detect and attempt to identify lore pickups when they enter or spawn within
+ Uncategorized: Something that I haven't run across yet, so haven't been able to place in a group.
+ Opting into the automated report option permits the collection of required information to be mailed to me when you open the bank, saving you the trouble.

Each category can independently have notifications output to either chat (System channel) or as FIFO alerts. By default, if it is able to precisely identify a lore that the character has not picked up, it will ignore it. When sending a notification through the chat, a set of additional details can be displayed. Those marked with a '*' will always be displayed with Uncategorized lore and are used to identify it in the index.
Each category can independently have notifications output to either chat (System channel), as FIFO alerts, or with ingame waypoints. By default, if it is able to precisely identify a lore that the character has not picked up, it will ignore it. When sending a notification through the chat, a set of additional details can be displayed. Those marked with a '*' will always be displayed with Uncategorized lore and are used to identify it in the index.
+ Timestamp: Puts a timestamp on detections, so you can know when the drop was without having to timestamp all of the System channel (revealing the mysteriously blank lines that it otherwise hides).
+ Location*: Map name and coordinate vector for the lore
+ The vector has been swizzled into [x,z,y] format, where y is the vertical coordinate
Expand All @@ -29,16 +30,20 @@ To improve efficiency and reduce false-positives, it only checks against the exi
All settings are saved account wide and will be shared across characters. If you'd rather have different settings for each character, renaming the file "LoginPrefs.xml" to "CharPrefs.xml" when installing/upgrading the mod should work without any problems. A clean install of the mod is recommended if doing this, as it will be unable to transfer existing settings anyway.

## Installation
Any packaged releases can be installed by copying the contents into [Game Directory]\Data\Gui\Customized\Flash and restarting the client.
The packaged release should be unzipped into the appropriate folder and the client restarted.
TSW: [TSW Directory]\Data\Gui\Customized\Flash.
SWL: [SWL Directory]\Data\Gui\Custom\Flash.

When upgrading, existing .bxml files in the LoreHound directory should be deleted to ensure changes in the .xml files are loaded (whichever is newer seems to take precedence).

The update system *should* carry forward settings from v0.4.0-beta onwards. However, v1.0.x will be the last release to support upgrades from the v0.x pre-release line. Starting with v1.1.0 directly upgrading from versions prior to v1.0.0 may result in settings being lost, reset, or potentially invalid.
An internal update system *should* carry forward settings from previous versions. To simplify the system, major versions will be used as thresholds, v1.0.x will upgrade from any v0.y, but later versions require a staged upgrade through v1.0. Starting with v1.1.0 directly upgrading from versions prior to v1.0.0 may result in settings being lost, reset, or potentially invalid.

If upgrading from v0.1.1-alpha, a clean reinstall is recommended. Remove the existing mod entirely and login to the game to clear any existing settings before installing a more recent version.

## Change Log
Version 1.1.2
Version 1.2.0
+ Expanded options for tracking known/unkown lore
+ Expanded options for waypoint notifications
+ Unifies lore tracking and waypoints, should no longer forget to provide despawn notifications

Version 1.1.0
Expand Down Expand Up @@ -110,21 +115,16 @@ The following issues are known to exist in the most recent release:
+ A brief lag may be observed after reloading the ui, where the full size icon is displayed rather than attached to the topbar
+ This is intentional and reduces the occurence of bugs related to other mods integrating with the topbar

This version of the mod has been lightly tested in SWL and found to work with the following known caveats:
+ It does not integrate with the default top-bar
SWL compatibility issues:
+ GUI editing is not currently working, so the icon cannot be moved or resized

## Testing and Further Developments
I'm relatively satisfied with the features that exist, and will continue providing basic support for bug fixes and updates to files if needed. However, due to the current situation, I am unlikely to get around to implementing the remaining features or attempting to port to SWL until more information is available:
+ More flexible alert settings, at the category level
+ Known|unknown filter
+ Waypoints by category
This continues to be something of a work in progress, though I'm mostly satisfied that it achives the objectives. I am considering:
+ Some form of whitelisting to further filter the accepted values:
+ The *easy* version would be one that simply works on loreIDs after initial filtering, as a global white list.
+ More complicated systems (intelligent per-category whitelists, random drops only, etc.) would require additional information to be saved about each lore entry.
+ Actual localization would be nice, but I'm not going to rely on Google and my limited knowledge of French to be at all accurate. Somebody else will have to provide me with translations, if there is sufficient interest.
+ My previously mentioned second project is currently on hold. While I still think it has value, I am not likely to develop it further until I have had a chance to look at SWL and decide which, if either, I will be playing.
+ As SWL is likely to have slightly different mod interface requirements, am considering changes to the framework design to make it easier to port|back-port my mods. Thinking of using dependency injection, instead of inheritance, of the framework.
+ Was considering a map replacement mod that would permit more extensive custom markings, and could tie in with LoreHound to populate the lore locations. This was placed on hiatus due to the SWL release, and is not yet in development.

A feature for helping with The Abandoned lore was found to be unworkable. Lore.IsLockedForChar either does not work as advertised, or requires GM permissions.

Expand Down
12 changes: 8 additions & 4 deletions config/Strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,18 @@
en="Dropped Lore" />
<String tag="SettingGroupUncategorized"
en="Uncategorized Lore" />
<String tag="LoreSettingWP"
en="Show Waypoints" />
<String tag="LoreSettingFifo"
en="FIFO Alerts" />
<String tag="LoreSettingChat"
en="System Chat Messages" />
<String tag="LoreStatesTitle"
en="Notify for:" />
<String tag="LoreSettingUncollected"
en="Uncollected Lore" />
<String tag="LoreSettingCollected"
en="Already Collected Lore" />
<String tag="SettingGroupDetails"
en="Extra Chat Details" />
<String tag="DetailSettingTimestamp"
Expand All @@ -71,12 +79,8 @@
en="Other Options" />
<String tag="OtherSettingEnable"
en="Enable Mod" />
<String tag="OtherSettingUnclaim"
en="Ignore Unclaimed Lore" /> <!-- Tag is not a typo, honest -->
<String tag="OtherSettingInactive"
en="Ignore Off Season Lore" />
<String tag="OtherSettingWaypoint"
en="Show Waypoints" />
<String tag="OtherSettingDespawn"
en="Track Despawns" />
<String tag="OtherSettingReporting"
Expand Down
96 changes: 63 additions & 33 deletions efd/LoreHound/LoreHound.as
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class efd.LoreHound.LoreHound extends Mod {
// Dev/debug settings at top so commenting out leaves no hanging ','
// Trace : true,
Name : "LoreHound",
Version : "1.1.2",
Version : "1.2.0",
Type : e_ModType_Reactive,
MinUpgradableVersion : "1.0.0",
IconData : { UpdateState : UpdateIcon,
Expand Down Expand Up @@ -89,10 +89,17 @@ class efd.LoreHound.LoreHound extends Mod {
Config.NewSetting("FifoLevel", ef_LoreType_None); // DEPRECATED(v1.2.0.alpha) : Renamed
Config.NewSetting("ChatLevel", ef_LoreType_Drop | ef_LoreType_Uncategorized); // DEPRECATED(v1.2.0.alpha) : Renamed

Config.NewSetting("IgnoreUnclaimedLore", true); // Ignore lore if the player hasn't picked it up already
// Renaming and expanding options for v1.2
Config.NewSetting("FifoAlerts", ef_LoreType_None); // FIFO onscreen alerts
Config.NewSetting("ChatAlerts", ef_LoreType_Drop | ef_LoreType_Uncategorized); // System chat alerts
Config.NewSetting("WaypointAlerts", ef_LoreType_Drop | ef_LoreType_Uncategorized); // Display onscreen waypoints for lore
Config.NewSetting("AlertForCollected", ef_LoreType_Drop | ef_LoreType_Uncategorized); // Alert the player for lore they already have
Config.NewSetting("AlertForUncollected", ef_LoreType_Uncategorized); // Alert the player for lore they haven't picked up yet

Config.NewSetting("IgnoreUnclaimedLore", true); // DEPRECATED(v1.2.0.alpha) : Renamed and expanded
Config.NewSetting("IgnoreOffSeasonLore", true); // Ignore event lore if the event isn't running (TODO: Test this when a game event is running)
Config.NewSetting("TrackDespawns", true); // Track lore drops for when they despawn
Config.NewSetting("ShowWaypoints", true); // Show onscreen waypoints for any reported lores
Config.NewSetting("TrackDespawns", true); // Track timed lore comb drops, and notify when they despawn
Config.NewSetting("ShowWaypoints", true); // DEPRECATED(v1.2.0.alpha) : Renamed and expanded
Config.NewSetting("CheckNewContent", false); // DEPRECATED(v1.1.0.alpha): Renamed
Config.NewSetting("ExtraTesting", false); // Does extra tests to detect lore that isn't on the index list at all yet (ie: new content!)

Expand All @@ -118,16 +125,20 @@ class efd.LoreHound.LoreHound extends Mod {
/// Mod framework extensions and overrides
private function ConfigChanged(setting:String, newValue, oldValue):Void {
switch(setting) {
case "ShowWaypoints":
case "WaypointAlerts":
if (newValue) {
var addedTypes:Number = newValue & ~oldValue;
var removedTypes:Number = oldValue & ~newValue;
for (var key:String in TrackedLore) {
var lore:LoreData = TrackedLore[key];
// TODO: This is a bit of a hack, it'll do slightly odd things if people toggle it around incomplete dynels (like inactive event lore)
// Still is quicker than doing a full identification and reasonably accurate
CreateWaypoint(lore.DynelInst, AttemptIdentification(lore));
if (addedTypes & lore.Type) {
// TODO: This is a bit of a hack, it may do slightly odd things if people toggle it around incomplete dynels (like inactive event lore)
// Still is quicker than doing a full identification and reasonably accurate
CreateWaypoint(lore.DynelInst, AttemptIdentification(lore));
}
if (removedTypes & lore.Type) { RemoveWaypoint(lore); }
}
}
else { ClearWaypoints(); }
} else { ClearWaypoints(); }
break;
default:
super.ConfigChanged(setting, newValue, oldValue);
Expand Down Expand Up @@ -189,11 +200,25 @@ class efd.LoreHound.LoreHound extends Mod {
ChatMsg(LocaleManager.GetString("Patch", "AutoReportRepair"));
}
}
if (CompareVersions("1.2.0.alpha", oldVersion) > 0) {
// Rename *level settings to *alert
Config.SetValue("FifoAlerts", Config.GetValue("FifoLevel"));
Config.SetValue("ChatAlerts", Config.GetValue("ChatLevel"));
// Copy waypoint settings to new per-category setting
var existingAlerts = Config.GetValue("FifoLevel") | Config.GetValue("ChatLevel");
Config.SetValue("WaypointAlerts", (Config.GetValue("ShowWaypoints") ? existingAlerts : ef_LoreType_None));
// Copy unclaimed lore to per-category setting (no existing setting for claimed lore)
Config.SetValue("AlertForUncollected", (Config.GetValue("IgnoreUnclaimedLore") ? ef_LoreType_Uncategorized : ef_LoreType_All - ef_LoreType_Despawn));
}
}

private function LoadComplete():Void {
super.LoadComplete();
Config.DeleteSetting("CheckNewContent"); // DEPRECATED(v1.1.0.alpha): Renamed
Config.DeleteSetting("FifoLevel"); // DEPRECATED(v1.2.0.alpha) : Renamed
Config.DeleteSetting("ChatLevel"); // DEPRECATED(v1.2.0.alpha) : Renamed
Config.DeleteSetting("ShowWaypoints"); // DEPRECATED(v1.2.0.alpha) : Renamed
Config.DeleteSetting("IgnoreUnclaimedLore"); // DEPRECATED(v1.2.0.alpha) : Renamed
}

private function Activate():Void {
Expand Down Expand Up @@ -352,11 +377,16 @@ class efd.LoreHound.LoreHound extends Mod {
TraceMsg("LoreID not available, limiting analysis");
}
} else { // Tests require a valid LoreID
if (Config.GetValue("IgnoreUnclaimedLore") && !lore.IsKnown() && lore.Type != ef_LoreType_Uncategorized) { return false; }
if (lore.IsKnown) {
if (!(lore.Type & Config.GetValue("AlertForCollected"))) { return false; }
} else {
if (!(lore.Type & Config.GetValue("AlertForUncollected"))) { return false; }
}
}
// Pass conditions
if ((Config.GetValue("FifoLevel") & lore.Type) ||
(Config.GetValue("ChatLevel") & lore.Type) ||
if ((Config.GetValue("FifoAlerts") & lore.Type) ||
(Config.GetValue("ChatAlerts") & lore.Type) ||
(Config.GetValue("WaypointAlerts") & lore.Type) ||
(lore.Type == LoreData.ef_LoreType_Uncategorized && AutoReport.IsEnabled) ||
DumpToLog){ return true; }

Expand All @@ -372,13 +402,10 @@ class efd.LoreHound.LoreHound extends Mod {
var despawnedId:String = new ID32(type, instance).toString();
var lore:LoreData = TrackedLore[despawnedId];
if (lore) { // Ensure the despawned dynel was tracked by this mod
lore.Type |= LoreData.ef_LoreType_Despawn;
// Remove lore waypoint
if (Config.GetValue("ShowWaypoints")) {
delete WaypointSystem.m_CurrentPFInterface.m_Waypoints[despawnedId];
WaypointSystem.m_CurrentPFInterface.SignalWaypointRemoved.Emit(lore.DynelID);
}
// Despawn notification
lore.Type |= LoreData.ef_LoreType_Despawn; // Set the despawn flag

if (Config.GetValue("WaypointAlerts") & lore.Type) { RemoveWaypoint(lore); }
// Despawn notifications
if ((lore.Type & LoreData.ef_LoreType_Drop) && Config.GetValue("TrackDespawns")) {
if (FilterLore(lore)) { // Despawn notifications are subject to same filters as regular ones
var messageStrings:Array = GetMessageStrings(lore);
Expand All @@ -397,13 +424,6 @@ class efd.LoreHound.LoreHound extends Mod {
UpdateIcon();
}

private function ClearWaypoints():Void {
for (var key:String in TrackedLore) {
delete WaypointSystem.m_CurrentPFInterface.m_Waypoints[key];
WaypointSystem.m_CurrentPFInterface.SignalWaypointRemoved.Emit(TrackedLore[key].DynelID);
}
}

/// Lore identification
// Much of the primary categorization info is now contained in the xml data file
private function ClassifyID(categorizationId:Number):Number {
Expand Down Expand Up @@ -586,13 +606,13 @@ class efd.LoreHound.LoreHound extends Mod {
}

private function DispatchMessages(messageStrings:Array, lore:LoreData, detailStrings:Array):Void {
if (Config.GetValue("ShowWaypoints") && !(lore.Type & LoreData.ef_LoreType_Despawn)) {
if ((Config.GetValue("WaypointAlerts") & lore.Type) && !(lore.Type & LoreData.ef_LoreType_Despawn)) {
CreateWaypoint(lore.DynelInst, messageStrings[0]);
}
if (Config.GetValue("FifoLevel") & lore.Type) {
if (Config.GetValue("FifoAlerts") & lore.Type) {
FifoMsg(messageStrings[1]);
}
if (Config.GetValue("ChatLevel") & lore.Type) {
if (Config.GetValue("ChatAlerts") & lore.Type) {
ChatMsg(messageStrings[2], { forceTimestamp : (Config.GetValue("Details") & ef_Details_Timestamp) });
for (var i:Number = 0; i < detailStrings.length; ++i) {
ChatMsg(detailStrings[i], { noPrefix : true });
Expand Down Expand Up @@ -640,15 +660,25 @@ class efd.LoreHound.LoreHound extends Mod {
WaypointSystem.m_CurrentPFInterface.SignalWaypointAdded.Emit(waypoint.m_Id);
}

private function RemoveWaypoint(lore:LoreData):Void {
delete WaypointSystem.m_CurrentPFInterface.m_Waypoints[lore.DynelID.toString()];
WaypointSystem.m_CurrentPFInterface.SignalWaypointRemoved.Emit(lore.DynelID);
}

private function ClearWaypoints():Void {
for (var key:String in TrackedLore) { RemoveWaypoint(TrackedLore[key]); }
}

// Ugly, but I don't really see any alternative to doing a per/frame update
private function UpdateWaypoints():Void {
if (Config.GetValue("ShowWaypoints")) {
for (var key:String in TrackedLore) {
for (var key:String in TrackedLore) {
var lore:LoreData = TrackedLore[key];
if (Config.GetValue("WaypointAlerts") & lore.Type) {
// The waypoints that are added to the PFInterface are constantly stomped by the C++ side.
// So I'm updating the data held by the rendered copy, and then forcing it to redo the layout before it gets stomped again.
// As long as the mod is updated after the main interface, this should work.
// To do this properly, I'd have to implement my own waypoint system, which just isn't worth it at this point.
var dynel:Dynel = TrackedLore[key].DynelInst;
var dynel:Dynel = lore.DynelInst;
var scrPos:Point = dynel.GetScreenPosition();
var waypoint:CustomWaypoint = WaypointSystem.m_RenderedWaypoints[key];
waypoint.m_Waypoint.m_ScreenPositionX = scrPos.x;
Expand Down
Loading

0 comments on commit 4502e7c

Please sign in to comment.