You can subscribe to this list here.
| 2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(18) |
Oct
(11) |
Nov
(9) |
Dec
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2005 |
Jan
|
Feb
(6) |
Mar
|
Apr
(10) |
May
(38) |
Jun
(15) |
Jul
(32) |
Aug
|
Sep
(17) |
Oct
(11) |
Nov
|
Dec
(14) |
| 2006 |
Jan
(2) |
Feb
(5) |
Mar
(3) |
Apr
(2) |
May
(3) |
Jun
(7) |
Jul
|
Aug
|
Sep
(3) |
Oct
(2) |
Nov
(6) |
Dec
(3) |
| 2007 |
Jan
|
Feb
(17) |
Mar
(5) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2008 |
Jan
(11) |
Feb
|
Mar
|
Apr
(4) |
May
|
Jun
(6) |
Jul
|
Aug
|
Sep
(6) |
Oct
(4) |
Nov
(1) |
Dec
|
| 2009 |
Jan
(3) |
Feb
(2) |
Mar
(4) |
Apr
|
May
(4) |
Jun
(3) |
Jul
|
Aug
(5) |
Sep
(3) |
Oct
(2) |
Nov
|
Dec
(6) |
| 2010 |
Jan
|
Feb
(6) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2011 |
Jan
(2) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2012 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
(8) |
Aug
|
Sep
(2) |
Oct
(2) |
Nov
(4) |
Dec
(5) |
| 2013 |
Jan
(2) |
Feb
|
Mar
(2) |
Apr
(2) |
May
(1) |
Jun
(2) |
Jul
(2) |
Aug
(2) |
Sep
|
Oct
(2) |
Nov
(2) |
Dec
(2) |
| 2014 |
Jan
(3) |
Feb
(2) |
Mar
(3) |
Apr
(4) |
May
(4) |
Jun
(3) |
Jul
(4) |
Aug
(5) |
Sep
|
Oct
(2) |
Nov
(5) |
Dec
(2) |
| 2015 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
(2) |
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
(10) |
Dec
|
| 2016 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(4) |
Aug
(2) |
Sep
(2) |
Oct
(3) |
Nov
(4) |
Dec
(2) |
| 2017 |
Jan
(2) |
Feb
|
Mar
(2) |
Apr
(4) |
May
(2) |
Jun
(2) |
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(2) |
| 2018 |
Jan
(4) |
Feb
(2) |
Mar
(2) |
Apr
(2) |
May
(2) |
Jun
(2) |
Jul
(8) |
Aug
(2) |
Sep
(2) |
Oct
(2) |
Nov
(4) |
Dec
(6) |
| 2019 |
Jan
(2) |
Feb
(2) |
Mar
(2) |
Apr
(4) |
May
(2) |
Jun
(3) |
Jul
(3) |
Aug
(2) |
Sep
(2) |
Oct
(13) |
Nov
(6) |
Dec
(4) |
| 2020 |
Jan
(7) |
Feb
(7) |
Mar
(7) |
Apr
(8) |
May
(5) |
Jun
(3) |
Jul
(10) |
Aug
(4) |
Sep
|
Oct
(37) |
Nov
(30) |
Dec
(8) |
| 2021 |
Jan
(14) |
Feb
(9) |
Mar
(7) |
Apr
(17) |
May
(3) |
Jun
(10) |
Jul
(7) |
Aug
(3) |
Sep
(3) |
Oct
(4) |
Nov
(15) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(3) |
Mar
(3) |
Apr
(3) |
May
(3) |
Jun
(3) |
Jul
(3) |
Aug
(5) |
Sep
(6) |
Oct
(4) |
Nov
(34) |
Dec
(17) |
| 2023 |
Jan
(3) |
Feb
(3) |
Mar
(29) |
Apr
(2) |
May
(18) |
Jun
(12) |
Jul
(12) |
Aug
(2) |
Sep
(7) |
Oct
(2) |
Nov
(2) |
Dec
(2) |
| 2024 |
Jan
(2) |
Feb
(10) |
Mar
(17) |
Apr
(6) |
May
(3) |
Jun
(9) |
Jul
(22) |
Aug
(48) |
Sep
(3) |
Oct
(2) |
Nov
(2) |
Dec
(8) |
| 2025 |
Jan
(3) |
Feb
(2) |
Mar
(9) |
Apr
(7) |
May
(3) |
Jun
(3) |
Jul
(2) |
Aug
(2) |
Sep
(11) |
Oct
(6) |
Nov
(9) |
Dec
(4) |
| 2026 |
Jan
(5) |
Feb
(6) |
Mar
(3) |
Apr
(7) |
May
(2) |
Jun
(11) |
Jul
(21) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: <xer...@us...> - 2026-07-24 20:43:32
|
Revision: 1681
http://sourceforge.net/p/seq/svn/1681
Author: xerxes00
Date: 2026-07-24 20:43:30 +0000 (Fri, 24 Jul 2026)
Log Message:
-----------
Document capture/map/log settings in seqdef.xml; fix EQDateTimeFormat typo
Add CaptureBufferSize, CaptureSnapLen, MapDir, LogWorldPackets,
WorldLogFilename and DBStrFile to seqdef.xml with their existing code
defaults, so they appear in --dump-config and can be edited without
knowing the internal name. No behavior change.
Fix a misspelled preference key in MessageWindow: it read
"EQDateTimeForamt" while Terminal reads/writes "EQDateTimeFormat", so
the message window never picked up the configured format.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/conf/seqdef.xml
showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp
Modified: showeq/branches/xerxes-trunk-dev/conf/seqdef.xml
===================================================================
--- showeq/branches/xerxes-trunk-dev/conf/seqdef.xml 2026-07-24 20:22:38 UTC (rev 1680)
+++ showeq/branches/xerxes-trunk-dev/conf/seqdef.xml 2026-07-24 20:43:30 UTC (rev 1681)
@@ -9,6 +9,14 @@
<seqpreferences version="1.0" >
<!-- ============================================================= -->
<section name="Network" >
+ <property name="CaptureBufferSize" >
+ <int value="4" />
+ <comment>libpcap capture buffer size in MB</comment>
+ </property>
+ <property name="CaptureSnapLen" >
+ <int value="2" />
+ <comment>libpcap per-packet snap length in KB (value is multiplied by 1024)</comment>
+ </property>
<property name="Device" >
<string value="eth0" />
<comment>your network device</comment>
@@ -560,6 +568,10 @@
<!-- ============================================================= -->
<!-- Map Manager Options -->
<section name="MapMgr" >
+ <property name="MapDir" >
+ <string value="" />
+ <comment>Shared maps directory (also settable with --maps-dir); empty = use the user/pkg maps dir</comment>
+ </property>
<property name="DefaultLineColor" >
<color name="gray" />
<comment>Default color for new lines</comment>
@@ -2110,6 +2122,14 @@
<!-- ============================================================= -->
<!-- Packet Logging options -->
<section name="PacketLogging" >
+ <property name="LogWorldPackets" >
+ <bool value="false" />
+ <comment>Log world packets to the world log file</comment>
+ </property>
+ <property name="WorldLogFilename" >
+ <string value="world.log" />
+ <comment>Filename for world packet logging</comment>
+ </property>
<property name="LogAllPackets" >
<bool value="false" />
<comment>Log al packets to global log file</comment>
@@ -2351,6 +2371,10 @@
<!-- ============================================================= -->
<!-- Options to Control the User Interface -->
<section name="Interface" >
+ <property name="DBStrFile" >
+ <string value="dbstr_us.txt" />
+ <comment>String database file (AA titles, etc.); required for AA ability names</comment>
+ </property>
<property name="Caption" >
<string value="ShowEQ - Main (ctrl+alt+t to toggle menubar)" />
<comment>Window caption</comment>
Modified: showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp 2026-07-24 20:22:38 UTC (rev 1680)
+++ showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp 2026-07-24 20:43:30 UTC (rev 1681)
@@ -498,7 +498,7 @@
m_dateTimeFormat = pSEQPrefs->getPrefString("DateTimeFormat",
preferenceName(),
m_dateTimeFormat);
- m_eqDateTimeFormat = pSEQPrefs->getPrefString("EQDateTimeForamt",
+ m_eqDateTimeFormat = pSEQPrefs->getPrefString("EQDateTimeFormat",
preferenceName(),
m_eqDateTimeFormat);
m_displayType = pSEQPrefs->getPrefBool("DisplayType", preferenceName(),
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-24 20:22:40
|
Revision: 1680
http://sourceforge.net/p/seq/svn/1680
Author: xerxes00
Date: 2026-07-24 20:22:38 +0000 (Fri, 24 Jul 2026)
Log Message:
-----------
Add command-line options to select data locations for multiple configs
ShowEQ locates its user config, opcode files, EQ client data files, and
maps relative to a single per-user directory ($HOME/.showeq). Running
several independent configurations (e.g. one per server or game version)
therefore meant juggling $HOME, which also affects everything else the
process resolves from home. These options let a location be chosen
explicitly instead, so multiple configs can coexist from one install
without repurposing $HOME.
New options:
--user-dir=DIR Use DIR as the per-user data directory instead of
$HOME/.showeq (resolved before the config file is
read, so it must be scanned ahead of getopt_long).
--game-files=DIR Read spells_us.txt, dbstr_us.txt and eqstr_us.txt
from DIR (these differ per game version).
--maps-dir=DIR Shared maps directory, searched (read and write)
ahead of the user/pkg maps dirs. Also settable as
the MapDir preference under [MapMgr].
--zone-opcodes=FILE Override the zone/world opcodes file for this run.
--world-opcodes=FILE
--dump-config Print every effective preference with its value and
source (cmdline/user/default), then exit.
DataLocationMgr::findExistingFile() now uses an absolute filename as-is,
so any file preference (SpellsFile, ZoneOPCodes, ...) can point at a file
shared between configurations rather than copied into each user dir.
Command-line overrides are applied as Runtime prefs (not written back to
showeq.xml). At startup a short summary of any active location overrides
is printed. All options are optional; with none given, behavior is
unchanged. Documented in --help, showeq.1, and README.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/README
showeq/branches/xerxes-trunk-dev/showeq.1
showeq/branches/xerxes-trunk-dev/src/datalocationmgr.cpp
showeq/branches/xerxes-trunk-dev/src/datalocationmgr.h
showeq/branches/xerxes-trunk-dev/src/main.cpp
showeq/branches/xerxes-trunk-dev/src/xmlpreferences.cpp
showeq/branches/xerxes-trunk-dev/src/xmlpreferences.h
Modified: showeq/branches/xerxes-trunk-dev/README
===================================================================
--- showeq/branches/xerxes-trunk-dev/README 2026-07-24 02:40:56 UTC (rev 1679)
+++ showeq/branches/xerxes-trunk-dev/README 2026-07-24 20:22:38 UTC (rev 1680)
@@ -52,6 +52,41 @@
The file name each feature looks for can be overridden in the config
(e.g. the DBStrFile setting under [Interface]).
+CHOOSING DATA LOCATIONS
+-----------------------
+Several command-line options select where ShowEQ reads and writes, which
+makes it easy to run more than one independent configuration (for example
+one per server or game version) from a single install:
+
+ --user-dir=DIR Use DIR as the per-user data directory (config, logs,
+ opcodes, filters) instead of $HOME/.showeq. Each config
+ gets its own DIR; nothing is shared through $HOME.
+ --game-files=DIR Read the EverQuest client data files (spells_us.txt,
+ dbstr_us.txt, eqstr_us.txt) from DIR. These differ per
+ game version, so a directory per version keeps one copy
+ of each rather than duplicating them.
+ --maps-dir=DIR Use DIR as a shared maps directory (maps are usually the
+ same across configurations). Also settable as the MapDir
+ preference under [MapMgr]; the option overrides the pref.
+ --zone-opcodes=FILE Override the zone opcodes file for this run. FILE may be
+ --world-opcodes=FILE a bare name (found in the data dir) or an absolute path
+ to a file shared elsewhere on disk.
+
+Any file preference (SpellsFile, DBStrFile, ZoneOPCodes, ...) may be set to
+an absolute path in the config, in which case that exact file is used - a
+convenient way to share one copy of a data file between configurations
+instead of copying it into each user directory.
+
+Command-line overrides apply for that run only and are not written back to
+your config file. Preference lookup order is: command line, then your config
+file (showeq.xml), then the installed defaults (seqdef.xml). Run
+
+ ./showeq --dump-config
+
+to print every effective preference, its value, and which of those three it
+comes from - useful for seeing settings that are supplied by the defaults
+file rather than your own config.
+
ALTERNATE ADVANCEMENT WINDOW
----------------------------
View -> Alternate Advancement lists the AAs your character owns, with the
Modified: showeq/branches/xerxes-trunk-dev/showeq.1
===================================================================
--- showeq/branches/xerxes-trunk-dev/showeq.1 2026-07-24 02:40:56 UTC (rev 1679)
+++ showeq/branches/xerxes-trunk-dev/showeq.1 2026-07-24 20:22:38 UTC (rev 1680)
@@ -17,9 +17,40 @@
.PP
.SH "OPTIONS"
.PP
-.IP "\fB-i <device>\fP"
+.IP "\fB-i <device>\fP"
Specify which network device to bind to
-.IP
+.IP
+.IP "\fB--user-dir <dir>\fP"
+Use <dir> as the user data directory (per-user config, logs, maps and
+filters) instead of the default ~/.showeq. Lets several independent
+ShowEQ configurations coexist without relying on $HOME.
+.IP
+.IP "\fB--zone-opcodes <file>\fP"
+Use <file> as the zone opcodes file for this session, overriding the
+ZoneOPCodes preference. <file> may be a bare name (resolved in the data
+directory) or an absolute path to a file shared elsewhere on disk.
+.IP
+.IP "\fB--world-opcodes <file>\fP"
+As --zone-opcodes, but for the world opcodes file (WorldOPCodes).
+.IP
+.IP "\fB--game-files <dir>\fP"
+Read the EverQuest client data files (spells_us.txt, dbstr_us.txt and
+eqstr_us.txt) from <dir>. These differ per game version, so a directory
+per version keeps one copy of each instead of duplicating them in every
+user directory.
+.IP
+.IP "\fB--maps-dir <dir>\fP"
+Use <dir> as a shared maps directory, searched (for both reading and
+writing) ahead of the per-user and package maps directories. Lets a
+single set of maps be shared between ShowEQ configurations. Overrides the
+MapDir preference (section MapMgr) if both are given.
+.IP
+.IP "\fB--dump-config\fP"
+Print every effective preference, its value, and the tier it comes from
+(cmdline / user / default), then exit. Command-line overrides are applied
+first, so this shows exactly what ShowEQ would use. Useful for seeing
+settings that come from the defaults file rather than your own config.
+.IP
.IP "\fB-b\fP"
Broken Decode option to skip spawn packet handling
when Verant changes the coding.
Modified: showeq/branches/xerxes-trunk-dev/src/datalocationmgr.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/datalocationmgr.cpp 2026-07-24 02:40:56 UTC (rev 1679)
+++ showeq/branches/xerxes-trunk-dev/src/datalocationmgr.cpp 2026-07-24 20:22:38 UTC (rev 1680)
@@ -30,13 +30,19 @@
#include <QFileInfo>
#include <QRegExp>
-DataLocationMgr::DataLocationMgr(const QString& homeSubDir)
+DataLocationMgr::DataLocationMgr(const QString& homeSubDir,
+ const QString& configDir)
{
// create package directory object
m_pkgData = PKGDATADIR;
- // create the user directory object
- m_userData = QDir::homePath() + "/" + homeSubDir;
+ // create the user directory object; an explicit user directory (from the
+ // --user-dir command-line option) is used verbatim, otherwise it defaults
+ // to homeSubDir under the user's home directory (i.e. ~/.showeq).
+ if (!configDir.isEmpty())
+ m_userData = configDir;
+ else
+ m_userData = QDir::homePath() + "/" + homeSubDir;
}
DataLocationMgr::~DataLocationMgr()
@@ -63,11 +69,32 @@
return true;
}
-QFileInfo DataLocationMgr::findExistingFile(const QString& subdir,
+QFileInfo DataLocationMgr::findExistingFile(const QString& subdir,
const QString& filename,
- bool caseSensitive,
+ bool caseSensitive,
bool preferUser) const
{
+ // an absolute filename is used as-is, bypassing the data-directory search.
+ // This lets a preference or command-line option (e.g. --zone-opcodes) point
+ // at a file anywhere on disk, including one shared between several ShowEQ
+ // configurations rather than copied into each user directory.
+ if (QDir::isAbsolutePath(filename))
+ return QFileInfo(filename);
+
+ // a shared maps directory (--maps-dir), when set, is searched ahead of the
+ // per-user/pkg maps dirs; fall through to the normal search if the file is
+ // not found there.
+ if (subdir == "maps" && !m_mapsDir.isEmpty())
+ {
+ QDir mapsDir(m_mapsDir);
+ if (mapsDir.exists())
+ {
+ QFileInfo fi = findFile(mapsDir, filename, caseSensitive, false);
+ if (fi.exists())
+ return fi;
+ }
+ }
+
// find the file using the preferred search ordering
if (preferUser)
return findFile(m_userData, m_pkgData, subdir, filename, caseSensitive);
@@ -80,6 +107,14 @@
bool caseSensitive,
bool preferUser) const
{
+ // writes to the maps subdir go to the shared maps directory when one is set
+ if (subdir == "maps" && !m_mapsDir.isEmpty())
+ {
+ QFileInfo mapsDirInfo(m_mapsDir);
+ if (mapsDirInfo.exists() && mapsDirInfo.isDir() && mapsDirInfo.isWritable())
+ return QFileInfo(QDir(m_mapsDir), filename);
+ }
+
if (preferUser)
return findWriteFile(m_userData, m_pkgData, subdir, filename,
caseSensitive);
Modified: showeq/branches/xerxes-trunk-dev/src/datalocationmgr.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/datalocationmgr.h 2026-07-24 02:40:56 UTC (rev 1679)
+++ showeq/branches/xerxes-trunk-dev/src/datalocationmgr.h 2026-07-24 20:22:38 UTC (rev 1680)
@@ -31,9 +31,14 @@
class DataLocationMgr
{
public:
- DataLocationMgr(const QString& homeSubDir);
+ DataLocationMgr(const QString& homeSubDir, const QString& configDir = QString());
~DataLocationMgr();
bool setupUserDirectory();
+
+ // Set a shared maps directory (from --maps-dir). When set, map files are
+ // looked up here ahead of the per-user/pkg maps dirs, so a single copy of
+ // the maps can be shared between ShowEQ configurations.
+ void setMapsDir(const QString& dir) { m_mapsDir = dir; }
QFileInfo findExistingFile(const QString& subdir, const QString& filename,
bool caseSensitive = false,
bool preferUser = true) const;
@@ -57,6 +62,7 @@
QString m_pkgData;
QString m_userData;
+ QString m_mapsDir;
};
#endif // _DATALOCATIONMGR_H_
Modified: showeq/branches/xerxes-trunk-dev/src/main.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/main.cpp 2026-07-24 02:40:56 UTC (rev 1679)
+++ showeq/branches/xerxes-trunk-dev/src/main.cpp 2026-07-24 20:22:38 UTC (rev 1680)
@@ -99,6 +99,12 @@
#define RESTORE_ZONE_STATE 7
#define RESTORE_SPAWNS 8
#define RESTORE_ALL 9
+#define USER_DIR_OPTION 128
+#define ZONE_OPCODES_OPTION 129
+#define WORLD_OPCODES_OPTION 130
+#define GAME_FILES_OPTION 131
+#define MAPS_DIR_OPTION 132
+#define DUMP_CONFIG_OPTION 133
/* Note that ASCII 32 is a space, best to stop at 31 and pick up again
at 128 or higher
@@ -142,6 +148,12 @@
{"default-class", required_argument, NULL, 'Z'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
+ {"user-dir", required_argument, NULL, USER_DIR_OPTION},
+ {"zone-opcodes", required_argument, NULL, ZONE_OPCODES_OPTION},
+ {"world-opcodes", required_argument, NULL, WORLD_OPCODES_OPTION},
+ {"game-files", required_argument, NULL, GAME_FILES_OPTION},
+ {"maps-dir", required_argument, NULL, MAPS_DIR_OPTION},
+ {"dump-config", no_argument, NULL, DUMP_CONFIG_OPTION},
{"ip-address", required_argument, NULL, IPADDR_OPTION},
{"mac-address", required_argument, NULL, MACADDR_OPTION},
{"global-log-filename", required_argument, NULL, GLOBAL_LOG_FILENAME_OPTION},
@@ -183,6 +195,7 @@
int option_index = 0;
bool bOptionHelp = false;
+ bool bDumpConfig = false;
#undef OFFTEST
#ifdef OFFTEST
@@ -207,9 +220,31 @@
/* Print the version number */
displayVersion();
- // create the data location manager (with user data under ~/.showeq
- DataLocationMgr dataLocMgr(".showeq");
+ // --user-dir must be resolved before the DataLocationMgr is constructed,
+ // because the configuration file is read (below) before getopt_long()
+ // parses the command line further down. Do a minimal early scan for it
+ // here; the option is still listed in option_list so it is accepted (as a
+ // no-op) by the main parse loop and appears in the usage output.
+ QString userDir;
+ // additional data-location overrides captured during option parsing, for
+ // the startup summary printed once the command line has been processed
+ QString mapsDirOverride, gameFilesOverride, zoneOpcodesOverride, worldOpcodesOverride;
+ for (int i = 1; i < argc; i++)
+ {
+ const QString arg = QString::fromLocal8Bit(argv[i]);
+ if (arg == "--user-dir")
+ {
+ if (i + 1 < argc)
+ userDir = QString::fromLocal8Bit(argv[++i]);
+ }
+ else if (arg.startsWith("--user-dir="))
+ userDir = arg.section('=', 1);
+ }
+ // create the data location manager (with user data under ~/.showeq,
+ // unless --user-dir provided an explicit directory)
+ DataLocationMgr dataLocMgr(".showeq", userDir);
+
// setup the user directory
dataLocMgr.setupUserDirectory();
@@ -292,6 +327,14 @@
showeq_params->saveRestoreBaseFilename = dataLocMgr.findWriteFile("tmp", pSEQPrefs->getPrefString("BaseFilename", section, "last")).absoluteFilePath();
showeq_params->filterZoneDataLog = 0;
+ // a shared maps directory may be set in the config file (MapDir); the
+ // --maps-dir command-line option below overrides it.
+ {
+ QString mapDirPref = pSEQPrefs->getPrefString("MapDir", "MapMgr", "");
+ if (!mapDirPref.isEmpty())
+ dataLocMgr.setMapsDir(mapDirPref);
+ }
+
/* Parse the commandline for commandline parameters */
while ((opt = getopt_long( argc,
argv,
@@ -716,6 +759,53 @@
}
+ /* Override the zone/world opcode file for this session. The value may
+ be a bare filename (resolved in the user/pkg data dir) or an
+ absolute path to a file anywhere on disk. */
+ case ZONE_OPCODES_OPTION:
+ zoneOpcodesOverride = QString::fromLocal8Bit(optarg);
+ pSEQPrefs->setPrefString("ZoneOPCodes", "Network", optarg,
+ XMLPreferences::Runtime);
+ break;
+
+ case WORLD_OPCODES_OPTION:
+ worldOpcodesOverride = QString::fromLocal8Bit(optarg);
+ pSEQPrefs->setPrefString("WorldOPCodes", "Network", optarg,
+ XMLPreferences::Runtime);
+ break;
+
+ /* --game-files DIR: point the EQ client data files (spells, dbstr,
+ eqstr) at DIR. These differ per game version, so grouping them under
+ one directory keeps a single copy per version. */
+ case GAME_FILES_OPTION:
+ gameFilesOverride = QString::fromLocal8Bit(optarg);
+ pSEQPrefs->setPrefString("SpellsFile", "Interface",
+ QString::fromLocal8Bit(optarg) + "/spells_us.txt",
+ XMLPreferences::Runtime);
+ pSEQPrefs->setPrefString("DBStrFile", "Interface",
+ QString::fromLocal8Bit(optarg) + "/dbstr_us.txt",
+ XMLPreferences::Runtime);
+ pSEQPrefs->setPrefString("FormatFile", "Interface",
+ QString::fromLocal8Bit(optarg) + "/eqstr_us.txt",
+ XMLPreferences::Runtime);
+ break;
+
+ /* --maps-dir DIR: use DIR as a shared maps directory, searched ahead
+ of the per-user/pkg maps dirs (maps are the same across versions). */
+ case MAPS_DIR_OPTION:
+ mapsDirOverride = QString::fromLocal8Bit(optarg);
+ dataLocMgr.setMapsDir(mapsDirOverride);
+ break;
+
+ /* Print the effective configuration and exit (handled after the loop) */
+ case DUMP_CONFIG_OPTION:
+ bDumpConfig = true;
+ break;
+
+ /* Handled by the early --user-dir pre-scan above; accept as no-op */
+ case USER_DIR_OPTION:
+ break;
+
/* Spit out the help */
case 'h': /* Fall through */
default:
@@ -732,6 +822,33 @@
exit (0);
}
+ // Report any data-location overrides given on the command line, so it is
+ // clear at startup which non-default directories/files are in use.
+ if (!userDir.isEmpty() || !gameFilesOverride.isEmpty() ||
+ !mapsDirOverride.isEmpty() || !zoneOpcodesOverride.isEmpty() ||
+ !worldOpcodesOverride.isEmpty())
+ {
+ printf("ShowEQ location overrides:\n");
+ if (!userDir.isEmpty())
+ printf(" user dir: %s\n", userDir.toLatin1().data());
+ if (!gameFilesOverride.isEmpty())
+ printf(" game files: %s\n", gameFilesOverride.toLatin1().data());
+ if (!mapsDirOverride.isEmpty())
+ printf(" maps dir: %s\n", mapsDirOverride.toLatin1().data());
+ if (!zoneOpcodesOverride.isEmpty())
+ printf(" zone opcodes: %s\n", zoneOpcodesOverride.toLatin1().data());
+ if (!worldOpcodesOverride.isEmpty())
+ printf(" world opcodes: %s\n", worldOpcodesOverride.toLatin1().data());
+ }
+
+ // dump the effective configuration (with command-line overrides applied)
+ // and exit, for config discoverability.
+ if (bDumpConfig)
+ {
+ pSEQPrefs->dumpEffectivePreferences();
+ exit (0);
+ }
+
/* Set up individual files for logging selected packet types based on
a common filename base. The types to log were found by following
where pre_worked was a precondition for further analysis.
@@ -830,6 +947,18 @@
printf (" -h, --help Shows this help\n");
printf (" -o CONFIGFILE Alternate showeq.xml pathname\n");
+ printf (" --user-dir=DIR User data directory for config, logs,\n");
+ printf (" maps and filters (default: ~/.showeq)\n");
+ printf (" --zone-opcodes=FILE Use FILE as the zone opcodes file\n");
+ printf (" (bare name in the data dir, or abs path)\n");
+ printf (" --world-opcodes=FILE Use FILE as the world opcodes file\n");
+ printf (" (bare name in the data dir, or abs path)\n");
+ printf (" --game-files=DIR Read spells_us.txt, dbstr_us.txt and\n");
+ printf (" eqstr_us.txt from DIR (per game version)\n");
+ printf (" --maps-dir=DIR Shared maps directory, searched ahead of\n");
+ printf (" the user/pkg maps dirs\n");
+ printf (" --dump-config Print every effective preference and its\n");
+ printf (" source (cmdline/user/default), then exit\n");
printf (" -V, --version Prints ShowEQ version number\n");
printf (" -i, --net-interface=DEVICE Specify which network device to bind to\n");
printf (" -r, --realtime Set the network thread realtime\n");
Modified: showeq/branches/xerxes-trunk-dev/src/xmlpreferences.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/xmlpreferences.cpp 2026-07-24 02:40:56 UTC (rev 1679)
+++ showeq/branches/xerxes-trunk-dev/src/xmlpreferences.cpp 2026-07-24 20:22:38 UTC (rev 1680)
@@ -37,6 +37,7 @@
#include <QRegExp>
#include <QKeySequence>
#include <QTextStream>
+#include <QSet>
const float seqPrefVersion = 1.0;
@@ -148,7 +149,54 @@
loadPreferences(m_filename, m_userSections);
}
-void XMLPreferences::loadPreferences(const QString& filename,
+void XMLPreferences::dumpEffectivePreferences() const
+{
+ // union of all section names across the three tiers
+ QSet<QString> sectionSet;
+ for (PrefSectionDict::const_iterator it = m_runtimeSections.constBegin();
+ it != m_runtimeSections.constEnd(); ++it)
+ sectionSet.insert(it.key());
+ for (PrefSectionDict::const_iterator it = m_userSections.constBegin();
+ it != m_userSections.constEnd(); ++it)
+ sectionSet.insert(it.key());
+ for (PrefSectionDict::const_iterator it = m_defaultsSections.constBegin();
+ it != m_defaultsSections.constEnd(); ++it)
+ sectionSet.insert(it.key());
+
+ QStringList sections = sectionSet.values();
+ sections.sort();
+
+ printf("Effective ShowEQ preferences (name = value <- source):\n");
+ for (const QString& section : sections)
+ {
+ printf("[%s]\n", section.toLatin1().data());
+
+ PreferenceDict* rd = m_runtimeSections.value(section, nullptr);
+ PreferenceDict* ud = m_userSections.value(section, nullptr);
+ PreferenceDict* dd = m_defaultsSections.value(section, nullptr);
+
+ // union of preference names in this section across the three tiers
+ QSet<QString> nameSet;
+ if (rd) for (PreferenceDict::const_iterator it = rd->constBegin(); it != rd->constEnd(); ++it) nameSet.insert(it.key());
+ if (ud) for (PreferenceDict::const_iterator it = ud->constBegin(); it != ud->constEnd(); ++it) nameSet.insert(it.key());
+ if (dd) for (PreferenceDict::const_iterator it = dd->constBegin(); it != dd->constEnd(); ++it) nameSet.insert(it.key());
+
+ QStringList names = nameSet.values();
+ names.sort();
+ for (const QString& name : names)
+ {
+ QVariant* v = nullptr;
+ const char* src = "?";
+ if (rd && (v = rd->value(name, nullptr)) != nullptr) src = "cmdline";
+ else if (ud && (v = ud->value(name, nullptr)) != nullptr) src = "user";
+ else if (dd && (v = dd->value(name, nullptr)) != nullptr) src = "default";
+ printf(" %-32s = %-26s <- %s\n", name.toLatin1().data(),
+ v ? v->toString().toLatin1().data() : "", src);
+ }
+ }
+}
+
+void XMLPreferences::loadPreferences(const QString& filename,
PrefSectionDict& dict)
{
QDomDocument doc(seqPrefName);
Modified: showeq/branches/xerxes-trunk-dev/src/xmlpreferences.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/xmlpreferences.h 2026-07-24 02:40:56 UTC (rev 1679)
+++ showeq/branches/xerxes-trunk-dev/src/xmlpreferences.h 2026-07-24 20:22:38 UTC (rev 1680)
@@ -196,7 +196,12 @@
void save(); // Saves all modified values to the appropriate file
void load(); // Loads values from files into the appropriate caches
void revert(); // Reloads values from files into the appropriate caches
-
+
+ // print every effective preference (across all sections) to stdout, showing
+ // its value and which tier it comes from (cmdline / user / default). Used by
+ // the --dump-config command-line option for config discoverability.
+ void dumpEffectivePreferences() const;
+
protected:
// loads a preference dictionary from the specified filename
void loadPreferences(const QString& filename, PrefSectionDict& dict);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-24 02:40:59
|
Revision: 1679
http://sourceforge.net/p/seq/svn/1679
Author: xerxes00
Date: 2026-07-24 02:40:56 +0000 (Fri, 24 Jul 2026)
Log Message:
-----------
Spell list: honor the NPC display-name option
- Caster/target columns now render through the NPC display-name option
(transformed/cleaned/unstripped), matching the spawn windows; refreshed
in place when the option changes.
- These are strings captured at cast time, so the transform still works
after the spawn despawns.
- Store the raw target name from the buff-list decode instead of
pre-stripping its digits, so the option can control it (default still
shows the clean name).
Depends on the buff-window commit (OP_BuffList/OP_PetBuffList decode);
merge after r1671/r1672.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/src/interface.cpp
showeq/branches/xerxes-trunk-dev/src/spelllist.cpp
showeq/branches/xerxes-trunk-dev/src/spelllist.h
showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
Modified: showeq/branches/xerxes-trunk-dev/src/interface.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-24 02:39:26 UTC (rev 1678)
+++ showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-24 02:40:56 UTC (rev 1679)
@@ -4088,6 +4088,8 @@
m_spawnList2->refreshItemNames();
if (m_spawnPointList != 0)
m_spawnPointList->spawnPointList()->refresh();
+ if (m_spellList != 0)
+ m_spellList->spellList()->refreshItemNames();
}
void
Modified: showeq/branches/xerxes-trunk-dev/src/spelllist.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spelllist.cpp 2026-07-24 02:39:26 UTC (rev 1678)
+++ showeq/branches/xerxes-trunk-dev/src/spelllist.cpp 2026-07-24 02:40:56 UTC (rev 1679)
@@ -30,9 +30,11 @@
#include <QLayout>
#include <QList>
#include <QMenu>
+#include <QScrollBar>
#include "spelllist.h"
#include "main.h"
+#include "spawn.h"
SpellListItem::SpellListItem(SEQListViewItem *parent) : SEQListViewItem(parent)
{
@@ -92,9 +94,14 @@
setText(SPELLCOL_SPELLID, QString("%1").arg(m_item->spellId()));
setText(SPELLCOL_SPELLNAME, m_item->spellName());
setText(SPELLCOL_CASTERID, QString("%1").arg(m_item->casterId()));
- setText(SPELLCOL_CASTERNAME, m_item->casterName());
+ // caster/target were captured as raw names at cast time; honor the NPC
+ // display-name option at render (still works after the spawn is gone,
+ // since these are stored strings, not live spawn lookups)
+ setText(SPELLCOL_CASTERNAME,
+ npcDisplayName(m_item->casterName(), showeq_params->npcNameDisplay));
setText(SPELLCOL_TARGETID, QString("%1").arg(m_item->targetId()));
- setText(SPELLCOL_TARGETNAME, m_item->targetName());
+ setText(SPELLCOL_TARGETNAME,
+ npcDisplayName(m_item->targetName(), showeq_params->npcNameDisplay));
setText(SPELLCOL_CASTTIME, m_item->castTimeStr());
setText(SPELLCOL_DURATION, m_item->durationStr());
}
@@ -308,6 +315,25 @@
}
}
+// Re-render every spell row so the caster/target columns pick up the current
+// NPC display-name option. In place (no rebuild), so selection is preserved.
+void SpellList::refreshItemNames()
+{
+ bool wasSorting = isSortingEnabled();
+ setSortingEnabled(false);
+ int scrollPos = verticalScrollBar()->value();
+
+ SEQListViewItemIterator it(this);
+ while (*it)
+ {
+ ((SpellListItem*)*it)->update();
+ ++it;
+ }
+
+ setSortingEnabled(wasSorting);
+ verticalScrollBar()->setValue(scrollPos);
+}
+
void SpellList::clear()
{
SEQListView::clear();
Modified: showeq/branches/xerxes-trunk-dev/src/spelllist.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spelllist.h 2026-07-24 02:39:26 UTC (rev 1678)
+++ showeq/branches/xerxes-trunk-dev/src/spelllist.h 2026-07-24 02:40:56 UTC (rev 1679)
@@ -77,6 +77,7 @@
SpellListItem* Selected();
SpellListItem* InsertSpell(const SpellItem *item);
void DeleteItem(const SpellItem *item);
+ void refreshItemNames();
//SpellItem* AddCategory(QString& name, QColor color = Qt::black);
//void RemCategory(SpellListItem *);
//void clearCategories();
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-24 02:39:26 UTC (rev 1678)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-24 02:40:56 UTC (rev 1679)
@@ -383,11 +383,9 @@
const Item* tgt = m_spawnShell->findID(tSpawn, spawnId);
if (!tgt)
return;
+ // store the raw name; the spell list applies the NPC display-name option
+ // (strip/transform) at render time
targetName = tgt->name();
- // Spawn names carry a numeric instance suffix (e.g. a trailing "00"); show
- // the clean name in the spell list.
- while (!targetName.isEmpty() && targetName.at(targetName.length() - 1).isDigit())
- targetName.chop(1);
}
size_t pos = 15;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-24 02:39:28
|
Revision: 1678
http://sourceforge.net/p/seq/svn/1678
Author: xerxes00
Date: 2026-07-24 02:39:26 +0000 (Fri, 24 Jul 2026)
Log Message:
-----------
Add NPC display-name option; fix spawn-list self/pet/zone bugs
NPC Display Name feature
- New Options submenu "NPC Display Name" with a tri-state radio, saved as
[SpawnList] NpcNameDisplay; replaces the old showRealName bool:
- Transformed (default): stripped and article-reordered for name
sorting, e.g. "a_Giant_Spider00" -> "Giant Spider, a".
- Cleaned: digits and underscores removed, article left in place,
e.g. "a_Giant_Spider00" -> "a Giant Spider".
- Unstripped: the raw wire name, e.g. "a_Giant_Spider00".
- Shared name helpers in spawn.cpp (cleanSpawnName/transformSpawnName/
npcDisplayName) and Item::displayName(); applied at render across the
spawn list, spawn list 2, spawn point list (Name+Last), spawn detail
view, map hover tooltips, and the spawn message-log line. Toggling
refreshes the open windows in place (selection, scroll, sort, and tree
expansion preserved).
Display vs filters (decoupled)
- The option only changes the name TEXT shown in the windows. Filter
matching is unaffected: it still runs on filterString()/filterFlags()
(built from transformedName()), independent of the display option, so
the same spawns are caught/filtered/alerted regardless of which name
form is displayed. Map aggro and filter notifications likewise still
match on transformedName(). No filter files need to change.
Bug fixes surfaced along the way
- seqwindow: fall back to the default caption when the saved one is empty
(fixes the blank spawn point window title).
- spawnlist: fix the File -> Rebuild SpawnList menu action. It was
rebuilding the list but dropping most spawns and leaving every category
count at 0 (an internal category iterator wasn't being reset between
spawns). A rebuild now repopulates every category correctly.
- spawnlist: self-player now added to the tree (the shell announces it
via changeItem, not addItem).
- spawnlist: re-parent pets under an owner added after them (pets were
stranded at top level; fixes pet not nesting under the player).
- spawnlist clear(): preserve category expansion across a zone.
- seqdef.xml: SpawnPointList font matched to the spawn lists.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/conf/seqdef.xml
showeq/branches/xerxes-trunk-dev/src/interface.cpp
showeq/branches/xerxes-trunk-dev/src/interface.h
showeq/branches/xerxes-trunk-dev/src/main.cpp
showeq/branches/xerxes-trunk-dev/src/main.h
showeq/branches/xerxes-trunk-dev/src/map.cpp
showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
showeq/branches/xerxes-trunk-dev/src/seqwindow.cpp
showeq/branches/xerxes-trunk-dev/src/showspawn.cpp
showeq/branches/xerxes-trunk-dev/src/spawn.cpp
showeq/branches/xerxes-trunk-dev/src/spawn.h
showeq/branches/xerxes-trunk-dev/src/spawnlist.cpp
showeq/branches/xerxes-trunk-dev/src/spawnlist.h
showeq/branches/xerxes-trunk-dev/src/spawnlist2.cpp
showeq/branches/xerxes-trunk-dev/src/spawnlist2.h
showeq/branches/xerxes-trunk-dev/src/spawnlistcommon.cpp
showeq/branches/xerxes-trunk-dev/src/spawnpointlist.cpp
Modified: showeq/branches/xerxes-trunk-dev/conf/seqdef.xml
===================================================================
--- showeq/branches/xerxes-trunk-dev/conf/seqdef.xml 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/conf/seqdef.xml 2026-07-24 02:39:26 UTC (rev 1678)
@@ -3185,7 +3185,7 @@
<!-- ============================================================= -->
<section name="SpawnPointList" >
<property name="Font" >
- <font family="Helvetica" bold="false" strikeout="false" underline="false" pointsize="8" italic="false" />
+ <font family="adobe-helvetica" bold="false" strikeout="false" underline="false" pointsize="8" italic="false" />
</property>
<property name="ShowCoord1" >
<bool value="true" />
Modified: showeq/branches/xerxes-trunk-dev/src/interface.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -1801,6 +1801,32 @@
m_action_opt_KeepSelectedVisible->setCheckable(true);
m_action_opt_KeepSelectedVisible->setChecked(showeq_params->keep_selected_visible);
+ // NPC Display Name submenu - how NPC names render in the spawn lists,
+ // spawn point list, and spawn detail view (does not affect filtering)
+ QMenu* pNpcNameMenu = pOptMenu->addMenu("NPC Display Name");
+ m_actionGroup_npcNameDisplay = new QActionGroup(this);
+ m_actionGroup_npcNameDisplay->setExclusive(true);
+ m_action_npcName_transformed = pNpcNameMenu->addAction("Show NPC Transformed Name");
+ m_action_npcName_transformed->setCheckable(true);
+ m_action_npcName_transformed->setData(tNpcNameTransformed);
+ m_actionGroup_npcNameDisplay->addAction(m_action_npcName_transformed);
+ m_action_npcName_cleaned = pNpcNameMenu->addAction("Show NPC Cleaned Name");
+ m_action_npcName_cleaned->setCheckable(true);
+ m_action_npcName_cleaned->setData(tNpcNameCleaned);
+ m_actionGroup_npcNameDisplay->addAction(m_action_npcName_cleaned);
+ m_action_npcName_unstripped = pNpcNameMenu->addAction("Show NPC Unstripped Name");
+ m_action_npcName_unstripped->setCheckable(true);
+ m_action_npcName_unstripped->setData(tNpcNameUnstripped);
+ m_actionGroup_npcNameDisplay->addAction(m_action_npcName_unstripped);
+ switch (showeq_params->npcNameDisplay)
+ {
+ case tNpcNameCleaned: m_action_npcName_cleaned->setChecked(true); break;
+ case tNpcNameUnstripped: m_action_npcName_unstripped->setChecked(true); break;
+ default: m_action_npcName_transformed->setChecked(true); break;
+ }
+ connect(m_actionGroup_npcNameDisplay, SIGNAL(triggered(QAction*)),
+ this, SLOT(select_opt_NpcNameDisplay(QAction*)));
+
m_action_opt_LogSpawns = pOptMenu->addAction("Log Spawns", this,
SLOT(toggle_opt_LogSpawns()));
m_action_opt_LogSpawns->setCheckable(true);
@@ -4043,6 +4069,28 @@
}
void
+EQInterface::select_opt_NpcNameDisplay (QAction* action)
+{
+ if (action == 0)
+ return;
+
+ showeq_params->npcNameDisplay = (uint8_t)action->data().toInt();
+ pSEQPrefs->setPrefInt("NpcNameDisplay", "SpawnList",
+ showeq_params->npcNameDisplay);
+
+ // redraw the affected windows so the new form shows immediately. The
+ // category tree is refreshed in place so it keeps its expansion state;
+ // spawn list 2 is a flat list (nothing to collapse) so it rebuilds; the
+ // point list re-runs its row update.
+ if (m_spawnList != 0)
+ m_spawnList->spawnList()->refreshItemNames();
+ if (m_spawnList2 != 0)
+ m_spawnList2->refreshItemNames();
+ if (m_spawnPointList != 0)
+ m_spawnPointList->spawnPointList()->refresh();
+}
+
+void
EQInterface::toggle_opt_UseUpdateRadius (void)
{
showeq_params->useUpdateRadius = !(showeq_params->useUpdateRadius);
Modified: showeq/branches/xerxes-trunk-dev/src/interface.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.h 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/interface.h 2026-07-24 02:39:26 UTC (rev 1678)
@@ -263,6 +263,7 @@
void toggle_opt_TarSelect();
void toggle_opt_TarDeselect();
void toggle_opt_KeepSelectedVisible();
+ void select_opt_NpcNameDisplay(QAction* action);
void toggle_opt_LogSpawns();
void toggle_opt_PvPTeams();
void toggle_opt_PvPDeity();
@@ -506,6 +507,10 @@
QAction* m_action_opt_TarSelect;
QAction* m_action_opt_TarDeselect;
QAction* m_action_opt_KeepSelectedVisible;
+ QActionGroup* m_actionGroup_npcNameDisplay;
+ QAction* m_action_npcName_transformed;
+ QAction* m_action_npcName_cleaned;
+ QAction* m_action_npcName_unstripped;
QAction* m_action_opt_LogSpawns;
QAction* m_action_opt_PvPTeams;
QAction* m_action_opt_PvPDeity;
Modified: showeq/branches/xerxes-trunk-dev/src/main.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/main.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/main.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -274,7 +274,7 @@
/* Tells SEQ whether or not to display casting messages (Turn this off if you're on a big raid) */
section = "SpawnList";
- showeq_params->showRealName = pSEQPrefs->getPrefBool("ShowRealName", section, false);
+ showeq_params->npcNameDisplay = (uint8_t)pSEQPrefs->getPrefInt("NpcNameDisplay", section, tNpcNameTransformed);
/* Different files for different kinds of raw data */
Modified: showeq/branches/xerxes-trunk-dev/src/main.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/main.h 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/main.h 2026-07-24 02:39:26 UTC (rev 1678)
@@ -37,6 +37,15 @@
#include "config.h"
//----------------------------------------------------------------------
+// how NPC names are shown in the spawn/spawn-point lists and the spawn
+// detail view (does not affect filter matching)
+enum NpcNameDisplay
+{
+ tNpcNameTransformed = 0, // "giant spider, a" (stripped + article reordered)
+ tNpcNameCleaned = 1, // "a giant spider" (stripped, article in place)
+ tNpcNameUnstripped = 2, // "a_giant_spider15" (raw wire name)
+};
+
// bogus structure that should die soon
struct ShowEQParams
{
@@ -49,8 +58,8 @@
bool walkpathrecord;
uint32_t walkpathlength;
bool systime_spawntime;
- bool showRealName;
-
+ uint8_t npcNameDisplay; // one of enum NpcNameDisplay
+
bool saveZoneState;
bool savePlayerState;
bool saveSpawns;
Modified: showeq/branches/xerxes-trunk-dev/src/map.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/map.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/map.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -4421,12 +4421,12 @@
"%.3s/Z: %5d/%5d/%5d\n"
"Last: %s\n"
"Spawned: %s\t Remaining: %s\t Count: %d",
- sp->name().toLatin1().data(),
+ npcDisplayName(sp->name(), showeq_params->npcNameDisplay).toLatin1().data(),
showeq_params->retarded_coords ? "Y/X" : "X/Y",
showeq_params->retarded_coords ? sp->y() : sp->x(),
showeq_params->retarded_coords ? sp->x() : sp->y(),
sp->z(),
- sp->last().toLatin1().data(),
+ npcDisplayName(sp->last(), showeq_params->npcNameDisplay).toLatin1().data(),
spawned.toLatin1().data(),
remaining.toLatin1().data(),
sp->count());
@@ -4435,12 +4435,12 @@
"%.3s/Z: %5d/%5d/%5d\n"
"Last: %s\n"
"Spawned: %s\t Remaining: %s\t Count: %d",
- sp->name().toLatin1().data(),
+ npcDisplayName(sp->name(), showeq_params->npcNameDisplay).toLatin1().data(),
showeq_params->retarded_coords ? "Y/X" : "X/Y",
showeq_params->retarded_coords ? sp->y() : sp->x(),
showeq_params->retarded_coords ? sp->x() : sp->y(),
sp->z(),
- sp->last().toLatin1().data(),
+ npcDisplayName(sp->last(), showeq_params->npcNameDisplay).toLatin1().data(),
spawned.toLatin1().data(),
remaining.toLatin1().data(),
sp->count());
@@ -4502,7 +4502,7 @@
string = QString::asprintf("%s %s%s\n"
"Level: %2d\tHP: %s\t %.3s/Z: %5d/%5d/%5d\n"
"Race: %s\t Class: %s",
- spawn->transformedName().toUtf8().data(),
+ spawn->displayName().toUtf8().data(),
lastName.toUtf8().data(),
guild.toLatin1().data(),
spawn->level(), hp.toLatin1().data(),
@@ -4516,7 +4516,7 @@
string.sprintf("%s %s%s\n"
"Level: %2d\tHP: %s\t %.3s/Z: %5d/%5d/%5d\n"
"Race: %s\t Class: %s",
- spawn->transformedName().toUtf8().data(),
+ spawn->displayName().toUtf8().data(),
lastName.toUtf8().data(),
guild.toLatin1().data(),
spawn->level(), hp.toLatin1().data(),
@@ -4543,7 +4543,7 @@
string = QString::asprintf("%s\n"
"%.3s/Z: %5d/%5d/%5d\n"
"Race: %s\t Class: %s",
- item->transformedName().toUtf8().data(),
+ item->displayName().toUtf8().data(),
showeq_params->retarded_coords ? "Y/X" : "X/Y",
showeq_params->retarded_coords ? item->y() : item->x(),
showeq_params->retarded_coords ? item->x() : item->y(),
@@ -4554,7 +4554,7 @@
string.sprintf("%s\n"
"%.3s/Z: %5d/%5d/%5d\n"
"Race: %s\t Class: %s",
- item->transformedName().toUtf8().data(),
+ item->displayName().toUtf8().data(),
showeq_params->retarded_coords ? "Y/X" : "X/Y",
showeq_params->retarded_coords ? item->y() : item->x(),
showeq_params->retarded_coords ? item->x() : item->y(),
Modified: showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -1661,7 +1661,7 @@
else
message = "%1: %2/%3/%4 at %6,%5,%7%8";
- m_messages->addMessage(type, message.arg(prefix).arg(item->transformedName())
+ m_messages->addMessage(type, message.arg(prefix).arg(item->displayName())
.arg(item->raceString()).arg(item->classString())
.arg(item->x()).arg(item->y()).arg(item->z())
.arg(spawnInfo));
Modified: showeq/branches/xerxes-trunk-dev/src/seqwindow.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/seqwindow.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/seqwindow.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -39,9 +39,13 @@
{
setObjectName(name);
setWindowFlags(f);
- // set the windows caption
- QDockWidget::setWindowTitle(pSEQPrefs->getPrefString("Caption", preferenceName(),
- caption));
+ // set the windows caption - fall back to the passed-in default when the
+ // saved caption is empty (an empty stored value should never blank the title)
+ QString savedCaption = pSEQPrefs->getPrefString("Caption", preferenceName(),
+ caption);
+ if (savedCaption.isEmpty())
+ savedCaption = caption;
+ QDockWidget::setWindowTitle(savedCaption);
setFeatures(QDockWidget::DockWidgetClosable |
QDockWidget::DockWidgetMovable |
Modified: showeq/branches/xerxes-trunk-dev/src/showspawn.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/showspawn.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/showspawn.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -245,7 +245,7 @@
// display the data
out << "<H1>" << spawn.realName() << "</H1>\n";
- out << "<P>ShortName: " << spawn.transformedName() << "<BR>\n";
+ out << "<P>ShortName: " << spawn.displayName() << "<BR>\n";
out << "Level: " << spawn.level() << "<BR>\n";
out << "HP: " << spawn.HP() << "/"
<< spawn.maxHP() << "<BR>\n";
Modified: showeq/branches/xerxes-trunk-dev/src/spawn.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawn.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawn.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -42,6 +42,7 @@
#include "spawnshell.h"
#include "fixpt.h"
#include "util.h"
+#include "main.h"
//----------------------------------------------------------------------
// constants
@@ -272,6 +273,74 @@
return name();
}
+QString Item::cleanedName() const
+{
+ return name();
+}
+
+QString Item::displayName() const
+{
+ // resolve through the virtual name methods so spawns get their stripped
+ // forms while non-spawn items (doors/drops) stay on their raw name
+ switch (showeq_params->npcNameDisplay)
+ {
+ case tNpcNameCleaned: return cleanedName();
+ case tNpcNameUnstripped: return name();
+ default: return transformedName();
+ }
+}
+
+//----------------------------------------------------------------------
+// NPC name normalization helpers (see spawn.h)
+QString cleanSpawnName(const QString& rawName)
+{
+ QString newName = rawName;
+ newName.replace(QRegExp("[0-9]"), "");
+ newName.replace(QRegExp("_"), " ");
+ return newName;
+}
+
+QString transformSpawnName(const QString& rawName)
+{
+ QString temp = cleanSpawnName(rawName);
+ QString article;
+
+ if (temp.startsWith("a "))
+ {
+ temp = temp.mid(2);
+ article = "a";
+ }
+ else if (temp.startsWith("an "))
+ {
+ temp = temp.mid(3);
+ article = "an";
+ }
+ else if (temp.startsWith("the "))
+ {
+ temp = temp.mid(4);
+ article = "the";
+ }
+
+ if (!article.isEmpty())
+ {
+ temp += ", ";
+ temp += article;
+ }
+
+ return temp;
+}
+
+QString npcDisplayName(const QString& rawName, int mode)
+{
+ // mode values mirror enum NpcNameDisplay in main.h
+ switch (mode)
+ {
+ case 1: return cleanSpawnName(rawName); // tNpcNameCleaned
+ case 2: return rawName; // tNpcNameUnstripped
+ default: return transformSpawnName(rawName); // tNpcNameTransformed
+ }
+}
+
uint16_t Item::race() const
{
return 0;
@@ -833,40 +902,12 @@
QString Spawn::cleanedName() const
{
- QString newName = name();
- newName.replace(QRegExp("[0-9]"), "");
- newName.replace(QRegExp("_"), " ");
- return newName;
+ return cleanSpawnName(name());
}
QString Spawn::transformedName() const
{
- QString temp = cleanedName();
- QString article;
-
- if (temp.startsWith( "a " ))
- {
- temp = temp.mid( 2 );
- article = "a";
- }
- else if (temp.startsWith( "an " ))
- {
- temp = temp.mid( 3 );
- article = "an";
- }
- else if (temp.startsWith( "the " ))
- {
- temp = temp.mid( 4 );
- article = "the";
- }
-
- if (!article.isEmpty())
- {
- temp += ", ";
- temp += article;
- }
-
- return temp;
+ return transformSpawnName(name());
}
uint16_t Spawn::race() const
Modified: showeq/branches/xerxes-trunk-dev/src/spawn.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawn.h 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawn.h 2026-07-24 02:39:26 UTC (rev 1678)
@@ -57,6 +57,17 @@
struct doorStruct;
//----------------------------------------------------------------------
+// NPC name normalization helpers (shared by Spawn, SpawnPoint, and the
+// spawn detail view). All operate on the raw wire name.
+// cleanSpawnName: strip trailing spawn digits, turn '_' into ' '
+// transformSpawnName: cleanSpawnName, then move a leading a/an/the article
+// to the end (for name-sorted lists)
+// npcDisplayName: pick a form by NpcNameDisplay mode (see main.h)
+QString cleanSpawnName(const QString& rawName);
+QString transformSpawnName(const QString& rawName);
+QString npcDisplayName(const QString& rawName, int mode);
+
+//----------------------------------------------------------------------
// enumerated types
// type of item
enum spawnItemType
@@ -153,6 +164,11 @@
// virtual methods that provide reasonable default values/behaviour
virtual QString name() const;
virtual QString transformedName() const;
+ virtual QString cleanedName() const;
+ // the name to show in the UI, resolved from the NPC display-name option.
+ // Non-spawn items keep their raw name in every mode (their transformed/
+ // cleaned forms both return name()).
+ QString displayName() const;
virtual uint16_t race() const;
virtual QString raceString() const;
virtual uint8_t classVal() const;
Modified: showeq/branches/xerxes-trunk-dev/src/spawnlist.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawnlist.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawnlist.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -50,6 +50,8 @@
#include <cmath>
#include <regex.h>
#include <QMenu>
+#include <QScrollBar>
+#include <QSet>
#include <QApplication>
// ------------------------------------------------------
@@ -198,6 +200,17 @@
SEQListViewItemIterator it(this);
SpawnListItem *i = Find(it, item);
+
+ // if the item isn't in the tree yet, add it. The self-player is announced
+ // by the spawn shell via changeItem (not addItem), so without this it would
+ // never appear in the spawn list (it does appear in spawn list 2, which
+ // adds-on-change).
+ if (i == NULL)
+ {
+ addItem(item);
+ return;
+ }
+
while (i)
{
// reinsert only if level, NPC or filterFlags changes
@@ -442,6 +455,31 @@
j->update(m_player, tSpawnChangedALL);
} // else
+ // If this item can own pets (it's a spawn/player that is not itself a pet),
+ // re-parent any of its pets that were added before it. Pets added before
+ // their owner appeared went to the top level and never nested; now that the
+ // owner exists, re-add them so they nest. Covers the self-player, whose pet
+ // is often present before the player row is created.
+ if ((spawn != NULL) && (spawn->petOwnerID() == 0))
+ {
+ const ItemMap& spawnMap = m_spawnShell->getConstMap(tSpawn);
+ ItemConstIterator sit(spawnMap);
+ QList<const Item*> pets;
+ while (sit.hasNext())
+ {
+ sit.next();
+ const Item* s = sit.value();
+ if (s && (s->type() == tSpawn) &&
+ (((const Spawn*)s)->petOwnerID() == item->id()))
+ pets.append(s);
+ }
+ for (int p = 0; p < pets.count(); p++)
+ {
+ delItem(pets[p]);
+ addItem(pets[p]);
+ }
+ }
+
return;
} // end addItem
@@ -728,6 +766,15 @@
void SpawnList::clear(void)
{
//seqDebug("SpawnList::clear()");
+ // remember which categories are expanded so the tree keeps its expansion
+ // state across a rebuild (e.g. on zoning). Category pointers are stable
+ // across zones, so we key on them.
+ QSet<const void*> expanded;
+ QHash<void*, SpawnListItem*>::const_iterator eit;
+ for (eit = m_categoryListItems.begin(); eit != m_categoryListItems.end(); ++eit)
+ if (eit.value() && eit.value()->isExpanded())
+ expanded.insert(eit.key());
+
SEQListView::clear();
m_categoryListItems.clear();
@@ -752,6 +799,10 @@
// update count
litem->updateTitle(cat->name());
+
+ // restore prior expansion state
+ if (expanded.contains((void*)cat))
+ litem->setExpanded(true);
}
} // end clear
@@ -834,6 +885,36 @@
repaint();
}
+// Re-set the displayed name on every spawn row in place. Used when the NPC
+// display-name option changes - avoids a full rebuild so the category tree
+// keeps its expansion and selection state.
+void SpawnList::refreshItemNames()
+{
+ // suspend sorting while renaming: changing a row's name re-sorts the tree,
+ // which would move rows out from under the live iterator (visited twice or
+ // skipped, leaving a mix of old and new names). Re-sort once at the end.
+ bool wasSorting = isSortingEnabled();
+ setSortingEnabled(false);
+
+ // remember the scroll position so the view does not snap when the re-sort
+ // moves rows around (names change their sort key)
+ int scrollPos = verticalScrollBar()->value();
+
+ SEQListViewItemIterator it(this);
+ while (*it)
+ {
+ SpawnListItem* slitem = (SpawnListItem*)*it;
+ // skip category header rows (they have no backing item)
+ if (slitem->item() != NULL)
+ slitem->update(m_player, tSpawnChangedName);
+ ++it;
+ }
+
+ // re-enable sorting, which resorts by the current sort column/order
+ setSortingEnabled(wasSorting);
+ verticalScrollBar()->setValue(scrollPos);
+}
+
void SpawnList::playerLevelChanged(uint8_t)
{
SEQListViewItemIterator it(this);
@@ -984,6 +1065,10 @@
// retrieve the filter string
filterStr = filterString(item, flags);
+ // reset the category iterator for this spawn (it is shared across
+ // the whole populate, so it must be rewound before each spawn)
+ cit.toFront();
+
// iterate over all the categories
while (cit.hasNext())
{
@@ -1020,8 +1105,9 @@
}
}
- // done adding items, now iterate over all the categories and
+ // done adding items, now iterate over all the categories and
// update the counts
+ cit.toFront();
while (cit.hasNext())
{
cat = cit.next();
Modified: showeq/branches/xerxes-trunk-dev/src/spawnlist.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawnlist.h 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawnlist.h 2026-07-24 02:39:26 UTC (rev 1678)
@@ -118,6 +118,7 @@
void loadedCategories(void);
void rebuildSpawnList();
+ void refreshItemNames();
void playerLevelChanged(uint8_t);
void styleChanged();
Modified: showeq/branches/xerxes-trunk-dev/src/spawnlist2.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawnlist2.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawnlist2.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -28,6 +28,7 @@
#include "main.h"
#include <QComboBox>
+#include <QScrollBar>
#include <QSpinBox>
#include <QTimer>
#include <QLayout>
@@ -617,6 +618,32 @@
populateSpawns();
}
+// Re-set the displayed name on every visible row in place. Used when the NPC
+// display-name option changes - a full rebuild would clear the selection and
+// re-emit spawnSelected, hijacking the player's current target.
+void SpawnListWindow2::refreshItemNames(void)
+{
+ // suspend sorting while renaming so the live iterator is not disturbed
+ bool wasSorting = m_spawnList->isSortingEnabled();
+ m_spawnList->setSortingEnabled(false);
+
+ // remember the scroll position so the view does not snap when the re-sort
+ // moves rows around (names change their sort key)
+ int scrollPos = m_spawnList->verticalScrollBar()->value();
+
+ SEQListViewItemIterator it(m_spawnList);
+ while (*it)
+ {
+ SpawnListItem* slitem = (SpawnListItem*)*it;
+ if (slitem->item() != NULL)
+ slitem->update(m_player, tSpawnChangedName);
+ ++it;
+ }
+
+ m_spawnList->setSortingEnabled(wasSorting);
+ m_spawnList->verticalScrollBar()->setValue(scrollPos);
+}
+
void SpawnListWindow2::refresh(void)
{
#if 0 // ZBTEMP
Modified: showeq/branches/xerxes-trunk-dev/src/spawnlist2.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawnlist2.h 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawnlist2.h 2026-07-24 02:39:26 UTC (rev 1678)
@@ -89,6 +89,7 @@
int32_t degrees);
void rebuildSpawnList(void);
+ void refreshItemNames(void);
void refresh(void);
virtual void savePrefs(void);
Modified: showeq/branches/xerxes-trunk-dev/src/spawnlistcommon.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawnlistcommon.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawnlistcommon.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -183,11 +183,8 @@
if (changeType & tSpawnChangedName)
{
- // Name
- if (!showeq_params->showRealName)
- buff = item()->transformedName();
- else
- buff = item()->name();
+ // Name - honor the NPC display-name option (non-spawn items keep raw name)
+ buff = item()->displayName();
if (spawn != NULL)
{
Modified: showeq/branches/xerxes-trunk-dev/src/spawnpointlist.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spawnpointlist.cpp 2026-07-23 02:45:49 UTC (rev 1677)
+++ showeq/branches/xerxes-trunk-dev/src/spawnpointlist.cpp 2026-07-24 02:39:26 UTC (rev 1678)
@@ -87,8 +87,8 @@
setText(tSpawnPointRemaining, tmpStr);
// set the name and last spawn info
- setText(tSpawnPointName, m_spawnPoint->name());
- setText(tSpawnPointLast, m_spawnPoint->last());
+ setText(tSpawnPointName, npcDisplayName(m_spawnPoint->name(), showeq_params->npcNameDisplay));
+ setText(tSpawnPointLast, npcDisplayName(m_spawnPoint->last(), showeq_params->npcNameDisplay));
// construct and set the spawned string
QDateTime dateTime;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-23 02:45:52
|
Revision: 1677
http://sourceforge.net/p/seq/svn/1677
Author: xerxes00
Date: 2026-07-23 02:45:49 +0000 (Thu, 23 Jul 2026)
Log Message:
-----------
EQL: exact self mana from the stat-sync wide form; map stance/invocation ids
Mana (patch from Skik):
- Route the self mana pair from the stat-sync wide form (statUpdateEQL
case 2) into the new Player::setMana. Only EQL source with a real max,
and the only one that updates during regen. Stock OP_ManaChange stays
wired (cast-only, current-only).
- Keep the wire max in its own field (m_wireMaxMana, uint32) so
calcMaxMana recomputes and max-less ManaChange emits can't clobber it.
StatList prefers it over the high-water guess, so the displayed max
follows gear and buffs. Inert on live - nothing sets the wire max
there, so the guess behavior is unchanged.
Opcodes (ids from Skik):
- Map OP_Stance and OP_Invocation: Legends swappable stance / invocation
server echoes, 4 byte ability id. Mapped only, priority 0 / noHandler -
didn't take the handler half.
Thanks to Skik for both.
Modified Paths:
--------------
showeq/branches/showeqlegends/conf/zoneopcodes.xml
showeq/branches/showeqlegends/src/player.cpp
showeq/branches/showeqlegends/src/player.h
showeq/branches/showeqlegends/src/spawnshell.cpp
showeq/branches/showeqlegends/src/statlist.cpp
Modified: showeq/branches/showeqlegends/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/showeqlegends/conf/zoneopcodes.xml 2026-07-22 23:28:54 UTC (rev 1676)
+++ showeq/branches/showeqlegends/conf/zoneopcodes.xml 2026-07-23 02:45:49 UTC (rev 1677)
@@ -1246,4 +1246,14 @@
<comment>SpellFadeCode</comment>
<payload dir="both" typename="spellFadedStruct" sizechecktype="none"/>
</opcode>
+ <opcode id="0fab" name="OP_Stance" priority="0" updated="07/14/26">
+ <priorityNote>noHandler</priorityNote>
+ <comment>EQ Legends swappable stance; server echo carries active ability id - 4 bytes</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="3b12" name="OP_Invocation" priority="0" updated="07/14/26">
+ <priorityNote>noHandler</priorityNote>
+ <comment>EQ Legends swappable invocation; server echo carries active ability id - 4 bytes</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
</seqopcodes>
Modified: showeq/branches/showeqlegends/src/player.cpp
===================================================================
--- showeq/branches/showeqlegends/src/player.cpp 2026-07-22 23:28:54 UTC (rev 1676)
+++ showeq/branches/showeqlegends/src/player.cpp 2026-07-23 02:45:49 UTC (rev 1677)
@@ -151,6 +151,7 @@
m_maxAGI = 0;
m_maxWIS = 0;
m_maxMana = 0;
+ m_wireMaxMana = 0; // EQL
m_maxHP = 0;
m_curHP = 0;
m_food = 0;
@@ -648,6 +649,25 @@
savePlayerState();
}
+void Player::setMana(uint32_t cur, uint32_t max)
+{
+ // EQL stat-sync wide form carries the player's exact current+max mana
+ // (gear+buff-inclusive). OP_ManaChange also rides the Legends wire, but it
+ // only fires on a cast and carries current with no max, so this is the only
+ // authoritative max and the only source that tracks regen. Hold the max
+ // separately as the wire max so a later calcMaxMana recompute (wear/remove
+ // item) can't clobber the displayed value.
+ m_mana = cur;
+ m_maxMana = max;
+ m_wireMaxMana = max;
+ m_validMana = true;
+
+ emit manaChanged(m_mana, m_maxMana);
+
+ if (showeq_params->savePlayerState)
+ savePlayerState();
+}
+
void Player::updateAltExp(const uint8_t* data)
{
const altExpUpdateStruct* altexp = (const altExpUpdateStruct*)data;
Modified: showeq/branches/showeqlegends/src/player.h
===================================================================
--- showeq/branches/showeqlegends/src/player.h 2026-07-22 23:28:54 UTC (rev 1676)
+++ showeq/branches/showeqlegends/src/player.h 2026-07-23 02:45:49 UTC (rev 1677)
@@ -81,6 +81,12 @@
void loadProfile(const playerProfileStruct& player);
void increaseSkill(const uint8_t* skilli);
void manaChange(const uint8_t* mana);
+ // EQL: exact current+max mana from the Legends stat channel
+ // (SpawnShell::statUpdateEQL wide form) - the only EQL source carrying a
+ // max (OP_ManaChange is cast-only and current-only). Stores the wire max
+ // separately (m_wireMaxMana) so a later calcMaxMana estimate can't clobber
+ // the display.
+ void setMana(uint32_t cur, uint32_t max);
void updateExp(const uint8_t* exp);
void updateAltExp(const uint8_t* altexp);
void updateLevel(const uint8_t* levelup);
@@ -144,6 +150,9 @@
uint8_t getMaxWIS() { return m_maxWIS; }
uint16_t getMaxMana() { return m_maxMana; }
uint16_t getMana() { return m_mana; }
+ // Exact gear+buff-inclusive max mana from the EQL stat-sync wide form;
+ // 0 on Live/Test (no wire max), where the display uses the estimate.
+ uint32_t wireMaxMana() const { return m_wireMaxMana; }
uint32_t getSpellBookSlot(uint32_t slotid) { return m_spellBookSlots[slotid]; }
uint32_t getCurrentExp() { return m_currentExp; }
@@ -242,6 +251,9 @@
uint16_t m_plusHP;
uint16_t m_maxMana;
+ // EQL: exact wire max mana; 0 => use estimate. uint32 not uint16 - the
+ // stat-sync wide form carries 64-bit values and setMana takes uint32.
+ uint32_t m_wireMaxMana = 0;
uint8_t m_maxSTR;
uint8_t m_maxSTA;
uint8_t m_maxCHA;
Modified: showeq/branches/showeqlegends/src/spawnshell.cpp
===================================================================
--- showeq/branches/showeqlegends/src/spawnshell.cpp 2026-07-22 23:28:54 UTC (rev 1676)
+++ showeq/branches/showeqlegends/src/spawnshell.cpp 2026-07-23 02:45:49 UTC (rev 1677)
@@ -1160,10 +1160,12 @@
// This decoder only PARSES the Legends container; it emits a stock
// hpNpcUpdateStruct into the stock display paths (SpawnShell::updateNpcHP
// for spawns, Player::updateNpcHP for self - each does its own spawnId
- // routing, exactly as stock wires OP_HPUpdate to both). Mana rides stock
- // OP_ManaChange; self endurance goes to Player::updateEnduranceEQL (Stam
- // row). Food/water do NOT ride this channel (verified with destroyed-food
- // + out-of-food captures).
+ // routing, exactly as stock wires OP_HPUpdate to both). Self mana (exact
+ // cur/max, gear+buff-inclusive) goes to Player::setMana; stock OP_ManaChange
+ // still fires alongside on casts (current only, no max) and stays wired.
+ // Self endurance goes to Player::updateEnduranceEQL (Stam row). Food/water
+ // do NOT ride this channel (verified with destroyed-food + out-of-food
+ // captures).
if (dir != DIR_Server)
return;
@@ -1227,7 +1229,11 @@
m_player->updateNpcHP((const uint8_t*)&hp);
break;
}
- case 2: // mana - the player's mana rides stock OP_ManaChange
+ case 2: // mana - EQL carries the player's exact cur/max here; OP_ManaChange
+ // fires only on a cast and carries no max, so this is the only
+ // source of a real max for the display (vs the calcMaxMana estimate).
+ if (wide && uint16_t(spawnId) == m_player->id())
+ m_player->setMana(uint32_t(cur), uint32_t(max));
break;
case 3: // endurance - self only, onto the Stam row
if (uint16_t(spawnId) == m_player->id())
Modified: showeq/branches/showeqlegends/src/statlist.cpp
===================================================================
--- showeq/branches/showeqlegends/src/statlist.cpp 2026-07-22 23:28:54 UTC (rev 1676)
+++ showeq/branches/showeqlegends/src/statlist.cpp 2026-07-23 02:45:49 UTC (rev 1677)
@@ -178,12 +178,21 @@
m_statList[LIST_MANA]->setText (1, buf);
- if (val > m_guessMaxMana) {
- m_guessMaxMana = val;
+ // EQL supplies the exact gear+buff-inclusive max mana on the wire
+ // (Player::setMana). When present it is authoritative and tracks
+ // equip/unequip and buffs, so use it directly instead of the high-water
+ // estimate, which only ever climbs and drifts a point above the true max.
+ uint32_t wireMax = m_player->wireMaxMana();
+ if (wireMax > 0) {
+ m_guessMaxMana = wireMax;
+ } else {
+ if (val > m_guessMaxMana) {
+ m_guessMaxMana = val;
+ }
+ if (max > m_guessMaxMana) {
+ m_guessMaxMana = max;
+ }
}
- if (max > m_guessMaxMana) {
- m_guessMaxMana = max;
- }
if (m_guessMaxMana < 0)
m_guessMaxMana = 0;
@@ -288,11 +297,18 @@
{
valStr = QString::number(value);
- // attempt to calculate the maximum amount of mana
- if (value > m_guessMaxMana)
- m_guessMaxMana = value;
- if (max > m_guessMaxMana)
- m_guessMaxMana = max;
+ // attempt to calculate the maximum amount of mana; EQL provides the
+ // exact wire max (Player::setMana) which is authoritative when present.
+ uint32_t wireMax = m_player->wireMaxMana();
+ if (wireMax > 0)
+ m_guessMaxMana = wireMax;
+ else
+ {
+ if (value > m_guessMaxMana)
+ m_guessMaxMana = value;
+ if (max > m_guessMaxMana)
+ m_guessMaxMana = max;
+ }
if (m_guessMaxMana < 0)
m_guessMaxMana = 0;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cn...@us...> - 2026-07-22 23:28:56
|
Revision: 1676
http://sourceforge.net/p/seq/svn/1676
Author: cn187
Date: 2026-07-22 23:28:54 +0000 (Wed, 22 Jul 2026)
Log Message:
-----------
Release 6.4.25
- Updated version to 6.4.25
- Support for EQ Patch 07/15/26
- Struct and opcode updates (Newby)
Modified Paths:
--------------
showeq/branches/cn187_devel/ChangeLog
showeq/branches/cn187_devel/conf/zoneopcodes.xml
showeq/branches/cn187_devel/configure.in
showeq/branches/cn187_devel/src/everquest.h
Modified: showeq/branches/cn187_devel/ChangeLog
===================================================================
--- showeq/branches/cn187_devel/ChangeLog 2026-07-18 03:23:00 UTC (rev 1675)
+++ showeq/branches/cn187_devel/ChangeLog 2026-07-22 23:28:54 UTC (rev 1676)
@@ -1,3 +1,9 @@
+cn187 (7/15/26)
+----------------
+- Update to version 6.4.25
+- Support for EQ Patch 7/15/26
+- Struct and opcode updates (Newby)
+
BlueAdept (5/21/26)
----------------
- Update to version 6.4.24
Modified: showeq/branches/cn187_devel/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/cn187_devel/conf/zoneopcodes.xml 2026-07-18 03:23:00 UTC (rev 1675)
+++ showeq/branches/cn187_devel/conf/zoneopcodes.xml 2026-07-22 23:28:54 UTC (rev 1676)
@@ -3,37 +3,37 @@
<seqopcodes>
<!-- Critical opcodes used directly by ShowEQ -->
- <opcode id="e284" name="OP_PlayerProfile" updated="05/20/26">
+ <opcode id="d4b8" name="OP_PlayerProfile" updated="07/15/26">
<comment>CharProfileCode</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="a5bf" name="OP_ZoneEntry" updated="05/20/26">
+ <opcode id="abdb" name="OP_ZoneEntry" updated="07/15/26">
<comment>ZoneEntryCode</comment>
<payload dir="client" typename="ClientZoneEntryStruct" sizechecktype="match"/>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="7e22" name="OP_TimeOfDay" updated="05/20/26">
+ <opcode id="4968" name="OP_TimeOfDay" updated="07/15/26">
<comment>TimeOfDayCode</comment>
<payload dir="server" typename="timeOfDayStruct" sizechecktype="match"/>
</opcode>
- <opcode id="a923" name="OP_NewZone" updated="05/20/26">
+ <opcode id="1a58" name="OP_NewZone" updated="07/15/26">
<comment>NewZoneCode</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="33ec" name="OP_SpawnDoor" updated="05/20/26">
+ <opcode id="cb57" name="OP_SpawnDoor" updated="07/15/26">
<comment>DoorSpawnsCode</comment>
<payload dir="server" typename="doorStruct" sizechecktype="modulus"/>
</opcode>
- <opcode id="92dc" name="OP_GroundSpawn" updated="05/20/26">
+ <opcode id="66a8" name="OP_GroundSpawn" updated="07/15/26">
<comment>MakeDropCode</comment>
<payload dir="server" typename="makeDropStruct" sizechecktype="none"/>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ad5c" name="OP_SendZonePoints" updated="05/20/26">
+ <opcode id="57f6" name="OP_SendZonePoints" updated="07/15/26">
<comment>Coords in a zone that will port you to another zone</comment>
<payload dir="server" typename="zonePointsStruct" sizechecktype="none"/>
</opcode>
- <opcode id="0c97" name="OP_AAExpUpdate" updated="05/20/26">
+ <opcode id="b10f" name="OP_AAExpUpdate" updated="07/15/26">
<comment>Receiving AA experience. Also when percent to AA changes.</comment>
<payload dir="server" typename="altExpUpdateStruct" sizechecktype="match"/>
</opcode>
@@ -41,32 +41,32 @@
<comment>ExpUpdateCode</comment>
<payload dir="server" typename="expUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9f2b" name="OP_GuildMOTD" updated="05/20/26">
+ <opcode id="3425" name="OP_GuildMOTD" updated="07/15/26">
<comment>GuildMOTD</comment>
<payload dir="server" typename="guildMOTDStruct" sizechecktype="none"/>
</opcode>
- <opcode id="f8d1" name="OP_ClientUpdate" updated="05/20/26">
+ <opcode id="76e4" name="OP_ClientUpdate" updated="07/15/26">
<comment>Position updates</comment>
<payload dir="server" typename="playerSpawnPosStruct" sizechecktype="match"/>
<payload dir="both" typename="playerSelfPosStruct" sizechecktype="match"/>
</opcode>
- <opcode id="917c" name="OP_NpcMoveUpdate" updated="05/20/26">
+ <opcode id="612e" name="OP_NpcMoveUpdate" updated="07/15/26">
<comment>Position updates</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="4a4f" name="OP_MobUpdate" updated="05/20/26">
+ <opcode id="6a5a" name="OP_MobUpdate" updated="07/15/26">
<comment>MobUpdateCode</comment>
<payload dir="both" typename="spawnPositionUpdate" sizechecktype="match"/>
</opcode>
- <opcode id="94d4" name="OP_DeleteSpawn" updated="05/20/26">
+ <opcode id="18c6" name="OP_DeleteSpawn" updated="07/15/26">
<comment>DeleteSpawnCode</comment>
<payload dir="both" typename="deleteSpawnStruct" sizechecktype="match"/>
</opcode>
- <opcode id="eb88" name="OP_RemoveSpawn" updated="05/20/26">
+ <opcode id="d631" name="OP_RemoveSpawn" updated="07/15/26">
<comment>Remove spawn from zone</comment>
<payload dir="both" typename="removeSpawnStruct" sizechecktype="none"/>
</opcode>
- <opcode id="1eb2" name="OP_Death" updated="05/20/26">
+ <opcode id="75b4" name="OP_Death" updated="07/15/26">
<comment>old NewCorpseCode</comment>
<payload dir="server" typename="newCorpseStruct" sizechecktype="match"/>
</opcode>
@@ -74,7 +74,7 @@
<comment>SpawnUpdateCode</comment>
<payload dir="both" typename="SpawnUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9826" name="OP_SpawnAppearance" updated="05/20/26">
+ <opcode id="9f7c" name="OP_SpawnAppearance" updated="07/15/26">
<comment>SpawnAppearanceCode</comment>
<payload dir="both" typename="spawnAppearanceStruct" sizechecktype="match"/>
</opcode>
@@ -86,15 +86,15 @@
<comment>NpcHpUpdateCode Update HP % of a PC or NPC</comment>
<payload dir="both" typename="hpNpcUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9abe" name="OP_GuildMemberUpdate" updated="05/20/26">
+ <opcode id="0ad8" name="OP_GuildMemberUpdate" updated="07/15/26">
<comment>Info regarding guild members</comment>
<payload dir="server" typename="GuildMemberUpdate" sizechecktype="match"/>
</opcode>
- <opcode id="ab5e" name="OP_ClickObject" updated="05/20/26">
+ <opcode id="d84f" name="OP_ClickObject" updated="07/15/26">
<comment>Items dropped on the ground</comment>
<payload dir="both" typename="remDropStruct" sizechecktype="match"/>
</opcode>
- <opcode id="049e" name="OP_Action" updated="05/20/26">
+ <opcode id="dda7" name="OP_Action" updated="07/15/26">
<comment>Spells cast etc</comment>
<payload dir="both" typename="actionStruct" sizechecktype="match"/>
<payload dir="both" typename="actionAltStruct" sizechecktype="match"/>
@@ -103,11 +103,11 @@
<comment>Combat actions i.e. bash, kick etc</comment>
<payload dir="both" typename="action2Struct" sizechecktype="match"/>
</opcode>
- <opcode id="a1e7" name="OP_Consider" updated="05/20/26">
+ <opcode id="7a5b" name="OP_Consider" updated="07/15/26">
<comment>ConsiderCode</comment>
<payload dir="both" typename="considerStruct" sizechecktype="match"/>
</opcode>
- <opcode id="1994" name="OP_TargetMouse" updated="05/20/26">
+ <opcode id="12e2" name="OP_TargetMouse" updated="07/15/26">
<comment>Targeting a person - old ClientTargetCode</comment>
<payload dir="both" typename="clientTargetStruct" sizechecktype="match"/>
</opcode>
@@ -123,7 +123,7 @@
<comment>Server putting players into shroud form</comment>
<payload dir="server" typename="spawnShroudSelf" sizechecktype="none"/>
</opcode>
- <opcode id="9148" name="OP_ZoneChange" updated="05/20/26">
+ <opcode id="4068" name="OP_ZoneChange" updated="07/15/26">
<comment>old ZoneChangeCode</comment>
<payload dir="both" typename="zoneChangeStruct" sizechecktype="match"/>
</opcode>
@@ -191,19 +191,19 @@
<comment>EmoteTextCode</comment>
<payload dir="both" typename="emoteTextStruct" sizechecktype="none"/>
</opcode>
- <opcode id="44a0" name="OP_SimpleMessage" updated="05/20/26">
+ <opcode id="2892" name="OP_SimpleMessage" updated="07/15/26">
<comment>SimpleMessageCode</comment>
<payload dir="server" typename="simpleMessageStruct" sizechecktype="match"/>
</opcode>
- <opcode id="5b40" name="OP_FormattedMessage" updated="05/20/26">
+ <opcode id="1d0d" name="OP_FormattedMessage" updated="07/15/26">
<comment>FormattedMessageCode i.e. pet dismissed etc</comment>
<payload dir="server" typename="formattedMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="498b" name="OP_CommonMessage" updated="05/20/26">
+ <opcode id="547a" name="OP_CommonMessage" updated="07/15/26">
<comment>ChannelMessageCode i.e. /tell /ooc /shout etc</comment>
<payload dir="both" typename="channelMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="7162" name="OP_SpecialMesg" updated="05/20/26">
+ <opcode id="b8f3" name="OP_SpecialMesg" updated="07/15/26">
<comment>Communicate textual info to client including hail responses etc</comment>
<payload dir="server" typename="specialMessageStruct" sizechecktype="none"/>
</opcode>
@@ -315,7 +315,7 @@
<comment>List of group members - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="4058" name="OP_GuildMemberList" updated="05/20/26">
+ <opcode id="5af5" name="OP_GuildMemberList" updated="07/15/26">
<comment>List of guild members - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
@@ -375,7 +375,7 @@
<comment>Fellowship information - 2576 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="8d86" name="OP_ExpandedGuildInfo" updated="05/20/26">
+ <opcode id="3ef7" name="OP_ExpandedGuildInfo" updated="07/15/26">
<comment>Guild ranks and other misc guild data - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
@@ -543,7 +543,7 @@
<comment>Listing of all guilds. Can be triggered by /lfg search?</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="d5e8" name="OP_GuildsInZoneList" updated="05/20/26">
+ <opcode id="68f4" name="OP_GuildsInZoneList" updated="07/15/26">
<comment>Listing of guild names present in the current zone. Generally seen on zoning</comment>
<payload dir="server" typename="guildsInZoneListStruct" sizechecktype="none"/>
</opcode>
@@ -603,7 +603,7 @@
<comment>Free to play nags and other data - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="695f" name="OP_Find" updated="05/20/26">
+ <opcode id="2e60" name="OP_Find" updated="07/15/26">
<comment>Find window data - variable length, 24 min</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
Modified: showeq/branches/cn187_devel/configure.in
===================================================================
--- showeq/branches/cn187_devel/configure.in 2026-07-18 03:23:00 UTC (rev 1675)
+++ showeq/branches/cn187_devel/configure.in 2026-07-22 23:28:54 UTC (rev 1676)
@@ -2,7 +2,7 @@
dnl $Id$ $Name$
AC_PREREQ(2.59)
-AC_INIT(showeq, 6.4.24)
+AC_INIT(showeq, 6.4.25)
AC_CONFIG_SRCDIR(src/main.cpp)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_SYSTEM
Modified: showeq/branches/cn187_devel/src/everquest.h
===================================================================
--- showeq/branches/cn187_devel/src/everquest.h 2026-07-18 03:23:00 UTC (rev 1675)
+++ showeq/branches/cn187_devel/src/everquest.h 2026-07-22 23:28:54 UTC (rev 1676)
@@ -1121,23 +1121,24 @@
struct
{
+ unsigned heading:12; // heading
signed animation:10; // current animation
- unsigned pitch:12; // pitch (up/down heading)
unsigned padding00:10;
signed deltaZ:13; // change in z
- signed deltaHeading:10; // change in heading
- unsigned padding01:9;
+ signed deltaX:13; // change in x
+ unsigned padding01:6;
- signed z:19; // z coord (3rd loc value)
- unsigned heading:12; // heading
+ signed x:19; // x coord (1st loc value)
+ unsigned pitch:12; // pitch (up/down heading)
unsigned padding02:1;
- signed deltaX:13; // change in x
signed y:19; // y coord (2nd loc value)
+ signed deltaHeading:10; // change in heading
+ unsigned padding03:3;
+ signed z:19; // z coord (3rd loc value)
signed deltaY:13; // change in y
- signed x:19; // x coord (1st loc value)
};
int32_t posData[5];
@@ -2400,23 +2401,24 @@
/*0000*/ uint16_t spawnId;
/*0002*/ uint16_t spawnId2;
/*0004*/
+ unsigned heading:12; // heading
signed animation:10; // current animation
- unsigned pitch:12; // pitch (up/down heading)
unsigned padding00:10;
/*0008*/
signed deltaZ:13; // change in z
- signed deltaHeading:10; // change in heading
- unsigned padding01:9;
+ signed deltaX:13; // change in x
+ unsigned padding01:6;
/*0012*/
- signed z:19; // z coord (3rd loc value)
- unsigned heading:12; // heading
+ signed x:19; // x coord (1st loc value)
+ unsigned pitch:12; // pitch (up/down heading)
unsigned padding02:1;
/*0016*/
- signed deltaX:13; // change in x
signed y:19; // y coord (2nd loc value)
+ signed deltaHeading:10; // change in heading
+ unsigned padding03:3;
/*0020*/
+ signed z:19; // z coord (3rd loc value)
signed deltaY:13; // change in y
- signed x:19; // x coord (1st loc value)
/*0024*/
};
@@ -2431,27 +2433,27 @@
/*0002*/ uint16_t spawnId; // Player's spawn id
/*0004*/ uint16_t unknown0004; // ***Placeholder
/*0006*/
+ float z; // z coord (3rd loc value)
+/*0010*/
float y; // y coord (2nd loc value)
-/*0010*/
- unsigned pitch:12; // pitch (up/down heading)
+/*0014*/
unsigned heading:12; // heading
- unsigned padding01:8;
-/*0014*/
- float deltaY; // change in y
+ unsigned padding02:20;
/*0018*/
- signed animation:10; // current animation
- unsigned padding03:22;
+ float x; // x coord (1st loc value)
/*0022*/
- float z; // z coord (3rd loc value)
+ float deltaZ; // change in z
/*0026*/
- float x; // x coord (1st loc value)
+ unsigned pitch:12; // pitch (up/down heading)
+ unsigned padding05:20;
/*0030*/
float deltaX; // change in x
/*0034*/
+ float deltaY; // change in y
+/*0038*/
+ signed animation:10; // current animation
signed deltaHeading:10; // change in heading
- unsigned padding07:22;
-/*0038*/
- float deltaZ; // change in z
+ unsigned padding08:12;
/*0042*/
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-18 03:23:02
|
Revision: 1675
http://sourceforge.net/p/seq/svn/1675
Author: xerxes00
Date: 2026-07-18 03:23:00 +0000 (Sat, 18 Jul 2026)
Log Message:
-----------
loot: corpse-contents window + route loot-colored messages to a Loot category
- decode OP_LootDrops (loot-window contents) and print "corpse: item1, item2"
under a new MT_Loot category
- route server loot-colored messages (CC_User_Loot) to MT_Loot in
chatColor2MessageType, so "you looted X", lore/no-room/too-far failures and
the like read as Loot: instead of General:
- MT_Loot gets its own blue color in the message window and terminal
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
showeq/branches/xerxes-trunk-dev/src/interface.cpp
showeq/branches/xerxes-trunk-dev/src/message.cpp
showeq/branches/xerxes-trunk-dev/src/message.h
showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
showeq/branches/xerxes-trunk-dev/src/messageshell.h
showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp
showeq/branches/xerxes-trunk-dev/src/terminal.cpp
Modified: showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-18 03:23:00 UTC (rev 1675)
@@ -480,6 +480,10 @@
<comment>Loot item from corpse - 20 bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
+ <opcode id="e781" name="OP_LootDrops" updated="07/15/26">
+ <comment>Corpse loot-window contents: count@10, corpse name NUL@14, then per-item clean name + 0x12 serialized link</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
<opcode id="ffff" name="OP_EndLootRequest" updated="11/28/12">
<comment>DoneLootingCode - 4 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
Modified: showeq/branches/xerxes-trunk-dev/src/interface.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-18 03:23:00 UTC (rev 1675)
@@ -750,6 +750,11 @@
m_packet->connect2("OP_MoneyOnCorpse", SP_Zone, DIR_Server,
"moneyOnCorpseStruct", SZC_Match,
m_messageShell, SLOT(moneyOnCorpse(const uint8_t*)));
+ // Corpse loot-window contents (variable length); print "corpse: items"
+ // as MT_Loot. The whole loot window (coin + items) rides this one opcode.
+ m_packet->connect2("OP_LootDrops", SP_Zone, DIR_Server,
+ "uint8_t", SZC_None,
+ m_messageShell, SLOT(lootDrops(const uint8_t*, size_t, uint8_t)));
m_packet->connect2("OP_Logout", SP_Zone, DIR_Server,
"uint16_t", SZC_Match,
m_messageShell, SLOT(logOut(const uint8_t*, size_t, uint8_t)));
Modified: showeq/branches/xerxes-trunk-dev/src/message.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/message.cpp 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/src/message.cpp 2026-07-18 03:23:00 UTC (rev 1675)
@@ -62,5 +62,6 @@
"Hunt",
"Locate",
"Chat", // UCS: MT_ChatChannel
+ "Loot", // corpse loot-window contents (MT_Loot)
};
Modified: showeq/branches/xerxes-trunk-dev/src/message.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/message.h 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/src/message.h 2026-07-18 03:23:00 UTC (rev 1675)
@@ -69,7 +69,8 @@
MT_Hunt,
MT_Locate,
MT_ChatChannel, // UCS: cross-zone/General channel chat
- MT_Max = MT_ChatChannel,
+ MT_Loot, // corpse loot-window contents (OP_LootDrops)
+ MT_Max = MT_Loot,
};
//----------------------------------------------------------------------
Modified: showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-18 03:23:00 UTC (rev 1675)
@@ -432,6 +432,9 @@
case CC_User_Random:
messageType = MT_Random;
break;
+ case CC_User_Loot:
+ messageType = MT_Loot;
+ break;
default:
messageType = MT_General;
break;
@@ -450,9 +453,10 @@
QString tempStr;
size_t messagesLen = len - ((uint8_t*)&fmsg->messages[0] - (uint8_t*)fmsg);
- m_messages->addMessage(chatColor2MessageType(fmsg->messageColor),
+
+ m_messages->addMessage(chatColor2MessageType(fmsg->messageColor),
m_eqStrings->formatMessage(fmsg->messageFormat,
- fmsg->messages,
+ fmsg->messages,
messagesLen));
}
@@ -515,6 +519,62 @@
}
+// Corpse loot-window contents (OP_LootDrops): the items you can loot off a
+// corpse, pushed when the loot window opens (and re-pushed at zone-in for a
+// corpse you still have rights to). Layout:
+// [2 bytes][u32][u32 corpseId @6][u32 count @10][corpse name NUL @14]
+// then per-item fields. Each item name is a clean NUL-terminated string;
+// the serialized link that follows repeats the name mangled (leading
+// capital fused to the hex), so we keep only NUL chunks that are entirely a
+// clean item name. Emits "corpse: item1, item2" under MT_Loot.
+void MessageShell::lootDrops(const uint8_t* data, size_t len, uint8_t dir)
+{
+ if (dir != DIR_Server || len < 15)
+ return;
+ uint32_t count = (uint32_t)data[10] | ((uint32_t)data[11] << 8) |
+ ((uint32_t)data[12] << 16) | ((uint32_t)data[13] << 24);
+ int i = 14;
+ while (i < (int)len && data[i] != 0) i++;
+ QString corpse = QString::fromLatin1((const char*)(data + 14), i - 14);
+ if (count == 0 || i >= (int)len) // empty corpse - nothing to loot
+ return;
+ i++; // skip corpse-name NUL
+
+ QStringList items;
+ int start = i;
+ for (int j = i; j <= (int)len; j++)
+ {
+ if (j == (int)len || data[j] == 0)
+ {
+ int clen = j - start;
+ if (clen >= 3 && clen <= 40)
+ {
+ bool ok = true, hasLower = false;
+ unsigned char c0 = data[start];
+ if (!((c0 >= 'A' && c0 <= 'Z') || (c0 >= 'a' && c0 <= 'z'))) ok = false;
+ for (int k = start; ok && k < j; k++)
+ {
+ unsigned char c = data[k];
+ if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || c == ' ' || c == '\'' ||
+ c == '+' || c == '.' || c == '`' || c == '-'))
+ ok = false;
+ if (c >= 'a' && c <= 'z') hasLower = true;
+ }
+ if (ok && hasLower)
+ {
+ QString nm = QString::fromLatin1((const char*)(data + start), clen);
+ if (!items.contains(nm)) items.append(nm);
+ }
+ }
+ start = j + 1;
+ }
+ }
+ if (items.isEmpty())
+ return;
+ m_messages->addMessage(MT_Loot, corpse + ": " + items.join(", "));
+}
+
void MessageShell::moneyOnCorpse(const uint8_t* data)
{
const moneyOnCorpseStruct* money = (const moneyOnCorpseStruct*)data;
Modified: showeq/branches/xerxes-trunk-dev/src/messageshell.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messageshell.h 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/src/messageshell.h 2026-07-18 03:23:00 UTC (rev 1675)
@@ -64,6 +64,8 @@
void specialMessage(const uint8_t* smsg, size_t, uint8_t);
// UCS: display decoded Universal Chat Service cross-zone/global chat.
void ucsChatMessage(const uint8_t* data, size_t len, uint8_t dir);
+ // corpse loot-window contents (OP_LootDrops): "corpse: item1, item2".
+ void lootDrops(const uint8_t* data, size_t len, uint8_t dir);
void guildMOTD(const uint8_t* gmotd, size_t, uint8_t);
void consent(const uint8_t* consent, size_t, uint8_t);
void moneyOnCorpse(const uint8_t* money);
Modified: showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp 2026-07-18 03:23:00 UTC (rev 1675)
@@ -590,6 +590,7 @@
// (RGB 125,75,175). The load() below uses this as the default, so a
// user-set color preference still overrides it.
m_typeStyles[MT_ChatChannel].setColor(QColor(125, 75, 175));
+ m_typeStyles[MT_Loot].setColor(QColor(90, 90, 255));
QString typeName;
// iterate over the message types, filling in various menus and getting
Modified: showeq/branches/xerxes-trunk-dev/src/terminal.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/terminal.cpp 2026-07-18 02:18:34 UTC (rev 1674)
+++ showeq/branches/xerxes-trunk-dev/src/terminal.cpp 2026-07-18 03:23:00 UTC (rev 1675)
@@ -69,6 +69,7 @@
"\e[1;37;44m", // 34 - Locate
NULL, // 35
"\e[38;2;125;75;175m", // 36 - Chat (UCS: in-game universal-chat purple 125,75,175)
+ "\e[38;2;90;90;255m", // 37 - Loot (in-game loot-message blue 90,90,255)
};
//----------------------------------------------------------------------
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-18 02:18:37
|
Revision: 1674
http://sourceforge.net/p/seq/svn/1674
Author: xerxes00
Date: 2026-07-18 02:18:34 +0000 (Sat, 18 Jul 2026)
Log Message:
-----------
ucs-chat: decode cross-zone Universal Chat Service channel chat
- learn the UCS session port from its SessionResponse (XOR format 0x04) and
decode the chained-XOR data packets inline, emitting channel chat under a
new MT_ChatChannel ("Chat") category
- packetcapture: include WorldServerChat2Port in the post-detection filter so
the separate UCS session survives filter narrowing
- messageshell: drop the client-dir MOTD duplicate of outgoing channel
commands (they echo back over UCS as Chat)
- learn full channel names from /list and join notices to repair the
seed-masked first character on chat lines
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/src/interface.cpp
showeq/branches/xerxes-trunk-dev/src/message.cpp
showeq/branches/xerxes-trunk-dev/src/message.h
showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
showeq/branches/xerxes-trunk-dev/src/messageshell.h
showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp
showeq/branches/xerxes-trunk-dev/src/packet.cpp
showeq/branches/xerxes-trunk-dev/src/packet.h
showeq/branches/xerxes-trunk-dev/src/packetcapture.cpp
showeq/branches/xerxes-trunk-dev/src/terminal.cpp
Modified: showeq/branches/xerxes-trunk-dev/src/interface.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-18 02:18:34 UTC (rev 1674)
@@ -720,6 +720,11 @@
"specialMessageStruct", SZC_None,
m_messageShell,
SLOT(specialMessage(const uint8_t*, size_t, uint8_t)));
+ // UCS: decoded cross-zone/global chat -> message log. This is a plain Qt
+ // connect (a custom EQPacket signal, not an opcode), so it does NOT go
+ // through connect2's opcode registration.
+ connect(m_packet, SIGNAL(decodedChatMessage(const uint8_t*, size_t, uint8_t)),
+ m_messageShell, SLOT(ucsChatMessage(const uint8_t*, size_t, uint8_t)));
m_packet->connect2("OP_GuildMOTD", SP_Zone, DIR_Server,
"guildMOTDStruct", SZC_None,
m_messageShell,
Modified: showeq/branches/xerxes-trunk-dev/src/message.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/message.cpp 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/message.cpp 2026-07-18 02:18:34 UTC (rev 1674)
@@ -61,5 +61,6 @@
"Caution",
"Hunt",
"Locate",
+ "Chat", // UCS: MT_ChatChannel
};
Modified: showeq/branches/xerxes-trunk-dev/src/message.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/message.h 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/message.h 2026-07-18 02:18:34 UTC (rev 1674)
@@ -68,7 +68,8 @@
MT_Caution,
MT_Hunt,
MT_Locate,
- MT_Max = MT_Locate,
+ MT_ChatChannel, // UCS: cross-zone/General channel chat
+ MT_Max = MT_ChatChannel,
};
//----------------------------------------------------------------------
Modified: showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-18 02:18:34 UTC (rev 1674)
@@ -21,6 +21,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <QStringList> // UCS: channel-name learning
+
#include "messageshell.h"
#include "eqstr.h"
#include "messages.h"
@@ -88,10 +90,13 @@
//-----------------------------------------------------------------------------
// Tells and Group by us happen twice *shrug*. Ignore the client->server one.
- if (dir == DIR_Client &&
+ if (dir == DIR_Client &&
(cmsg->chanNum == MT_Tell || cmsg->chanNum == MT_Group || cmsg->chanNum == MT_Guild ||
cmsg->chanNum == MT_OOC || cmsg->chanNum == MT_Shout || cmsg->chanNum == MT_Auction ||
- cmsg->chanNum == MT_System || cmsg->chanNum == MT_Raid))
+ cmsg->chanNum == MT_System || cmsg->chanNum == MT_Raid ||
+ cmsg->chanNum == MT_Motd)) // UCS: outgoing channel commands echo back
+ // over UCS as "Chat:"; drop the client-dir MOTD
+ // duplicate. (Real server MOTD is DIR_Server.)
{
return;
}
@@ -179,6 +184,199 @@
cmsg = 0;
}
+// UCS: true if >=85% of the string is printable ASCII. A bad XOR decode
+// yields mostly non-printable bytes, so this gates out garbage records.
+static bool mostlyPrintable(const QString& s)
+{
+ if (s.isEmpty())
+ return false;
+ int p = 0;
+ for (int i = 0; i < s.length(); ++i)
+ if (s[i].unicode() >= 32 && s[i].unicode() < 127)
+ ++p;
+ return (p * 100) >= (s.length() * 85);
+}
+
+// UCS: full channel names learned at runtime. Every per-message channel name
+// has its first character in the seed-masked header (so it decodes garbled),
+// but the FULL name appears un-masked inside /list output and join/invite
+// notices. We harvest those and use them to repair the garbled first char on
+// chat lines.
+static QStringList s_ucsChannels;
+
+static void ucsLearnName(const QString& name)
+{
+ if ((name.length() >= 2) && !s_ucsChannels.contains(name))
+ s_ucsChannels.append(name);
+}
+
+// Scan a decoded buffer's text for channel names: "/list" prints
+// "Channels: 1=General2(400), 2=myraid(1), ..."; join/invite notices say
+// "channel <name>" / "joined <name>".
+static void ucsLearnChannels(const QString& text)
+{
+ int i = 0;
+ while ((i = text.indexOf('=', i)) >= 0) // <n>=<name>(
+ {
+ int j = i + 1;
+ QString name;
+ while ((j < text.length()) &&
+ (text[j].isLetterOrNumber() || (text[j] == '_')))
+ name += text[j++];
+ if ((j < text.length()) && (text[j] == '('))
+ ucsLearnName(name);
+ i = (j > i) ? j : (i + 1);
+ }
+ QStringList kws;
+ kws << "channel " << "joined ";
+ for (int w = 0; w < kws.size(); ++w)
+ {
+ int p = text.indexOf(kws[w]);
+ if (p < 0)
+ continue;
+ p += kws[w].length();
+ QString name;
+ while ((p < text.length()) &&
+ (text[p].isLetterOrNumber() || (text[p] == '_')))
+ name += text[p++];
+ ucsLearnName(name);
+ }
+}
+
+// Repair a channel name whose readable tail (first char may be masked/garbled)
+// is `tail`: match a learned name equal to the tail or to the tail minus its
+// first char; else rebuild the auto-joined "General*" channels; else best-effort.
+static QString ucsResolveChannel(const QString& tail)
+{
+ if (tail.isEmpty())
+ return QString();
+ for (int c = 0; c < s_ucsChannels.size(); ++c)
+ {
+ const QString& name = s_ucsChannels[c];
+ if (tail.endsWith(name) || ((name.length() >= 2) && tail.endsWith(name.mid(1))))
+ return name;
+ }
+ int g = tail.indexOf("eneral"); // General, General1, General2, ...
+ if (g >= 0)
+ return QString("General") + tail.mid(g + 6);
+ return tail;
+}
+
+// UCS: display decoded Universal Chat Service (channel) chat. The buffer
+// arrives XOR-decoded from EQPacket::decodeUCSPacket, SOE OP_Packet-wrapped
+// with a VARIABLE header, so we anchor on the "SPAM:" trailer that ends every
+// real chat record. NUL('\0')-separated layout around it:
+// [4-byte masked hdr]<channel>\0 <server>.<sender>\0 <message>\0 SPAM:<n>:<id>\0
+// message = field before "SPAM:", <server>.<sender> = field before that,
+// <channel> = field before that (first char masked -> repaired via
+// ucsResolveChannel), and sender = text after the LAST '.'. One packet may
+// carry several records (SOE combine). Incoming (server) direction only.
+// Every read is bounds-checked.
+void MessageShell::ucsChatMessage(const uint8_t* data, size_t len, uint8_t dir)
+{
+ if (dir != DIR_Server) // outgoing rides the zone server
+ return;
+ if ((data == NULL) || (len < 8))
+ return;
+
+ // Learn full channel names from any /list / join / invite text in this buffer.
+ ucsLearnChannels(QString::fromLatin1((const char*)data, (int)len));
+
+ size_t scan = 0;
+ while (scan + 5 <= len)
+ {
+ size_t p = scan;
+ bool found = false;
+ for (; p + 5 <= len; ++p)
+ {
+ if (data[p] == 'S' && data[p+1] == 'P' && data[p+2] == 'A' &&
+ data[p+3] == 'M' && data[p+4] == ':')
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ scan = p + 5;
+
+ if ((p < 2) || (data[p-1] != 0)) // "SPAM:" must follow a NUL
+ continue;
+
+ // message = field ending at the NUL just before "SPAM:".
+ size_t msgEnd = p - 1;
+ size_t msgStart = msgEnd;
+ while ((msgStart > 0) && (data[msgStart-1] != 0))
+ --msgStart;
+ if ((msgStart >= msgEnd) || (msgStart < 2))
+ continue;
+
+ // <server>.<sender> = the field ending at the NUL before the message.
+ size_t ssEnd = msgStart - 1;
+ size_t ssStart = ssEnd;
+ while ((ssStart > 0) && (data[ssStart-1] != 0))
+ --ssStart;
+ if (ssStart >= ssEnd)
+ continue;
+
+ QString message = QString::fromLatin1((const char*)(data + msgStart),
+ (int)(msgEnd - msgStart));
+ QString serverSender = QString::fromLatin1((const char*)(data + ssStart),
+ (int)(ssEnd - ssStart));
+ int dot = serverSender.lastIndexOf('.');
+ QString sender = (dot >= 0) ? serverSender.mid(dot + 1) : serverSender;
+
+ // <channel> = the field before <server>.<sender>. Take its trailing
+ // printable run (drops leading masked-header bytes), then repair the
+ // first char.
+ QString channel;
+ if (ssStart >= 2)
+ {
+ size_t chEnd = ssStart - 1;
+ size_t chStart = chEnd;
+ while ((chStart > 0) && (data[chStart-1] != 0))
+ --chStart;
+ QString field = QString::fromLatin1((const char*)(data + chStart),
+ (int)(chEnd - chStart));
+ int k = field.length();
+ while ((k > 0) && (field[k-1].unicode() >= 32) && (field[k-1].unicode() < 127))
+ --k;
+ channel = ucsResolveChannel(field.mid(k));
+ }
+
+ if (!mostlyPrintable(sender) || !mostlyPrintable(message) ||
+ (sender.length() > 32))
+ continue;
+
+ // Server-assigned spam score = the digits right after "SPAM:". The game
+ // client hides/marks score>0 lines; we SHOW everything and tag score>0
+ // with "(SPAM)" so filtered chat stays visible.
+ bool spam = false;
+ {
+ size_t q = p + 5; // p..p+4 == "SPAM:"
+ long score = 0;
+ bool haveDigit = false;
+ while ((q < len) && (data[q] >= '0') && (data[q] <= '9'))
+ {
+ score = (score * 10) + (data[q] - '0');
+ haveDigit = true;
+ ++q;
+ }
+ spam = haveDigit && (score > 0);
+ }
+
+ QString inner = spam
+ ? QString("(SPAM) '%1' - %2").arg(sender).arg(message)
+ : QString("'%1' - %2").arg(sender).arg(message);
+ QString text = channel.isEmpty()
+ ? inner
+ : QString("#%1: %2").arg(channel).arg(inner);
+ // MT_ChatChannel gives UCS chat its own "Chat" category, so the console
+ // prefix is "Chat:" instead of the redundant "General:".
+ m_messages->addMessage(MT_ChatChannel, text);
+ }
+}
+
static MessageType chatColor2MessageType(ChatColor chatColor)
{
MessageType messageType;
Modified: showeq/branches/xerxes-trunk-dev/src/messageshell.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messageshell.h 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/messageshell.h 2026-07-18 02:18:34 UTC (rev 1674)
@@ -62,6 +62,8 @@
void formattedMessage(const uint8_t* cmsg, size_t, uint8_t);
void simpleMessage(const uint8_t* cmsg, size_t, uint8_t);
void specialMessage(const uint8_t* smsg, size_t, uint8_t);
+ // UCS: display decoded Universal Chat Service cross-zone/global chat.
+ void ucsChatMessage(const uint8_t* data, size_t len, uint8_t dir);
void guildMOTD(const uint8_t* gmotd, size_t, uint8_t);
void consent(const uint8_t* consent, size_t, uint8_t);
void moneyOnCorpse(const uint8_t* money);
Modified: showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/messagewindow.cpp 2026-07-18 02:18:34 UTC (rev 1674)
@@ -586,6 +586,11 @@
m_typeFilterMenu->addSeparator();
+ // UCS: default the "Chat" category to the in-game universal-chat purple
+ // (RGB 125,75,175). The load() below uses this as the default, so a
+ // user-set color preference still overrides it.
+ m_typeStyles[MT_ChatChannel].setColor(QColor(125, 75, 175));
+
QString typeName;
// iterate over the message types, filling in various menus and getting
// font color preferences
Modified: showeq/branches/xerxes-trunk-dev/src/packet.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/packet.cpp 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/packet.cpp 2026-07-18 02:18:34 UTC (rev 1674)
@@ -33,6 +33,7 @@
#include <QTimer>
#include <QFileInfo>
+#include <QByteArray> // UCS: buffer for inline UCS chat decode
#include "everquest.h"
#include "packet.h"
@@ -325,6 +326,7 @@
m_ip = inet_ntoa(ia);
m_detectingClient = (m_ip == AUTOMATIC_CLIENT_IP);
+ m_ucsPort = 0; // UCS chat session port, learned from the wire
}
@@ -642,8 +644,32 @@
seqInfo("Client Detected: %s", m_ip.toLatin1().data());
}
+ // UCS (Universal Chat Service): cross-zone / global-channel chat rides a
+ // separate, persistent SOE session whose SessionResponse advertises format
+ // byte 0x04 (XOR-obfuscated) rather than 0x01 (zlib). Its UDP port varies
+ // by server (e.g. 9875 on some, 9877 on others), so learn it from the wire
+ // instead of hardcoding. payload()[11] is the SessionResponse format byte.
+ {
+ const uint8_t* soe = packet.getUDPPayload();
+ uint32_t soeLen = packet.getUDPPayloadLength();
+ if (soe && soeLen >= 12 &&
+ soe[0] == 0x00 && soe[1] == 0x02 && soe[11] == 0x04)
+ m_ucsPort = packet.getSourcePort(); // SessionResponse is server->client
+ }
+
// Dispatch based on known streams
- if ((packet.getDestPort() == ChatServerPort) ||
+ if (m_ucsPort &&
+ ((packet.getDestPort() == m_ucsPort) ||
+ (packet.getSourcePort() == m_ucsPort)))
+ {
+ // UCS chat session: decode + emit it ourselves. The XOR-obfuscated data
+ // packets have no cleartext SOE framing, so the normal stream/CRC path
+ // would choke. Must sit before the chat-port drops below, since the UCS
+ // port can coincide with one of them.
+ decodeUCSPacket(packet);
+ return;
+ }
+ else if ((packet.getDestPort() == ChatServerPort) ||
(packet.getSourcePort() == ChatServerPort))
{
// Drop chat server traffic
@@ -699,6 +725,50 @@
} /* end dispatchPacket() */
////////////////////////////////////////////////////
+// UCS: decode a Universal Chat Service (cross-zone chat) SOE data packet
+// inline.
+//
+// The chat session is a standard SOE session using SOE's XOR "encode" mode
+// (format byte 0x04) rather than zlib. Its data packets are obfuscated with a
+// self-synchronizing chained XOR that needs no key: for the raw UDP payload,
+// plain[i] = cipher[i] ^ cipher[i-4] for i>=4 (the first 4 bytes are a masked
+// header we leave alone). SOE control packets carry no chat and are harmlessly
+// ignored downstream (the parser anchors on a chat-only trailer). These data
+// packets have no cleartext SOE framing, so the normal stream/CRC/reassembly
+// path can't handle them; we decode and emit here instead.
+void EQPacket::decodeUCSPacket(EQUDPIPPacketFormat& packet)
+{
+ // Full UDP payload starting at the SOE net-opcode. UCS chat data is
+ // OP_Packet-wrapped, so the encrypted region sits after a variable-length
+ // SOE header. We deliberately do NOT strip that header: the chained XOR
+ // below is position-absolute, so decoding the whole payload leaves the
+ // encrypted region correctly decoded wherever it begins, and the consumer
+ // anchors its parse on a trailer rather than a fixed offset.
+ const uint8_t* raw = packet.getUDPPayload();
+ uint32_t rawLen = packet.getUDPPayloadLength();
+
+ // Too short to carry a chat record (ACKs, keepalives, etc.) -> ignore.
+ if ((raw == NULL) || (rawLen < 12))
+ return;
+
+ // Self-synchronizing XOR: plain[i] = cipher[i] ^ cipher[i-4] for i>=4. Read
+ // the ORIGINAL ciphertext at i-4 (from a pristine input buffer), NOT the
+ // already-decoded value -- decoding forward in place corrupts everything
+ // from byte 8 on.
+ QByteArray in((const char*)raw, rawLen);
+ QByteArray buf(in);
+ int len = in.size();
+ for (int i = 4; i < len; ++i)
+ buf[i] = (char)((uint8_t)in[i] ^ (uint8_t)in[i - 4]);
+
+ // Direction: from our client, or to it.
+ uint8_t dir = (packet.getIPv4SourceN() == m_client_addr) ?
+ DIR_Client : DIR_Server;
+
+ emit decodedChatMessage((const uint8_t*)buf.data(), (size_t)buf.size(), dir);
+}
+
+////////////////////////////////////////////////////
// Handle zone2client stream closing
void EQPacket::closeStream(uint32_t sessionId, EQStreamID streamId)
{
Modified: showeq/branches/xerxes-trunk-dev/src/packet.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/packet.h 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/packet.h 2026-07-18 02:18:34 UTC (rev 1674)
@@ -164,6 +164,9 @@
uint16_t opcode, const EQPacketOPCode* opcodeEntry,
bool unknown);
+ // UCS: decoded cross-zone/global chat payload, ready for display.
+ void decodedChatMessage(const uint8_t* data, size_t len, uint8_t dir);
+
private:
void validateIP();
@@ -177,6 +180,11 @@
bool m_detectingClient;
in_addr_t m_client_addr;
+ // UCS (Universal Chat Service) session port, learned dynamically from the
+ // SessionResponse whose format byte is 0x04 (XOR-obfuscated chat session).
+ // Varies by server, so it is not hardcoded. 0 = not yet seen.
+ in_port_t m_ucsPort;
+
uint16_t m_arqSeqGiveUp;
QString m_device;
QString m_ip;
@@ -202,6 +210,9 @@
void connectStream(EQPacketStream* stream);
void dispatchPacket (int size, unsigned char *buffer);
void dispatchPacket(EQUDPIPPacketFormat& packet);
+ // UCS: decode a Universal Chat Service (cross-zone chat) SOE data packet
+ // inline, bypassing the normal stream/CRC/reassembly path.
+ void decodeUCSPacket(EQUDPIPPacketFormat& packet);
protected slots:
void resetEQPacket();
void dispatchWorldChatData (size_t len, uint8_t* data, uint8_t direction = 0);
Modified: showeq/branches/xerxes-trunk-dev/src/packetcapture.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/packetcapture.cpp 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/packetcapture.cpp 2026-07-18 02:18:34 UTC (rev 1674)
@@ -393,11 +393,15 @@
}
else
{
- // restrict to client/zone port and world server ports
+ // restrict to client/zone port and world server ports. Include
+ // WorldServerChat2Port (UCS/xgame chat) so the separate cross-zone
+ // chat session survives the post-detection filter narrowing - it
+ // rides a different port than the zone stream.
pfb += sprintf(pfb, "udp");
- pfb += sprintf(pfb, " and (portrange %d-%d or port %d or port %d)",
+ pfb += sprintf(pfb, " and (portrange %d-%d or port %d or port %d or port %d)",
WorldServerGeneralMinPort, WorldServerGeneralMaxPort,
- WorldServerChatPort, (client_port) ? client_port : zone_port);
+ WorldServerChatPort, WorldServerChat2Port,
+ (client_port) ? client_port : zone_port);
}
if (address_type == IP_ADDRESS_TYPE)
Modified: showeq/branches/xerxes-trunk-dev/src/terminal.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/terminal.cpp 2026-07-18 01:43:54 UTC (rev 1673)
+++ showeq/branches/xerxes-trunk-dev/src/terminal.cpp 2026-07-18 02:18:34 UTC (rev 1674)
@@ -67,6 +67,8 @@
"\e[1;37;43m", // 32 - Caution
"\e[1;37;46m", // 33 - Hunt
"\e[1;37;44m", // 34 - Locate
+ NULL, // 35
+ "\e[38;2;125;75;175m", // 36 - Chat (UCS: in-game universal-chat purple 125,75,175)
};
//----------------------------------------------------------------------
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-18 01:43:57
|
Revision: 1673
http://sourceforge.net/p/seq/svn/1673
Author: xerxes00
Date: 2026-07-18 01:43:54 +0000 (Sat, 18 Jul 2026)
Log Message:
-----------
live-fixes: logout/exp opcode wiring, modern exp+AA display, parser/map/payload fixes
- map + wire OP_Logout (camp-accept handshake) and OP_ExpUpdate; add a
uint16_t payload primitive so 2-byte opcodes can strict size-match
- player: drop the legacy calc_exp bar reconstruction (2001/2005) that
renders as garbage on current EQ; show Exp and AA only from their wire
updates, blank until the first arrives (no zone-in flash)
- eqstr: stop parsing length-prefixed args past the payload end
- mapcore: keep comma-bearing map location labels intact
- packetstream: clear the payload candidate on no-match so the warning fires
- util: add Berserker to the class string
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
showeq/branches/xerxes-trunk-dev/src/eqstr.cpp
showeq/branches/xerxes-trunk-dev/src/interface.cpp
showeq/branches/xerxes-trunk-dev/src/mapcore.cpp
showeq/branches/xerxes-trunk-dev/src/packetinfo.cpp
showeq/branches/xerxes-trunk-dev/src/packetstream.cpp
showeq/branches/xerxes-trunk-dev/src/player.cpp
showeq/branches/xerxes-trunk-dev/src/player.h
showeq/branches/xerxes-trunk-dev/src/util.cpp
Modified: showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-18 01:43:54 UTC (rev 1673)
@@ -37,8 +37,8 @@
<comment>Receiving AA experience. Also when percent to AA changes.</comment>
<payload dir="server" typename="altExpUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_ExpUpdate" updated="07/19/23">
- <comment>ExpUpdateCode</comment>
+ <opcode id="10cc" name="OP_ExpUpdate" updated="07/15/26">
+ <comment>ExpUpdateCode - exp permille@0 (0..100000), type@8 0=set/2=update</comment>
<payload dir="server" typename="expUpdateStruct" sizechecktype="match"/>
</opcode>
<opcode id="3425" name="OP_GuildMOTD" updated="07/15/26">
@@ -295,9 +295,10 @@
<comment>Movement history for speed/movement hack detection</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Logout" updated="12/12/12">
- <comment></comment>
- <payload dir="server" typename="uint8_t" sizechecktype="match"/>
+ <opcode id="deb4" name="OP_Logout" updated="07/15/26">
+ <comment>Camp accept - s2c 2B {00 01}; c2s 0B completion</comment>
+ <payload dir="server" typename="uint16_t" sizechecktype="match"/>
+ <payload dir="client" typename="none" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_UIUpdate" updated="05/21/14">
<comment>Seems to be sent to handle a variety of UI updates - Variable length</comment>
Modified: showeq/branches/xerxes-trunk-dev/src/eqstr.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/eqstr.cpp 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/eqstr.cpp 2026-07-18 01:43:54 UTC (rev 1673)
@@ -182,12 +182,18 @@
size_t totalArgsLen = 0;
const char* curArg;
uint32_t curSize = 0;
- while (totalArgsLen < argsLen)
+ while (totalArgsLen + 4 <= argsLen)
{
curArg = arguments + totalArgsLen;
curSize = eqtohuint32((const uint8_t*) curArg);
curArg += 4;
+ // a wire length beyond the remaining payload means the arguments
+ // are not in this length-prefixed layout - stop rather than
+ // allocate off garbage
+ if (curSize > argsLen - totalArgsLen - 4)
+ break;
+
if (curSize > 0) {
// insert argument into the argument list
argList.push_back(QString::fromUtf8(curArg, curSize));
Modified: showeq/branches/xerxes-trunk-dev/src/interface.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-18 01:43:54 UTC (rev 1673)
@@ -746,7 +746,7 @@
"moneyOnCorpseStruct", SZC_Match,
m_messageShell, SLOT(moneyOnCorpse(const uint8_t*)));
m_packet->connect2("OP_Logout", SP_Zone, DIR_Server,
- "none", SZC_Match,
+ "uint16_t", SZC_Match,
m_messageShell, SLOT(logOut(const uint8_t*, size_t, uint8_t)));
m_packet->connect2("OP_NewZone", SP_Zone, DIR_Server,
"uint8_t", SZC_None,
Modified: showeq/branches/xerxes-trunk-dev/src/mapcore.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/mapcore.cpp 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/mapcore.cpp 2026-07-18 01:43:54 UTC (rev 1673)
@@ -1127,9 +1127,9 @@
filelines, count, (const char*)*lit);
#endif
- if (count != 8)
+ if (count < 8)
{
- seqWarn("Error reading L line %d on map '%s'! %d is an incorrect field count!",
+ seqWarn("Error reading P line %d on map '%s'! %d is an incorrect field count!",
filelines, fileName.toLatin1().data(), count);
continue;
}
@@ -1142,8 +1142,14 @@
g = (*fit++).toUShort();
b = (*fit++).toUShort();
fit++; // skip unknown
- name = (*fit); // Location name, conver
-
+ // Location name is the remaining field(s). Labels can contain the field
+ // separator, e.g. "Locked_Door_(Shiny_Metal_Key,Picklock_40)", which the
+ // comma split breaks into extra fields (count > 8), so rejoin from here
+ // to the end instead of taking a single field.
+ name.clear();
+ for (; fit != fields.end(); ++fit)
+ name += (name.isEmpty() ? QString() : QString(",")) + *fit;
+
// convert underscores to spaces.
name.replace("_", " ");
Modified: showeq/branches/xerxes-trunk-dev/src/packetinfo.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/packetinfo.cpp 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/packetinfo.cpp 2026-07-18 01:43:54 UTC (rev 1673)
@@ -98,6 +98,7 @@
// these we add manually to handle strings and octet streams
addStruct("char", sizeof(char));
addStruct("uint8_t", sizeof(uint8_t));
+ addStruct("uint16_t", sizeof(uint16_t));
addStruct("none", 0);
addStruct("unknown", 0);
}
Modified: showeq/branches/xerxes-trunk-dev/src/packetstream.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/packetstream.cpp 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/packetstream.cpp 2026-07-18 01:43:54 UTC (rev 1673)
@@ -126,9 +126,12 @@
return false;
}
- EQPacketPayload* payload;
+ EQPacketPayload* payload = nullptr;
- // try to find a matching payload for this opcode
+ // try to find a matching payload for this opcode. The candidate must be
+ // cleared when it does not match: leaving the loop variable set silently
+ // binds the receiver to the LAST payload of the opcode when no typename
+ // matches, bypassing the no-matching-payload warning below.
EQPayloadListIterator pit(*opcode);
while (pit.hasNext())
{
@@ -136,10 +139,11 @@
if (!payload)
break;
// if all the parameters match, then use this payload
- if ((payload->dir() & m_dir) &&
- (payload->typeName() == payloadType) &&
+ if ((payload->dir() & m_dir) &&
+ (payload->typeName() == payloadType) &&
(payload->sizeCheckType() == szt))
break;
+ payload = nullptr;
}
// if no payload found, create one and issue a warning
Modified: showeq/branches/xerxes-trunk-dev/src/player.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/player.cpp 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/player.cpp 2026-07-18 01:43:54 UTC (rev 1673)
@@ -192,6 +192,8 @@
m_playerLanguages[a] = 255; // indicate an invalid value
m_mana = 0;
+ m_expBarProgress = -1;
+ m_validAltExp = false;
setLevel (1);
setRace (1);
setClassVal (1);
@@ -352,6 +354,9 @@
void Player::player(const charProfileStruct* player)
{
+ // new zone-in: let the first real exp/AA opcode print, then dedup the
+ // 2-3 identical repeats the server sends right after
+ m_lastExpRaw = m_lastAltExpRaw = 0xffffffff;
QString messag;
if (m_name != player->name)
@@ -410,13 +415,26 @@
// Exp
m_currentExp = player->exp;
- m_currentAltExp = player->expAA;
+ // The profile's expAA is on a different scale than the display and reads
+ // as garbage; the real value comes from OP_AAExpUpdate (updateAltExp).
+ // Don't let the profile clobber a wire value we've already received.
+ if (!m_validAltExp)
+ m_currentAltExp = player->expAA;
m_validExp = true;
-
- emit expChangedInt (m_currentExp, m_minExp, m_maxExp);
- emit expAltChangedInt(m_currentAltExp, 0, 15000000);
- emit setAltExp(m_currentAltExp, 15000000, 15000000/330, m_currentAApts);
+ // Show the exp bar only from the wire's exact permille. The legacy
+ // m_currentExp/m_minExp/m_maxExp reconstruction (calc_exp, from 2001/2005)
+ // predates the modern permille wire format and renders as garbage on
+ // current EQ, so suppress it until the first OP_ExpUpdate set arrives
+ // (a few seconds after zone-in) rather than flashing a bad value.
+ if (m_expBarProgress >= 0)
+ emit expChangedInt (int(m_expBarProgress), 0, 100000);
+ // Same for AA: suppress until the first OP_AAExpUpdate set (see updateAltExp).
+ if (m_validAltExp)
+ {
+ emit expAltChangedInt(m_currentAltExp, 0, 15000000);
+ emit setAltExp(m_currentAltExp, 15000000, 15000000/330, m_currentAApts);
+ }
if (showeq_params->savePlayerState)
savePlayerState();
@@ -611,6 +629,10 @@
void Player::updateAltExp(const uint8_t* data)
{
const altExpUpdateStruct* altexp = (const altExpUpdateStruct*)data;
+ // server re-sends the same AA update at zone-in; skip no-change repeats
+ if (altexp->altexp == m_lastAltExpRaw)
+ return;
+ m_lastAltExpRaw = altexp->altexp;
/* purple: I got no idea what is up here. This seems to be written like
* the packet from the server gives the entire exp bump and not
@@ -624,7 +646,11 @@
else
expIncrement = 0;
*/
- uint32_t realExp = altexp->altexp * (15000000 / 330);
+ // This EQ era sends altexp as percent x 1000 (0-100000); convert to the
+ // 0-330 tick scale the emitted totals expect. (Stock's raw altexp *
+ // (15000000/330) assumed 0-330 and produced multi-billion garbage.)
+ uint32_t altTicks = uint32_t(uint64_t(altexp->altexp) * 330 / 100000);
+ uint32_t realExp = altTicks * (15000000 / 330);
uint32_t expIncrement;
if (realExp > m_currentExp)
@@ -638,10 +664,11 @@
m_currentAApts = altexp->aapoints;
m_currentAltExp = realExp;
+ m_validAltExp = true;
emit expAltChangedInt(m_currentAltExp, 0, 15000000);
- emit newAltExp(expIncrement, m_currentAltExp, altexp->altexp,
+ emit newAltExp(expIncrement, m_currentAltExp, altTicks,
15000000, 15000000/330, m_currentAApts);
if (showeq_params->savePlayerState)
@@ -651,6 +678,10 @@
void Player::updateExp(const uint8_t* data)
{
const expUpdateStruct* exp = (const expUpdateStruct*)data;
+ // server re-sends the same exp update at zone-in; skip no-change repeats
+ if (exp->exp == m_lastExpRaw)
+ return;
+ m_lastExpRaw = exp->exp;
// if this is just setting the percentage, then do nothing (use info from
// player packet).
@@ -665,7 +696,10 @@
}
#endif
- uint32_t realExp = (m_tickExp * exp->exp) + m_minExp;
+ // This EQ era sends exp as level progress in percent x 1000 (0-100000);
+ // convert to the 0-330 tick scale the math below expects.
+ uint32_t expTicks = uint32_t(uint64_t(exp->exp) * 330 / 100000);
+ uint32_t realExp = (m_tickExp * expTicks) + m_minExp;
uint32_t expIncrement;
// if realExperience is greater then current expereince, calculate the
@@ -680,11 +714,16 @@
m_validExp = true;
// signal the new experience
- emit newExp(expIncrement, realExp, exp->exp,
+ emit newExp(expIncrement, realExp, expTicks,
m_minExp, m_maxExp, m_tickExp);
-
- emit expChangedInt (realExp, m_minExp, m_maxExp);
+ // Display the wire's exact bar progress (percent*1000, 0-100000). The
+ // realExp reconstruction above feeds the console prints only; the permille
+ // is authoritative and avoids a calc_exp reconstruction that can invert
+ // (m_maxExp below m_minExp) on some level curves.
+ m_expBarProgress = exp->exp;
+ emit expChangedInt (int(exp->exp), 0, 100000);
+
if(m_freshKill)
{
emit expGained( m_lastSpawnKilledName,
@@ -746,7 +785,9 @@
expIncrement,
m_zoneMgr->longZoneName());
- emit expChangedInt( m_currentExp, m_minExp, m_maxExp);
+ // permille only; suppress the legacy calc_exp fallback (see player())
+ if (m_expBarProgress >= 0)
+ emit expChangedInt (int(m_expBarProgress), 0, 100000);
// update the con table
fillConTable();
@@ -1015,10 +1056,29 @@
valid = m_validStam;
break;
case LIST_EXP:
- curValue = m_currentExp;
- maxValue = m_maxExp;
- valid = m_validExp;
+ // Only the wire permille is trustworthy on modern EQ; the legacy
+ // m_currentExp/m_maxExp values render as garbage (see player()), so mark
+ // the row invalid until the first OP_ExpUpdate set populates the permille.
+ if (m_expBarProgress >= 0)
+ {
+ curValue = uint32_t(m_expBarProgress);
+ maxValue = 100000;
+ valid = m_validExp;
+ }
+ else
+ {
+ curValue = 0;
+ maxValue = 100000;
+ valid = false;
+ }
break;
+ case LIST_ALTEXP:
+ // Only trust the wire value from OP_AAExpUpdate; the profile's expAA reads
+ // as garbage, so mark the row invalid until the first update arrives.
+ curValue = m_currentAltExp;
+ maxValue = 15000000;
+ valid = m_validAltExp;
+ break;
case LIST_FOOD:
curValue = m_food;
maxValue = 127;
Modified: showeq/branches/xerxes-trunk-dev/src/player.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/player.h 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/player.h 2026-07-18 01:43:54 UTC (rev 1673)
@@ -248,8 +248,18 @@
// ExperienceWindow needs this
uint32_t m_currentAltExp;
+ int64_t m_expBarProgress; // exact level progress from the wire
+ // (percent*1000, 0-100000); -1 = unset.
+ // Display uses this instead of the calc_exp
+ // reconstruction, whose curve can invert
+ // (m_maxExp below m_minExp) on some levels.
+ bool m_validAltExp; // true once OP_AAExpUpdate has set a real AA
+ // value; until then the profile's expAA reads
+ // as garbage, so the AA bar/row is suppressed.
uint16_t m_currentAApts;
uint32_t m_currentExp;
+ uint32_t m_lastExpRaw = 0xffffffff; // dedup redundant zone-in exp packets
+ uint32_t m_lastAltExpRaw = 0xffffffff; // dedup redundant zone-in AA-exp packets
uint32_t m_minExp;
uint32_t m_maxExp;
uint32_t m_tickExp;
Modified: showeq/branches/xerxes-trunk-dev/src/util.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/util.cpp 2026-07-18 00:12:00 UTC (rev 1672)
+++ showeq/branches/xerxes-trunk-dev/src/util.cpp 2026-07-18 01:43:54 UTC (rev 1673)
@@ -284,12 +284,14 @@
class_str += "ENC ";
if (classes & 16384)
class_str += "BST ";
+ if (classes & 32768)
+ class_str += "BER ";
if (classes >= 32768) // 2^15 aka (1 << 15)
{
int new_class;
- for (int i = 15; i < 31; ++i)
- {
+ for (int i = 16; i < 31; ++i)
+ {
new_class = 1 << i;
if (classes & new_class)
{
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-18 00:12:02
|
Revision: 1672
http://sourceforge.net/p/seq/svn/1672
Author: xerxes00
Date: 2026-07-18 00:12:00 +0000 (Sat, 18 Jul 2026)
Log Message:
-----------
Widen spell ids to 32-bit
EQ spell ids now exceed 65535 (e.g. pet illusions at 69633), so the
uint16_t spell id used throughout the spell subsystem truncated them and
resolved the wrong name (69633 & 0xffff = 4097). Widen the id to uint32_t
across Spell, SpellItem, the buff list, spell()/findSpell()/update()/
spell_name(), and the spell-file parse; the spell array stays a flat table
(max id ~74000, ~580KB). Show an unknown-id name in decimal so it can be
looked up, and fix an off-by-one so the highest-id spell is reachable.
Spell id 32-bit widening contributed by Skik.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/src/everquest.h
showeq/branches/xerxes-trunk-dev/src/spells.cpp
showeq/branches/xerxes-trunk-dev/src/spells.h
showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
showeq/branches/xerxes-trunk-dev/src/spellshell.h
showeq/branches/xerxes-trunk-dev/src/util.cpp
showeq/branches/xerxes-trunk-dev/src/util.h
Modified: showeq/branches/xerxes-trunk-dev/src/everquest.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/everquest.h 2026-07-18 00:07:36 UTC (rev 1671)
+++ showeq/branches/xerxes-trunk-dev/src/everquest.h 2026-07-18 00:12:00 UTC (rev 1672)
@@ -2079,7 +2079,7 @@
{
/*0000*/ uint16_t target; // Target ID
/*0002*/ uint16_t source; // SourceID
-/*0004*/ int16_t spell; // SpellID
+/*0004*/ uint16_t spell; // SpellID (unsigned: modern IDs > 32767 sign-extend if int16)
/*0006*/ uint8_t unknown0006[6];
/*0012*/ uint8_t level; // Caster level
/*0013*/ uint8_t unknown0013[43]; // ***Placeholder
@@ -2095,7 +2095,7 @@
{
/*0000*/ uint16_t target; // Target ID
/*0002*/ uint16_t source; // SourceID
-/*0004*/ int16_t spell; // SpellID
+/*0004*/ uint16_t spell; // SpellID (unsigned: modern IDs > 32767 sign-extend if int16)
/*0006*/ uint8_t unknown0006[6];
/*0012*/ uint8_t level; // Caster level
/*0013*/ uint8_t unknown0013[43]; // ***Placeholder
Modified: showeq/branches/xerxes-trunk-dev/src/spells.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spells.cpp 2026-07-18 00:07:36 UTC (rev 1671)
+++ showeq/branches/xerxes-trunk-dev/src/spells.cpp 2026-07-18 00:12:00 UTC (rev 1672)
@@ -171,7 +171,7 @@
QStringList spellInfo = spells_enLine.split("^");
// I'll add support for the rest of the fields later
- m_spell = spellInfo[0].toUShort();
+ m_spell = spellInfo[0].toUInt();
m_name = spellInfo[1];
m_buffDurationFormula = spellInfo[11].toUShort(); //spells_us.txt layout changed December 2018
m_buffDurationArgument = spellInfo[12].toUShort(); //spells_us.txt layout changed December 2018
@@ -336,7 +336,7 @@
// if a spell list has been allocated, delete it's elements and then itself
if (m_spells)
{
- for (int i = 0; i <= m_maxSpell; i++)
+ for (uint32_t i = 0; i <= m_maxSpell; i++)
{
if (m_spells[i] != NULL)
{
@@ -350,10 +350,11 @@
}
}
-const Spell* Spells::spell(uint16_t spell) const
+const Spell* Spells::spell(uint32_t spell) const
{
- // make sure the spell is within range
- if (spell >= m_maxSpell)
+ // make sure the spell is within range (array is sized [m_maxSpell + 1], so
+ // the highest id is a valid index)
+ if (spell > m_maxSpell)
return NULL;
// return the appropriate spell
Modified: showeq/branches/xerxes-trunk-dev/src/spells.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spells.h 2026-07-18 00:07:36 UTC (rev 1671)
+++ showeq/branches/xerxes-trunk-dev/src/spells.h 2026-07-18 00:12:00 UTC (rev 1672)
@@ -45,7 +45,7 @@
~Spell();
// accessors
- uint16_t spell() const { return m_spell; }
+ uint32_t spell() const { return m_spell; }
const QString& name() const { return m_name; }
uint8_t level(uint8_t class_) const;
uint8_t targetType() const { return m_targetType; }
@@ -57,7 +57,7 @@
private:
QString m_name;
- uint16_t m_spell;
+ uint32_t m_spell;
int16_t m_buffDurationFormula;
int16_t m_buffDurationArgument;
uint8_t m_targetType;
@@ -73,11 +73,11 @@
void loadSpells(const QString& spellsFileName);
void unloadSpells(void);
- const Spell* spell(uint16_t spell) const;
- uint16_t maxSpell() const { return m_maxSpell; }
+ const Spell* spell(uint32_t spell) const;
+ uint32_t maxSpell() const { return m_maxSpell; }
private:
- uint16_t m_maxSpell;
+ uint32_t m_maxSpell;
Spell** m_spells;
};
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-18 00:07:36 UTC (rev 1671)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-18 00:12:00 UTC (rev 1672)
@@ -87,7 +87,7 @@
return text;
}
-void SpellItem::update(uint16_t spellId, const Spell* spell, int duration,
+void SpellItem::update(uint32_t spellId, const Spell* spell, int duration,
uint16_t casterId, const QString& casterName,
uint16_t targetId, const QString& targetName)
{
@@ -143,7 +143,7 @@
clear();
}
-SpellItem* SpellShell::findSpell(uint16_t spellId,
+SpellItem* SpellShell::findSpell(uint32_t spellId,
uint16_t targetId, const QString& targetName)
{
for(QList<SpellItem*>::Iterator it = m_spellList.begin();
@@ -162,7 +162,7 @@
return NULL;
}
-SpellItem* SpellShell::findSpell(int spell_id)
+SpellItem* SpellShell::findSpell(uint32_t spell_id)
{
for(QList<SpellItem*>::Iterator it = m_spellList.begin();
it != m_spellList.end();
@@ -363,7 +363,7 @@
uint32_t spawnId = *(const uint32_t*)data;
uint8_t count = data[9];
- QList<uint16_t> listed;
+ QList<uint32_t> listed;
// The list is scoped to the spawn id it carries: the player (OP_BuffList),
// the pet (OP_PetBuffList), etc. Resolve the owner - player when the id
@@ -406,7 +406,7 @@
if (pos < len) pos++; // NUL
pos += 4; // u32 slot
- listed.append(uint16_t(spellId));
+ listed.append(spellId);
// A null spell (id not in this spells_us.txt - e.g. a new spell after a
// game patch, or no spell file) is still shown and tracked: update() falls
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.h 2026-07-18 00:07:36 UTC (rev 1671)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.h 2026-07-18 00:12:00 UTC (rev 1672)
@@ -63,7 +63,7 @@
SpellItem();
// get accessors
- uint16_t spellId() const;
+ uint32_t spellId() const;
uint16_t targetId() const;
uint16_t casterId() const;
time_t castTime() const;
@@ -78,7 +78,7 @@
void setPermanent(bool p) { m_permanent = p; }
// set accessors
- void setSpellId(uint16_t spellid);
+ void setSpellId(uint32_t spellid);
void setTargetId(uint16_t target);
void setCasterId(uint16_t caster);
void setSpellName(const QString& name);
@@ -86,10 +86,10 @@
void setTargetName(const QString& name);
void updateCastTime();
- void update(uint16_t spellId, const Spell* spell, int duration,
+ void update(uint32_t spellId, const Spell* spell, int duration,
uint16_t casterId, const QString& casterName,
uint16_t targetId, const QString& targetName);
-
+
private:
QString m_spellName;
QString m_casterName;
@@ -98,8 +98,8 @@
bool m_permanent;
timeval m_castTime;
- uint16_t m_spellId;
- uint16_t m_casterId;
+ uint32_t m_spellId;
+ uint16_t m_casterId;
uint16_t m_targetId;
struct startCastStruct m_cast; // Needed?
@@ -106,7 +106,7 @@
};
-inline uint16_t SpellItem::spellId() const
+inline uint32_t SpellItem::spellId() const
{
return m_spellId;
}
@@ -151,7 +151,7 @@
return m_casterName;
}
-inline void SpellItem::setSpellId(uint16_t spellid)
+inline void SpellItem::setSpellId(uint32_t spellid)
{
m_spellId = spellid;
}
@@ -213,10 +213,10 @@
protected:
void deleteSpell(SpellItem *);
- SpellItem* findSpell(uint16_t spellId,
+ SpellItem* findSpell(uint32_t spellId,
uint16_t targetId, const QString& targetName);
- SpellItem* findSpell(int spell_id);
- SpellItem* FindSpell(int spell_id, int target_id);
+ SpellItem* findSpell(uint32_t spell_id);
+ SpellItem* FindSpell(uint32_t spell_id, int target_id);
private:
Player* m_player;
Modified: showeq/branches/xerxes-trunk-dev/src/util.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/util.cpp 2026-07-18 00:07:36 UTC (rev 1671)
+++ showeq/branches/xerxes-trunk-dev/src/util.cpp 2026-07-18 00:12:00 UTC (rev 1672)
@@ -121,12 +121,12 @@
}
QString
-spell_name (uint16_t spellId)
+spell_name (uint32_t spellId)
{
if (spellId < (sizeof(spellInfo) / sizeof(spellInfoStruct)))
return spellInfo[spellId].name;
else
- return QString::number(spellId, 16);
+ return QString::number(spellId);
}
QString
Modified: showeq/branches/xerxes-trunk-dev/src/util.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/util.h 2026-07-18 00:07:36 UTC (rev 1671)
+++ showeq/branches/xerxes-trunk-dev/src/util.h 2026-07-18 00:12:00 UTC (rev 1672)
@@ -51,7 +51,7 @@
QString Commanate (uint32_t number);
QString classString(uint8_t classVal);
-QString spell_name (uint16_t spellId);
+QString spell_name (uint32_t spellId);
QString language_name (uint8_t langId);
QString skill_name (uint16_t skillId);
QString size_name (uint8_t size);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-18 00:07:39
|
Revision: 1671
http://sourceforge.net/p/seq/svn/1671
Author: xerxes00
Date: 2026-07-18 00:07:36 +0000 (Sat, 18 Jul 2026)
Log Message:
-----------
Add pet buff window, buff-list decode, and buff-freeze zones
Decode OP_BuffList (self) and OP_PetBuffList (pet) as authoritative
per-spawn buff sets: add/update buffs with the server's real remaining
durations, prune buffs the server dropped (so clicking a buff off removes
it from the list), and resolve the owner by spawn id (an unresolved spawn
is skipped, never mis-attributed to the player). Skip the non-list marker
records, and show a spell with no spells_us.txt entry by its numeric id so
it never silently vanishes. Map OP_TargetBuffList and OP_ShortBuffList for
documentation (not yet wired).
Hold buff durations steady in buff-freeze zones (Plane of Knowledge, guild
lobby/hall, Nexus) for spells flagged duration-frozen in spells_us.txt
(new field-125 parse), matching the client. Trim the numeric instance
suffix from spawn names shown in the list.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
showeq/branches/xerxes-trunk-dev/src/interface.cpp
showeq/branches/xerxes-trunk-dev/src/spells.cpp
showeq/branches/xerxes-trunk-dev/src/spells.h
showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
showeq/branches/xerxes-trunk-dev/src/spellshell.h
Modified: showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-17 20:05:20 UTC (rev 1670)
+++ showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-18 00:07:36 UTC (rev 1671)
@@ -1008,4 +1008,20 @@
<comment></comment>
</opcode>
-->
+ <opcode id="0ddc" name="OP_BuffList" updated="07/15/26">
+ <comment>Authoritative per-spawn buff set (spellId + remaining ticks + caster); re-fires on every buff change.</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="9090" name="OP_PetBuffList" updated="07/15/26">
+ <comment>Per-spawn buff set for the player's pet; same format as OP_BuffList, decoded by SpellShell::buffList.</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="d702" name="OP_TargetBuffList" updated="07/15/26">
+ <comment>Buff set of the current target; same format as OP_BuffList. Mapped to silence the unknown log; not wired to the spell list (avoids target-buff clutter).</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="0faf" name="OP_ShortBuffList" updated="07/15/26">
+ <comment>Self short-buff/song window (Chorus of Marr etc). Fixed-size format, distinct from OP_BuffList; mapped to silence the unknown log, decoder TBD.</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
</seqopcodes>
Modified: showeq/branches/xerxes-trunk-dev/src/interface.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-17 20:05:20 UTC (rev 1670)
+++ showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-18 00:07:36 UTC (rev 1671)
@@ -986,6 +986,11 @@
// connect the SpellShell slots to ZoneMgr signals
connect(m_zoneMgr, SIGNAL(zoneChanged(const QString&)),
m_spellShell, SLOT(zoneChanged()));
+ // track whether the current zone freezes buff durations
+ connect(m_zoneMgr, SIGNAL(zoneBegin(const QString&)),
+ m_spellShell, SLOT(updateFreezeZone(const QString&)));
+ connect(m_zoneMgr, SIGNAL(zoneChanged(const QString&)),
+ m_spellShell, SLOT(updateFreezeZone(const QString&)));
// connect the SpellShell slots to SpawnShell signals
connect(m_spawnShell, SIGNAL(killSpawn(const Item*, const Item*, uint16_t)),
@@ -1004,6 +1009,16 @@
m_packet->connect2("OP_Buff", SP_Zone, DIR_Server|DIR_Client,
"buffStruct", SZC_Match,
m_spellShell, SLOT(buff(const uint8_t*, size_t, uint8_t)));
+ // OP_BuffList is the authoritative per-spawn buff set, re-sent on every buff
+ // change with real remaining durations; buffList adds/updates and prunes.
+ // OP_PetBuffList is the same format for the player's pet, so it shares the
+ // handler (which scopes everything by the spawn id in the packet).
+ m_packet->connect2("OP_BuffList", SP_Zone, DIR_Server,
+ "uint8_t", SZC_None,
+ m_spellShell, SLOT(buffList(const uint8_t*, size_t, uint8_t)));
+ m_packet->connect2("OP_PetBuffList", SP_Zone, DIR_Server,
+ "uint8_t", SZC_None,
+ m_spellShell, SLOT(buffList(const uint8_t*, size_t, uint8_t)));
m_packet->connect2("OP_Action", SP_Zone, DIR_Server|DIR_Client,
"actionStruct", SZC_Match,
m_spellShell, SLOT(action(const uint8_t*, size_t, uint8_t)));
Modified: showeq/branches/xerxes-trunk-dev/src/spells.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spells.cpp 2026-07-17 20:05:20 UTC (rev 1670)
+++ showeq/branches/xerxes-trunk-dev/src/spells.cpp 2026-07-18 00:07:36 UTC (rev 1671)
@@ -176,6 +176,9 @@
m_buffDurationFormula = spellInfo[11].toUShort(); //spells_us.txt layout changed December 2018
m_buffDurationArgument = spellInfo[12].toUShort(); //spells_us.txt layout changed December 2018
m_targetType = uint8_t(spellInfo[32].toUShort()); //spells_us.txt layout changed December 2018
+ // durationfreeze (IS_COUNTDOWN_HELD): set on beneficial buffs that the server
+ // holds steady in buff-freeze zones (Plane of Knowledge, guild lobby, etc).
+ m_buffDurationFrozen = (spellInfo.count() > 125) && (spellInfo[125].toUShort() != 0);
for (size_t i = 0; i < playerClasses; i++)
m_classLevels[i] = uint8_t(spellInfo[38 + i].toUShort()); //spells_us.txt layout changed December 2018
Modified: showeq/branches/xerxes-trunk-dev/src/spells.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spells.h 2026-07-17 20:05:20 UTC (rev 1670)
+++ showeq/branches/xerxes-trunk-dev/src/spells.h 2026-07-18 00:07:36 UTC (rev 1671)
@@ -49,6 +49,7 @@
const QString& name() const { return m_name; }
uint8_t level(uint8_t class_) const;
uint8_t targetType() const { return m_targetType; }
+ bool buffDurationFrozen() const { return m_buffDurationFrozen; }
QString spellField(uint8_t field) const;
@@ -60,6 +61,7 @@
int16_t m_buffDurationFormula;
int16_t m_buffDurationArgument;
uint8_t m_targetType;
+ bool m_buffDurationFrozen;
uint8_t m_classLevels[playerClasses];
};
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-17 20:05:20 UTC (rev 1670)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-18 00:07:36 UTC (rev 1671)
@@ -129,7 +129,8 @@
m_player(player),
m_spawnShell(spawnshell),
m_spells(spells),
- m_lastPlayerSpell(0)
+ m_lastPlayerSpell(0),
+ m_freezeZone(false)
{
setObjectName("spellshell");
m_timer = new QTimer(this);
@@ -345,6 +346,131 @@
}
}
+// OP_BuffList: the authoritative buff set for a spawn, re-sent on every buff
+// change (zone-in, cast, click-off) with real remaining durations. It is the
+// source of truth for the spell list: it adds/updates the buffs it carries and
+// prunes any it dropped (which is how a clicked-off buff leaves the window).
+void SpellShell::buffList(const uint8_t* data, size_t len, uint8_t dir)
+{
+ if (dir == DIR_Client || len < 15)
+ return;
+
+ // byte 8 == 1 marks an authoritative full buff list; the server also sends
+ // byte 8 == 0 records (a single 0xffffffff slot) that are not a list - ignore
+ // them so the prune step below never runs against a bogus empty set.
+ if (data[8] != 1)
+ return;
+
+ uint32_t spawnId = *(const uint32_t*)data;
+ uint8_t count = data[9];
+ QList<uint16_t> listed;
+
+ // The list is scoped to the spawn id it carries: the player (OP_BuffList),
+ // the pet (OP_PetBuffList), etc. Resolve the owner - player when the id
+ // matches, otherwise the named spawn. An unresolved spawn is skipped rather
+ // than blamed on the player, so a not-yet-tracked pet can never prune the
+ // player's own buffs.
+ uint16_t targetId = uint16_t(spawnId);
+ QString targetName;
+ bool isPlayer = false;
+ if (spawnId == m_player->id())
+ {
+ targetName = m_player->name();
+ isPlayer = true;
+ }
+ else
+ {
+ const Item* tgt = m_spawnShell->findID(tSpawn, spawnId);
+ if (!tgt)
+ return;
+ targetName = tgt->name();
+ // Spawn names carry a numeric instance suffix (e.g. a trailing "00"); show
+ // the clean name in the spell list.
+ while (!targetName.isEmpty() && targetName.at(targetName.length() - 1).isDigit())
+ targetName.chop(1);
+ }
+
+ size_t pos = 15;
+ for (uint8_t n = 0; n < count && pos + 12 <= len; n++)
+ {
+ uint32_t spellId = *(const uint32_t*)(data + pos);
+
+ // Record head: spellId, remaining ticks at +4, then the printable caster
+ // name begins at +12.
+ int32_t remaining = *(const int32_t*)(data + pos + 4);
+ pos += 12;
+
+ QString caster;
+ while (pos < len && data[pos])
+ caster += QChar(data[pos++]);
+ if (pos < len) pos++; // NUL
+ pos += 4; // u32 slot
+
+ listed.append(uint16_t(spellId));
+
+ // A null spell (id not in this spells_us.txt - e.g. a new spell after a
+ // game patch, or no spell file) is still shown and tracked: update() falls
+ // back to the decimal spell id for the name so it stays lookupable.
+ const Spell* spell = m_spells->spell(spellId);
+
+ // remaining <= 0 => permanent buff (no timer; only a click-off removes it)
+ bool permanent = (remaining <= 0);
+ int duration = permanent ? 0 : remaining * 6;
+
+ // For the player's own buffs, match id-agnostically: the profile
+ // (buffLoad) and casts (selfStartSpellCast) may have keyed this buff under
+ // a different player spawn id (it churns at zone-in), so find it by spell +
+ // player name and adopt the current id, merging rather than duplicating.
+ SpellItem* item = NULL;
+ if (isPlayer)
+ {
+ for (QList<SpellItem*>::Iterator it = m_spellList.begin();
+ it != m_spellList.end(); ++it)
+ if (((*it)->spellId() == spellId) && ((*it)->targetName() == targetName))
+ {
+ item = *it;
+ break;
+ }
+ }
+ else
+ item = findSpell(spellId, targetId, targetName);
+
+ if (item)
+ {
+ item->update(spellId, spell, duration, 0, caster, targetId, targetName);
+ item->setPermanent(permanent);
+ emit changeSpell(item);
+ }
+ else
+ {
+ item = new SpellItem();
+ item->update(spellId, spell, duration, 0, caster, targetId, targetName);
+ item->setPermanent(permanent);
+ m_spellList.append(item);
+ if ((m_spellList.count() > 0) && (!m_timer->isActive()))
+ m_timer->start(1000 *
+ pSEQPrefs->getPrefInt("SpellTimer", "SpellList", 6));
+ emit addSpell(item);
+ }
+ }
+
+ // The list is authoritative for this spawn: prune tracked buffs it dropped.
+ // Match the player's buffs by name (id-agnostic) so stale-id entries left by
+ // the zone-in id churn are also pruned; other spawns match by id.
+ QList<SpellItem*> stripped;
+ for (QList<SpellItem*>::Iterator it = m_spellList.begin();
+ it != m_spellList.end(); ++it)
+ {
+ bool owned = isPlayer ? ((*it)->targetName() == targetName)
+ : ((*it)->targetId() == targetId);
+ if (owned && !listed.contains((*it)->spellId()))
+ stripped.append(*it);
+ }
+ for (QList<SpellItem*>::Iterator it = stripped.begin();
+ it != stripped.end(); ++it)
+ deleteSpell(*it);
+}
+
void SpellShell::action(const uint8_t* data, size_t, uint8_t)
{
const actionStruct* a = (const actionStruct*)data;
@@ -486,7 +612,7 @@
m_lastPlayerSpell = 0;
SpellItem* spell;
for(QList<SpellItem*>::Iterator it = m_spellList.begin();
- it != m_spellList.end(); it++)
+ it != m_spellList.end(); it++)
{
spell = *it;
@@ -496,6 +622,24 @@
}
}
+// Zones where the server holds buff durations steady (the client shows them
+// frozen). In these zones, spells flagged duration-frozen in spells_us.txt do
+// not count down in the spell list. This is a maintained list - append new
+// buff-freeze zones (short names) as they are found.
+void SpellShell::updateFreezeZone(const QString& shortZoneName)
+{
+ static const char* freezeZones[] = {
+ "poknowledge", "guildlobby", "guildhall", "nexus"
+ };
+ m_freezeZone = false;
+ for (size_t i = 0; i < sizeof(freezeZones) / sizeof(freezeZones[0]); i++)
+ if (shortZoneName == freezeZones[i])
+ {
+ m_freezeZone = true;
+ break;
+ }
+}
+
void SpellShell::killSpawn(const Item* deceased)
{
uint16_t id = deceased->id();
@@ -549,7 +693,13 @@
// permanent buffs (profile duration -1, e.g. illusions/forms) do not
// count down or expire - only a fade removes them.
- if (spell->permanent())
+ // In a buff-freeze zone the server holds durations steady, so a spell that
+ // is flagged duration-frozen in spells_us.txt (buffDurationFrozen) must not
+ // tick down here either. Both conditions are required: the zone freezes AND
+ // the spell is flagged - detrimental/non-frozen spells still count down.
+ const Spell* sp = m_spells->spell(spell->spellId());
+ if (spell->permanent() ||
+ (m_freezeZone && sp && sp->buffDurationFrozen()))
{
it++;
continue;
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.h 2026-07-17 20:05:20 UTC (rev 1670)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.h 2026-07-18 00:07:36 UTC (rev 1671)
@@ -202,10 +202,12 @@
void selfStartSpellCast(const uint8_t*);
void buffLoad(const spellBuff*);
void buff(const uint8_t*, size_t, uint8_t);
+ void buffList(const uint8_t*, size_t, uint8_t);
void action(const uint8_t*, size_t, uint8_t);
void simpleMessage(const uint8_t* cmsg, size_t, uint8_t);
void spellMessage(QString&);
void zoneChanged(void);
+ void updateFreezeZone(const QString& shortZoneName);
void killSpawn(const Item* deceased);
void timeout();
@@ -223,6 +225,7 @@
QList<SpellItem *> m_spellList;
SpellItem* m_lastPlayerSpell;
QTimer *m_timer;
+ bool m_freezeZone;
};
#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-17 20:05:22
|
Revision: 1670
http://sourceforge.net/p/seq/svn/1670
Author: xerxes00
Date: 2026-07-17 20:05:20 +0000 (Fri, 17 Jul 2026)
Log Message:
-----------
Handle permanent buffs in the spell list
Permanent profile buffs (duration -1) were computed as a small negative
duration, so timeout() expired them one tick after load and dropped them
from the spell list. Track a permanent flag on SpellItem: buffLoad marks
duration -1 as permanent, durationStr shows "Permanent", timeout() skips
them, and the list renders them green instead of expiry-red.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/src/spelllist.cpp
showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
showeq/branches/xerxes-trunk-dev/src/spellshell.h
Modified: showeq/branches/xerxes-trunk-dev/src/spelllist.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spelllist.cpp 2026-07-17 20:00:59 UTC (rev 1669)
+++ showeq/branches/xerxes-trunk-dev/src/spelllist.cpp 2026-07-17 20:05:20 UTC (rev 1670)
@@ -74,7 +74,11 @@
//color change by Worried
//change spell colors according to time remaining
- if (m_item->duration() > 120)
+ // permanent buffs (no timer) are not "about to expire" - show them green
+ // rather than the red the <=12s bucket would otherwise give.
+ if (m_item->permanent())
+ this->setTextColor(QColor(0, 140, 0));
+ else if (m_item->duration() > 120)
this->setTextColor(Qt::black);
else if (m_item->duration() <= 120 and m_item->duration() > 60)
this->setTextColor(QColor(128,54,193));
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-17 20:00:59 UTC (rev 1669)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-17 20:05:20 UTC (rev 1670)
@@ -36,6 +36,7 @@
SpellItem::SpellItem()
: m_duration(0),
+ m_permanent(false),
m_spellId(0),
m_casterId(0),
m_targetId(0)
@@ -69,6 +70,8 @@
QString SpellItem::durationStr() const
{
+ if (m_permanent)
+ return "Permanent";
QString text;
int d = m_duration;
if (d < 0)
@@ -269,19 +272,25 @@
#endif // DIAG_SPELLSHELL
const Spell* spell = m_spells->spell(c->spellid);
- int duration = c->duration * 6;
+ // A profile buff with duration -1 is permanent (no timer); it must not
+ // enter the countdown as a small negative duration, which the list would
+ // render red and timeout() would expire after one tick.
+ bool permanent = (c->duration == -1);
+ int duration = permanent ? 0 : c->duration * 6;
SpellItem *item = findSpell(c->spellid, m_player->id(), m_player->name());
- if (item)
+ if (item)
{ // exists
- item->update(c->spellid, spell, duration,
+ item->update(c->spellid, spell, duration,
0, "Buff", m_player->id(), m_player->name());
+ item->setPermanent(permanent);
emit changeSpell(item);
- }
- else
+ }
+ else
{ // new spell
item = new SpellItem();
- item->update(c->spellid, spell, duration,
+ item->update(c->spellid, spell, duration,
0, "Buff", m_player->id(), m_player->name());
+ item->setPermanent(permanent);
m_spellList.append(item);
if ((m_spellList.count() > 0) && (!m_timer->isActive()))
m_timer->start(1000 *
@@ -538,6 +547,14 @@
{
spell = *it;
+ // permanent buffs (profile duration -1, e.g. illusions/forms) do not
+ // count down or expire - only a fade removes them.
+ if (spell->permanent())
+ {
+ it++;
+ continue;
+ }
+
int d = spell->duration() -
pSEQPrefs->getPrefInt("SpellTimer", "SpellList", 6);
if (d > -6)
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.h 2026-07-17 20:00:59 UTC (rev 1669)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.h 2026-07-17 20:05:20 UTC (rev 1670)
@@ -74,7 +74,9 @@
const QString targetName() const;
const QString casterName() const;
void setDuration(int);
-
+ bool permanent() const { return m_permanent; }
+ void setPermanent(bool p) { m_permanent = p; }
+
// set accessors
void setSpellId(uint16_t spellid);
void setTargetId(uint16_t target);
@@ -93,6 +95,7 @@
QString m_casterName;
QString m_targetName;
int m_duration;
+ bool m_permanent;
timeval m_castTime;
uint16_t m_spellId;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-17 20:01:02
|
Revision: 1669
http://sourceforge.net/p/seq/svn/1669
Author: xerxes00
Date: 2026-07-17 20:00:59 +0000 (Fri, 17 Jul 2026)
Log Message:
-----------
Quality-of-life and log hygiene fixes
Reduces redundant map reloads (skip the reload zoneEnd() issues right
after zoneBegin() loaded the same zone, and the pre-zone unknown-zone
load attempt). Routes spell-timer notices to the MT_Spell message type
so they filter with cast messages. Tidies money/LDoN reporting to skip
empty wallet lines and collapse all-zero point lines, and trims noisy
debug logging.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/conf/seqdef.xml
showeq/branches/xerxes-trunk-dev/src/category.cpp
showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.cpp
showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.h
showeq/branches/xerxes-trunk-dev/src/filtermgr.cpp
showeq/branches/xerxes-trunk-dev/src/guild.cpp
showeq/branches/xerxes-trunk-dev/src/map.cpp
showeq/branches/xerxes-trunk-dev/src/map.h
showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
Modified: showeq/branches/xerxes-trunk-dev/conf/seqdef.xml
===================================================================
--- showeq/branches/xerxes-trunk-dev/conf/seqdef.xml 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/conf/seqdef.xml 2026-07-17 20:00:59 UTC (rev 1669)
@@ -291,7 +291,7 @@
<comment>Display Cold Resist</comment>
</property>
<property name="showAGI" >
- <bool value="false" />
+ <bool value="true" />
<comment>Display AGIlity</comment>
</property>
<property name="showINT" >
Modified: showeq/branches/xerxes-trunk-dev/src/category.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/category.cpp 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/category.cpp 2026-07-17 20:00:59 UTC (rev 1669)
@@ -370,7 +370,7 @@
// signal that the categories have been loaded
emit loadedCategories();
- seqInfo("Categories Reloaded");
+ seqDebug("Categories Reloaded");
}
void CategoryMgr::savePrefs(void)
Modified: showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.cpp 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.cpp 2026-07-17 20:00:59 UTC (rev 1669)
@@ -73,6 +73,18 @@
return ret;
}
+// Spell-timer notices (e.g. "'...' finished") emitted as MT_Spell
+// so they fall under the same filter as cast messages, instead of the MT_Info
+// bucket seqInfo would put them in.
+int seqSpell(const char* format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int ret = seqMessage(MT_Spell, format, ap);
+ va_end(ap);
+ return ret;
+}
+
int seqWarn(const char* format, ...)
{
va_list ap;
Modified: showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.h 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/diagnosticmessages.h 2026-07-17 20:00:59 UTC (rev 1669)
@@ -26,6 +26,7 @@
int seqDebug(const char* format, ...);
int seqInfo(const char* format, ...);
+int seqSpell(const char* format, ...);
int seqWarn(const char* format, ...);
void seqFatal(const char* format, ...);
Modified: showeq/branches/xerxes-trunk-dev/src/filtermgr.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/filtermgr.cpp 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/filtermgr.cpp 2026-07-17 20:00:59 UTC (rev 1669)
@@ -135,7 +135,8 @@
m_filterFile = fileInfo.absoluteFilePath();
- seqInfo("Loading Filters from '%s'", m_filterFile.toLatin1().data());
+ if (!m_filterFile.isEmpty())
+ seqInfo("Loading Filters from '%s'", m_filterFile.toLatin1().data());
m_filters->load(m_filterFile);
@@ -149,7 +150,8 @@
m_filterFile = fileInfo.absoluteFilePath();
- seqInfo("Loading Filters from '%s'", m_filterFile.toLatin1().data());
+ if (!m_filterFile.isEmpty())
+ seqInfo("Loading Filters from '%s'", m_filterFile.toLatin1().data());
m_filters->load(m_filterFile);
@@ -240,7 +242,8 @@
m_zoneFilterFile = fileInfo.absoluteFilePath();
- seqInfo("Loading Zone Filter File: %s", m_zoneFilterFile.toLatin1().data());
+ if (!m_zoneFilterFile.isEmpty())
+ seqInfo("Loading Zone Filter File: %s", m_zoneFilterFile.toLatin1().data());
m_zoneFilters->load(m_zoneFilterFile);
@@ -256,7 +259,8 @@
m_zoneFilterFile = fileInfo.absoluteFilePath();
- seqInfo("Loading Zone Filter File: %s", m_zoneFilterFile.toLatin1().data());
+ if (!m_zoneFilterFile.isEmpty())
+ seqInfo("Loading Zone Filter File: %s", m_zoneFilterFile.toLatin1().data());
m_zoneFilters->load(m_zoneFilterFile);
Modified: showeq/branches/xerxes-trunk-dev/src/guild.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/guild.cpp 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/guild.cpp 2026-07-17 20:00:59 UTC (rev 1669)
@@ -201,7 +201,7 @@
}
guildsfile.close();
- seqInfo("GuildMgr: Guildsfile loaded");
+ seqDebug("GuildMgr: Guildsfile loaded");
}
else
seqWarn("GuildMgr: Could not load guildsfile, %s", guildsFileName.toLatin1().data());
Modified: showeq/branches/xerxes-trunk-dev/src/map.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/map.cpp 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/map.cpp 2026-07-17 20:00:59 UTC (rev 1669)
@@ -332,7 +332,8 @@
// clear the map data
m_mapData.clear();
-
+ m_loadedZoneName = QString();
+
// signal that the map has been unloaded
emit mapUnloaded();
@@ -349,7 +350,8 @@
// clear the map data
m_mapData.clear();
-
+ m_loadedZoneName = QString();
+
// signal that the map has been unloaded
emit mapUnloaded();
@@ -370,7 +372,17 @@
void MapMgr::loadZoneMap(const QString& shortZoneName)
{
+ // Pre-zone placeholder: at startup (and between sessions) the zone is
+ // "unknown" - no real zone yet - so don't try to load, or warn about a
+ // missing map for, "unknown". Real zones without a map still warn.
+ if (shortZoneName.isEmpty() || shortZoneName == "unknown")
+ return;
+ // Skip the redundant reload zoneEnd() issues for a zone zoneBegin()
+ // already loaded. A genuine re-zone clears m_loadedZoneName first.
+ if (shortZoneName == m_loadedZoneName)
+ return;
+
bool found = false;
QString extension = "";
@@ -422,6 +434,9 @@
}
loadFileMap(mapFiles);
+
+ // remember the loaded zone so zoneEnd() won't reload it
+ m_loadedZoneName = shortZoneName;
}
void MapMgr::loadMap ()
@@ -490,9 +505,9 @@
#endif /* DEBUGMAP */
if (import)
- seqInfo("Attempting to import map: %s", fileName.toLatin1().data());
+ seqDebug("Attempting to import map: %s", fileName.toLatin1().data());
else
- seqInfo("Attempting to load map: %s", fileName.toLatin1().data());
+ seqDebug("Attempting to load map: %s", fileName.toLatin1().data());
// if not a forced load, and the same map is already loaded, do nothing
Modified: showeq/branches/xerxes-trunk-dev/src/map.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/map.h 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/map.h 2026-07-17 20:00:59 UTC (rev 1669)
@@ -226,6 +226,11 @@
MapData m_mapData;
QHash<int, uint16_t> m_spawnAggroRange;
+ // Short zone name currently loaded; used to skip the redundant reload that
+ // zoneEnd() issues right after zoneBegin() already loaded the same zone.
+ // Cleared whenever the map data is cleared for a genuine reload.
+ QString m_loadedZoneName;
+
QString m_curLineColor;
QString m_curLineName;
QString m_curLocationColor;
Modified: showeq/branches/xerxes-trunk-dev/src/messageshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/messageshell.cpp 2026-07-17 20:00:59 UTC (rev 1669)
@@ -463,7 +463,7 @@
void MessageShell::zoneEntryClient(const ClientZoneEntryStruct* zsentry)
{
- m_messages->addMessage(MT_Zone, "EntryCode: Client");
+ m_messages->addMessage(MT_Debug, "EntryCode: Client");
}
void MessageShell::zoneChanged(const zoneChangeStruct* zoneChange, size_t, uint8_t dir)
@@ -492,7 +492,7 @@
QString tempStr;
tempStr = "NewCode: Zone: ";
tempStr += newZoneShortName + " (" + newZoneLongName + ")";
- m_messages->addMessage(MT_Zone, tempStr);
+ m_messages->addMessage(MT_Debug, tempStr);
}
void MessageShell::zoneBegin(const QString& shortZoneName)
@@ -951,39 +951,54 @@
#endif
m_messages->addMessage(MT_Player, message);
+ // Money lines: skip any wallet that is entirely empty.
+ if (player->profile.platinum || player->profile.gold ||
+ player->profile.silver || player->profile.copper)
+ {
#if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
message = QString::asprintf("PlayerMoney: P=%d G=%d S=%d C=%d",
- player->profile.platinum, player->profile.gold,
+ player->profile.platinum, player->profile.gold,
player->profile.silver, player->profile.copper);
#else
message.sprintf("PlayerMoney: P=%d G=%d S=%d C=%d",
- player->profile.platinum, player->profile.gold,
+ player->profile.platinum, player->profile.gold,
player->profile.silver, player->profile.copper);
#endif
m_messages->addMessage(MT_Player, message);
-
+ }
+
+ if (player->platinum_bank || player->gold_bank ||
+ player->silver_bank || player->copper_bank)
+ {
#if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
message = QString::asprintf("BankMoney: P=%d G=%d S=%d C=%d",
- player->platinum_bank, player->gold_bank,
+ player->platinum_bank, player->gold_bank,
player->silver_bank, player->copper_bank);
#else
message.sprintf("BankMoney: P=%d G=%d S=%d C=%d",
- player->platinum_bank, player->gold_bank,
+ player->platinum_bank, player->gold_bank,
player->silver_bank, player->copper_bank);
#endif
m_messages->addMessage(MT_Player, message);
+ }
+ if (player->profile.platinum_cursor || player->profile.gold_cursor ||
+ player->profile.silver_cursor || player->profile.copper_cursor)
+ {
#if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
message = QString::asprintf("CursorMoney: P=%d G=%d S=%d C=%d",
- player->profile.platinum_cursor, player->profile.gold_cursor,
+ player->profile.platinum_cursor, player->profile.gold_cursor,
player->profile.silver_cursor, player->profile.copper_cursor);
#else
message.sprintf("CursorMoney: P=%d G=%d S=%d C=%d",
- player->profile.platinum_cursor, player->profile.gold_cursor,
+ player->profile.platinum_cursor, player->profile.gold_cursor,
player->profile.silver_cursor, player->profile.copper_cursor);
#endif
m_messages->addMessage(MT_Player, message);
+ }
+ if (player->platinum_shared)
+ {
#if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
message = QString::asprintf("SharedMoney: P=%d",
player->platinum_shared);
@@ -992,15 +1007,19 @@
player->platinum_shared);
#endif
m_messages->addMessage(MT_Player, message);
+ }
+ if (player->currentRadCrystals || player->currentEbonCrystals)
+ {
#if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
- message = QString::asprintf("DoN Crystals: Radiant=%d Ebon=%d",
- player->currentRadCrystals, player->currentEbonCrystals);
+ message = QString::asprintf("DoN Crystals: Radiant=%d Ebon=%d",
+ player->currentRadCrystals, player->currentEbonCrystals);
#else
- message.sprintf("DoN Crystals: Radiant=%d Ebon=%d",
- player->currentRadCrystals, player->currentEbonCrystals);
+ message.sprintf("DoN Crystals: Radiant=%d Ebon=%d",
+ player->currentRadCrystals, player->currentEbonCrystals);
#endif
- m_messages->addMessage(MT_Player, message);
+ m_messages->addMessage(MT_Player, message);
+ }
// charProfileStruct.exp hasn't been found
// message = "Exp: " + Commanate(player->exp);
@@ -1062,18 +1081,19 @@
}
}
- message = "LDoN Earned Guk Points: " + Commanate(player->ldon_guk_points);
- m_messages->addMessage(MT_Player, message);
- message = "LDoN Earned Mira Points: " + Commanate(player->ldon_mir_points);
- m_messages->addMessage(MT_Player, message);
- message = "LDoN Earned MMC Points: " + Commanate(player->ldon_mmc_points);
- m_messages->addMessage(MT_Player, message);
- message = "LDoN Earned Ruj Points: " + Commanate(player->ldon_ruj_points);
- m_messages->addMessage(MT_Player, message);
- message = "LDoN Earned Tak Points: " + Commanate(player->ldon_tak_points);
- m_messages->addMessage(MT_Player, message);
- message = "LDoN Unspent Points: " + Commanate(player->ldon_avail_points);
- m_messages->addMessage(MT_Player, message);
+ // LDoN points on one line; skip entirely when everything is zero.
+ if (player->ldon_guk_points || player->ldon_mir_points ||
+ player->ldon_mmc_points || player->ldon_ruj_points ||
+ player->ldon_tak_points || player->ldon_avail_points)
+ {
+ message = "LDoN Points: Guk=" + Commanate(player->ldon_guk_points)
+ + " Mir=" + Commanate(player->ldon_mir_points)
+ + " MMC=" + Commanate(player->ldon_mmc_points)
+ + " Ruj=" + Commanate(player->ldon_ruj_points)
+ + " Tak=" + Commanate(player->ldon_tak_points)
+ + " Unspent=" + Commanate(player->ldon_avail_points);
+ m_messages->addMessage(MT_Player, message);
+ }
}
void MessageShell::increaseSkill(const uint8_t* data)
Modified: showeq/branches/xerxes-trunk-dev/src/spellshell.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-17 18:19:21 UTC (rev 1668)
+++ showeq/branches/xerxes-trunk-dev/src/spellshell.cpp 2026-07-17 20:00:59 UTC (rev 1669)
@@ -443,16 +443,20 @@
// Your xxx has worn off.
// Your target resisted the xxx spell.
// Your spell fizzles.
- seqInfo("*** spellMessage *** %s", spell.toLatin1().data());
+#ifdef DIAG_SPELLSHELL
+ seqDebug("*** spellMessage *** %s", spell.toLatin1().data());
+#endif // DIAG_SPELLSHELL
+ // Dead: the spellMessage signal is never emitted (no caller in any tree),
+ // so this handler never runs.
if (spell.left(25) == QString("Your target resisted the ")) {
spell = spell.right(spell.length() - 25);
spell = spell.left(spell.length() - 7);
- seqInfo("RESIST: '%s'", spell.toLatin1().data());
+ //seqInfo("RESIST: '%s'", spell.toLatin1().data());
b = true;
} else if (spell.right(20) == QString(" spell has worn off.")) {
spell = spell.right(spell.length() - 5);
spell = spell.left(spell.length() - 20);
- seqInfo("WORE OFF: '%s'", spell.toLatin1().data());
+ //seqInfo("WORE OFF: '%s'", spell.toLatin1().data());
b = true;
}
@@ -544,7 +548,7 @@
}
else
{
- seqInfo("SpellItem '%s' finished.", (*it)->spellName().toLatin1().data());
+ seqSpell("'%s' finished.", (*it)->spellName().toLatin1().data());
if (m_lastPlayerSpell == spell)
m_lastPlayerSpell = 0;
emit delSpell(spell);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-17 18:19:24
|
Revision: 1668
http://sourceforge.net/p/seq/svn/1668
Author: xerxes00
Date: 2026-07-17 18:19:21 +0000 (Fri, 17 Jul 2026)
Log Message:
-----------
Add Alternate Advancement window
Adds a dockable AA list window (View -> Alternate Advancement) showing
owned AAs with name, rank, points spent, and unspent/assigned/total
totals. AA names resolve via a new DBStr loader for dbstr_us.txt
(graceful fallback to ids without it). Builds the table from
OP_SendAATable and the character profile.
Modified Paths:
--------------
showeq/branches/xerxes-trunk-dev/README
showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
showeq/branches/xerxes-trunk-dev/src/Makefile.am
showeq/branches/xerxes-trunk-dev/src/everquest.h
showeq/branches/xerxes-trunk-dev/src/interface.cpp
showeq/branches/xerxes-trunk-dev/src/interface.h
showeq/branches/xerxes-trunk-dev/src/s_everquest.h
Added Paths:
-----------
showeq/branches/xerxes-trunk-dev/src/aalist.cpp
showeq/branches/xerxes-trunk-dev/src/aalist.h
showeq/branches/xerxes-trunk-dev/src/aamgr.cpp
showeq/branches/xerxes-trunk-dev/src/aamgr.h
showeq/branches/xerxes-trunk-dev/src/dbstr.cpp
showeq/branches/xerxes-trunk-dev/src/dbstr.h
Modified: showeq/branches/xerxes-trunk-dev/README
===================================================================
--- showeq/branches/xerxes-trunk-dev/README 2026-07-17 17:48:07 UTC (rev 1667)
+++ showeq/branches/xerxes-trunk-dev/README 2026-07-17 18:19:21 UTC (rev 1668)
@@ -32,3 +32,39 @@
shows current command line arguments. Also look at the
conf/seqdef.xml file for configuration file options and defaults.
Most configuration changes can be done via the user interface.
+
+DATA FILES
+----------
+Some features read string/data files copied from the EverQuest client
+directory. Place these in a ShowEQ data directory - either your per-user
+dir ($HOME/.showeq) or the installed package data dir (pkgdatadir,
+e.g. /usr/local/share/showeq/). ShowEQ searches the per-user dir first,
+then pkgdatadir.
+
+ spells_us.txt spell data
+ eqstr_us.txt formatted message strings
+ dbstr_us.txt string database (AA titles, etc.) - required for the
+ Alternate Advancement window to show ability NAMES.
+ Without it, that window still works but lists abilities
+ as "AA title <id>". The filename is dbstr_us.txt (the
+ US-English database); there is no dbstr_en.txt.
+
+The file name each feature looks for can be overridden in the config
+(e.g. the DBStrFile setting under [Interface]).
+
+ALTERNATE ADVANCEMENT WINDOW
+----------------------------
+View -> Alternate Advancement lists the AAs your character owns, with the
+ability name, current rank (rank / max rank), points spent, and a footer
+of unspent / assigned / total AA points. Its purpose is to see at a glance
+which AAs you are actively leveling without scrolling the in-game AA UI.
+
+A "Hide AAs at max rank" checkbox at the bottom hides abilities already at
+their maximum rank so only in-progress ones remain. Its state is saved to
+the config file (HideMaxedAA under the [AAList] section) and restored on
+the next run; it defaults to off.
+
+Caveat: "max rank" is the ability's cap, not necessarily what you can buy
+right now - higher ranks may carry a character-level requirement, so an
+ability shown below its max (e.g. 3/4) does not guarantee the next rank is
+purchasable yet.
Modified: showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-17 17:48:07 UTC (rev 1667)
+++ showeq/branches/xerxes-trunk-dev/conf/zoneopcodes.xml 2026-07-17 18:19:21 UTC (rev 1668)
@@ -634,8 +634,9 @@
<opcode id="ffff" name="OP_VeteranRewards" updated="04/18/11">
<comment></comment>
</opcode>
- <opcode id="ffff" name="OP_SendAATable" updated="08/12/09">
- <comment></comment>
+ <opcode id="2719" name="OP_SendAATable" updated="07/15/26">
+ <comment>AA window</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
<opcode id="ffff" name="OP_SendAAStats" updated="08/12/09">
<comment></comment>
Modified: showeq/branches/xerxes-trunk-dev/src/Makefile.am
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/Makefile.am 2026-07-17 17:48:07 UTC (rev 1667)
+++ showeq/branches/xerxes-trunk-dev/src/Makefile.am 2026-07-17 18:19:21 UTC (rev 1668)
@@ -5,6 +5,9 @@
bin_PROGRAMS = showeq
showeq_SOURCES = \
+ aalist.cpp \
+ aamgr.cpp \
+ dbstr.cpp \
bazaarlog.cpp \
category.cpp \
combatlog.cpp \
@@ -74,6 +77,8 @@
showeq_moc_SRCS = \
+ aalist.moc \
+ aamgr.moc \
bazaarlog.moc \
category.moc \
combatlog.moc \
@@ -127,6 +132,8 @@
nodist_showeq_SOURCES = ui_mapicondialog.h $(showeq_moc_SRCS)
$(srcdir)/bazaarlog.cpp: bazaarlog.moc
+$(srcdir)/aalist.cpp: aalist.moc
+$(srcdir)/aamgr.cpp: aamgr.moc
$(srcdir)/category.cpp: category.moc
$(srcdir)/combatlog.cpp: combatlog.moc
$(srcdir)/compass.cpp: compass.moc
Added: showeq/branches/xerxes-trunk-dev/src/aalist.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/aalist.cpp (rev 0)
+++ showeq/branches/xerxes-trunk-dev/src/aalist.cpp 2026-07-17 18:19:21 UTC (rev 1668)
@@ -0,0 +1,156 @@
+/*
+ * aalist.cpp
+ * Copyright 2026 by the respective ShowEQ Developers
+ *
+ * This file is part of ShowEQ.
+ * http://www.sourceforge.net/projects/seq
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "aalist.h"
+#include "aamgr.h"
+#include "main.h" // for pSEQPrefs
+
+#include <QHeaderView>
+#include <QWidget>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QCheckBox>
+
+AAList::AAList(AAMgr* aaMgr, QWidget* parent, const char* name)
+ : SEQListView("AAList", parent, name),
+ m_aaMgr(aaMgr),
+ m_hideMaxed(false)
+{
+ m_hideMaxed = pSEQPrefs->getPrefBool("HideMaxedAA", preferenceName(), false);
+
+ addColumn("Ability");
+ addColumn("Rank");
+ addColumn("Points");
+
+ restoreColumns();
+
+ // Column sizing, applied AFTER restoreColumns so it is not overridden:
+ // the Ability column auto-fits the widest displayed name; Rank and
+ // Points are pinned to the same small width; nothing stretches to fill
+ // the pane (empty space to the right).
+ header()->setStretchLastSection(false);
+ header()->setSectionResizeMode(AACOL_NAME, QHeaderView::ResizeToContents);
+ header()->setSectionResizeMode(AACOL_RANK, QHeaderView::Interactive);
+ header()->setSectionResizeMode(AACOL_POINTS, QHeaderView::Interactive);
+ setColumnWidth(AACOL_RANK, 56);
+ setColumnWidth(AACOL_POINTS, 56);
+
+ // refresh only when the AA data actually changes
+ connect(m_aaMgr, SIGNAL(aaChanged()), this, SLOT(rebuild()));
+
+ rebuild();
+}
+
+AAList::~AAList()
+{
+}
+
+void AAList::setHideMaxed(bool hide)
+{
+ m_hideMaxed = hide;
+ pSEQPrefs->setPrefBool("HideMaxedAA", preferenceName(), hide);
+ rebuild();
+}
+
+void AAList::rebuild()
+{
+ // owned set is small; a full repopulate is simplest and cheap
+ clear();
+
+ const QList<AAMgr::Row> rows = m_aaMgr->ownedRows();
+ for (int i = 0; i < rows.size(); i++)
+ {
+ const AAMgr::Row& r = rows[i];
+
+ // optionally hide abilities already at their max rank. NOTE: max rank
+ // is the ability's cap, not necessarily obtainable right now - higher
+ // ranks can carry level requirements - so a non-maxed ability is not a
+ // guarantee the next rank is buyable yet.
+ if (m_hideMaxed && r.maxRank && r.rank >= r.maxRank)
+ continue;
+
+ QString rankStr;
+ if (r.maxRank)
+ rankStr = QString("%1/%2").arg(r.rank).arg(r.maxRank);
+ else if (r.rank)
+ rankStr = QString::number(r.rank);
+
+ QStringList vals;
+ vals << r.name << rankStr << QString::number(r.points);
+ SEQListViewItem* item = new SEQListViewItem(this, vals);
+ item->setTextAlignment(AACOL_RANK, Qt::AlignRight);
+ item->setTextAlignment(AACOL_POINTS, Qt::AlignRight);
+ }
+}
+
+AAListWindow::AAListWindow(AAMgr* aaMgr, QWidget* parent, const char* name)
+ : SEQWindow("AAList", "ShowEQ - Alternate Advancement", parent, name),
+ m_aaMgr(aaMgr)
+{
+ // container holds the list plus a totals footer line
+ QWidget* container = new QWidget(this);
+ QVBoxLayout* layout = new QVBoxLayout(container);
+ layout->setContentsMargins(2, 2, 2, 2);
+ layout->setSpacing(2);
+
+ m_aaList = new AAList(aaMgr, container, name);
+ m_totals = new QLabel(container);
+ m_hideMaxed = new QCheckBox("Hide AAs at max rank", container);
+ m_hideMaxed->setChecked(m_aaList->hideMaxed());
+ m_hideMaxed->setToolTip("Hide abilities already at their maximum rank.\n"
+ "Note: an ability that is not maxed may still be\n"
+ "un-buyable right now - higher ranks can require a\n"
+ "higher character level.");
+
+ layout->addWidget(m_aaList);
+ layout->addWidget(m_totals);
+ layout->addWidget(m_hideMaxed);
+
+ setWidget(container);
+
+ connect(m_hideMaxed, SIGNAL(toggled(bool)), m_aaList, SLOT(setHideMaxed(bool)));
+
+ connect(m_aaMgr, SIGNAL(aaChanged()), this, SLOT(updateTotals()));
+ updateTotals();
+}
+
+AAListWindow::~AAListWindow()
+{
+}
+
+void AAListWindow::updateTotals(void)
+{
+ m_totals->setText(QString("Unspent: %1 Assigned: %2 Total: %3")
+ .arg(m_aaMgr->unspent())
+ .arg(m_aaMgr->assigned())
+ .arg(m_aaMgr->spent()));
+}
+
+void AAListWindow::savePrefs(void)
+{
+ SEQWindow::savePrefs();
+ m_aaList->savePrefs();
+}
+
+#ifndef QMAKEBUILD
+#include "aalist.moc"
+#endif
Added: showeq/branches/xerxes-trunk-dev/src/aalist.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/aalist.h (rev 0)
+++ showeq/branches/xerxes-trunk-dev/src/aalist.h 2026-07-17 18:19:21 UTC (rev 1668)
@@ -0,0 +1,80 @@
+/*
+ * aalist.h
+ * Copyright 2026 by the respective ShowEQ Developers
+ *
+ * This file is part of ShowEQ.
+ * http://www.sourceforge.net/projects/seq
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EQAALIST_H
+#define EQAALIST_H
+
+#include <QWidget>
+
+#include "seqlistview.h"
+#include "seqwindow.h"
+
+#define AACOL_NAME 0
+#define AACOL_RANK 1
+#define AACOL_POINTS 2
+
+class AAMgr;
+class QLabel;
+class QCheckBox;
+
+class AAList : public SEQListView
+{
+ Q_OBJECT
+
+ public:
+ AAList(AAMgr* aaMgr, QWidget* parent = 0, const char* name = 0);
+ ~AAList();
+
+ public slots:
+ void rebuild();
+ void setHideMaxed(bool hide);
+
+ public:
+ bool hideMaxed() const { return m_hideMaxed; }
+
+ private:
+ AAMgr* m_aaMgr;
+ bool m_hideMaxed;
+};
+
+class AAListWindow : public SEQWindow
+{
+ Q_OBJECT
+
+ public:
+ AAListWindow(AAMgr* aaMgr, QWidget* parent = 0, const char* name = 0);
+ ~AAListWindow();
+
+ AAList* aaList() { return m_aaList; }
+
+ public slots:
+ void savePrefs(void);
+ void updateTotals(void);
+
+ private:
+ AAMgr* m_aaMgr;
+ AAList* m_aaList;
+ QLabel* m_totals;
+ QCheckBox* m_hideMaxed;
+};
+
+#endif // EQAALIST_H
Added: showeq/branches/xerxes-trunk-dev/src/aamgr.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/aamgr.cpp (rev 0)
+++ showeq/branches/xerxes-trunk-dev/src/aamgr.cpp 2026-07-17 18:19:21 UTC (rev 1668)
@@ -0,0 +1,163 @@
+/*
+ * aamgr.cpp
+ * Copyright 2026 by the respective ShowEQ Developers
+ *
+ * This file is part of ShowEQ.
+ * http://www.sourceforge.net/projects/seq
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "aamgr.h"
+#include "dbstr.h"
+#include "diagnosticmessages.h"
+
+#include <cstring>
+#include <algorithm>
+
+#include <QTimer>
+
+AAMgr::AAMgr(DBStr* dbstr, QObject* parent, const char* name)
+ : QObject(parent),
+ m_dbstr(dbstr),
+ m_spent(0),
+ m_assigned(0),
+ m_unspent(0),
+ m_changeScheduled(false)
+{
+ setObjectName(name);
+}
+
+AAMgr::~AAMgr()
+{
+}
+
+// Coalesce a whole record burst into a single UI refresh: schedule one
+// deferred emit rather than emitting per changed record.
+void AAMgr::markChanged()
+{
+ if (m_changeScheduled)
+ return;
+ m_changeScheduled = true;
+ QTimer::singleShot(0, this, SLOT(emitChanged()));
+}
+
+void AAMgr::emitChanged()
+{
+ m_changeScheduled = false;
+ emit aaChanged();
+}
+
+void AAMgr::aaInfo(const uint8_t* data, size_t len)
+{
+ // Only the fixed head (through rank, 37 bytes) is needed. The rest is a
+ // variable count-prefixed skills-requirement block plus prev/next ids.
+ if (len < sizeof(aaInfoStruct))
+ return;
+
+ const aaInfoStruct* r = (const aaInfoStruct*)data;
+
+ AADef def;
+ def.titleSID = r->titleSID;
+ def.rank = r->rank;
+ def.cost = r->cost;
+ def.aaID = r->aaID;
+
+ // update definition only if new or changed (avoids churn on re-sent bursts)
+ QHash<int32_t, AADef>::const_iterator it = m_defs.constFind(r->descID);
+ if (it == m_defs.constEnd() ||
+ it->titleSID != def.titleSID || it->rank != def.rank ||
+ it->cost != def.cost || it->aaID != def.aaID)
+ {
+ m_defs.insert(r->descID, def);
+
+ // track highest rank seen per AA title (ranks only grow within a session)
+ uint32_t& mx = m_maxRank[def.titleSID];
+ if (def.rank > mx)
+ mx = def.rank;
+
+ markChanged();
+ }
+}
+
+void AAMgr::player(const charProfileStruct* profile)
+{
+ if (!profile)
+ return;
+
+ // Rebuild the owned set from the profile's aa_array. Each nonzero entry
+ // is an owned AA: AA = current-rank descID, value = cumulative points.
+ QHash<int32_t, uint32_t> owned;
+ for (int i = 0; i < MAX_AA; i++)
+ {
+ const uint32_t val = profile->profile.aa_array[i].value;
+ if (val)
+ owned.insert((int32_t)profile->profile.aa_array[i].AA, val);
+ }
+
+ if (owned != m_owned ||
+ profile->profile.aa_spent != m_spent ||
+ profile->profile.aa_assigned != m_assigned ||
+ profile->profile.aa_unspent != m_unspent)
+ {
+ m_owned = owned;
+ m_spent = profile->profile.aa_spent;
+ m_assigned = profile->profile.aa_assigned;
+ m_unspent = profile->profile.aa_unspent;
+ markChanged();
+ }
+}
+
+QList<AAMgr::Row> AAMgr::ownedRows() const
+{
+ QList<Row> rows;
+
+ for (QHash<int32_t, uint32_t>::const_iterator it = m_owned.constBegin();
+ it != m_owned.constEnd(); ++it)
+ {
+ Row row;
+ row.points = it.value();
+
+ QHash<int32_t, AADef>::const_iterator dit = m_defs.constFind(it.key());
+ if (dit != m_defs.constEnd())
+ {
+ row.rank = dit->rank;
+ row.maxRank = m_maxRank.value(dit->titleSID, dit->rank);
+ row.name = m_dbstr ? m_dbstr->find(dit->titleSID) : QString();
+ if (row.name.isEmpty())
+ row.name = QString("AA title %1").arg(dit->titleSID);
+ }
+ else
+ {
+ // definition not received yet (profile arrived before the table)
+ row.rank = 0;
+ row.maxRank = 0;
+ row.name = QString("AA #%1").arg(it.key());
+ }
+
+ rows.append(row);
+ }
+
+ std::sort(rows.begin(), rows.end(),
+ [](const Row& a, const Row& b) {
+ return a.name.localeAwareCompare(b.name) < 0;
+ });
+
+ return rows;
+}
+
+#ifndef QMAKEBUILD
+#include "aamgr.moc"
+#endif
Added: showeq/branches/xerxes-trunk-dev/src/aamgr.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/aamgr.h (rev 0)
+++ showeq/branches/xerxes-trunk-dev/src/aamgr.h 2026-07-17 18:19:21 UTC (rev 1668)
@@ -0,0 +1,104 @@
+/*
+ * aamgr.h
+ * Copyright 2026 by the respective ShowEQ Developers
+ *
+ * This file is part of ShowEQ.
+ * http://www.sourceforge.net/projects/seq
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _AAMGR_H_
+#define _AAMGR_H_
+
+#include <cstdint>
+#include <QObject>
+#include <QHash>
+#include <QList>
+#include <QString>
+
+#include "everquest.h"
+
+class DBStr;
+
+//----------------------------------------------------------------------
+// AAMgr
+//
+// Builds an in-memory Alternate Advancement table from the OP_SendAATable
+// record burst the server sends at zone-in (one aaInfoStruct per AA rank),
+// and tracks which AAs the player owns from the character profile. Holds
+// no state on disk; the table is rebuilt from the wire each session. It
+// only signals aaChanged() when the definitions or the owned set actually
+// change, so ordinary zoning (an identical burst) does not churn the UI.
+class AAMgr : public QObject
+{
+ Q_OBJECT
+
+ public:
+ // per-rank definition
+ struct AADef
+ {
+ int32_t titleSID;
+ uint32_t rank;
+ uint32_t cost;
+ uint32_t aaID;
+ };
+
+ // one resolved row for display (an owned AA)
+ struct Row
+ {
+ QString name;
+ uint32_t rank;
+ uint32_t maxRank;
+ uint32_t points; // cumulative points spent (aa_array.value)
+ };
+
+ AAMgr(DBStr* dbstr, QObject* parent = 0, const char* name = 0);
+ ~AAMgr();
+
+ // owned AAs, resolved to name/rank/points, sorted by name
+ QList<Row> ownedRows() const;
+
+ // AA point totals from the character profile
+ uint32_t spent() const { return m_spent; }
+ uint32_t assigned() const { return m_assigned; }
+ uint32_t unspent() const { return m_unspent; }
+
+ public slots:
+ // OP_SendAATable record (one AA rank). Variable length; reads fixed head.
+ void aaInfo(const uint8_t* data, size_t len);
+ // character profile - supplies the owned AA set (descID -> cumulative pts)
+ void player(const charProfileStruct* profile);
+
+ signals:
+ void aaChanged();
+
+ private slots:
+ void emitChanged();
+
+ private:
+ void markChanged();
+
+ DBStr* m_dbstr;
+ QHash<int32_t, AADef> m_defs; // descID -> definition
+ QHash<int32_t, uint32_t> m_maxRank; // titleSID -> highest rank seen
+ QHash<int32_t, uint32_t> m_owned; // descID -> cumulative points
+ uint32_t m_spent; // profile aa_spent
+ uint32_t m_assigned; // profile aa_assigned
+ uint32_t m_unspent; // profile aa_unspent
+ bool m_changeScheduled;
+};
+
+#endif // _AAMGR_H_
Added: showeq/branches/xerxes-trunk-dev/src/dbstr.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/dbstr.cpp (rev 0)
+++ showeq/branches/xerxes-trunk-dev/src/dbstr.cpp 2026-07-17 18:19:21 UTC (rev 1668)
@@ -0,0 +1,104 @@
+/*
+ * dbstr.cpp
+ * Copyright 2026 by the respective ShowEQ Developers
+ *
+ * This file is part of ShowEQ.
+ * http://www.sourceforge.net/projects/seq
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "dbstr.h"
+#include "diagnosticmessages.h"
+
+#include <QFile>
+#include <QByteArray>
+#include <QStringList>
+#if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
+#include <QRegularExpression>
+#else
+#include <QRegExp>
+#endif
+
+DBStr::DBStr()
+ : m_loaded(false)
+{
+}
+
+DBStr::~DBStr()
+{
+}
+
+bool DBStr::load(const QString& fileName, int keepType)
+{
+ m_strings.clear();
+ m_loaded = false;
+
+ QFile dbFile(fileName);
+ if (!dbFile.open(QIODevice::ReadOnly))
+ {
+ seqWarn("DBStr: Failed to open '%s'", fileName.toLatin1().data());
+ return false;
+ }
+
+ QByteArray textData(dbFile.size() + 1, '\0');
+ dbFile.read(textData.data(), textData.size());
+
+ // handle either line-termination style
+#if (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
+ QRegularExpression lineTerm("[\r\n]{1,2}");
+#else
+ QRegExp lineTerm("[\r\n]{1,2}");
+#endif
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
+ QStringList lines = QString::fromUtf8(textData).split(lineTerm, Qt::SkipEmptyParts);
+#else
+ QStringList lines = QString::fromUtf8(textData).split(lineTerm, QString::SkipEmptyParts);
+#endif
+
+ // lines are: id^type^text^flag^ . Keep only the requested type. The text
+ // itself never contains '^', so a plain split is safe (id/type/text are
+ // the first three fields).
+ for (QStringList::Iterator it = lines.begin(); it != lines.end(); ++it)
+ {
+ const QStringList f = (*it).split('^');
+ if (f.size() < 3)
+ continue;
+
+ bool okId = false, okType = false;
+ const int type = f[1].toInt(&okType);
+ if (!okType || type != keepType)
+ continue;
+
+ const uint32_t id = f[0].toUInt(&okId);
+ if (!okId)
+ continue;
+
+ m_strings.insert(id, f[2]);
+ }
+
+ m_loaded = true;
+
+ seqInfo("DBStr: loaded %d type-%d strings from '%s'",
+ m_strings.count(), keepType, fileName.toLatin1().data());
+
+ return true;
+}
+
+QString DBStr::find(uint32_t id) const
+{
+ return m_strings.value(id);
+}
Added: showeq/branches/xerxes-trunk-dev/src/dbstr.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/dbstr.h (rev 0)
+++ showeq/branches/xerxes-trunk-dev/src/dbstr.h 2026-07-17 18:19:21 UTC (rev 1668)
@@ -0,0 +1,55 @@
+/*
+ * dbstr.h
+ * Copyright 2026 by the respective ShowEQ Developers
+ *
+ * This file is part of ShowEQ.
+ * http://www.sourceforge.net/projects/seq
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _DBSTR_H_
+#define _DBSTR_H_
+
+#include <cstdint>
+#include <QHash>
+#include <QString>
+
+//----------------------------------------------------------------------
+// DBStr
+//
+// Loader for the client's dbstr_us.txt string database. Lines are
+// '^'-delimited: id^type^text^flag^ . The (id, type) pair is the key;
+// type 1 is the display name used by AA titles, spells, etc.
+class DBStr
+{
+ public:
+ DBStr();
+ ~DBStr();
+
+ // load dbstr_us.txt; retains only the requested type (default 1, names)
+ bool load(const QString& dbstrFile, int keepType = 1);
+
+ // look up a string by its dbstr id; empty QString if absent
+ QString find(uint32_t id) const;
+
+ bool loaded() const { return m_loaded; }
+
+ protected:
+ QHash<uint32_t, QString> m_strings;
+ bool m_loaded;
+};
+
+#endif // _DBSTR_H_
Modified: showeq/branches/xerxes-trunk-dev/src/everquest.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/everquest.h 2026-07-17 17:48:07 UTC (rev 1667)
+++ showeq/branches/xerxes-trunk-dev/src/everquest.h 2026-07-17 18:19:21 UTC (rev 1668)
@@ -479,6 +479,28 @@
/*012*/
};
+/*
+ * OP_SendAATable. One record per AA rank, sent as a burst at zone-in. The
+ * record is variable length: a count-prefixed skills-requirement block and
+ * prev/next rank ids follow the fixed head below. Only the fixed head is
+ * needed to build the descID -> name/rank table, so the payload size check
+ * is SZC_None and the handler reads just this head.
+ */
+struct aaInfoStruct
+{
+/*000*/ int32_t descID; // per-rank id; matches charProfileStruct.aa_array[].AA
+/*004*/ uint8_t unknown004; // always 1
+/*005*/ int32_t hotKeySID;
+/*009*/ int32_t hotKeySID2;
+/*013*/ int32_t titleSID; // dbstr type-1 name id (shared by all ranks of an AA)
+/*017*/ int32_t descSID2; // dbstr description id (per-rank)
+/*021*/ uint32_t reqLevel;
+/*025*/ uint32_t cost; // points for THIS rank (aa_array.value is cumulative)
+/*029*/ uint32_t aaID; // activation ability id
+/*033*/ uint32_t rank; // current rank this record describes
+/*037*/
+};
+
/**
* Used in charProfileStruct. An item inline in the stream, used in Bandolier and Potion Belt.
* Size: 72 Octets
Modified: showeq/branches/xerxes-trunk-dev/src/interface.cpp
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-17 17:48:07 UTC (rev 1667)
+++ showeq/branches/xerxes-trunk-dev/src/interface.cpp 2026-07-17 18:19:21 UTC (rev 1668)
@@ -37,6 +37,9 @@
#include "spelllist.h"
#include "player.h"
#include "skilllist.h"
+#include "aalist.h"
+#include "aamgr.h"
+#include "dbstr.h"
#include "statlist.h"
#include "group.h"
#include "netdiag.h"
@@ -125,6 +128,9 @@
m_spawnList2(0),
m_spellList(0),
m_skillList(0),
+ m_aaList(0),
+ m_aaMgr(0),
+ m_dbStr(0),
m_statList(0),
m_spawnPointList(0),
m_packet(0),
@@ -295,6 +301,16 @@
// Create our player object
m_player = new Player(this, m_zoneMgr, m_guildmgr);
+ // Create the AA string database (dbstr_us.txt) and the AA manager. The
+ // manager builds an in-memory AA name/rank table from OP_SendAATable and
+ // tracks owned AAs from the character profile.
+ QString dbstrFileName = pSEQPrefs->getPrefString("DBStrFile", "Interface",
+ "dbstr_us.txt");
+ QFileInfo dbstrInfo = m_dataLocationMgr->findExistingFile(".", dbstrFileName);
+ m_dbStr = new DBStr();
+ m_dbStr->load(dbstrInfo.absoluteFilePath());
+ m_aaMgr = new AAMgr(m_dbStr, this, "aamgr");
+
// Create the filter manager
m_filterMgr = new FilterMgr(m_dataLocationMgr,
pSEQPrefs->getPrefString("FilterFile",
@@ -476,6 +492,10 @@
if (pSEQPrefs->getPrefBool("ShowPlayerSkills", section, true))
showSkillList();
+ // Alternate Advancement window (created only when shown)
+ if (pSEQPrefs->getPrefBool("ShowPlayerAA", section, false))
+ showAAList();
+
//
// Create the Player Status listview (ONLY CREATED WHEN NEEDED FLOYD!!!!)
//
@@ -571,6 +591,14 @@
m_packet->connect2("OP_PlayerProfile", SP_Zone, DIR_Server,
"uint8_t", SZC_None,
m_zoneMgr, SLOT(zonePlayer(const uint8_t*, size_t)));
+
+ // AA definition table (one record per AA rank, burst at zone-in) and
+ // the owned-AA set from the character profile feed the AA manager.
+ m_packet->connect2("OP_SendAATable", SP_Zone, DIR_Server,
+ "uint8_t", SZC_None,
+ m_aaMgr, SLOT(aaInfo(const uint8_t*, size_t)));
+ connect(m_zoneMgr, SIGNAL(playerProfile(const charProfileStruct*)),
+ m_aaMgr, SLOT(player(const charProfileStruct*)));
m_packet->connect2("OP_ZoneChange", SP_Zone, DIR_Client|DIR_Server,
"zoneChangeStruct", SZC_Match,
m_zoneMgr, SLOT(zoneChange(const uint8_t*, size_t, uint8_t)));
@@ -1216,6 +1244,10 @@
if (m_eqStrings != 0)
delete m_eqStrings;
+ // m_aaMgr is parented to this and freed by Qt; m_dbStr is not a QObject
+ if (m_dbStr != 0)
+ delete m_dbStr;
+
if (m_player != 0)
delete m_player;
@@ -1311,6 +1343,10 @@
SLOT(toggle_view_PlayerSkills()));
m_action_view_PlayerSkills->setCheckable(true);
+ m_action_view_PlayerAA = pViewMenu->addAction("Alternate Advancement", this,
+ SLOT(toggle_view_PlayerAA()));
+ m_action_view_PlayerAA->setCheckable(true);
+
m_action_view_Compass = pViewMenu->addAction("Compass", this,
SLOT(toggle_view_Compass()));
m_action_view_Compass->setCheckable(true);
@@ -4388,6 +4424,24 @@
pSEQPrefs->setPrefBool("ShowPlayerSkills", "Interface", !wasVisible);
}
+void EQInterface::toggle_view_PlayerAA(void)
+{
+ bool wasVisible = ((m_aaList != 0) && m_aaList->isVisible());
+
+ if (!wasVisible)
+ showAAList();
+ else
+ {
+ m_aaList->savePrefs();
+ m_aaList->hide();
+ removeWindowMenu(m_aaList);
+ delete m_aaList;
+ m_aaList = 0;
+ }
+
+ pSEQPrefs->setPrefBool("ShowPlayerAA", "Interface", !wasVisible);
+}
+
void
EQInterface::toggle_view_Compass(void)
{
@@ -5532,6 +5586,8 @@
m_skillList->isVisible());
m_action_view_PlayerSkills_Options->setEnabled((m_skillList !=0) &&
m_skillList->isVisible());
+ m_action_view_PlayerAA->setChecked((m_aaList != 0) &&
+ m_aaList->isVisible());
m_action_view_PlayerStats->setChecked((m_statList != 0) &&
m_statList->isVisible());
@@ -6238,6 +6294,32 @@
m_skillList->activateWindow();
}
+void EQInterface::showAAList(void)
+{
+ // if it doesn't exist, create it
+ if (m_aaList == 0)
+ {
+ m_aaList = new AAListWindow(m_aaMgr, 0, "aalist");
+ setDockEnabled(m_aaList,
+ pSEQPrefs->getPrefBool("DockablePlayerAA", "Interface", true));
+ Qt::DockWidgetArea edge = (Qt::DockWidgetArea)pSEQPrefs->getPrefInt("Dock",
+ m_aaList->preferenceName(), Qt::LeftDockWidgetArea);
+ addDockWidget(edge, m_aaList);
+ m_aaList->setFloating(!pSEQPrefs->getPrefBool("DockedPlayerAA", "Interface", true));
+
+ // connect aa list window slots to interface signals
+ connect(this, SIGNAL(saveAllPrefs(void)), m_aaList, SLOT(savePrefs(void)));
+ connect(this, SIGNAL(restoreFonts(void)), m_aaList, SLOT(restoreFont(void)));
+
+ // insert its menu into the window menu
+ insertWindowMenu(m_aaList);
+ }
+
+ // make sure it's visible
+ m_aaList->show();
+ m_aaList->activateWindow();
+}
+
void EQInterface::showSpellList(void)
{
// if it doesn't exist, create it
Modified: showeq/branches/xerxes-trunk-dev/src/interface.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/interface.h 2026-07-17 17:48:07 UTC (rev 1667)
+++ showeq/branches/xerxes-trunk-dev/src/interface.h 2026-07-17 18:19:21 UTC (rev 1668)
@@ -54,6 +54,9 @@
class SpellListWindow;
class SkillListWindow;
class StatListWindow;
+class AAListWindow;
+class AAMgr;
+class DBStr;
class SpawnPointWindow;
class EQPacket;
class ZoneMgr;
@@ -277,6 +280,7 @@
void toggle_view_PlayerStats();
void toggle_view_Compass();
void toggle_view_PlayerSkills();
+ void toggle_view_PlayerAA();
void toggle_view_Map(QAction* map);
void toggle_view_NetDiag();
void toggle_view_GuildList();
@@ -336,6 +340,7 @@
void showSpawnPointList(void);
void showStatList(void);
void showSkillList(void);
+ void showAAList(void);
void showSpellList(void);
void showCompass(void);
void showNetDiag(void);
@@ -378,6 +383,9 @@
SpawnListWindow2* m_spawnList2;
SpellListWindow* m_spellList;
SkillListWindow* m_skillList;
+ AAListWindow* m_aaList;
+ AAMgr* m_aaMgr;
+ DBStr* m_dbStr;
StatListWindow* m_statList;
SpawnPointWindow* m_spawnPointList;
EQPacket* m_packet;
@@ -481,6 +489,7 @@
QAction* m_action_view_SpawnPointList;
QAction* m_action_view_PlayerStats;
QAction* m_action_view_PlayerSkills;
+ QAction* m_action_view_PlayerAA;
QAction* m_action_view_Compass;
QAction* m_action_view_Map[maxNumMaps];
QAction* m_action_view_MessageWindow[maxNumMessageWindows];
Modified: showeq/branches/xerxes-trunk-dev/src/s_everquest.h
===================================================================
--- showeq/branches/xerxes-trunk-dev/src/s_everquest.h 2026-07-17 17:48:07 UTC (rev 1667)
+++ showeq/branches/xerxes-trunk-dev/src/s_everquest.h 2026-07-17 18:19:21 UTC (rev 1668)
@@ -19,6 +19,7 @@
AddStruct(Color_Struct);
AddStruct(spellBuff);
AddStruct(AA_Array);
+AddStruct(aaInfoStruct);
AddStruct(InlineItem);
AddStruct(BandolierStruct);
AddStruct(TributeStruct);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-17 17:48:08
|
Revision: 1667
http://sourceforge.net/p/seq/svn/1667
Author: xerxes00
Date: 2026-07-17 17:48:07 +0000 (Fri, 17 Jul 2026)
Log Message:
-----------
Create xerxes-trunk-dev development branch from trunk
Added Paths:
-----------
showeq/branches/xerxes-trunk-dev/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-16 19:53:53
|
Revision: 1666
http://sourceforge.net/p/seq/svn/1666
Author: xerxes00
Date: 2026-07-16 19:53:51 +0000 (Thu, 16 Jul 2026)
Log Message:
-----------
Merge 6.4.25 (trunk r1663) into the Legends branch.
Takes the version bump (now 6.4.25) and the everquest.h struct updates;
the position structs are reconciled to keep the Legends layouts where
they differ from live. conf/zoneopcodes.xml is intentionally left as the
Legends opcode map - trunk's live-id rotation is not merged.
Modified Paths:
--------------
showeq/branches/showeqlegends/ChangeLog
showeq/branches/showeqlegends/configure.in
showeq/branches/showeqlegends/src/everquest.h
Property Changed:
----------------
showeq/branches/showeqlegends/
Index: showeq/branches/showeqlegends
===================================================================
--- showeq/branches/showeqlegends 2026-07-16 19:05:22 UTC (rev 1665)
+++ showeq/branches/showeqlegends 2026-07-16 19:53:51 UTC (rev 1666)
Property changes on: showeq/branches/showeqlegends
___________________________________________________________________
Added: svn:mergeinfo
## -0,0 +1 ##
+/showeq/trunk:1663
\ No newline at end of property
Modified: showeq/branches/showeqlegends/ChangeLog
===================================================================
--- showeq/branches/showeqlegends/ChangeLog 2026-07-16 19:05:22 UTC (rev 1665)
+++ showeq/branches/showeqlegends/ChangeLog 2026-07-16 19:53:51 UTC (rev 1666)
@@ -1,3 +1,9 @@
+cn187 (7/15/26)
+----------------
+- Update to version 6.4.25
+- Support for EQ Patch 7/15/26
+- Struct and opcode updates (Newby)
+
BlueAdept (5/21/26)
----------------
- Update to version 6.4.24
Modified: showeq/branches/showeqlegends/configure.in
===================================================================
--- showeq/branches/showeqlegends/configure.in 2026-07-16 19:05:22 UTC (rev 1665)
+++ showeq/branches/showeqlegends/configure.in 2026-07-16 19:53:51 UTC (rev 1666)
@@ -2,7 +2,7 @@
dnl $Id$ $Name$
AC_PREREQ(2.59)
-AC_INIT(showeq, 6.4.24)
+AC_INIT(showeq, 6.4.25)
AC_CONFIG_SRCDIR(src/main.cpp)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_SYSTEM
Modified: showeq/branches/showeqlegends/src/everquest.h
===================================================================
--- showeq/branches/showeqlegends/src/everquest.h 2026-07-16 19:05:22 UTC (rev 1665)
+++ showeq/branches/showeqlegends/src/everquest.h 2026-07-16 19:53:51 UTC (rev 1666)
@@ -597,7 +597,7 @@
/*0012*/ float z; // Zone in z coord in next zone
/*0016*/ float heading; // Zone in heading in next zone
/*0020*/ uint32_t unknown0020; // *** Placeholder
-/*0024*/
+/*0024*/ // EQL: struct ends here (trimmed to the wire size)
};
/*
@@ -2547,23 +2547,24 @@
/*0000*/ uint16_t spawnId;
/*0002*/ uint16_t spawnId2;
/*0004*/
+ unsigned heading:12; // heading
signed animation:10; // current animation
- unsigned pitch:12; // pitch (up/down heading)
unsigned padding00:10;
/*0008*/
signed deltaZ:13; // change in z
- signed deltaHeading:10; // change in heading
- unsigned padding01:9;
+ signed deltaX:13; // change in x
+ unsigned padding01:6;
/*0012*/
- signed z:19; // z coord (3rd loc value)
- unsigned heading:12; // heading
+ signed x:19; // x coord (1st loc value)
+ unsigned pitch:12; // pitch (up/down heading)
unsigned padding02:1;
/*0016*/
- signed deltaX:13; // change in x
signed y:19; // y coord (2nd loc value)
+ signed deltaHeading:10; // change in heading
+ unsigned padding03:3;
/*0020*/
+ signed z:19; // z coord (3rd loc value)
signed deltaY:13; // change in y
- signed x:19; // x coord (1st loc value)
/*0024*/
};
@@ -2572,24 +2573,39 @@
** Length: 42 Octets
** OpCode: PlayerPosCode
*/
+// EQL note: on EQ Legends this struct is NOT the self-position wire form.
+// The Legends c2s self-state (17-byte float records) is decoded raw in
+// Player::playerSelfState; the stock connects that consume this struct are
+// disconnected on Legends (see interface.cpp). Struct kept at the stock
+// live layout.
struct playerSelfPosStruct
{
-/*0000*/ float x; // x coord (Legends float at offset 0)
-/*0004*/ float y; // y coord
-/*0008*/ float z; // z coord
-/*0012*/ uint8_t posFlag; // 0x02 moving marker
-/*0013*/ uint8_t unknown0013;
-/*0014*/ uint8_t unknown0014;
-/*0015*/ uint8_t seq; // increments each update
-/*0016*/ uint16_t headingRaw; // heading region
- uint16_t spawnId;
- float deltaX;
- float deltaY;
- float deltaZ;
- unsigned heading:12;
- signed deltaHeading:10;
- unsigned pitch:12;
- signed animation:10;
+/*0000*/ uint16_t unknown0000; // ***Placeholder (update time counter?)
+/*0002*/ uint16_t spawnId; // Player's spawn id
+/*0004*/ uint16_t unknown0004; // ***Placeholder
+/*0006*/
+ float z; // z coord (3rd loc value)
+/*0010*/
+ float y; // y coord (2nd loc value)
+/*0014*/
+ unsigned heading:12; // heading
+ unsigned padding02:20;
+/*0018*/
+ float x; // x coord (1st loc value)
+/*0022*/
+ float deltaZ; // change in z
+/*0026*/
+ unsigned pitch:12; // pitch (up/down heading)
+ unsigned padding05:20;
+/*0030*/
+ float deltaX; // change in x
+/*0034*/
+ float deltaY; // change in y
+/*0038*/
+ signed animation:10; // current animation
+ signed deltaHeading:10; // change in heading
+ unsigned padding08:12;
+/*0042*/
};
/*
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <xer...@us...> - 2026-07-16 19:05:25
|
Revision: 1665
http://sourceforge.net/p/seq/svn/1665
Author: xerxes00
Date: 2026-07-16 19:05:22 +0000 (Thu, 16 Jul 2026)
Log Message:
-----------
Update opcode maps for the July 14 EQLegends patch.
r1662 shipped the 7/7 maps by mistake (code was current, maps were
not). zoneopcodes.xml: all zone ids re-verified on the 7/14 rotation,
now with priority/priorityNote annotations for patch-day triage
(ignored by ShowEQ; scheme documented in the file header and README).
worldopcodes.xml: the ids needed for world-session tracking are
re-verified on 7/14; entries still dated 07/07/26 have not been
re-checked since that patch. DTD updated for the new attributes.
Modified Paths:
--------------
showeq/branches/showeqlegends/README
showeq/branches/showeqlegends/conf/seqopcodes.dtd
showeq/branches/showeqlegends/conf/worldopcodes.xml
showeq/branches/showeqlegends/conf/zoneopcodes.xml
Modified: showeq/branches/showeqlegends/README
===================================================================
--- showeq/branches/showeqlegends/README 2026-07-16 11:02:58 UTC (rev 1664)
+++ showeq/branches/showeqlegends/README 2026-07-16 19:05:22 UTC (rev 1665)
@@ -15,6 +15,24 @@
Please read the ChangeLog and NEWS files for more information.
+EQ LEGENDS OPCODE MAP
+---------------------
+On this branch, conf/zoneopcodes.xml and conf/worldopcodes.xml are the
+EQ Legends opcode maps; server patches rotate the ids, so these files
+are what changes on patch day. Each zone opcode carries a hunt-priority
+annotation (ignored by ShowEQ at runtime):
+
+ priority="-1" dead - never hunt (no handler in the code, packet
+ proven absent/superseded on Legends, or an unmapped
+ catalog name inherited from live)
+ priority="0" mapped and harmless but nothing consumes it
+ priority="1"-"10" how important the opcode is to re-find after a
+ patch (10 = ShowEQ is broken without it)
+
+A <priorityNote> element (sibling of <comment>) holds the reason or
+status behind the priority; <comment> holds wire format knowledge.
+See the header comment in conf/zoneopcodes.xml.
+
INSTALLATION
------------
See the file 'INSTALL' for installation and configuration information.
Modified: showeq/branches/showeqlegends/conf/seqopcodes.dtd
===================================================================
--- showeq/branches/showeqlegends/conf/seqopcodes.dtd 2026-07-16 11:02:58 UTC (rev 1664)
+++ showeq/branches/showeqlegends/conf/seqopcodes.dtd 2026-07-16 19:05:22 UTC (rev 1665)
@@ -2,14 +2,18 @@
<!ATTLIST seqopcodes
version CDATA #IMPLIED>
-<!ELEMENT opcode (comment|payload)* >
+<!ELEMENT opcode (comment|priorityNote|payload)* >
<!ATTLIST opcode
id CDATA #REQUIRED
name CDATA ""
+ priority CDATA ""
+ implicitlen CDATA ""
updated CDATA "">
<!ELEMENT comment (#PCDATA)>
+<!ELEMENT priorityNote (#PCDATA)>
+
<!ELEMENT payload EMPTY>
<!ATTLIST payload
dir CDATA "both"
Modified: showeq/branches/showeqlegends/conf/worldopcodes.xml
===================================================================
--- showeq/branches/showeqlegends/conf/worldopcodes.xml 2026-07-16 11:02:58 UTC (rev 1664)
+++ showeq/branches/showeqlegends/conf/worldopcodes.xml 2026-07-16 19:05:22 UTC (rev 1665)
@@ -11,7 +11,7 @@
</opcode>
-->
- <opcode id="bc01" name="OP_GuildList" updated="07/07/26">
+ <opcode id="2efb" name="OP_GuildList" updated="07/14/26">
<comment>old GuildListCode</comment>
<payload dir="server" typename="worldGuildListStruct" sizechecktype="none"/>
</opcode>
@@ -21,7 +21,7 @@
</opcode>
<!-- Not necessary for SEQ to run but here to name packets in logs -->
- <opcode id="7b6a" name="OP_SendLoginInfo" updated="07/07/26">
+ <opcode id="204f" name="OP_SendLoginInfo" updated="07/14/26">
<comment>Client starting world session by asking for login information</comment>
</opcode>
<opcode id="b537" name="OP_LogServer" updated="07/07/26">
@@ -30,13 +30,13 @@
<opcode id="b8cc" name="OP_ApproveWorld" updated="07/07/26">
<comment></comment>
</opcode>
- <opcode id="26bf" name="OP_EnterWorld" updated="07/07/26">
+ <opcode id="0935" name="OP_EnterWorld" updated="07/14/26">
<comment>Server approval for client to enter world</comment>
</opcode>
<opcode id="6bcf" name="OP_ExpansionInfo" updated="07/07/26">
<comment>Which expansions user has</comment>
</opcode>
- <opcode id="84f6" name="OP_SendCharInfo" updated="07/07/26">
+ <opcode id="7fc9" name="OP_SendCharInfo" updated="07/14/26">
<comment>Send all chars visible @ char select</comment>
</opcode>
<opcode id="2de1" name="OP_SendSpellChecksum" updated="07/07/26">
@@ -51,13 +51,13 @@
<opcode id="a958" name="OP_SendSkillCapsChecksum" updated="07/07/26">
<comment>Third client verification packet</comment>
</opcode>
- <opcode id="bb67" name="OP_SetChatServer" updated="07/07/26">
+ <opcode id="8eaa" name="OP_SetChatServer" updated="07/14/26">
<comment>Chatserver? IP,Port,servername.Charname,password(?)</comment>
</opcode>
<opcode id="f22b" name="OP_SetChatServer2" updated="07/07/26">
<comment>Chatserver? IP,Port,servername.Charname,password(?)</comment>
</opcode>
- <opcode id="35d4" name="OP_ZoneServerInfo" updated="07/07/26">
+ <opcode id="0861" name="OP_ZoneServerInfo" updated="07/14/26">
<comment>old ZoneServerInfo</comment>
</opcode>
<opcode id="fc46" name="OP_WorldComplete" updated="07/07/26">
@@ -66,8 +66,9 @@
<opcode id="48f9" name="OP_DeleteCharacter" updated="07/07/26">
<comment>Delete character @ char select</comment>
</opcode>
- <opcode id="0634" name="OP_CharacterCreate" updated="07/07/26">
- <comment>Create character @ char select</comment>
+ <opcode id="08d0" name="OP_CharacterCreate" updated="07/14/26">
+ <comment>07/14 rotation; char name + appearance</comment>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
<opcode id="a24a" name="OP_ApproveName" updated="07/07/26">
<comment>Approving new character name @ char creation</comment>
Modified: showeq/branches/showeqlegends/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/showeqlegends/conf/zoneopcodes.xml 2026-07-16 11:02:58 UTC (rev 1664)
+++ showeq/branches/showeqlegends/conf/zoneopcodes.xml 2026-07-16 19:05:22 UTC (rev 1665)
@@ -2,1044 +2,1248 @@
<!DOCTYPE seqopcodes SYSTEM "seqopcodes.dtd">
<seqopcodes>
+ <!-- priority / priorityNote are ignored by ShowEQ at load; they exist
+ for patch-day tooling and humans.
+ priority -1 dead - never hunt (no handler, or proven absent /
+ superseded on Legends, or an unmapped catalog name
+ inherited from live)
+ priority 0 mapped and harmless but nothing consumes it
+ priority 1..10 hunt priority after a patch rotates ids
+ (10 = ShowEQ is broken without it)
+ priorityNote holds a short status/reason; the comment holds only
+ the wire format (size / offsets). Decoder wiring and verification
+ detail live in the source, not here.
+ -->
+
<!-- Critical opcodes used directly by ShowEQ -->
- <opcode id="62f0" name="OP_PlayerProfile" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified 42485B</comment>
+ <opcode id="6a88" name="OP_PlayerProfile" priority="10" updated="07/14/26">
+ <comment>CharProfileCode</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="4606" name="OP_ZoneEntry" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified both dirs, c2s 92B</comment>
+ <opcode id="144f" name="OP_ZoneEntry" priority="10" updated="07/14/26">
+ <comment>ZoneEntryCode</comment>
<payload dir="client" typename="ClientZoneEntryStruct" sizechecktype="match"/>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="34c7" name="OP_TimeOfDay" updated="07/07/26">
- <comment>07/07 rotation; 8B, stock layout byte-identical (u16 year 3172 + u16 pad); wire-verified across 6 sessions, advances at EQ game rate with correct day rollover</comment>
+ <opcode id="0b7f" name="OP_TimeOfDay" priority="3" updated="07/14/26">
+ <comment>TimeOfDayCode</comment>
<payload dir="server" typename="timeOfDayStruct" sizechecktype="match"/>
</opcode>
- <opcode id="1dbf" name="OP_NewZone" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified 336B</comment>
+ <opcode id="65dd" name="OP_NewZone" priority="10" updated="07/14/26">
+ <comment>NewZoneCode</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="71ca" name="OP_SpawnDoor" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified door defs; payload matched to code registration (modulus) to clear connect2 warning</comment>
+ <opcode id="75dd" name="OP_SpawnDoor" priority="9" updated="07/14/26">
+ <comment>DoorSpawnsCode</comment>
<payload dir="server" typename="doorStruct" sizechecktype="modulus"/>
</opcode>
- <opcode id="0def" name="OP_GroundSpawn" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified IT defs</comment>
+ <opcode id="7e02" name="OP_GroundSpawn" priority="9" updated="07/14/26">
+ <comment>MakeDropCode</comment>
<payload dir="server" typename="makeDropStruct" sizechecktype="none"/>
</opcode>
- <opcode id="069f" name="OP_SendZonePoints" updated="07/07/26">
- <comment>07/07 rotation; u32 count + count*32B rows (stock 24B zonePoint fields + 8 zero bytes) + 32B ff trailer; wire-verified befallen/felwithea vs known zone lines and neighbor zone ids</comment>
+ <opcode id="5926" name="OP_SendZonePoints" priority="5" updated="07/14/26">
+ <comment>Coords in a zone that will port you to another zone</comment>
<payload dir="server" typename="zonePointsStruct" sizechecktype="none"/>
</opcode>
- <opcode id="42d1" name="OP_AAExpUpdate" updated="07/07/26">
- <comment>EQL 12B: u32 AA per-point progress permille*1000 (in-game-calibrated against the AA bar), u32 unassigned AA, u32 varying suffix. Was cross-wired to 6801 (which is regular exp)</comment>
+ <opcode id="7830" name="OP_AAExpUpdate" priority="4" updated="07/14/26">
+ <comment>Receiving AA experience. Also when percent to AA changes.</comment>
<payload dir="server" typename="altExpUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="6801" name="OP_ExpUpdate" updated="07/07/26">
- <comment>EQL 16B: u32 exp permille*1000 (in-game-calibrated against the exp bar), u32 0, u32 unassigned AA, u32 0. Was cross-wired to 42d1 (which is the AA bar)</comment>
+ <opcode id="53b7" name="OP_ExpUpdate" priority="4" updated="07/14/26">
+ <comment>ExpUpdateCode</comment>
<payload dir="server" typename="expUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="46df" name="OP_GuildMOTD" updated="07/07/26">
- <comment>07/07 rotation; stock guildMOTDStruct byte-perfect (target@8, sender@72, message@140; 656B = header + msg buffer); wire-verified vs known MOTD text at zone-in</comment>
+ <opcode id="5924" name="OP_GuildMOTD" priority="2" updated="07/14/26">
+ <comment>GuildMOTD</comment>
<payload dir="server" typename="guildMOTDStruct" sizechecktype="none"/>
</opcode>
- <opcode id="7171" name="OP_ClientUpdate" updated="07/07/26">
- <comment>07/08/26 server payload sizecheck none->match to satisfy connect2 (playerPosUpdate was unwired; other PCs stuck at safe point)</comment>
+ <opcode id="5188" name="OP_ClientUpdate" priority="10" updated="07/14/26">
+ <comment>Position updates</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
- <payload dir="server" typename="playerPosUpdateEQLStruct" sizechecktype="match"/>
</opcode>
- <opcode id="67e0" name="OP_MobUpdate" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified 14B</comment>
+ <opcode id="3348" name="OP_MobUpdate" priority="10" updated="07/14/26">
+ <comment>MobUpdateCode</comment>
<payload dir="both" typename="spawnPositionUpdate" sizechecktype="none"/>
</opcode>
- <opcode id="59a1" name="OP_DeleteSpawn" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified 4B, death trio</comment>
+ <opcode id="0e2c" name="OP_DeleteSpawn" priority="10" updated="07/14/26">
+ <comment>DeleteSpawnCode</comment>
<payload dir="both" typename="deleteSpawnStruct" sizechecktype="match"/>
</opcode>
- <opcode id="71ad" name="OP_RemoveSpawn" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified 5B s2c + 4B c2s</comment>
+ <opcode id="483c" name="OP_RemoveSpawn" priority="10" updated="07/14/26">
+ <comment>Remove spawn from zone</comment>
<payload dir="both" typename="removeSpawnStruct" sizechecktype="none"/>
</opcode>
- <opcode id="5c62" name="OP_WearChange" updated="07/07/26">
- <comment>07/09/26 EQL wire-verified via marked equip/unequip capture: 32B {u32 spawnId, u32 wearSlot(7=pri,8=sec), u32 material, 20B zero}; client-sent for self, server-broadcast for others, preceded by 2575/2a0a value-0x40 trigger. Stock handler is a wear no-op (subcommand 17 HP only) so the 27B match never firing = stock-equivalent; id mapped for log identification</comment>
+ <opcode id="2874" name="OP_WearChange" priority="2" updated="07/14/26">
+ <priorityNote>stock handler no-op; id mapped for log id only</priorityNote>
+ <comment>SpawnUpdateCode</comment>
<payload dir="both" typename="SpawnUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="1bdc" name="OP_SpawnAppearance" updated="07/07/26">
- <comment>EQL u32-widened stock struct, fixed 24B (3748/3748 pcap-library packets); type 6=position (110 sit/100 stand/111 duck), 13=anon, 36=LFG, 22=tick; decoded by SpawnShell::spawnEventEQL</comment>
+ <opcode id="4170" name="OP_SpawnAppearance" priority="10" updated="07/14/26">
+ <comment>SpawnAppearanceCode</comment>
<payload dir="both" typename="spawnEventEQLStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_Stamina" updated="07/19/23">
+ <opcode id="3b0c" name="OP_Stamina" priority="4" updated="07/14/26">
<comment>Server updating on hunger/thirst</comment>
<payload dir="server" typename="staminaStruct" sizechecktype="match"/>
</opcode>
- <opcode id="2735" name="OP_HPUpdate" updated="07/07/26">
- <comment>EQL stat-sync channel, fully decoded: u32 spawnId, u8 flags (bit0 wide-i64/narrow-percent, bit1 HP, bit2 mana, bit3 endurance, bits4-5 reason), per-stat {i64 cur,max} or u8 percent, optional trailing u32; flags 0x31 = 6s keepalive. Decoder SpawnShell::spawnStatEQL feeds spawn HP cur/max and player mana (stock manaChanged); endurance consumed (no stock display); food/water never ride this channel</comment>
+ <opcode id="a5c0" name="OP_HPUpdate" priority="10" updated="07/14/26">
+ <comment>NpcHpUpdateCode Update HP % of a PC or NPC</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="51ed" name="OP_GuildMemberUpdate" updated="07/07/26">
- <comment>07/07 rotation; stock struct + u32 rank inserted @8 (name->12, 88B total unchanged); wire-verified across 6 promote/demote clicks (rank 7..2)</comment>
+ <opcode id="0717" name="OP_GuildMemberUpdate" priority="3" updated="07/14/26">
+ <comment>Info regarding guild members</comment>
<payload dir="server" typename="GuildMemberUpdate" sizechecktype="match"/>
</opcode>
- <opcode id="04d1" name="OP_ClickObject" updated="07/07/26">
- <comment>07/07 rotation; stock remDropStruct byte-perfect (u16 dropId matches ground spawn id, u16 spawnId=player); wire-verified drop+pickup</comment>
- <payload dir="both" typename="remDropStruct" sizechecktype="match"/>
+ <opcode id="597e" name="OP_ClickObject" priority="9" updated="07/14/26">
+ <comment>Items dropped on the ground</comment>
+ <payload dir="server" typename="remDropStruct" sizechecktype="match"/>
</opcode>
- <opcode id="73de" name="OP_Action" updated="07/07/26">
- <comment>EQL 0x73de = stock actionStruct (64B; spell@4 verified vs known cast 434, type@56=231 spell-action on all 1040 corpus records); 88B alt form = actionAltStruct</comment>
+ <opcode id="76e5" name="OP_Action" priority="7" updated="07/14/26">
+ <comment>Spells cast etc</comment>
<payload dir="both" typename="actionStruct" sizechecktype="match"/>
<payload dir="both" typename="actionAltStruct" sizechecktype="match"/>
</opcode>
- <opcode id="1734" name="OP_Action2" updated="07/07/26">
- <comment>EQL per-hit combat: tgt u16, src u16, dmg@8, spell@20 (ffffffff=melee), type u32@24; wire-verified vs 8 known hits + Envenomed Breath 434</comment>
+ <opcode id="5446" name="OP_Action2" priority="7" updated="07/14/26">
+ <comment>Combat actions i.e. bash, kick etc</comment>
<payload dir="both" typename="action2Struct" sizechecktype="match"/>
</opcode>
- <opcode id="4212" name="OP_Consider" updated="07/07/26">
- <comment>fixed 24B both dirs (98/98 pcap-library packets); response: selfId, targetId, faction, level; struct trimmed 32->24 to restore size check</comment>
+ <opcode id="1f81" name="OP_Consider" priority="9" updated="07/14/26">
+ <comment>ConsiderCode</comment>
<payload dir="both" typename="considerStruct" sizechecktype="match"/>
</opcode>
- <opcode id="2867" name="OP_TargetMouse" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified 4B</comment>
+ <opcode id="3ef7" name="OP_TargetMouse" priority="9" updated="07/14/26">
+ <comment>Targeting a person - old ClientTargetCode</comment>
<payload dir="both" typename="clientTargetStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_SpawnRename" updated="07/19/23">
+ <opcode id="ffff" name="OP_SpawnRename" priority="6" updated="07/19/23">
<comment>Spawns getting renamed after initial NewSpawn</comment>
<payload dir="server" typename="spawnRenameStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_Illusion" updated="07/19/23">
+ <opcode id="2e7d" name="OP_Illusion" priority="8" updated="07/14/26">
<comment>Spawn being illusioned (changing forms)</comment>
<payload dir="both" typename="spawnIllusionStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_Shroud" updated="07/19/23">
- <comment>Server putting players into shroud form</comment>
- <payload dir="server" typename="spawnShroudSelf" sizechecktype="none"/>
- </opcode>
- <opcode id="76d3" name="OP_ZoneChange" updated="07/07/26">
- <comment>EQL c2s zone-change request, fixed 484B (32/32 pcap-library packets), carries position but no zone id; server never sends it (zone change = session teardown + new session). Handler only sets m_zoning</comment>
+ <opcode id="4ca8" name="OP_ZoneChange" priority="10" updated="07/14/26">
+ <priorityNote>server never sends it; handler only sets m_zoning</priorityNote>
+ <comment>old ZoneChangeCode</comment>
<payload dir="both" typename="zoneChangeEQLStruct" sizechecktype="match"/>
</opcode>
- <opcode id="6e69" name="OP_GroupInvite" updated="07/07/26">
- <comment>EQL group invite: fixed 168B (invitee@0, inviter@64); struct padded 152->168 to restore size check; wire-verified /say-marked invite</comment>
+ <opcode id="7869" name="OP_GroupInvite" priority="4" updated="07/14/26">
+ <comment>You invite someone while ungrouped or get invited by someone ungrouped</comment>
<payload dir="both" typename="groupInviteStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_GroupInvite2" updated="02/17/21">
- <payload dir="both" typename="groupInviteStruct" sizechecktype="none"/>
- <comment>You're inviting someone and you are grouped or get invited by a group</comment>
- </opcode>
- <opcode id="ffff" name="OP_GroupCancelInvite" updated="02/17/21">
- <payload dir="both" typename="groupDeclineStruct" sizechecktype="match"/>
+ <opcode id="0ff2" name="OP_GroupCancelInvite" priority="4" updated="07/14/26">
+ <priorityNote>single sample; reason byte unverified</priorityNote>
<comment>Declining to join a group</comment>
+ <payload dir="both" typename="groupDeclineStruct" sizechecktype="none"/>
</opcode>
- <opcode id="1512" name="OP_GroupFollow" updated="07/07/26">
- <comment>EQL group member-add: invitee name@64 matches stock groupFollowStruct; fixed 168B (8/8 pcap-library packets), struct padded 152->168; stock addGroupMember + groupFollow</comment>
+ <opcode id="41d7" name="OP_GroupFollow" priority="4" updated="07/14/26">
+ <comment>You join a group or player joins group</comment>
<payload dir="server" typename="groupFollowStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_GroupFollow2" updated="02/17/21">
- <payload dir="server" typename="groupFollowStruct" sizechecktype="match"/>
- <comment>Player joins your group</comment>
- </opcode>
- <opcode id="397d" name="OP_GroupUpdate" updated="07/07/26">
- <comment>EQL full group roster: u32 groupId, u32 count, leader name@8, then count 44B member records from @18 (name NUL-term); resent at zone-in; count=1=solo; decoded by GroupMgr::groupRosterEQL</comment>
+ <opcode id="d305" name="OP_GroupUpdate" priority="6" updated="07/14/26">
+ <comment>Group updates</comment>
+ <comment>168B group roster refresh (fires at join/disband, member name@64)</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="09aa" name="OP_GroupDisband" updated="07/07/26">
- <comment>EQL group member-remove/leave: membername@64 matches stock groupDisbandStruct; fixed 168B (4/4 pcap-library packets), struct padded 152->168; stock removeGroupMember + groupDisband</comment>
+ <opcode id="227d" name="OP_GroupDisband" priority="4" updated="07/14/26">
+ <comment>You disband from group</comment>
<payload dir="server" typename="groupDisbandStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_GroupDisband2" updated="02/17/21">
- <comment>Other disbands from group</comment>
- <payload dir="server" typename="groupDisbandStruct" sizechecktype="match"/>
- </opcode>
- <opcode id="ffff" name="OP_GroupLeader" updated="02/17/21">
+ <opcode id="4546" name="OP_GroupLeader" priority="4" updated="07/14/26">
+ <priorityNote>single sample; unconfirmed on /makeleader</priorityNote>
<comment>Group leader change</comment>
- <payload dir="server" typename="groupLeaderChangeStruct" sizechecktype="match"/>
+ <payload dir="server" typename="groupLeaderChangeStruct" sizechecktype="none"/>
</opcode>
- <opcode id="3ada" name="OP_Buff" updated="07/07/26">
- <comment>compact buff apply/fade record; decoded by SpellShell::buffChange.
- No size check: the shared handler takes both the 16B (live) and 24B
- (Legends, this id) forms, so there is no single size to match. Not the
- stock 168B buffStruct.</comment>
+ <opcode id="6c3c" name="OP_Buff" priority="6" updated="07/14/26">
+ <priorityNote>client dir = memorize/forget, consumed silently</priorityNote>
+ <comment>old BuffDropCode</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="5591" name="OP_BeginCast" updated="07/07/26">
- <comment>07/07 rotation; stock beginCastStruct (spellId u16@0, spawnId u16@4=caster); 19B EQL vs 11B stock; wire-verified vs known casts</comment>
+ <opcode id="6cbd" name="OP_BeginCast" priority="5" updated="07/14/26">
+ <comment>BeginCastCode</comment>
<payload dir="both" typename="beginCastStruct" sizechecktype="none"/>
</opcode>
- <opcode id="10b5" name="OP_CastSpell" updated="07/07/26">
- <comment>07/07 rotation; stock startCastStruct (slot@0, spellId@4, targetId@18) padded 39->40 to the fixed EQL size (76/76 pcap-library packets)</comment>
+ <opcode id="7a2f" name="OP_CastSpell" priority="5" updated="07/14/26">
+ <comment>StartCastCode</comment>
<payload dir="both" typename="startCastStruct" sizechecktype="match"/>
</opcode>
- <opcode id="0fa0" name="OP_SwapSpell" updated="07/07/26">
- <comment>EQL 07/07 rotation; stock tradeSpellBookSlotsStruct (slot1 u32@0, slot2 u32@4) 8B exact; wire-verified swapping spellbook slots 6/7</comment>
+ <opcode id="6f46" name="OP_SwapSpell" priority="3" updated="07/14/26">
+ <comment>TradeSpellBookSlotsCode</comment>
<payload dir="both" typename="tradeSpellBookSlotsStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_MemorizeSpell" updated="07/19/23">
- <comment>MemSpellCode</comment>
- <payload dir="both" typename="memSpellStruct" sizechecktype="match"/>
- </opcode>
- <opcode id="17af" name="OP_InspectAnswer" updated="07/07/26">
- <comment>07/07 rotation; stock inspectDataStruct byte-perfect incl. 1956B total size (3/3 captured inspects); size check restored</comment>
+ <opcode id="6a04" name="OP_InspectAnswer" priority="3" updated="07/14/26">
+ <comment>InspectDataCode</comment>
<payload dir="server" typename="inspectDataStruct" sizechecktype="match"/>
</opcode>
- <opcode id="1cde" name="OP_Emote" updated="07/07/26">
- <comment>07/09/26 EQL: wire-verified via marked capture; 4B header + emote text, 1028B fixed buffer so SZC_None</comment>
+ <opcode id="61a5" name="OP_Emote" priority="4" updated="07/14/26">
+ <comment>EmoteTextCode</comment>
<payload dir="both" typename="emoteTextStruct" sizechecktype="none"/>
</opcode>
- <opcode id="50a7" name="OP_SimpleMessage" updated="07/07/26">
- <comment>07/12/26 rotation, wire-verified</comment>
+ <opcode id="7b92" name="OP_SimpleMessage" priority="4" updated="07/14/26">
+ <comment>SimpleMessageCode</comment>
<payload dir="server" typename="simpleMessageStruct" sizechecktype="match"/>
</opcode>
- <opcode id="3c0a" name="OP_FormattedMessage" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified caret args</comment>
+ <opcode id="15d0" name="OP_FormattedMessage" priority="4" updated="07/14/26">
+ <comment>FormattedMessageCode i.e. pet dismissed etc</comment>
<payload dir="server" typename="formattedMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="55eb" name="OP_CommonMessage" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified /say both dirs</comment>
+ <opcode id="7015" name="OP_CommonMessage" priority="9" updated="07/14/26">
+ <comment>ChannelMessageCode i.e. /tell /ooc /shout etc</comment>
<payload dir="both" typename="channelMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="22e1" name="OP_SpecialMesg" updated="07/07/26">
- <comment>07/07/26 rotation, wire-verified NPC speech</comment>
+ <opcode id="2189" name="OP_SpecialMesg" priority="4" updated="07/14/26">
+ <comment>Communicate textual info to client including hail responses etc</comment>
<payload dir="server" typename="specialMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="08cb" name="OP_RandomReq" updated="07/07/26">
- <comment>EQL 07/07 rotation; stock randomReqStruct with 8B AND 9B wire forms observed (trailing byte optional) so no size check; wire-verified /random</comment>
+ <opcode id="5e9e" name="OP_RandomReq" priority="2" updated="07/14/26">
+ <comment>RandomReqCode</comment>
<payload dir="client" typename="randomReqStruct" sizechecktype="none"/>
</opcode>
- <opcode id="6589" name="OP_RandomReply" updated="07/07/26">
- <comment>EQL 07/07 rotation; stock randomStruct (bottom,top,result,name[64]) 76B exact; wire-verified /random 1 100 = 63</comment>
+ <opcode id="77bd" name="OP_RandomReply" priority="2" updated="07/14/26">
+ <comment>RandomCode</comment>
<payload dir="server" typename="randomStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_ConsentResponse" updated="02/17/21">
+ <opcode id="2265" name="OP_ConsentResponse" priority="3" updated="07/14/26">
<comment>Server replying with consent information after /consent</comment>
<payload dir="server" typename="consentResponseStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_DenyResponse" updated="02/17/21">
+ <opcode id="05fc" name="OP_DenyResponse" priority="3" updated="07/14/26">
<comment>Server replying with deny information after /deny</comment>
<payload dir="server" typename="consentResponseStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_ManaChange" updated="07/19/23">
+ <opcode id="2255" name="OP_ManaChange" priority="5" updated="07/14/26">
<comment>Mana change. Bards send this up with no size. Casters receive this for mana updates.</comment>
<payload dir="server" typename="manaDecrementStruct" sizechecktype="match"/>
- <payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_BazaarSearchRequest" updated="07/19/23">
- <comment>Bazaar search request </comment>
- <payload dir="client" typename="bazaarSearchQueryStruct" sizechecktype="none"/>
- </opcode>
- <opcode id="ffff" name="OP_BazaarSearchResponse" updated="07/19/23">
- <comment>Bazaar search Response - Struct incorrect </comment>
- <payload dir="server" typename="bazaarSearchResponseStruct" sizechecktype="modulus"/>
- </opcode>
- <opcode id="ffff" name="OP_MoneyOnCorpse" updated="07/19/23">
+ <opcode id="ffff" name="OP_MoneyOnCorpse" priority="4" updated="07/19/23">
<comment>MoneyOnCorpseCode</comment>
<payload dir="server" typename="moneyOnCorpseStruct" sizechecktype="match"/>
</opcode>
- <opcode id="6982" name="OP_SkillUpdate" updated="07/07/26">
- <comment>07/07 rotation; stock skillIncStruct byte-perfect (12B: skillId u32, value i32, +4); wire-verified Abjuration(4)=150</comment>
+ <opcode id="3873" name="OP_SkillUpdate" priority="5" updated="07/14/26">
+ <priorityNote>prior id 0dc7 was the zone-in bulk dump (OOB crash); bounds guard kept</priorityNote>
+ <comment>Skill up code</comment>
<payload dir="server" typename="skillIncStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_LevelUpdate" updated="07/19/23">
+ <opcode id="0d68" name="OP_LevelUpdate" priority="8" updated="07/14/26">
+ <priorityNote>single sample</priorityNote>
<comment>LevelUpUpdateCode</comment>
- <payload dir="server" typename="levelUpUpdateStruct" sizechecktype="match"/>
+ <payload dir="server" typename="levelUpUpdateStruct" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_DzSwitchInfo" updated="07/19/23">
- <comment>Expedition compass etc</comment>
- <payload dir="server" typename="dzSwitchInfo" sizechecktype="none"/>
+ <opcode id="ffff" name="OP_CorpseLocResponse" priority="2" updated="12/12/12">
+ <comment>old CorpseLocCode:</comment>
+ <payload dir="server" typename="corpseLocStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_DzInfo" updated="07/19/23">
- <comment>Expedition Information</comment>
- <payload dir="server" typename="dzInfo" sizechecktype="match"/>
+
+ <!-- Not necessary for SEQ to run but here to name packets in logs. -->
+ <opcode id="2ac8" name="OP_Logout" priority="3" updated="07/14/26">
+ <priorityNote>handler wired DIR_Client only</priorityNote>
+ <comment>Camp/logout handshake</comment>
+ <payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_EnvDamage" updated="02/17/21">
+ <opcode id="729e" name="OP_ExpandedGuildInfo" priority="0" updated="07/14/26">
+ <priorityNote>noHandler</priorityNote>
+ <comment>Guild ranks and other misc guild data - Variable length</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="4ecf" name="OP_Animation" priority="0" updated="07/14/26">
+ <priorityNote>noHandler</priorityNote>
+ <comment>Combat animation, emote animations etc - 4 bytes</comment>
+ <payload dir="both" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="0cdf" name="OP_InspectRequest" priority="0" updated="07/14/26">
+ <priorityNote>noHandler</priorityNote>
+ <comment>InspectRequestCode - 8 bytes</comment>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="7d46" name="OP_LootMessageEQL" priority="4" updated="07/14/26">
+ <comment>Loot-and-sell message</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="4d77" name="OP_MoneyUpdateEQL" priority="4" updated="07/14/26">
+ <comment>Money totals</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="3959" name="OP_GuildsInZoneList" priority="8" updated="07/14/26">
+ <comment>Listing of guild names present in the current zone. Generally seen on zoning</comment>
+ <payload dir="server" typename="guildsInZoneListStruct" sizechecktype="none"/>
+ </opcode>
+ <opcode id="6c4c" name="OP_NewGuildInZone" priority="8" updated="07/14/26">
+ <comment>An additional guild name has appeared in the current zone. Seen when a guilded player enters the current zone</comment>
+ <payload dir="server" typename="newGuildInZoneStruct" sizechecktype="none"/>
+ </opcode>
+ <opcode id="1a0b" name="OP_Find" priority="0" updated="07/14/26">
+ <priorityNote>noHandler</priorityNote>
+ <comment>Find window data - variable length, 24 min</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+
+ <!-- Below are used to help make sense of the logs when searching for opcodes
+ Using these marks unknown opcodes in logs for easier reading -->
+
+ <!-- Below are unverified -->
+ <opcode id="31ae" name="OP_SendAATable" priority="5" updated="07/14/26">
+ <comment>AA definition table</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+
+ <opcode id="1ce7" name="OP_HideCorpse" priority="0" updated="07/14/26">
+ <priorityNote>noHandler</priorityNote>
+ <comment>/hidecorpse request</comment>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="4fb6" name="OP_SelfPosEQL" priority="10" updated="07/14/26">
+ <comment>Client self-position</comment>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="021e" name="OP_NpcMoveUpdate" priority="10" updated="07/14/26">
+ <comment>Position updates</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="36bf" name="OP_Death" priority="7" updated="07/14/26">
+ <priorityNote>also fires on corpse decay</priorityNote>
+ <comment>old NewCorpseCode</comment>
+ <payload dir="server" typename="newCorpseStruct" sizechecktype="match"/>
+ </opcode>
+ <opcode id="7d1c" name="OP_DeathEQL" priority="9" updated="07/14/26">
+ <comment>Death/combat subcode channel</comment>
+ <payload dir="both" typename="deathRecordEQLStruct" sizechecktype="none"/>
+ </opcode>
+ <opcode id="591d" name="OP_GuildMemberList" priority="3" updated="07/14/26">
+ <comment>List of guild members - Variable length</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="73e2" name="OP_BuffList" priority="6" updated="07/14/26">
+ <comment>Per-spawn buff list</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="631c" name="OP_LoadoutSwapEQL" priority="3" updated="07/14/26">
+ <comment>Loadout-swap self refresh</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="6768" name="OP_LootDrops" priority="4" updated="07/14/26">
+ <comment>Personal loot list</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="713a" name="OP_BuffList2" priority="6" updated="07/14/26">
+ <comment>Per-spawn buff list (channel 2)</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="5c47" name="OP_BuffList3" priority="6" updated="07/14/26">
+ <comment>Per-spawn buff list (channel 3)</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="18ba" name="OP_DzSwitchInfoEQL" priority="3" updated="07/14/26">
+ <priorityNote>wired but untested on Legends</priorityNote>
+ <comment>Dynamic-zone switch info</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+
+ <!-- ==================================================================
+ priority="-1" TIER: dead entries - never hunt these on patch day.
+ Unmapped catalog names inherited from live (id ffff, no handler),
+ opcodes proven absent or superseded on Legends (see priorityNote),
+ and the pre-2005 historical catalog. Kept for name/reference value.
+ ================================================================== -->
+ <opcode id="ffff" name="OP_BazaarSearchRequest" priority="-1" updated="07/19/23">
+ <priorityNote>noHandler</priorityNote>
+ <comment>Bazaar search request</comment>
+ <payload dir="client" typename="bazaarSearchQueryStruct" sizechecktype="none"/>
+ </opcode>
+ <opcode id="ffff" name="OP_BazaarSearchResponse" priority="-1" updated="07/19/23">
+ <priorityNote>noHandler</priorityNote>
+ <comment>Bazaar search Response - Struct incorrect</comment>
+ <payload dir="server" typename="bazaarSearchResponseStruct" sizechecktype="modulus"/>
+ </opcode>
+ <opcode id="ffff" name="OP_EnvDamage" priority="-1" updated="02/17/21">
+ <priorityNote>noHandler</priorityNote>
<comment>Environmental Damage</comment>
<payload dir="client" typename="environmentDamageStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_SetRunMode" updated="07/19/23">
+ <opcode id="ffff" name="OP_SetRunMode" priority="-1" updated="07/19/23">
+ <priorityNote>noHandler</priorityNote>
<comment>old cRunToggleCode</comment>
<payload dir="client" typename="cRunToggleStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_Trader" updated="07/19/23">
+ <opcode id="ffff" name="OP_Trader" priority="-1" updated="07/19/23">
+ <priorityNote>noHandler</priorityNote>
<comment>PC's turning trader on and off</comment>
<payload dir="server" typename="bazaarTraderRequest" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_ItemLinkResponse" updated="06/19/19">
+ <opcode id="ffff" name="OP_ItemLinkResponse" priority="-1" updated="06/19/19">
+ <priorityNote>noHandler</priorityNote>
<comment>ItemInfoCode</comment>
<payload dir="server" typename="itemInfoStruct" sizechecktype="none"/>
<payload dir="client" typename="itemInfoReqStruct" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_BuffFadeMsg" updated="11/20/15">
- <comment>SpellFadeCode</comment>
- <payload dir="both" typename="spellFadedStruct" sizechecktype="none"/>
- </opcode>
- <opcode id="ffff" name="OP_CorpseLocResponse" updated="12/12/12">
- <comment>old CorpseLocCode:</comment>
- <payload dir="server" typename="corpseLocStruct" sizechecktype="match"/>
- </opcode>
- <opcode id="ffff" name="OP_ItemPacket" updated="11/28/12">
+ <opcode id="ffff" name="OP_ItemPacket" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>ItemCode</comment>
<payload dir="server" typename="itemPacketStruct" sizechecktype="none"/>
</opcode>
-
- <!-- Not necessary for SEQ to run but here to name packets in logs. -->
- <opcode id="ffff" name="OP_LeaderExpUpdate" updated="12/11/13">
+ <opcode id="ffff" name="OP_LeaderExpUpdate" priority="-1" updated="12/11/13">
+ <priorityNote>noHandler</priorityNote>
<comment>Leadership AA Exp Update</comment>
<payload dir="server" typename="leadExpUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_MovementHistory" updated="06/18/14">
+ <opcode id="ffff" name="OP_MovementHistory" priority="-1" updated="06/18/14">
+ <priorityNote>noHandler</priorityNote>
<comment>Movement history for speed/movement hack detection</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Logout" updated="12/12/12">
- <comment></comment>
- <payload dir="server" typename="uint8_t" sizechecktype="match"/>
- </opcode>
- <opcode id="ffff" name="OP_UIUpdate" updated="05/21/14">
+ <opcode id="ffff" name="OP_UIUpdate" priority="-1" updated="05/21/14">
+ <priorityNote>noHandler</priorityNote>
<comment>Seems to be sent to handle a variety of UI updates - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_GroupMemberList" updated="01/16/13">
+ <opcode id="ffff" name="OP_GroupMemberList" priority="-1" updated="01/16/13">
+ <priorityNote>noHandler</priorityNote>
<comment>List of group members - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_ManaUpdate" updated="07/19/23">
+ <opcode id="ffff" name="OP_ManaUpdate" priority="-1" updated="07/19/23">
+ <priorityNote>noHandler</priorityNote>
<comment>Mana Update opcode - 10 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_EndUpdate" updated="07/19/23">
+ <opcode id="ffff" name="OP_EndUpdate" priority="-1" updated="07/19/23">
+ <priorityNote>noHandler</priorityNote>
<comment>Endurance Update opcode - 10 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Marketplace" updated="11/28/12">
+ <opcode id="ffff" name="OP_Marketplace" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Marketplace data - Guessing variable length 11444 bytes as of 11/28/12</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_MarketplaceSelect" updated="11/28/12">
+ <opcode id="ffff" name="OP_MarketplaceSelect" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Sent when highlighting an item in Marketplace - 80 bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_DzMembers" updated="11/28/12">
+ <opcode id="ffff" name="OP_DzMembers" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Expedition Members - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Campfire" updated="11/28/12">
+ <opcode id="ffff" name="OP_Campfire" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Fellowship campfire information - 1076 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_SelectCampfire" updated="01/16/13">
+ <opcode id="ffff" name="OP_SelectCampfire" priority="-1" updated="01/16/13">
+ <priorityNote>noHandler</priorityNote>
<comment>Fellowship campfire Choices - Guessing variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Claims" updated="11/28/12">
+ <opcode id="ffff" name="OP_Claims" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Contents of claims window. /claim then refresh to capture packet - Guessing variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_VoiceChat" updated="11/20/15">
+ <opcode id="ffff" name="OP_VoiceChat" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Voice chat server info - Variable length (Data sent when joining group,raid etc)</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_PollQuestions" updated="11/20/15">
+ <opcode id="ffff" name="OP_PollQuestions" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>SOE in-game player poll questions - Variable length</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_PollResponses" updated="11/20/15">
+ <opcode id="ffff" name="OP_PollResponses" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Poll response choices - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_ShroudProgression" updated="11/20/15">
+ <opcode id="ffff" name="OP_ShroudProgression" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Unlocked shrouds - 293 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_ShroudTemplates" updated="10/23/12">
+ <opcode id="ffff" name="OP_ShroudTemplates" priority="-1" updated="10/23/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Shroud templates to choose from on shroud NPC - 18983 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Fellowship" updated="03/13/19">
+ <opcode id="ffff" name="OP_Fellowship" priority="-1" updated="03/13/19">
+ <priorityNote>noHandler</priorityNote>
<comment>Fellowship information - 2576 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="3aac" name="OP_ExpandedGuildInfo" updated="07/07/26">
- <comment>07/07 rotation; guild ranks/misc data channel (subtyped: 192B self-status w/ rank title + MOTD, 104/352/4184B rank-and-permission blobs at zone-in); not consumed</comment>
- <payload dir="server" typename="uint8_t" sizechecktype="none"/>
- </opcode>
- <opcode id="ffff" name="OP_GuildBank" updated="11/20/15">
+ <opcode id="ffff" name="OP_GuildBank" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Guild bank contents - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_OpenTradeskillContainer" updated="11/28/12">
+ <opcode id="ffff" name="OP_OpenTradeskillContainer" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Opens forge, kiln etc - 92 Bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeskillRecipes" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeskillRecipes" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Learned recipes - 84 Bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeSkillCombine" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeSkillCombine" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Tradeskill combine using new tradeskill window - 40 Bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeSkillResult" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeSkillResult" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Packets sent when tradeskill combine successful equals # of ingredients used in combine?- 12 Bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeSkillCombineOld" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeSkillCombineOld" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Tradeskill combine using old tradeskill window - 24 Bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_ItemPlayerPacket" updated="11/20/15">
+ <opcode id="ffff" name="OP_ItemPlayerPacket" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Inventory/bank items coming over during zone - Variable length</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TaskDescription" updated="11/20/15">
+ <opcode id="ffff" name="OP_TaskDescription" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Task descriptions coming down for task window - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TaskActivity" updated="11/20/15">
+ <opcode id="ffff" name="OP_TaskActivity" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Task activity descriptions coming down for task window - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_CompletedTasks" updated="11/20/15">
+ <opcode id="ffff" name="OP_CompletedTasks" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>Task history for task window - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_CustomTitles" updated="11/20/15">
+ <opcode id="ffff" name="OP_CustomTitles" priority="-1" updated="11/20/15">
+ <priorityNote>noHandler</priorityNote>
<comment>List of available titles - 1520 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="1293" name="OP_Animation" updated="07/07/26">
- <comment>EQL 0x1293 4B combat/emote animation tick (u16 spawnId + u8 + u8); community-corroborated</comment>
- <payload dir="both" typename="uint8_t" sizechecktype="none"/>
- </opcode>
- <opcode id="ffff" name="OP_WhoAllRequest" updated="11/28/12">
+ <opcode id="ffff" name="OP_WhoAllRequest" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>WhoAllReqCode - 156 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_WhoAllResponse" updated="11/28/12">
+ <opcode id="ffff" name="OP_WhoAllResponse" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>WhoAllOutputCode - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="2cc0" name="OP_InspectRequest" updated="07/07/26">
- <comment>07/09/26 EQL wire-verified via marked inspects: 8B {u32 targetId, u32 selfId}; no stock consumer - identification-only</comment>
- <payload dir="client" typename="uint8_t" sizechecktype="none"/>
- </opcode>
- <opcode id="ffff" name="OP_GetGuildMOTD" updated="11/28/12">
+ <opcode id="ffff" name="OP_GetGuildMOTD" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Request guildMOTD - 648 Bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeRequest" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeRequest" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>You request trade session - 8 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeDeny" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeDeny" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Target not ready to trade - 12 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeRequestAck" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeRequestAck" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Trade request recipient is acknowledging they are able to trade - 8 bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_CancelTrade" updated="11/28/12">
+ <opcode id="ffff" name="OP_CancelTrade" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Cancel a trade window - 8 bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_FinishTrade" updated="11/28/12">
+ <opcode id="ffff" name="OP_FinishTrade" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Trade is over - 12 bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeCoins" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeCoins" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>You put coins put in a trade window - 20 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeCoins2" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeCoins2" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Someone else puts coins put in your trade window - 12 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_TradeAcceptClick" updated="11/28/12">
+ <opcode id="ffff" name="OP_TradeAcceptClick" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>One side clicks Accept on the trade 8 bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_ItemLinkClick" updated="11/28/12">
+ <opcode id="ffff" name="OP_ItemLinkClick" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Click on itemlinks - 52 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_LootRequest" updated="11/28/12">
+ <opcode id="ffff" name="OP_LootRequest" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>LootCorpseCode - 4 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="32f7" name="OP_LootMessageEQL" updated="07/07/26">
- <comment>EQL loot-and-sell notification: u32 formatId (286) + preformatted text with inline item link; wire-verified</comment>
- <payload dir="server" typename="uint8_t" sizechecktype="none"/>
- </opcode>
- <opcode id="5a29" name="OP_LootDrops" updated="07/07/26">
- <comment>EQL personal loot list: [hdr][u32 corpseId@6][u32 count@10][corpse name NUL][per-item fields + clean NUL item names]; wire-verified</comment>
- <payload dir="server" typename="uint8_t" sizechecktype="none"/>
- </opcode>
- <opcode id="5203" name="OP_MoneyUpdateEQL" updated="07/07/26">
- <comment>EQL live money totals: 16B [u32 plat][u32 gold][u32 silver][u32 copper]; wire-verified</comment>
- <payload dir="server" typename="uint8_t" sizechecktype="none"/>
- </opcode>
- <opcode id="ffff" name="OP_LootItem" updated="11/28/12">
+ <opcode id="ffff" name="OP_LootItem" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Loot item from corpse - 20 bytes</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_EndLootRequest" updated="11/28/12">
+ <opcode id="ffff" name="OP_EndLootRequest" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>DoneLootingCode - 4 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Track" updated="11/28/12">
+ <opcode id="ffff" name="OP_Track" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Tracking data - Variable length</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_AutoAttack" updated="11/28/12">
+ <opcode id="ffff" name="OP_AutoAttack" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Attack on/off - 4 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_AutoAttack2" updated="11/28/12">
+ <opcode id="ffff" name="OP_AutoAttack2" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>Attack on/off appears to be same as OP_AutoAttack - 4 bytes</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_ClickDoor" updated="11/28/12">
+ <opcode id="ffff" name="OP_ClickDoor" priority="-1" updated="11/28/12">
+ <priorityNote>noHandler</priorityNote>
<comment>DoorOpenCode click request from ...
[truncated message content] |
|
From: <cn...@us...> - 2026-07-16 11:03:00
|
Revision: 1664
http://sourceforge.net/p/seq/svn/1664
Author: cn187
Date: 2026-07-16 11:02:58 +0000 (Thu, 16 Jul 2026)
Log Message:
-----------
Tag for release 6.4.25
Added Paths:
-----------
showeq/tags/v6_4_25/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cn...@us...> - 2026-07-16 11:02:11
|
Revision: 1663
http://sourceforge.net/p/seq/svn/1663
Author: cn187
Date: 2026-07-16 11:02:08 +0000 (Thu, 16 Jul 2026)
Log Message:
-----------
Release 6.4.25
- Updated version to 6.4.25
- Support for EQ Patch 07/15/26
- Struct and opcode updates (Newby)
Modified Paths:
--------------
showeq/trunk/ChangeLog
showeq/trunk/conf/zoneopcodes.xml
showeq/trunk/configure.in
showeq/trunk/src/everquest.h
Modified: showeq/trunk/ChangeLog
===================================================================
--- showeq/trunk/ChangeLog 2026-07-16 03:29:17 UTC (rev 1662)
+++ showeq/trunk/ChangeLog 2026-07-16 11:02:08 UTC (rev 1663)
@@ -1,3 +1,9 @@
+cn187 (7/15/26)
+----------------
+- Update to version 6.4.25
+- Support for EQ Patch 7/15/26
+- Struct and opcode updates (Newby)
+
BlueAdept (5/21/26)
----------------
- Update to version 6.4.24
Modified: showeq/trunk/conf/zoneopcodes.xml
===================================================================
--- showeq/trunk/conf/zoneopcodes.xml 2026-07-16 03:29:17 UTC (rev 1662)
+++ showeq/trunk/conf/zoneopcodes.xml 2026-07-16 11:02:08 UTC (rev 1663)
@@ -3,37 +3,37 @@
<seqopcodes>
<!-- Critical opcodes used directly by ShowEQ -->
- <opcode id="e284" name="OP_PlayerProfile" updated="05/20/26">
+ <opcode id="d4b8" name="OP_PlayerProfile" updated="07/15/26">
<comment>CharProfileCode</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="a5bf" name="OP_ZoneEntry" updated="05/20/26">
+ <opcode id="abdb" name="OP_ZoneEntry" updated="07/15/26">
<comment>ZoneEntryCode</comment>
<payload dir="client" typename="ClientZoneEntryStruct" sizechecktype="match"/>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="7e22" name="OP_TimeOfDay" updated="05/20/26">
+ <opcode id="4968" name="OP_TimeOfDay" updated="07/15/26">
<comment>TimeOfDayCode</comment>
<payload dir="server" typename="timeOfDayStruct" sizechecktype="match"/>
</opcode>
- <opcode id="a923" name="OP_NewZone" updated="05/20/26">
+ <opcode id="1a58" name="OP_NewZone" updated="07/15/26">
<comment>NewZoneCode</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="33ec" name="OP_SpawnDoor" updated="05/20/26">
+ <opcode id="cb57" name="OP_SpawnDoor" updated="07/15/26">
<comment>DoorSpawnsCode</comment>
<payload dir="server" typename="doorStruct" sizechecktype="modulus"/>
</opcode>
- <opcode id="92dc" name="OP_GroundSpawn" updated="05/20/26">
+ <opcode id="66a8" name="OP_GroundSpawn" updated="07/15/26">
<comment>MakeDropCode</comment>
<payload dir="server" typename="makeDropStruct" sizechecktype="none"/>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ad5c" name="OP_SendZonePoints" updated="05/20/26">
+ <opcode id="57f6" name="OP_SendZonePoints" updated="07/15/26">
<comment>Coords in a zone that will port you to another zone</comment>
<payload dir="server" typename="zonePointsStruct" sizechecktype="none"/>
</opcode>
- <opcode id="0c97" name="OP_AAExpUpdate" updated="05/20/26">
+ <opcode id="b10f" name="OP_AAExpUpdate" updated="07/15/26">
<comment>Receiving AA experience. Also when percent to AA changes.</comment>
<payload dir="server" typename="altExpUpdateStruct" sizechecktype="match"/>
</opcode>
@@ -41,32 +41,32 @@
<comment>ExpUpdateCode</comment>
<payload dir="server" typename="expUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9f2b" name="OP_GuildMOTD" updated="05/20/26">
+ <opcode id="3425" name="OP_GuildMOTD" updated="07/15/26">
<comment>GuildMOTD</comment>
<payload dir="server" typename="guildMOTDStruct" sizechecktype="none"/>
</opcode>
- <opcode id="f8d1" name="OP_ClientUpdate" updated="05/20/26">
+ <opcode id="76e4" name="OP_ClientUpdate" updated="07/15/26">
<comment>Position updates</comment>
<payload dir="server" typename="playerSpawnPosStruct" sizechecktype="match"/>
<payload dir="both" typename="playerSelfPosStruct" sizechecktype="match"/>
</opcode>
- <opcode id="917c" name="OP_NpcMoveUpdate" updated="05/20/26">
+ <opcode id="612e" name="OP_NpcMoveUpdate" updated="07/15/26">
<comment>Position updates</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="4a4f" name="OP_MobUpdate" updated="05/20/26">
+ <opcode id="6a5a" name="OP_MobUpdate" updated="07/15/26">
<comment>MobUpdateCode</comment>
<payload dir="both" typename="spawnPositionUpdate" sizechecktype="match"/>
</opcode>
- <opcode id="94d4" name="OP_DeleteSpawn" updated="05/20/26">
+ <opcode id="18c6" name="OP_DeleteSpawn" updated="07/15/26">
<comment>DeleteSpawnCode</comment>
<payload dir="both" typename="deleteSpawnStruct" sizechecktype="match"/>
</opcode>
- <opcode id="eb88" name="OP_RemoveSpawn" updated="05/20/26">
+ <opcode id="d631" name="OP_RemoveSpawn" updated="07/15/26">
<comment>Remove spawn from zone</comment>
<payload dir="both" typename="removeSpawnStruct" sizechecktype="none"/>
</opcode>
- <opcode id="1eb2" name="OP_Death" updated="05/20/26">
+ <opcode id="75b4" name="OP_Death" updated="07/15/26">
<comment>old NewCorpseCode</comment>
<payload dir="server" typename="newCorpseStruct" sizechecktype="match"/>
</opcode>
@@ -74,7 +74,7 @@
<comment>SpawnUpdateCode</comment>
<payload dir="both" typename="SpawnUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9826" name="OP_SpawnAppearance" updated="05/20/26">
+ <opcode id="9f7c" name="OP_SpawnAppearance" updated="07/15/26">
<comment>SpawnAppearanceCode</comment>
<payload dir="both" typename="spawnAppearanceStruct" sizechecktype="match"/>
</opcode>
@@ -86,15 +86,15 @@
<comment>NpcHpUpdateCode Update HP % of a PC or NPC</comment>
<payload dir="both" typename="hpNpcUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9abe" name="OP_GuildMemberUpdate" updated="05/20/26">
+ <opcode id="0ad8" name="OP_GuildMemberUpdate" updated="07/15/26">
<comment>Info regarding guild members</comment>
<payload dir="server" typename="GuildMemberUpdate" sizechecktype="match"/>
</opcode>
- <opcode id="ab5e" name="OP_ClickObject" updated="05/20/26">
+ <opcode id="d84f" name="OP_ClickObject" updated="07/15/26">
<comment>Items dropped on the ground</comment>
<payload dir="both" typename="remDropStruct" sizechecktype="match"/>
</opcode>
- <opcode id="049e" name="OP_Action" updated="05/20/26">
+ <opcode id="dda7" name="OP_Action" updated="07/15/26">
<comment>Spells cast etc</comment>
<payload dir="both" typename="actionStruct" sizechecktype="match"/>
<payload dir="both" typename="actionAltStruct" sizechecktype="match"/>
@@ -103,11 +103,11 @@
<comment>Combat actions i.e. bash, kick etc</comment>
<payload dir="both" typename="action2Struct" sizechecktype="match"/>
</opcode>
- <opcode id="a1e7" name="OP_Consider" updated="05/20/26">
+ <opcode id="7a5b" name="OP_Consider" updated="07/15/26">
<comment>ConsiderCode</comment>
<payload dir="both" typename="considerStruct" sizechecktype="match"/>
</opcode>
- <opcode id="1994" name="OP_TargetMouse" updated="05/20/26">
+ <opcode id="12e2" name="OP_TargetMouse" updated="07/15/26">
<comment>Targeting a person - old ClientTargetCode</comment>
<payload dir="both" typename="clientTargetStruct" sizechecktype="match"/>
</opcode>
@@ -123,7 +123,7 @@
<comment>Server putting players into shroud form</comment>
<payload dir="server" typename="spawnShroudSelf" sizechecktype="none"/>
</opcode>
- <opcode id="9148" name="OP_ZoneChange" updated="05/20/26">
+ <opcode id="4068" name="OP_ZoneChange" updated="07/15/26">
<comment>old ZoneChangeCode</comment>
<payload dir="both" typename="zoneChangeStruct" sizechecktype="match"/>
</opcode>
@@ -191,19 +191,19 @@
<comment>EmoteTextCode</comment>
<payload dir="both" typename="emoteTextStruct" sizechecktype="none"/>
</opcode>
- <opcode id="44a0" name="OP_SimpleMessage" updated="05/20/26">
+ <opcode id="2892" name="OP_SimpleMessage" updated="07/15/26">
<comment>SimpleMessageCode</comment>
<payload dir="server" typename="simpleMessageStruct" sizechecktype="match"/>
</opcode>
- <opcode id="5b40" name="OP_FormattedMessage" updated="05/20/26">
+ <opcode id="1d0d" name="OP_FormattedMessage" updated="07/15/26">
<comment>FormattedMessageCode i.e. pet dismissed etc</comment>
<payload dir="server" typename="formattedMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="498b" name="OP_CommonMessage" updated="05/20/26">
+ <opcode id="547a" name="OP_CommonMessage" updated="07/15/26">
<comment>ChannelMessageCode i.e. /tell /ooc /shout etc</comment>
<payload dir="both" typename="channelMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="7162" name="OP_SpecialMesg" updated="05/20/26">
+ <opcode id="b8f3" name="OP_SpecialMesg" updated="07/15/26">
<comment>Communicate textual info to client including hail responses etc</comment>
<payload dir="server" typename="specialMessageStruct" sizechecktype="none"/>
</opcode>
@@ -307,7 +307,7 @@
<comment>List of group members - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="4058" name="OP_GuildMemberList" updated="05/20/26">
+ <opcode id="5af5" name="OP_GuildMemberList" updated="07/15/26">
<comment>List of guild members - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
@@ -367,7 +367,7 @@
<comment>Fellowship information - 2576 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="8d86" name="OP_ExpandedGuildInfo" updated="05/20/26">
+ <opcode id="3ef7" name="OP_ExpandedGuildInfo" updated="07/15/26">
<comment>Guild ranks and other misc guild data - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
@@ -535,7 +535,7 @@
<comment>Listing of all guilds. Can be triggered by /lfg search?</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="d5e8" name="OP_GuildsInZoneList" updated="05/20/26">
+ <opcode id="68f4" name="OP_GuildsInZoneList" updated="07/15/26">
<comment>Listing of guild names present in the current zone. Generally seen on zoning</comment>
<payload dir="server" typename="guildsInZoneListStruct" sizechecktype="none"/>
</opcode>
@@ -595,7 +595,7 @@
<comment>Free to play nags and other data - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="695f" name="OP_Find" updated="05/20/26">
+ <opcode id="2e60" name="OP_Find" updated="07/15/26">
<comment>Find window data - variable length, 24 min</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
Modified: showeq/trunk/configure.in
===================================================================
--- showeq/trunk/configure.in 2026-07-16 03:29:17 UTC (rev 1662)
+++ showeq/trunk/configure.in 2026-07-16 11:02:08 UTC (rev 1663)
@@ -2,7 +2,7 @@
dnl $Id$ $Name$
AC_PREREQ(2.59)
-AC_INIT(showeq, 6.4.24)
+AC_INIT(showeq, 6.4.25)
AC_CONFIG_SRCDIR(src/main.cpp)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_SYSTEM
Modified: showeq/trunk/src/everquest.h
===================================================================
--- showeq/trunk/src/everquest.h 2026-07-16 03:29:17 UTC (rev 1662)
+++ showeq/trunk/src/everquest.h 2026-07-16 11:02:08 UTC (rev 1663)
@@ -1121,23 +1121,24 @@
struct
{
+ unsigned heading:12; // heading
signed animation:10; // current animation
- unsigned pitch:12; // pitch (up/down heading)
unsigned padding00:10;
signed deltaZ:13; // change in z
- signed deltaHeading:10; // change in heading
- unsigned padding01:9;
+ signed deltaX:13; // change in x
+ unsigned padding01:6;
- signed z:19; // z coord (3rd loc value)
- unsigned heading:12; // heading
+ signed x:19; // x coord (1st loc value)
+ unsigned pitch:12; // pitch (up/down heading)
unsigned padding02:1;
- signed deltaX:13; // change in x
signed y:19; // y coord (2nd loc value)
+ signed deltaHeading:10; // change in heading
+ unsigned padding03:3;
+ signed z:19; // z coord (3rd loc value)
signed deltaY:13; // change in y
- signed x:19; // x coord (1st loc value)
};
int32_t posData[5];
@@ -2400,23 +2401,24 @@
/*0000*/ uint16_t spawnId;
/*0002*/ uint16_t spawnId2;
/*0004*/
+ unsigned heading:12; // heading
signed animation:10; // current animation
- unsigned pitch:12; // pitch (up/down heading)
unsigned padding00:10;
/*0008*/
signed deltaZ:13; // change in z
- signed deltaHeading:10; // change in heading
- unsigned padding01:9;
+ signed deltaX:13; // change in x
+ unsigned padding01:6;
/*0012*/
- signed z:19; // z coord (3rd loc value)
- unsigned heading:12; // heading
+ signed x:19; // x coord (1st loc value)
+ unsigned pitch:12; // pitch (up/down heading)
unsigned padding02:1;
/*0016*/
- signed deltaX:13; // change in x
signed y:19; // y coord (2nd loc value)
+ signed deltaHeading:10; // change in heading
+ unsigned padding03:3;
/*0020*/
+ signed z:19; // z coord (3rd loc value)
signed deltaY:13; // change in y
- signed x:19; // x coord (1st loc value)
/*0024*/
};
@@ -2431,27 +2433,27 @@
/*0002*/ uint16_t spawnId; // Player's spawn id
/*0004*/ uint16_t unknown0004; // ***Placeholder
/*0006*/
+ float z; // z coord (3rd loc value)
+/*0010*/
float y; // y coord (2nd loc value)
-/*0010*/
- unsigned pitch:12; // pitch (up/down heading)
+/*0014*/
unsigned heading:12; // heading
- unsigned padding01:8;
-/*0014*/
- float deltaY; // change in y
+ unsigned padding02:20;
/*0018*/
- signed animation:10; // current animation
- unsigned padding03:22;
+ float x; // x coord (1st loc value)
/*0022*/
- float z; // z coord (3rd loc value)
+ float deltaZ; // change in z
/*0026*/
- float x; // x coord (1st loc value)
+ unsigned pitch:12; // pitch (up/down heading)
+ unsigned padding05:20;
/*0030*/
float deltaX; // change in x
/*0034*/
+ float deltaY; // change in y
+/*0038*/
+ signed animation:10; // current animation
signed deltaHeading:10; // change in heading
- unsigned padding07:22;
-/*0038*/
- float deltaZ; // change in z
+ unsigned padding08:12;
/*0042*/
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cn...@us...> - 2026-07-11 20:32:56
|
Revision: 1661
http://sourceforge.net/p/seq/svn/1661
Author: cn187
Date: 2026-07-11 20:32:53 +0000 (Sat, 11 Jul 2026)
Log Message:
-----------
Update for July 7 EQLegends patch.
Thanks Xerces.
Modified Paths:
--------------
showeq/branches/showeqlegends/conf/worldopcodes.xml
showeq/branches/showeqlegends/conf/zoneopcodes.xml
showeq/branches/showeqlegends/src/eqstr.cpp
showeq/branches/showeqlegends/src/everquest.h
showeq/branches/showeqlegends/src/group.cpp
showeq/branches/showeqlegends/src/group.h
showeq/branches/showeqlegends/src/guildshell.cpp
showeq/branches/showeqlegends/src/interface.cpp
showeq/branches/showeqlegends/src/messageshell.cpp
showeq/branches/showeqlegends/src/packetcapture.cpp
showeq/branches/showeqlegends/src/packetcommon.h
showeq/branches/showeqlegends/src/packetformat.cpp
showeq/branches/showeqlegends/src/packetformat.h
showeq/branches/showeqlegends/src/packetstream.cpp
showeq/branches/showeqlegends/src/player.cpp
showeq/branches/showeqlegends/src/player.h
showeq/branches/showeqlegends/src/s_everquest.h
showeq/branches/showeqlegends/src/spawn.cpp
showeq/branches/showeqlegends/src/spawn.h
showeq/branches/showeqlegends/src/spawnshell.cpp
showeq/branches/showeqlegends/src/spawnshell.h
showeq/branches/showeqlegends/src/spelllist.cpp
showeq/branches/showeqlegends/src/spellshell.cpp
showeq/branches/showeqlegends/src/spellshell.h
showeq/branches/showeqlegends/src/zonemgr.cpp
showeq/branches/showeqlegends/src/zonemgr.h
Modified: showeq/branches/showeqlegends/conf/worldopcodes.xml
===================================================================
--- showeq/branches/showeqlegends/conf/worldopcodes.xml 2026-07-11 20:22:48 UTC (rev 1660)
+++ showeq/branches/showeqlegends/conf/worldopcodes.xml 2026-07-11 20:32:53 UTC (rev 1661)
@@ -11,68 +11,68 @@
</opcode>
-->
- <opcode id="3ad6" name="OP_GuildList" updated="11/16/16">
+ <opcode id="bc01" name="OP_GuildList" updated="07/09/26">
<comment>old GuildListCode</comment>
<payload dir="server" typename="worldGuildListStruct" sizechecktype="none"/>
</opcode>
- <opcode id="08B3" name="OP_MOTD" updated="12/12/12">
+ <opcode id="f8e0" name="OP_MOTD" updated="07/09/26">
<comment>old MOTDCode Server message of the day</comment>
<payload dir="server" typename="worldMOTDStruct" sizechecktype="none"/>
</opcode>
<!-- Not necessary for SEQ to run but here to name packets in logs -->
- <opcode id="6893" name="OP_SendLoginInfo" updated="11/07/10">
+ <opcode id="7b6a" name="OP_SendLoginInfo" updated="07/09/26">
<comment>Client starting world session by asking for login information</comment>
</opcode>
- <opcode id="3288" name="OP_LogServer" updated="11/07/10">
+ <opcode id="b537" name="OP_LogServer" updated="07/09/26">
<comment></comment>
</opcode>
- <opcode id="115A" name="OP_ApproveWorld" updated="11/07/08">
+ <opcode id="b8cc" name="OP_ApproveWorld" updated="07/09/26">
<comment></comment>
</opcode>
- <opcode id="3288" name="OP_EnterWorld" updated="11/07/10">
+ <opcode id="26bf" name="OP_EnterWorld" updated="07/09/26">
<comment>Server approval for client to enter world</comment>
</opcode>
- <opcode id="1771" name="OP_ExpansionInfo" updated="11/07/10">
+ <opcode id="6bcf" name="OP_ExpansionInfo" updated="07/09/26">
<comment>Which expansions user has</comment>
</opcode>
- <opcode id="6685" name="OP_SendCharInfo" updated="07/18/12">
+ <opcode id="84f6" name="OP_SendCharInfo" updated="07/09/26">
<comment>Send all chars visible @ char select</comment>
</opcode>
- <opcode id="3C2D" name="OP_SendSpellChecksum" updated="11/07/10">
+ <opcode id="2de1" name="OP_SendSpellChecksum" updated="07/09/26">
<comment>Contains a snippet of spell data</comment>
</opcode>
- <opcode id="30E2" name="OP_SendExeChecksum" updated="11/07/10">
+ <opcode id="44d9" name="OP_SendExeChecksum" updated="07/09/26">
<comment>Second client verification packet</comment>
</opcode>
- <opcode id="2B5F" name="OP_SendBaseDataChecksum" updated="11/07/10">
+ <opcode id="289c" name="OP_SendBaseDataChecksum" updated="07/09/26">
<comment>Second client verification packet</comment>
</opcode>
- <opcode id="2874" name="OP_SendSkillCapsChecksum" updated="11/07/10">
+ <opcode id="a958" name="OP_SendSkillCapsChecksum" updated="07/09/26">
<comment>Third client verification packet</comment>
</opcode>
- <opcode id="28d4" name="OP_SetChatServer" updated="06/27/12">
+ <opcode id="bb67" name="OP_SetChatServer" updated="07/09/26">
<comment>Chatserver? IP,Port,servername.Charname,password(?)</comment>
</opcode>
- <opcode id="75f5" name="OP_SetChatServer2" updated="06/27/12">
+ <opcode id="f22b" name="OP_SetChatServer2" updated="07/09/26">
<comment>Chatserver? IP,Port,servername.Charname,password(?)</comment>
</opcode>
- <opcode id="777c" name="OP_ZoneServerInfo" updated="06/27/12">
+ <opcode id="35d4" name="OP_ZoneServerInfo" updated="07/09/26">
<comment>old ZoneServerInfo</comment>
</opcode>
- <opcode id="72F3" name="OP_WorldComplete" updated="11/07/10">
+ <opcode id="fc46" name="OP_WorldComplete" updated="07/09/26">
<comment>Client telling world server it is done. World replies by disconnecting.</comment>
</opcode>
- <opcode id="2730" name="OP_DeleteCharacter" updated="11/07/10">
+ <opcode id="48f9" name="OP_DeleteCharacter" updated="07/09/26">
<comment>Delete character @ char select</comment>
</opcode>
- <opcode id="49B6" name="OP_CharacterCreate" updated="11/07/10">
+ <opcode id="0634" name="OP_CharacterCreate" updated="07/09/26">
<comment>Create character @ char select</comment>
</opcode>
- <opcode id="6E97" name="OP_ApproveName" updated="11/07/10">
+ <opcode id="a24a" name="OP_ApproveName" updated="07/09/26">
<comment>Approving new character name @ char creation</comment>
</opcode>
- <opcode id="0005" name="OP_RandomNameGenerator" updated="11/07/10">
+ <opcode id="ffff" name="OP_RandomNameGenerator" updated="07/09/26">
<comment>Returns a random name</comment>
</opcode>
</seqopcodes>
Modified: showeq/branches/showeqlegends/conf/zoneopcodes.xml
===================================================================
--- showeq/branches/showeqlegends/conf/zoneopcodes.xml 2026-07-11 20:22:48 UTC (rev 1660)
+++ showeq/branches/showeqlegends/conf/zoneopcodes.xml 2026-07-11 20:32:53 UTC (rev 1661)
@@ -3,112 +3,103 @@
<seqopcodes>
<!-- Critical opcodes used directly by ShowEQ -->
- <opcode id="e284" name="OP_PlayerProfile" updated="05/20/26">
- <comment>CharProfileCode</comment>
+ <opcode id="62f0" name="OP_PlayerProfile" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified 42485B</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="a5bf" name="OP_ZoneEntry" updated="05/20/26">
- <comment>ZoneEntryCode</comment>
+ <opcode id="4606" name="OP_ZoneEntry" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified both dirs, c2s 92B</comment>
<payload dir="client" typename="ClientZoneEntryStruct" sizechecktype="match"/>
- <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="7e22" name="OP_TimeOfDay" updated="05/20/26">
- <comment>TimeOfDayCode</comment>
+ <opcode id="34c7" name="OP_TimeOfDay" updated="07/09/26">
+ <comment>07/07 rotation; 8B, stock layout byte-identical (u16 year 3172 + u16 pad); wire-verified across 6 sessions, advances at EQ game rate with correct day rollover</comment>
<payload dir="server" typename="timeOfDayStruct" sizechecktype="match"/>
</opcode>
- <opcode id="a923" name="OP_NewZone" updated="05/20/26">
- <comment>NewZoneCode</comment>
+ <opcode id="1dbf" name="OP_NewZone" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified 336B</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="33ec" name="OP_SpawnDoor" updated="05/20/26">
- <comment>DoorSpawnsCode</comment>
+ <opcode id="71ca" name="OP_SpawnDoor" updated="07/08/26">
+ <comment>07/07/26 rotation, wire-verified door defs; payload matched to code registration (modulus) to clear connect2 warning</comment>
<payload dir="server" typename="doorStruct" sizechecktype="modulus"/>
</opcode>
- <opcode id="92dc" name="OP_GroundSpawn" updated="05/20/26">
- <comment>MakeDropCode</comment>
+ <opcode id="0def" name="OP_GroundSpawn" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified IT defs</comment>
<payload dir="server" typename="makeDropStruct" sizechecktype="none"/>
- <payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ad5c" name="OP_SendZonePoints" updated="05/20/26">
- <comment>Coords in a zone that will port you to another zone</comment>
+ <opcode id="069f" name="OP_SendZonePoints" updated="07/09/26">
+ <comment>07/07 rotation; u32 count + count*32B rows (stock 24B zonePoint fields + 8 zero bytes) + 32B ff trailer; wire-verified befallen/felwithea vs known zone lines and neighbor zone ids</comment>
<payload dir="server" typename="zonePointsStruct" sizechecktype="none"/>
</opcode>
- <opcode id="0c97" name="OP_AAExpUpdate" updated="05/20/26">
- <comment>Receiving AA experience. Also when percent to AA changes.</comment>
- <payload dir="server" typename="altExpUpdateStruct" sizechecktype="match"/>
+ <opcode id="42d1" name="OP_AAExpUpdate" updated="07/09/26">
+ <comment>EQL 12B: u32 AA per-point progress permille*1000 (in-game-calibrated against the AA bar), u32 unassigned AA, u32 varying suffix. Was cross-wired to 6801 (which is regular exp)</comment>
+ <payload dir="server" typename="altExpUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_ExpUpdate" updated="07/19/23">
- <comment>ExpUpdateCode</comment>
+ <opcode id="6801" name="OP_ExpUpdate" updated="07/09/26">
+ <comment>EQL 16B: u32 exp permille*1000 (in-game-calibrated against the exp bar), u32 0, u32 unassigned AA, u32 0. Was cross-wired to 42d1 (which is the AA bar)</comment>
<payload dir="server" typename="expUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9f2b" name="OP_GuildMOTD" updated="05/20/26">
- <comment>GuildMOTD</comment>
+ <opcode id="46df" name="OP_GuildMOTD" updated="07/09/26">
+ <comment>07/07 rotation; stock guildMOTDStruct byte-perfect (target@8, sender@72, message@140; 656B = header + msg buffer); wire-verified vs known MOTD text at zone-in</comment>
<payload dir="server" typename="guildMOTDStruct" sizechecktype="none"/>
</opcode>
- <opcode id="f8d1" name="OP_ClientUpdate" updated="05/20/26">
- <comment>Position updates</comment>
- <payload dir="server" typename="playerSpawnPosStruct" sizechecktype="match"/>
- <payload dir="both" typename="playerSelfPosStruct" sizechecktype="match"/>
+ <opcode id="7171" name="OP_ClientUpdate" updated="07/08/26">
+ <comment>07/08/26 server payload sizecheck none->match to satisfy connect2 (playerPosUpdate was unwired; other PCs stuck at safe point)</comment>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
+ <payload dir="server" typename="playerPosUpdateEQLStruct" sizechecktype="match"/>
</opcode>
- <opcode id="917c" name="OP_NpcMoveUpdate" updated="05/20/26">
- <comment>Position updates</comment>
- <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ <opcode id="67e0" name="OP_MobUpdate" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified 14B</comment>
+ <payload dir="both" typename="spawnPositionUpdate" sizechecktype="none"/>
</opcode>
- <opcode id="4a4f" name="OP_MobUpdate" updated="05/20/26">
- <comment>MobUpdateCode</comment>
- <payload dir="both" typename="spawnPositionUpdate" sizechecktype="match"/>
- </opcode>
- <opcode id="94d4" name="OP_DeleteSpawn" updated="05/20/26">
- <comment>DeleteSpawnCode</comment>
+ <opcode id="59a1" name="OP_DeleteSpawn" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified 4B, death trio</comment>
<payload dir="both" typename="deleteSpawnStruct" sizechecktype="match"/>
</opcode>
- <opcode id="eb88" name="OP_RemoveSpawn" updated="05/20/26">
- <comment>Remove spawn from zone</comment>
- <payload dir="both" typename="removeSpawnStruct" sizechecktype="none"/>
+ <opcode id="71ad" name="OP_RemoveSpawn" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified 5B s2c + 4B c2s</comment>
+ <payload dir="both" typename="removeSpawnStruct" sizechecktype="none"/>
</opcode>
- <opcode id="1eb2" name="OP_Death" updated="05/20/26">
- <comment>old NewCorpseCode</comment>
- <payload dir="server" typename="newCorpseStruct" sizechecktype="match"/>
- </opcode>
- <opcode id="ffff" name="OP_WearChange" updated="07/19/23">
- <comment>SpawnUpdateCode</comment>
+ <opcode id="5c62" name="OP_WearChange" updated="07/09/26">
+ <comment>07/09/26 EQL wire-verified via marked equip/unequip capture: 32B {u32 spawnId, u32 wearSlot(7=pri,8=sec), u32 material, 20B zero}; client-sent for self, server-broadcast for others, preceded by 2575/2a0a value-0x40 trigger. Stock handler is a wear no-op (subcommand 17 HP only) so the 27B match never firing = stock-equivalent; id mapped for log identification</comment>
<payload dir="both" typename="SpawnUpdateStruct" sizechecktype="match"/>
</opcode>
- <opcode id="9826" name="OP_SpawnAppearance" updated="05/20/26">
- <comment>SpawnAppearanceCode</comment>
- <payload dir="both" typename="spawnAppearanceStruct" sizechecktype="match"/>
+ <opcode id="1bdc" name="OP_SpawnAppearance" updated="07/09/26">
+ <comment>EQL u32-widened stock struct, fixed 24B (3748/3748 pcap-library packets); type 6=position (110 sit/100 stand/111 duck), 13=anon, 36=LFG, 22=tick; decoded by SpawnShell::spawnEventEQL</comment>
+ <payload dir="both" typename="spawnEventEQLStruct" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_Stamina" updated="07/19/23">
<comment>Server updating on hunger/thirst</comment>
<payload dir="server" typename="staminaStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_HPUpdate" updated="07/19/23">
- <comment>NpcHpUpdateCode Update HP % of a PC or NPC</comment>
- <payload dir="both" typename="hpNpcUpdateStruct" sizechecktype="match"/>
+ <opcode id="2735" name="OP_HPUpdate" updated="07/09/26">
+ <comment>EQL stat-sync channel, fully decoded: u32 spawnId, u8 flags (bit0 wide-i64/narrow-percent, bit1 HP, bit2 mana, bit3 endurance, bits4-5 reason), per-stat {i64 cur,max} or u8 percent, optional trailing u32; flags 0x31 = 6s keepalive. Decoder SpawnShell::spawnStatEQL feeds spawn HP cur/max and player mana (stock manaChanged); endurance consumed (no stock display); food/water never ride this channel</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="9abe" name="OP_GuildMemberUpdate" updated="05/20/26">
- <comment>Info regarding guild members</comment>
+ <opcode id="51ed" name="OP_GuildMemberUpdate" updated="07/09/26">
+ <comment>07/07 rotation; stock struct + u32 rank inserted @8 (name->12, 88B total unchanged); wire-verified across 6 promote/demote clicks (rank 7..2)</comment>
<payload dir="server" typename="GuildMemberUpdate" sizechecktype="match"/>
</opcode>
- <opcode id="ab5e" name="OP_ClickObject" updated="05/20/26">
- <comment>Items dropped on the ground</comment>
+ <opcode id="04d1" name="OP_ClickObject" updated="07/09/26">
+ <comment>07/07 rotation; stock remDropStruct byte-perfect (u16 dropId matches ground spawn id, u16 spawnId=player); wire-verified drop+pickup</comment>
<payload dir="both" typename="remDropStruct" sizechecktype="match"/>
</opcode>
- <opcode id="049e" name="OP_Action" updated="05/20/26">
- <comment>Spells cast etc</comment>
+ <opcode id="73de" name="OP_Action" updated="07/09/26">
+ <comment>EQL 0x73de = stock actionStruct (64B; spell@4 verified vs known cast 434, type@56=231 spell-action on all 1040 corpus records); 88B alt form = actionAltStruct</comment>
<payload dir="both" typename="actionStruct" sizechecktype="match"/>
<payload dir="both" typename="actionAltStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_Action2" updated="04/17/24">
- <comment>Combat actions i.e. bash, kick etc</comment>
+ <opcode id="1734" name="OP_Action2" updated="07/08/26">
+ <comment>EQL per-hit combat: tgt u16, src u16, dmg@8, spell@20 (ffffffff=melee), type u32@24; wire-verified vs 8 known hits + Envenomed Breath 434</comment>
<payload dir="both" typename="action2Struct" sizechecktype="match"/>
</opcode>
- <opcode id="a1e7" name="OP_Consider" updated="05/20/26">
- <comment>ConsiderCode</comment>
+ <opcode id="4212" name="OP_Consider" updated="07/09/26">
+ <comment>fixed 24B both dirs (98/98 pcap-library packets); response: selfId, targetId, faction, level; struct trimmed 32->24 to restore size check</comment>
<payload dir="both" typename="considerStruct" sizechecktype="match"/>
</opcode>
- <opcode id="1994" name="OP_TargetMouse" updated="05/20/26">
- <comment>Targeting a person - old ClientTargetCode</comment>
+ <opcode id="2867" name="OP_TargetMouse" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified 4B</comment>
<payload dir="both" typename="clientTargetStruct" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_SpawnRename" updated="07/19/23">
@@ -123,13 +114,13 @@
<comment>Server putting players into shroud form</comment>
<payload dir="server" typename="spawnShroudSelf" sizechecktype="none"/>
</opcode>
- <opcode id="9148" name="OP_ZoneChange" updated="05/20/26">
- <comment>old ZoneChangeCode</comment>
- <payload dir="both" typename="zoneChangeStruct" sizechecktype="match"/>
+ <opcode id="76d3" name="OP_ZoneChange" updated="07/09/26">
+ <comment>EQL c2s zone-change request, fixed 484B (32/32 pcap-library packets), carries position but no zone id; server never sends it (zone change = session teardown + new session). Handler only sets m_zoning</comment>
+ <payload dir="both" typename="zoneChangeEQLStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_GroupInvite" updated="02/17/21">
- <payload dir="both" typename="groupInviteStruct" sizechecktype="none"/>
- <comment>You invite someone while ungrouped or get invited by someone ungrouped </comment>
+ <opcode id="6e69" name="OP_GroupInvite" updated="07/09/26">
+ <comment>EQL group invite: fixed 168B (invitee@0, inviter@64); struct padded 152->168 to restore size check; wire-verified /say-marked invite</comment>
+ <payload dir="both" typename="groupInviteStruct" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_GroupInvite2" updated="02/17/21">
<payload dir="both" typename="groupInviteStruct" sizechecktype="none"/>
@@ -139,20 +130,20 @@
<payload dir="both" typename="groupDeclineStruct" sizechecktype="match"/>
<comment>Declining to join a group</comment>
</opcode>
- <opcode id="ffff" name="OP_GroupFollow" updated="02/17/21">
+ <opcode id="1512" name="OP_GroupFollow" updated="07/09/26">
+ <comment>EQL group member-add: invitee name@64 matches stock groupFollowStruct; fixed 168B (8/8 pcap-library packets), struct padded 152->168; stock addGroupMember + groupFollow</comment>
<payload dir="server" typename="groupFollowStruct" sizechecktype="match"/>
- <comment>You join a group or player joins group</comment>
</opcode>
<opcode id="ffff" name="OP_GroupFollow2" updated="02/17/21">
<payload dir="server" typename="groupFollowStruct" sizechecktype="match"/>
<comment>Player joins your group</comment>
</opcode>
- <opcode id="ffff" name="OP_GroupUpdate" updated="06/19/19">
- <comment>Group updates</comment>
- <payload dir="both" typename="uint8_t" sizechecktype="none"/>
+ <opcode id="397d" name="OP_GroupUpdate" updated="07/09/26">
+ <comment>EQL full group roster: u32 groupId, u32 count, leader name@8, then count 44B member records from @18 (name NUL-term); resent at zone-in; count=1=solo; decoded by GroupMgr::groupRosterEQL</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_GroupDisband" updated="02/17/21">
- <comment>You disband from group</comment>
+ <opcode id="09aa" name="OP_GroupDisband" updated="07/09/26">
+ <comment>EQL group member-remove/leave: membername@64 matches stock groupDisbandStruct; fixed 168B (4/4 pcap-library packets), struct padded 152->168; stock removeGroupMember + groupDisband</comment>
<payload dir="server" typename="groupDisbandStruct" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_GroupDisband2" updated="02/17/21">
@@ -163,20 +154,20 @@
<comment>Group leader change</comment>
<payload dir="server" typename="groupLeaderChangeStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_Buff" updated="07/19/23">
- <comment>old BuffDropCode</comment>
- <payload dir="both" typename="buffStruct" sizechecktype="match"/>
+ <opcode id="3ada" name="OP_Buff" updated="07/09/26">
+ <comment>07/07 rotation; stock buffStruct padding-stripped, fixed 24B (264/264 pcap-library packets): u32 buffSlot/spellId/1/changeType(4=apply,1=fade)/0/unused; decoded by SpellShell::buffEQL</comment>
+ <payload dir="both" typename="buffEQLStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_BeginCast" updated="07/19/23">
- <comment>BeginCastCode</comment>
- <payload dir="both" typename="beginCastStruct" sizechecktype="match"/>
+ <opcode id="5591" name="OP_BeginCast" updated="07/09/26">
+ <comment>07/07 rotation; stock beginCastStruct (spellId u16@0, spawnId u16@4=caster); 19B EQL vs 11B stock; wire-verified vs known casts</comment>
+ <payload dir="both" typename="beginCastStruct" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_CastSpell" updated="12/05/23">
- <comment>StartCastCode</comment>
+ <opcode id="10b5" name="OP_CastSpell" updated="07/09/26">
+ <comment>07/07 rotation; stock startCastStruct (slot@0, spellId@4, targetId@18) padded 39->40 to the fixed EQL size (76/76 pcap-library packets)</comment>
<payload dir="both" typename="startCastStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_SwapSpell" updated="07/19/23">
- <comment>TradeSpellBookSlotsCode</comment>
+ <opcode id="0fa0" name="OP_SwapSpell" updated="07/09/26">
+ <comment>EQL 07/07 rotation; stock tradeSpellBookSlotsStruct (slot1 u32@0, slot2 u32@4) 8B exact; wire-verified swapping spellbook slots 6/7</comment>
<payload dir="both" typename="tradeSpellBookSlotsStruct" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_MemorizeSpell" updated="07/19/23">
@@ -183,12 +174,12 @@
<comment>MemSpellCode</comment>
<payload dir="both" typename="memSpellStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_InspectAnswer" updated="07/19/23">
- <comment>InspectDataCode</comment>
- <payload dir="both" typename="inspectDataStruct" sizechecktype="match"/>
+ <opcode id="17af" name="OP_InspectAnswer" updated="07/09/26">
+ <comment>07/07 rotation; stock inspectDataStruct byte-perfect incl. 1956B total size (3/3 captured inspects); size check restored</comment>
+ <payload dir="server" typename="inspectDataStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_Emote" updated="07/19/23">
- <comment>EmoteTextCode</comment>
+ <opcode id="1cde" name="OP_Emote" updated="07/09/26">
+ <comment>07/09/26 EQL: wire-verified via marked capture; 4B header + emote text, 1028B fixed buffer so SZC_None</comment>
<payload dir="both" typename="emoteTextStruct" sizechecktype="none"/>
</opcode>
<opcode id="44a0" name="OP_SimpleMessage" updated="05/20/26">
@@ -195,24 +186,24 @@
<comment>SimpleMessageCode</comment>
<payload dir="server" typename="simpleMessageStruct" sizechecktype="match"/>
</opcode>
- <opcode id="5b40" name="OP_FormattedMessage" updated="05/20/26">
- <comment>FormattedMessageCode i.e. pet dismissed etc</comment>
+ <opcode id="3c0a" name="OP_FormattedMessage" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified caret args</comment>
<payload dir="server" typename="formattedMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="498b" name="OP_CommonMessage" updated="05/20/26">
- <comment>ChannelMessageCode i.e. /tell /ooc /shout etc</comment>
+ <opcode id="55eb" name="OP_CommonMessage" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified /say both dirs</comment>
<payload dir="both" typename="channelMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="7162" name="OP_SpecialMesg" updated="05/20/26">
- <comment>Communicate textual info to client including hail responses etc</comment>
+ <opcode id="22e1" name="OP_SpecialMesg" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified NPC speech</comment>
<payload dir="server" typename="specialMessageStruct" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_RandomReq" updated="07/19/23">
- <comment>RandomReqCode</comment>
- <payload dir="client" typename="randomReqStruct" sizechecktype="match"/>
+ <opcode id="08cb" name="OP_RandomReq" updated="07/09/26">
+ <comment>EQL 07/07 rotation; stock randomReqStruct with 8B AND 9B wire forms observed (trailing byte optional) so no size check; wire-verified /random</comment>
+ <payload dir="client" typename="randomReqStruct" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_RandomReply" updated="07/19/23">
- <comment>RandomCode</comment>
+ <opcode id="6589" name="OP_RandomReply" updated="07/09/26">
+ <comment>EQL 07/07 rotation; stock randomStruct (bottom,top,result,name[64]) 76B exact; wire-verified /random 1 100 = 63</comment>
<payload dir="server" typename="randomStruct" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_ConsentResponse" updated="02/17/21">
@@ -240,8 +231,8 @@
<comment>MoneyOnCorpseCode</comment>
<payload dir="server" typename="moneyOnCorpseStruct" sizechecktype="match"/>
</opcode>
- <opcode id="ffff" name="OP_SkillUpdate" updated="07/19/23">
- <comment>Skill up code</comment>
+ <opcode id="6982" name="OP_SkillUpdate" updated="07/09/26">
+ <comment>07/07 rotation; stock skillIncStruct byte-perfect (12B: skillId u32, value i32, +4); wire-verified Abjuration(4)=150</comment>
<payload dir="server" typename="skillIncStruct" sizechecktype="match"/>
</opcode>
<opcode id="ffff" name="OP_LevelUpdate" updated="07/19/23">
@@ -307,10 +298,6 @@
<comment>List of group members - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="4058" name="OP_GuildMemberList" updated="05/20/26">
- <comment>List of guild members - Variable length</comment>
- <payload dir="server" typename="uint8_t" sizechecktype="none"/>
- </opcode>
<opcode id="ffff" name="OP_ManaUpdate" updated="07/19/23">
<comment>Mana Update opcode - 10 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
@@ -367,8 +354,8 @@
<comment>Fellowship information - 2576 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="8d86" name="OP_ExpandedGuildInfo" updated="05/20/26">
- <comment>Guild ranks and other misc guild data - Variable length</comment>
+ <opcode id="3aac" name="OP_ExpandedGuildInfo" updated="07/09/26">
+ <comment>07/07 rotation; guild ranks/misc data channel (subtyped: 192B self-status w/ rank title + MOTD, 104/352/4184B rank-and-permission blobs at zone-in); not consumed</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
<opcode id="ffff" name="OP_GuildBank" updated="11/20/15">
@@ -415,8 +402,8 @@
<comment>List of available titles - 1520 bytes</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_Animation" updated="11/28/12">
- <comment>Combat animation, emote animations etc - 4 bytes</comment>
+ <opcode id="1293" name="OP_Animation" updated="07/09/26">
+ <comment>EQL 0x1293 4B combat/emote animation tick (u16 spawnId + u8 + u8); community-corroborated</comment>
<payload dir="both" typename="uint8_t" sizechecktype="none"/>
</opcode>
<opcode id="ffff" name="OP_WhoAllRequest" updated="11/28/12">
@@ -427,8 +414,8 @@
<comment>WhoAllOutputCode - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_InspectRequest" updated="11/28/12">
- <comment>InspectRequestCode - 8 bytes</comment>
+ <opcode id="2cc0" name="OP_InspectRequest" updated="07/09/26">
+ <comment>07/09/26 EQL wire-verified via marked inspects: 8B {u32 targetId, u32 selfId}; no stock consumer - identification-only</comment>
<payload dir="client" typename="uint8_t" sizechecktype="none"/>
</opcode>
<opcode id="ffff" name="OP_GetGuildMOTD" updated="11/28/12">
@@ -535,12 +522,12 @@
<comment>Listing of all guilds. Can be triggered by /lfg search?</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="d5e8" name="OP_GuildsInZoneList" updated="05/20/26">
- <comment>Listing of guild names present in the current zone. Generally seen on zoning</comment>
+ <opcode id="6070" name="OP_GuildsInZoneList" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified</comment>
<payload dir="server" typename="guildsInZoneListStruct" sizechecktype="none"/>
</opcode>
- <opcode id="ffff" name="OP_NewGuildInZone" updated="07/19/23">
- <comment>An additional guild name has appeared in the current zone. Seen when a guilded player enters the current zone</comment>
+ <opcode id="4411" name="OP_NewGuildInZone" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified 26B</comment>
<payload dir="server" typename="newGuildInZoneStruct" sizechecktype="none"/>
</opcode>
<opcode id="ffff" name="OP_LFGGetMatchesRequest" updated="11/28/12">
@@ -595,8 +582,8 @@
<comment>Free to play nags and other data - Variable length</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
- <opcode id="695f" name="OP_Find" updated="05/20/26">
- <comment>Find window data - variable length, 24 min</comment>
+ <opcode id="56f9" name="OP_Find" updated="07/09/26">
+ <comment>07/07 rotation; Find window NPC/services table (variable ~2KB, pushed at zone-in); name-only, no consumer</comment>
<payload dir="server" typename="uint8_t" sizechecktype="none"/>
</opcode>
<opcode id="ffff" name="OP_ConsiderCorpse" updated="11/28/12">
@@ -1007,4 +994,36 @@
<comment></comment>
</opcode>
-->
+ <opcode id="1ede" name="OP_HideCorpse" updated="07/07/26">
+ <comment>07/07/26 rotation, wire-verified isolated press, 4B</comment>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="0201" name="OP_SelfPosEQL" updated="07/08/26">
+ <comment>c2s self-state; floats mapY/mapX/Z at 0/4/8; no facing word on wire</comment>
+ <payload dir="client" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="7352" name="OP_NpcMoveUpdate" updated="07/08/26">
+ <comment>07/08/26 relocated live-rate NPC pathing channel (was 2824 pre-patch); EQL bit layout: id16 pad16 spec6, sign+mag 19b x@38 y@57 z@76, h12@95; decoder npcMoveUpdateEQL</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="66cb" name="OP_Death" updated="07/09/26">
+ <comment>EQL 0x66cb = stock newCorpseStruct byte-perfect (corpseid always 0, corpses never spawn); fires once per death; community-corroborated</comment>
+ <payload dir="server" typename="newCorpseStruct" sizechecktype="match"/>
+ </opcode>
+ <opcode id="295d" name="OP_DeathEQL" updated="07/09/26">
+ <comment>EQL 0x295d multiplexed death/combat subcode channel (was named OP_Death until stock OP_Death relocated to 66cb); report-only decoder SpawnShell::deathRecordEQL</comment>
+ <payload dir="both" typename="deathRecordEQLStruct" sizechecktype="none"/>
+ </opcode>
+ <opcode id="31ed" name="OP_GuildMemberList" updated="07/09/26">
+ <comment>07/07 rotation; count-prefixed roster, near-stock entries (LP name, level, banker, classMask, rank, lastOn, tribute block, fullmember, LP note, u16 zoneId + u16 + u16 online); header is 1 byte wider than live</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="77ae" name="OP_BuffList" updated="07/09/26">
+ <comment>07/07 rotation; per-spawn buff list: u32 spawnId, u32, u8 1, u8 count, 5pad, then count 26B records {spellId, 1, i32 remainingTicks, 0, casterName NUL, u32 slot}; loads active buffs at zone-in w/ real remaining durations; decoded by SpellShell::buffListEQL</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
+ <opcode id="7477" name="OP_LoadoutSwapEQL" updated="07/09/26">
+ <comment>EQL-only: loadout-swap (class-switch) self refresh, ~118KB: u32 spawnId, u8 1, u16 innerLen, ZoneEntry-format self record (new classMask + level), serialized inventory tail. Preceded by c2s 6a67 request/ack + 7820 item burst. Decoder SpawnShell::loadoutSwapEQL -> Player::loadoutSwapEQL (level/class only). Live analog is OP_Shroud; stock handler cannot parse this layout</comment>
+ <payload dir="server" typename="uint8_t" sizechecktype="none"/>
+ </opcode>
</seqopcodes>
Modified: showeq/branches/showeqlegends/src/eqstr.cpp
===================================================================
--- showeq/branches/showeqlegends/src/eqstr.cpp 2026-07-11 20:22:48 UTC (rev 1660)
+++ showeq/branches/showeqlegends/src/eqstr.cpp 2026-07-11 20:32:53 UTC (rev 1661)
@@ -182,12 +182,18 @@
size_t totalArgsLen = 0;
const char* curArg;
uint32_t curSize = 0;
- while (totalArgsLen < argsLen)
+ while (totalArgsLen + 4 <= argsLen)
{
curArg = arguments + totalArgsLen;
curSize = eqtohuint32((const uint8_t*) curArg);
curArg += 4;
+ // a wire length beyond the remaining payload means the
+ // arguments are not in this length-prefixed layout (EQL
+ // messages) - stop rather than allocate off garbage
+ if (curSize > argsLen - totalArgsLen - 4)
+ break;
+
if (curSize > 0) {
// insert argument into the argument list
argList.push_back(QString::fromUtf8(curArg, curSize));
Modified: showeq/branches/showeqlegends/src/everquest.h
===================================================================
--- showeq/branches/showeqlegends/src/everquest.h 2026-07-11 20:22:48 UTC (rev 1660)
+++ showeq/branches/showeqlegends/src/everquest.h 2026-07-11 20:32:53 UTC (rev 1661)
@@ -694,6 +694,7 @@
/*00004*/ uint16_t gender; // Player Gender - 0 Male, 1 Female
/*00008*/ uint32_t race; // Player race
/*00012*/ uint32_t class_; // Player class
+ uint32_t classMask; // EQ Legends multiclass bitmask (bit N = class N)
/*00016*/ uint8_t unknown00016[44]; // ***Placeholder
/*00056*/ uint8_t level; // Level of player
/*00057*/ uint8_t level1; // Level of player (again?)
@@ -1112,6 +1113,7 @@
/*0000*/ uint32_t guildServerID;
/*0000*/ uint32_t guildstatus; // 0=member, 1=officer, 2=leader, -1=not guilded
/*0000*/ uint8_t class_;
+/*0000*/ uint32_t classMask; // EQ Legends multiclass bitmask (bit N = class N)
/*0000*/ uint8_t state; // stand state
/*0000*/ uint8_t light;
/*0000*/ char lastName[32];
@@ -1121,23 +1123,29 @@
struct
{
- signed animation:10; // current animation
- unsigned pitch:12; // pitch (up/down heading)
- unsigned padding00:10;
+ // 2026-07-07 EQL layout: z, x, y are the low 19 bits of
+ // three consecutive words, world value = field >> 3 (live
+ // 19-bit convention). x/y keep the EQ Legends transposed
+ // naming so setPos receives the same world axes as before.
+ // The high 13 bits of each coord word are presumed deltas
+ // but are unvalidated; heading/animation/pitch positions
+ // in words 3-4 are unmapped (0x6000/0 observed) - all are
+ // zeroed at consumption in spawn.cpp until wire-mapped.
+ signed z:19; // z coord (loc value 1)
+ signed deltaZ:13; // presumed change in z (unvalidated)
- signed deltaZ:13; // change in z
- signed deltaHeading:10; // change in heading
- unsigned padding01:9;
+ signed x:19; // x coord (EQ Legends x/y transposed)
+ signed deltaX:13; // presumed change in x (unvalidated)
- signed z:19; // z coord (3rd loc value)
- unsigned heading:12; // heading
- unsigned padding02:1;
+ signed y:19; // y coord (EQ Legends x/y transposed)
+ signed deltaY:13; // presumed change in y (unvalidated)
- signed deltaX:13; // change in x
- signed y:19; // y coord (2nd loc value)
+ unsigned heading:12; // candidate heading word (unvalidated)
+ unsigned padding00:20;
- signed deltaY:13; // change in y
- signed x:19; // x coord (1st loc value)
+ signed deltaHeading:10; // unmapped
+ signed animation:10; // unmapped
+ unsigned pitch:12; // unmapped
};
int32_t posData[5];
@@ -1390,7 +1398,12 @@
/*0083*/ uint8_t invertstate; // invert state
/*0084*/ uint32_t zonePoint;
/*0088*/ uint8_t unknown068[28]; // ***Placeholder
-/*0116*/ uint8_t unknown096[20]; // ***Placeholder
+/*0116*/ uint8_t unknown096[16]; // ***Placeholder
+ // (was 20: struct summed
+ // to 136 vs its declared
+ // 132; EQL wire rows are
+ // a true 132 - 31 and 51
+ // door tables verified)
/*0132*/
};
@@ -1516,6 +1529,94 @@
};
/*
+** EQ Legends OP_MobUpdate (opcode 0x67e0, 14 bytes, 2026-07-07 wire).
+** Coordinate block starts at payload offset 4 and packs, low bit first:
+** x : bits 0..18 z : bits 19..37 (7-bit gap) y : bits 45..63
+** each signed 19-bit, world value = field >> 3 (live convention).
+** Byte-packed as two u32 words to avoid int64 bitfield alignment; the
+** 7-bit gap places y in the high 19 bits of the second word.
+** Verified against spawn-struct positions on 21/25 wire packets.
+*/
+struct spawnPositionUpdateEQL
+{
+/*0000*/ int16_t spawnId;
+/*0002*/ uint8_t unk1[2];
+/*0004*/ signed x:19; // bits 0..18
+ signed z:19 __attribute__((packed)); // bits 19..37 (crosses word)
+ unsigned u3:7; // bits 38..44 (gap)
+ signed y:19; // bits 45..63
+/*0012*/ unsigned heading:12;
+ signed unused2:4;
+/*0014*/
+};
+
+/*
+** EQ Legends player waypoint position update
+** Wire: one-byte-netop 0x03 family, LE opcode 0x0b03, fixed 24 bytes.
+** posData words use the same bit layout as the spawnStruct union.
+*/
+struct playerPosUpdateEQLStruct
+{
+/*0000*/ uint32_t spawnId;
+/*0004*/ uint32_t flags; // 0x00010842 observed constant
+/*0008*/ uint32_t unknown0008; // zero observed
+/*0012*/ signed z:19, deltaZ:13; // coord block, same 19-bit
+/*0016*/ signed x:19; // >>3 packing as spawnStruct
+ unsigned heading:13; // h2048 heading (0..2047) in x-word high bits
+/*0020*/ signed y:19, deltaY:13; // deltas unvalidated, unused
+/*0024*/ uint32_t tail; // zero observed
+/*0028*/
+};
+
+/*
+** EQ Legends spawn appearance event (OP_SpawnAppearance = 0x1bdc)
+** Stock 8B spawnAppearanceStruct u32-widened; fixed 24 bytes on the
+** wire (3748/3748 captured packets, both directions).
+** Decoded by SpawnShell::spawnEventEQL.
+*/
+struct spawnEventEQLStruct
+{
+/*0000*/ uint32_t spawnId;
+/*0004*/ uint32_t type; // 6=position, 13=anon,
+ // 22=tick, 36=LFG, 41=time
+/*0008*/ uint32_t value;
+/*0012*/ uint32_t params[3]; // zeros observed
+/*0024*/
+};
+
+/*
+** EQ Legends buff change (OP_Buff = 0x3ada)
+** Stock 168B buffStruct padding-stripped; fixed 24 bytes on the wire
+** (264/264 captured packets, both directions).
+** Decoded by SpellShell::buffEQL.
+*/
+struct buffEQLStruct
+{
+/*0000*/ uint32_t buffSlot; // 0-14 buff window; 15 =
+ // bar refresh; >=190 scribe
+/*0004*/ uint32_t spellId;
+/*0008*/ uint32_t unknown0008; // 1 observed
+/*0012*/ uint32_t changeType; // 4=applied, 1=faded
+/*0016*/ uint32_t unknown0016; // 0 observed
+/*0020*/ uint32_t unknown0020; // NOT a duration (verified
+ // non-linear, revG)
+/*0024*/
+};
+
+/*
+** EQ Legends client zone-change request (OP_ZoneChange = 0x76d3)
+** Fixed 484 bytes on the wire (32/32 captured packets). Carries
+** position but no zone id; the server never sends this opcode (a
+** zone change is a session teardown + new session). Layout unmapped;
+** the struct exists to give SZC_Match a size to gate on.
+*/
+struct zoneChangeEQLStruct
+{
+/*0000*/ uint8_t unknown0000[484];
+/*0484*/
+};
+
+/*
** Rename a spawn
** Length: 195 Octets
** OpCode: SpawnRename
@@ -1823,8 +1924,9 @@
{
/*0000*/ char invitee[64]; // Invitee's Name
/*0064*/ char inviter[64]; // Inviter's Name
-/*0128*/ uint8_t unknown0128[24]; // ***Placeholder
-/*0152*/
+/*0128*/ uint8_t unknown0128[40]; // ***Placeholder (EQL wire
+ // is fixed 168B; stock 152)
+/*0168*/
};
/*
@@ -1855,8 +1957,9 @@
/*0064*/ char invitee[64]; // Invitee's Member Name
/*0128*/ uint8_t unknown0128[4]; // ***Placeholder
/*0132*/ uint32_t level; // Invitee's level
-/*0136*/ uint8_t unknown0136[16]; // ***Placeholder (zeros)
-/*0152*/
+/*0136*/ uint8_t unknown0136[32]; // ***Placeholder (EQL wire
+ // is fixed 168B; stock 152)
+/*0168*/
};
/*
@@ -1869,8 +1972,9 @@
{
/*0000*/ char yourname[64]; // Player Name
/*0064*/ char membername[64]; // Invited Member Name
-/*0128*/ uint8_t unknown0128[24]; // ***Placeholder
-/*0152*/
+/*0128*/ uint8_t unknown0128[40]; // ***Placeholder (EQL wire
+ // is fixed 168B; stock 152)
+/*0168*/
};
/*
@@ -1930,7 +2034,8 @@
/*
** Consider Struct
-** Length: 32 Octets
+** Length: 24 Octets (EQL wire; stock was 32 - trailing unknowns
+** trimmed so SZC_Match can gate the fixed 24B Legends payload)
** OpCode: considerCode
*/
@@ -1942,9 +2047,7 @@
/*0012*/ int32_t level; // Level
/*0016*/ int32_t unknown0016; // unknown
/*0020*/ int32_t unknown0020; // unknown (rarity?)
-/*0024*/ int32_t unknown0024; // unknown
-/*0028*/ int32_t unknown0028; // unknown
-/*0032*/
+/*0024*/
};
/*
@@ -1985,6 +2088,26 @@
/*0040*/
};
+/*
+** EQ Legends death/combat record (opcode 0x295d, subcode 0x07, 36 bytes)
+** A combat damage event; the fatal hit is not flagged - spawn removal
+** at death is carried by OP_RemoveSpawn/OP_DeleteSpawn, so consumers
+** must treat this as informational only.
+*/
+struct deathRecordEQLStruct
+{
+/*0000*/ uint16_t subcode; // 0x07 for the combat record
+/*0002*/ uint16_t unknown0002; // always 1 observed
+/*0004*/ uint32_t sourceId; // attacker or spell/skill source
+/*0008*/ uint32_t skillOrDamage; // small values (0, 8, 0xc) observed
+/*0012*/ uint32_t targetId; // spawn id of the victim
+/*0016*/ uint32_t unknown0016; // always 1 observed
+/*0020*/ uint32_t combatSeq; // global monotonic combat counter
+/*0024*/ uint32_t unknown0024; // 0, 3, 4 observed
+/*0028*/ uint8_t unknown0028[8]; // zero observed
+/*0036*/
+};
+
/**
** Environmental damage (lava, falls)
** Length: 46 Octets
@@ -2042,12 +2165,14 @@
/*0000*/ uint16_t target; // Target ID
/*0002*/ uint16_t source; // Source ID
/*0004*/ uint8_t unknown0004[4];
-/*0008*/ int32_t damage;
+/*0008*/ int32_t damage; // 0 = miss (EQL wire)
/*0012*/ int8_t unknown0012[8];
-/*0020*/ int32_t spell; // SpellID
-/*0024*/ uint8_t uknown0024[16];
-/*0040*/ uint8_t type; // Bash, kick, cast, etc.
-/*0041*/ uint8_t unknown0042[7];
+/*0020*/ int32_t spell; // SpellID, -1 = melee
+/*0024*/ uint32_t type; // Bash, kick, cast, etc.
+ // EQL 0x1734 carries this
+ // as u32 here; stock had
+ // u8 at offset 0040
+/*0028*/ uint8_t unknown0028[20];
/*0048*/
};
@@ -2107,8 +2232,10 @@
/*0018*/ uint32_t targetId; // The current selected target
/*0022*/ uint8_t unknown0022[2]; // ***Placeholder
/*0024*/ uint8_t unknown0024[2]; // ***Placeholder
-/*0026*/ uint8_t unknown0026[13]; // ***Placeholder (4/7/2009)
-/*0039*/
+/*0026*/ uint8_t unknown0026[14]; // ***Placeholder (EQL wire
+ // is fixed 40B, 76/76
+ // packets; stock was 39)
+/*0040*/
};
/*
@@ -2250,10 +2377,18 @@
struct expUpdateStruct
{
-/*0000*/ uint32_t exp; // experience value x/330
-/*0004*/ uint32_t unknown0004; // unknown
-/*0008*/ uint32_t type; // 0=set, 2=update
-/*0012*/ uint32_t unknown0012; // unknown
+/*0000*/ uint32_t exp; // EQ Legends: level progress
+ // on a 0-100000 scale
+ // (hundredths of a percent);
+ // live was x/330. NOTE: on
+ // Legends this rides opcode
+ // 6801 (in-game-calibrated
+ // against the exp bar; the
+ // ids were cross-wired)
+/*0004*/ uint32_t unknown0004; // 0 observed
+/*0008*/ uint32_t aaUnspent; // unassigned AA points
+ // (in-game-verified)
+/*0012*/ uint32_t unknown0012; // 0 observed
/*0016*/
};
@@ -2264,10 +2399,18 @@
*/
struct altExpUpdateStruct
{
-/*0000*/ uint32_t altexp; // alt exp x/330
-/*0004*/ uint32_t aapoints; // current number of AA points
-/*0008*/ uint8_t percent; // percentage in integer form
-/*0009*/ uint8_t unknown0009[3]; // ***Place Holder
+/*0000*/ uint32_t altexp; // EQ Legends: AA per-point
+ // progress on a 0-100000
+ // scale (live was x/330).
+ // NOTE: on Legends this
+ // rides opcode 42d1
+ // (in-game-calibrated
+ // against the AA bar; the
+ // ids were cross-wired)
+/*0004*/ uint32_t aapoints; // unassigned AA points
+ // (in-game-verified)
+/*0008*/ uint32_t unknown0008; // varying tail (suffix u32
+ // family)
/*0012*/
};
@@ -2427,32 +2570,22 @@
*/
struct playerSelfPosStruct
{
-/*0000*/ uint16_t unknown0000; // ***Placeholder (update time counter?)
-/*0002*/ uint16_t spawnId; // Player's spawn id
-/*0004*/ uint16_t unknown0004; // ***Placeholder
-/*0006*/
- float y; // y coord (2nd loc value)
-/*0010*/
- unsigned pitch:12; // pitch (up/down heading)
- unsigned heading:12; // heading
- unsigned padding01:8;
-/*0014*/
- float deltaY; // change in y
-/*0018*/
- signed animation:10; // current animation
- unsigned padding03:22;
-/*0022*/
- float z; // z coord (3rd loc value)
-/*0026*/
- float x; // x coord (1st loc value)
-/*0030*/
- float deltaX; // change in x
-/*0034*/
- signed deltaHeading:10; // change in heading
- unsigned padding07:22;
-/*0038*/
- float deltaZ; // change in z
-/*0042*/
+/*0000*/ float x; // x coord (Legends float at offset 0)
+/*0004*/ float y; // y coord
+/*0008*/ float z; // z coord
+/*0012*/ uint8_t posFlag; // 0x02 moving marker
+/*0013*/ uint8_t unknown0013;
+/*0014*/ uint8_t unknown0014;
+/*0015*/ uint8_t seq; // increments each update
+/*0016*/ uint16_t headingRaw; // heading region
+ uint16_t spawnId;
+ float deltaX;
+ float deltaY;
+ float deltaZ;
+ unsigned heading:12;
+ signed deltaHeading:10;
+ unsigned pitch:12;
+ signed animation:10;
};
/*
@@ -2658,11 +2791,15 @@
{
/*000*/ uint32_t guildId; // guild id
/*004*/ uint8_t unknown004[4]; // 4 bytes added 11/16/16
-/*008*/ char name[64]; // member name
-/*072*/ uint16_t zoneId; // zone id
-/*074*/ uint16_t zoneInstance; // zone instance
-/*076*/ uint32_t lastOn; // time the player was last on.
-/*080*/ uint8_t unknown080[8]; // 4 bytes added 11/28/12, +4 added 11/16/16
+/*008*/ uint32_t rank; // EQ Legends: member rank
+ // (inserted here; watched
+ // count down 7..2 across
+ // promote/demote clicks)
+/*012*/ char name[64]; // member name
+/*076*/ uint16_t zoneId; // zone id
+/*078*/ uint16_t zoneInstance; // zone instance
+/*080*/ uint32_t lastOn; // time the player was last on.
+/*084*/ uint8_t unknown084[4]; // EQL tail (uninit server mem)
/*088*/
};
Modified: showeq/branches/showeqlegends/src/group.cpp
===================================================================
--- showeq/branches/showeqlegends/src/group.cpp 2026-07-11 20:22:48 UTC (rev 1660)
+++ showeq/branches/showeqlegends/src/group.cpp 2026-07-11 20:32:53 UTC (rev 1661)
@@ -67,19 +67,15 @@
void GroupMgr::player(const charProfileStruct* player)
{
- // We receive a groupUpdate packet after playerProfile so we'll clear the
- // member list then repopulate it in case we lost someone during zoning
- m_memberCount = 0;
- m_membersInZoneCount = 0;
+ // EQ Legends does NOT resend the group roster on zone-in (verified
+ // 2026-07-09: zoned mid-group, no group packets followed the
+ // profile), so we must NOT clear here - the group persists across
+ // zones and is only changed by the per-member add/remove opcodes
+ // (0x1512 / 0x09aa). Clearing here (stock behavior, which relied on
+ // a post-profile groupUpdate to repopulate) would wipe the group on
+ // every zone with nothing to refill it.
+ (void)player;
- for(int i = 0; i < MAX_GROUP_MEMBERS; i++)
- {
- m_members[i]->m_name = "";
- m_members[i]->m_spawn = 0;
- }
-
- emit cleared();
-
// 9/3/2008 - Not used. Group data is no longer sent in charProfile. We still
// need to reset the data as done above.
#if 0
@@ -245,6 +241,71 @@
}
}
+void GroupMgr::groupRosterEQL(const uint8_t* data, size_t len)
+{
+ // EQ Legends full group roster (OP_GroupUpdate = 0x397d), resent at
+ // zone-in - the group analog of the buff list (0x77ae): it loads the
+ // members you already have when ShowEQ zones in or starts up mid-
+ // group, which the incremental 0x1512/0x09aa updates cannot. The
+ // stock groupUpdate parser cannot read this format (verified), so it
+ // needs a dedicated decoder. Header: u32 groupId | u32 count |
+ // leader name @8; then count 44-byte member records from offset 18
+ // (name NUL-terminated, possibly a leading NUL from the prior
+ // record's trailing index). count == 1 is the solo/not-grouped
+ // state. Authoritative: clear and repopulate.
+ if (len < 12)
+ return;
+
+ uint32_t count = *(const uint32_t*)(data + 4);
+
+ m_memberCount = 0;
+ m_membersInZoneCount = 0;
+ for (int i = 0; i < MAX_GROUP_MEMBERS; i++)
+ {
+ m_members[i]->m_name = "";
+ m_members[i]->m_spawn = 0;
+ }
+ emit cleared();
+
+ if (count < 2) // solo = not in a group
+ return;
+
+ for (uint32_t r = 0; r < count && r < MAX_GROUP_MEMBERS; r++)
+ {
+ size_t off = 18 + r * 44;
+ if (off >= len)
+ break;
+ while (off < len && data[off] == 0)
+ off++;
+ size_t s = off;
+ while (off < len && data[off])
+ off++;
+ if (off == s)
+ continue;
+ QString name = QString::fromLatin1((const char*)(data + s), int(off - s));
+
+ bool dup = false;
+ for (int j = 0; j < MAX_GROUP_MEMBERS; j++)
+ if (m_members[j]->m_name == name) { dup = true; break; }
+ if (dup)
+ continue;
+
+ for (int j = 0; j < MAX_GROUP_MEMBERS; j++)
+ {
+ if (m_members[j]->m_name.isEmpty())
+ {
+ m_members[j]->m_name = name;
+ m_memberCount++;
+ m_members[j]->m_spawn = m_spawnShell->findSpawnByName(name);
+ if (m_members[j]->m_spawn)
+ m_membersInZoneCount++;
+ emit added(name, m_members[j]->m_spawn);
+ break;
+ }
+ }
+ }
+}
+
void GroupMgr::addItem(const Item* item)
{
// only care about Spawn class
Modified: showeq/branches/showeqlegends/src/group.h
===================================================================
--- showeq/branches/showeqlegends/src/group.h 2026-07-11 20:22:48 UTC (rev 1660)
+++ showeq/branches/showeqlegends/src/group.h 2026-07-11 20:32:53 UTC (rev 1661)
@@ -64,6 +64,7 @@
void groupUpdate(const uint8_t* data, size_t size);
void addGroupMember(const uint8_t* data);
void removeGroupMember(const uint8_t* data);
+ void groupRosterEQL(const uint8_t* data, size_t len);
void addItem(const Item* item);
void delItem(const Item* item);
void killSpawn(const Item* item);
Modified: showeq/branches/showeqlegends/src/guildshell.cpp
===================================================================
--- showeq/branches/showeqlegends/src/guildshell.cpp 2026-07-11 20:22:48 UTC (rev 1660)
+++ showeq/branches/showeqlegends/src/guildshell.cpp 2026-07-11 20:32:53 UTC (rev 1661)
@@ -70,8 +70,12 @@
}
m_banker = m_banker % 2;
- // 4 byte class
- m_class = uint8_t(netStream.readUInt32NC());
+ // 4 byte class - EQ Legends sends the multiclass bitmask here
+ // (bit N = class N); display the lowest set bit as the class
+ uint32_t classMask = netStream.readUInt32NC();
+ m_class = 0;
+ for (int cb = 0; cb < 32; cb++)
+ if (classMask & (1 << cb)) { m_class = cb; break; }
// 4 byte rank (0 = member, 1 = officer, 2 = leader)
m_guildRank = netStream.readUInt32NC();
@@ -97,12 +101,12 @@
// public note
m_publicNote = netStream.readLPText();
- // 2 byte zoneInstance and zoneId for current zone
+ // EQ Legends tail (live skipped these 6 bytes unread): u16 zoneId,
+ // u16 unknown, u16 online flag. The wire is little-endian, so read
+ // NC (readUInt16 byte-swaps and turned zone 21 into 0x1500=5376).
m_zoneInstance = 0;
- m_zoneId = 0;
-
- // Unknown
- netStream.skipBytes(6);
+ m_zoneId = netStream.readUInt16NC();
+ netStream.skipBytes(4);
}
GuildMember::~GuildMember()
@@ -111,9 +115,15 @@
void GuildMember::update(const GuildMemberUpdate* gmu)
{
- m_zoneId = gmu->zoneId;
- m_zoneInstance = gmu->zoneInstance;
- m_lastOn = gmu->lastOn;
+ // EQ Legends: the 0x51ed member-update reliably carries only
+ // guildId, name, and rank - the zone/instance/lastOn tail is
+ // uninitialized server memory (0x7fff.. pointer bytes observed).
+ // A member ...
[truncated message content] |
|
From: <cn...@us...> - 2026-07-11 20:22:50
|
Revision: 1660
http://sourceforge.net/p/seq/svn/1660
Author: cn187
Date: 2026-07-11 20:22:48 +0000 (Sat, 11 Jul 2026)
Log Message:
-----------
Create branch for Legends support
Added Paths:
-----------
showeq/branches/showeqlegends/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cn...@us...> - 2026-06-27 20:13:00
|
Revision: 1659
http://sourceforge.net/p/seq/svn/1659
Author: cn187
Date: 2026-06-27 20:12:57 +0000 (Sat, 27 Jun 2026)
Log Message:
-----------
Fix typo in configure.in
Modified Paths:
--------------
showeq/branches/cn187_devel/configure.in
Modified: showeq/branches/cn187_devel/configure.in
===================================================================
--- showeq/branches/cn187_devel/configure.in 2026-06-27 20:12:06 UTC (rev 1658)
+++ showeq/branches/cn187_devel/configure.in 2026-06-27 20:12:57 UTC (rev 1659)
@@ -11,7 +11,7 @@
SOURCE_VERSION="unknown"
if test -f "$srcdir/.tarball-version"; then
rev=$(cat "$srcdir/.tarball-version")
- SOURCEVERSION="tarball-${rev}"
+ SOURCE_VERSION="tarball-${rev}"
elif test -d "$srcdir/.svn"; then
rev=$(cd "$srcdir" && svnversion -n . 2>/dev/null)
if test -n "$rev"; then
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cn...@us...> - 2026-06-27 20:12:08
|
Revision: 1658
http://sourceforge.net/p/seq/svn/1658
Author: cn187
Date: 2026-06-27 20:12:06 +0000 (Sat, 27 Jun 2026)
Log Message:
-----------
Fix typo in configure.in
Modified Paths:
--------------
showeq/trunk/configure.in
Modified: showeq/trunk/configure.in
===================================================================
--- showeq/trunk/configure.in 2026-06-27 20:05:12 UTC (rev 1657)
+++ showeq/trunk/configure.in 2026-06-27 20:12:06 UTC (rev 1658)
@@ -11,7 +11,7 @@
SOURCE_VERSION="unknown"
if test -f "$srcdir/.tarball-version"; then
rev=$(cat "$srcdir/.tarball-version")
- SOURCEVERSION="tarball-${rev}"
+ SOURCE_VERSION="tarball-${rev}"
elif test -d "$srcdir/.svn"; then
rev=$(cd "$srcdir" && svnversion -n . 2>/dev/null)
if test -n "$rev"; then
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cn...@us...> - 2026-06-27 20:05:14
|
Revision: 1657
http://sourceforge.net/p/seq/svn/1657
Author: cn187
Date: 2026-06-27 20:05:12 +0000 (Sat, 27 Jun 2026)
Log Message:
-----------
Display SOURCE_VERSION instead of main.cpp location in Version Info
Modified Paths:
--------------
showeq/branches/cn187_devel/src/main.cpp
Modified: showeq/branches/cn187_devel/src/main.cpp
===================================================================
--- showeq/branches/cn187_devel/src/main.cpp 2026-06-27 20:05:03 UTC (rev 1656)
+++ showeq/branches/cn187_devel/src/main.cpp 2026-06-27 20:05:12 UTC (rev 1657)
@@ -62,8 +62,6 @@
#endif
#include "datalocationmgr.h"
-static const char *id="@(#) $Id$ $Name$";
-
/* **********************************
defines used for option processing
********************************** */
@@ -777,9 +775,8 @@
/////////////////////////////////
// Display build information
- printf ("ShowEQ %s, Built from '%s' on %s at %s\n", VERSION,
- __FILE__, __DATE__, __TIME__);
- printf ("\tCVS: %s\n", id);
+ printf ("ShowEQ %s, Built from source version '%s' on %s at %s\n", VERSION,
+ SOURCE_VERSION, __DATE__, __TIME__);
#ifdef __GNUC__
#ifdef __GNUC_PATCHLEVEL__
printf ("\t\tUsing GCC version: %d.%d.%d\n",
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <cn...@us...> - 2026-06-27 20:05:05
|
Revision: 1656
http://sourceforge.net/p/seq/svn/1656
Author: cn187
Date: 2026-06-27 20:05:03 +0000 (Sat, 27 Jun 2026)
Log Message:
-----------
Identify source version used for configure/build
Modified Paths:
--------------
showeq/branches/cn187_devel/Makefile.am
showeq/branches/cn187_devel/configure.in
Modified: showeq/branches/cn187_devel/Makefile.am
===================================================================
--- showeq/branches/cn187_devel/Makefile.am 2026-06-27 20:04:13 UTC (rev 1655)
+++ showeq/branches/cn187_devel/Makefile.am 2026-06-27 20:05:03 UTC (rev 1656)
@@ -32,3 +32,4 @@
cp -p $(srcdir)/doc/*.txt $(distdir)/doc
cp -p $(srcdir)/doc/*.doc $(distdir)/doc
cp -p $(srcdir)/doc/*.html $(distdir)/doc
+ echo $(SOURCE_VERSION) > $(distdir)/.tarball-version
Modified: showeq/branches/cn187_devel/configure.in
===================================================================
--- showeq/branches/cn187_devel/configure.in 2026-06-27 20:04:13 UTC (rev 1655)
+++ showeq/branches/cn187_devel/configure.in 2026-06-27 20:05:03 UTC (rev 1656)
@@ -7,6 +7,43 @@
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_SYSTEM
+# detect source type and generate SOURCE_VERSION string
+SOURCE_VERSION="unknown"
+if test -f "$srcdir/.tarball-version"; then
+ rev=$(cat "$srcdir/.tarball-version")
+ SOURCEVERSION="tarball-${rev}"
+elif test -d "$srcdir/.svn"; then
+ rev=$(cd "$srcdir" && svnversion -n . 2>/dev/null)
+ if test -n "$rev"; then
+ SOURCE_VERSION="svn-r${rev}"
+ fi
+elif test -d "$srcdir/.git"; then
+ # test for git-svn first
+ hash=$(git show --oneline -s | cut -d' ' -f1)
+ rev=$(cd "$srcdir" && git svn find-rev ${hash})
+ if test -n "$rev"; then
+ dirty=$(cd "$srcdir" && git diff --quiet HEAD 2>/dev/null || echo "-dirty")
+ SOURCE_VERSION="svn-r${rev}${dirty}"
+ else
+ # otherwise use plain git
+ rev=$(cd "$srcdir" && git describe --tags --always --dirty 2>/dev/null)
+ if test -n "$rev"; then
+ SOURCE_VERSION="git-${rev}"
+ else
+ date=$(cd "$srcdir" && git log -1 --format=%cd --date=short 2>/dev/null)
+ hash=$(cd "$srcdir" && git rev-parse --short HEAD 2>/dev/null)
+ dirty=$(cd "$srcdir" && git diff --quiet HEAD 2>/dev/null || echo "-dirty")
+ SOURCE_VERSION="git-${date}-${hash}${dirty}"
+ fi
+ fi
+else
+ SOURCE_VERSION="unknown"
+fi
+
+AC_SUBST([SOURCE_VERSION])
+AC_DEFINE_UNQUOTED([SOURCE_VERSION], ["$SOURCE_VERSION"],
+ [Full source version string from VCS])
+
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(1.11 dist-bzip2)
AM_MAINTAINER_MODE
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|