EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=590)
-   -   Mercenaries (https://www.eqemulator.org/forums/showthread.php?t=35147)

trevius 04-02-2012 07:56 AM

Mercenaries
 
Since EQ is now F2P, I spent some time collecting data from Live for Mercenaries. There does not seem to be too many packets related to Mercs. Below is what I have figured out for mercenary packet structures. Hopefully I can get time to test some of this and maybe implement some basic handling for these packets, but I figured it would be good to post in case I don't get time to do that soon.

Mercenary Packet Structures:

Code:

// Currently unused, but may be good to have
enum MercStance
{
        MercPassive                = 1,
        MercBalanced        = 2,
        MercEfficient        = 3,
        MercReactive        = 4,
        MercAggressive        = 5,
        MercAssist                = 6,
        MercBurn                = 7,
        MercEfficient        = 8,
        MercBurnAE                = 9
};

// [OPCode: 0x27ac] On Live as of April 2 2012 [Server->Client]
struct MercenarySellList_Struct {
        int32 MercTypeCount;                                // Seen 2 - Iterations of MercCategory_Struct
        MercCategory_Struct Categories[0];        // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
        int32 MercCount;                                        // Seen 24 - Iterations of MercCategory_Struct
        MercenaryInfo_Struct Mercs[0];                        // Data for individual mercenaries in the Merchant List
};
 
struct MercCategory_Struct {
        int32 Category;                                                // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
};

// Used for Mercenary Merchant Lists and for Hired Mercenary Info Updates
struct MercenaryInfo_Struct {
        int32 MercID;                                        // ID unique to each type of mercenary (probably a DB id) - (if 1, do not send MercData_Struct - No merc hired)
        MercData_Struct MercData[0];        // Data for individual mercenaries - Not populated if no merc is hired
};

struct MercData_Struct {
/*0000*/        int32        MercType;                                // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0004*/        int32        MercDesc;                                // From dbstr_us.txt - 330020105^23^Race: Guktan<br>Type: Healer<br>Confidence: High<br>Proficiency: Apprentice, Tier V...
/*0008*/        int32        PurchaseCost;                        // Purchase Cost (in gold)
/*0012*/        int32        UpkeepCost;                                // Upkeep Cost (in gold)
/*0016*/        int32        Status;                                        // Required Account Status (Free = 0, Silver = 1, Gold = 2) at merchants - Seen 0 (suspended) or 1 (unsuspended) on hired mercs ?
/*0020*/        int32        AltCurrencyCost;                // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0
/*0024*/        int32        AltCurrencyUpkeep;                // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1
/*0028*/        int32        AltCurrencyType;                // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19
/*0032*/        int8        MercUnk01;                                // Unknown (always see 0)
/*0036*/        sint32        TimeLeft;                                // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc)
/*0040*/        int32        MerchantSlot;                        // Merchant Slot? Increments, but not always by 1 - May be for Merc Window Options (Seen 5, 36, 1 for active mercs)?
/*0044*/        int32        MercUnk02;                                // Unknown (always see 1)
/*0048*/        int32        StanceCount;                        // Iterations of MercStance_Struct - Normally 2 to 4 seen
/*0052*/        int32        MercUnk03;                                // Unknown (always 0 at merchant) - Seen on active merc: 93 a4 03 77, b8 ed 2f 26, 88 d5 8b c3, and 93 a4 ad 77
/*0056*/        int8        MercUnk04;                                // Seen 1
/*0060*/        char[0]        MercName;                                // Null Terminated Mercenary Name (00 at merchants)
/*0000*/        MercStance_Struct Stances[0];        // From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
};

// There appears to be extra data sent in this part of the struct sometimes that is unknown (normally 0, 1, or 2)
struct MercStance_Struct {
        int32 Stance;                                                // From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
};

// [OPCode: 0x6537] On Live as of April 2 2012 [Server->Client]
// Size 12 and sent on Zone-In if no mercenary is currently hired and when merc is dismissed
// Size varies if mercenary is hired or if browsing Mercenary Merchant
struct MercDataUpdate_Struct {
/*0000*/        sint32        MercStatus;                        // Seen 0 with merc and -1 with no merc hired
/*0004*/        int32        HiredCount;                        // Seen 1 with 1 merc hired and 0 with no merc hired
/*0008*/        MercenaryInfo_Struct MercData[0];        // Data for individual mercenaries in the Merchant List
};

// [OPCode: 0x495d] On Live as of April 2 2012 [Server->Client] [Size: 20]
// Sent on Zone-In, or after Dismissing, Suspending or Unsuspending Mercs
struct MercenaryUpdate_Struct {
/*0000*/        int32        MercEntityID;                // Seen 0 (no merc spawned) or 615843841 and 22779137
/*0004*/        int32        UpdateInterval;        // Seen 900000 - Matches from 0x6537 packet (15 minutes in ms?)
/*0008*/        int32        MercUnk01;                // Seen 180000 - 3 minutes in milleseconds?
/*0012*/        int32        MercState;                // Seen 5 (normal) or 1 (suspended)
/*0016*/        int32        SuspendedTime;        // Seen 0 (not suspended) or c9 c2 64 4f (suspended on Sat Mar 17 11:58:49 2012) - Unix Timestamp
/*0020*/
};

// [OPCode: 0x1a79] On Live as of April 2 2012 [Client->Server] [Size: 1] - Requesting to suspend or unsuspend merc
struct SuspendMercenary_Struct {
/*0000*/        int8        SuspendMerc;        // Seen 30 (48) for suspending or unsuspending
/*0001*/
};

// [OPCode: 0x2528] On Live as of April 2 2012 [Server->Client] [Size: 4] - Response to suspend merc with timestamp
struct SuspendMercenary_Struct {
/*0000*/        int32        SuspendTime;        // Unix Timestamp - Seen a9 11 78 4f
/*0004*/
};

// MercCommand field is possibly related to MerchantSlot field in MercData_Struct (seen same values)
// [OPCode: 0x4c6c] On Live as of April 2 2012 [Client->Server] [Size: 8] - Response to suspend merc with timestamp
struct MercCommand_Struct {
/*0000*/        int32 MercCommand;        // Seen 0 (zone in with no merc or suspended), 1 (dismiss merc), 5 (normal state), 36 (zone in with merc)
/*0004*/        int32 Option;                // Seen -1 (zone in with no merc), 0 (setting to passive stance), 1 (normal or setting to balanced stance)
/*0008*/
};


These are the opcodes that appear to be directly Mercenary related:

0x6537 Server->Client - Some kinda merc info update. Much smaller with no merc
0x0327 Client->Server - Labelled OP_MercenaryDataResponse in EQExtractor2 (size 0)
0x2ef8 Client->Server - Request dismiss merc (size 0)
0x495d Server->Client - Some merc status update from server - Maybe response to 0x4c6c
0x1a79 Client->Server - Requesting to suspend merc
0x2528 Server->Client - Response to suspend merc
0x4c6c Client->Server - Some kind of merc status change request from client - Examples:
24 00 00 00 01 00 00 00 - Zoning in
01 00 00 00 01 00 00 00 - Dismiss merc
05 00 00 00 01 00 00 00 - Right after purchasing merc
05 00 00 00 00 00 00 00 - Setting merc to passive
05 00 00 00 01 00 00 00 - Setting merc back to balanced
00 00 00 00 ff ff ff ff - Zoning in with no merc
01 00 00 00 01 00 00 00 - Right after previous update of zoning in with no merc

Using Mercenary Merchant:

0x4dd9 Client->Server - Right clicking merchant request
0x27ac Server->Client - Merc merchant response
0x3887 Server->Client - After merchant response
0x5e78 Client->Server - Request to view merc info while browsing merchant?
90 01 00 00 01 00 00 00 46 22 00 00 00 6e e4 03
0x5e78 Server->Client - Server response to 0x5e78
06 00 00 00
0x528f Server->Client - Seen after purchasing merc and when camping
0x6942 Server->Client - Response after purchasing merc - Purchase approval response?

I have a ton more data than I am showing here, but I don't want to post it all until I can organize it a bit more. I will post the rest of the structs for the above lists when I have time. At least the more complex structs should be in pretty good shape from the ones I posted above. The rest are all really small (16 bytes or less).

Secrets 04-02-2012 10:29 PM

Quote:

Originally Posted by trevius (Post 208554)
*snip*

This is actually going to help me a lot, I had mercenaries figured out to the point where I could actually have the window up, but I wasn't going off of live packet collects. I'll look into finding out what some of those unknowns are for you.

bad_captain 04-02-2012 10:53 PM

Trev, I have a lot of this worked out for SoD and UF, with the help of Derision. We are able to display the info in the merc merchant's window, and can spawn an npc that uses the merc window, changing stances, etc. I spent a lot of time getting all of the data (I generated quite a few hundred inserts for a basic db structure for mercs for types, subtypes, stances, handling different clients, and started on inventory and spells) for the freely available mercs before free to play which further restricted to just apprentice mercs (was apprentice t1-5 and journeymen 1-2).

If you plan on working on mercs, I can send all of it to you, or if you are just getting the info out there, I can use anything you have. I was trying to get to mercs within a few weeks. I've been really busy lately though.

Things have changed recently with the ability to have multiple mercs and such, but the basics should still be the same. I am on live trying to lvl up my toons to have a full group with mercs so I can continue to get spells cast as well as screenshots of equipment, etc. Let me know if there's anything you need.

trevius 04-03-2012 12:51 AM

Most of the data I have is related to what I already posted. Just the basic purchasing and usage packets and structs from Live. It sounds like you guys are a lot further along than I am lol. I only really worked on it for 1 day though. I didn't know anyone else was working on it. With your recent implementation of stances, I figured it would make it that much easier to add in a merc system.

I am a bit interested in the DB work you have done for them. I didn't think it would take hundreds of entries for it. I was figuring on 1 entry per merc subtype in a new merc table that just points to an NPC ID in the npc_types table. I haven't really played Live since 2005 until now (since it went free), so I am still really new to mercs. I guess there would be a lot of variations for merc races, and multiple types and subtypes.

I am not really too concerned with the DB entries, as I would probably just add somewhat customized entries anyway. I was more looking to get some basic functionality implemented that could be built upon. It sounds like you guys have already made it that far and are working on finishing stuff off.

I am no where near as skilled as Derision or you when it comes to that type of thing, so I will leave it up to the 2 of you :)

Maybe I can help you guys out if there is something you still need done. I am better with dissecting packets than I am with coding normally. I have quite a few characters in the 50 to 67 range, if there is something I can get with them that would be useful.

I can post the rest of the smaller structs later tonight (I still have to make them) if they would be useful. I also plan to write a script to help with opcode work a bit hopefully.

You should join the dev IRC channel. It might be easier to discuss and share info there. PM me if you don't know the channel name.

trevius 09-20-2012 06:39 AM

Bad_captain, did you ever get anywhere with this? I am curious how close this was to being functional. Even if it is only partly functional, it might be good to get it on the SVN so the rest can be completed as time permits. I could probably put some more work in on it, but didn't want to double any efforts that have already been made.

Noport 09-20-2012 08:06 AM

i'll post the newer opcodes real soon
Code:

Listing of hired mercenaries
OP_MercenaryList=0x5a0a


bad_captain 09-21-2012 12:53 AM

Sorry I dropped the ball on this one. I have meant to get back to this, but keep finding stuff to fix in bots, and with school just starting back up, I've been pretty busy. I'm in the middle of a bot AA rewrite, then I plan on getting back to this. I know I was slowed down working on all of the packet encoding/decoding, which I know you are adept at. If I can't get something going by next weekend (hopefully I will have time to at least get it somewhat respectable), I'll shoot you a diff or something.

I have been trying to level up on live to get some better logs/collects, but it's been slow going. I've been getting screenshots though, as weapons appear to change every 5 levels (not that I think we can get all equipment correct, but it's at least a start).

Noport 09-21-2012 04:34 AM

Bad_captain go grab my post of newer opcode and please update as needed thank you.
http://www.eqemulator.org/forums/sho...t=35640&page=2

trevius 10-12-2012 06:15 AM

I went through and refined, corrected, and added to the previous list of Mercenary related packet structures that I had posted. Each includes the opcode used on Live as well as the opcode name used on EQEmu currently where I could find them. I added notes for each struct to explain the packet a bit.

This should compile find on windows now, and should work for the initial changes to get mercs to be purchaseable and spawning at least. These structs are the ones used on Live as of April 12 2012, so these would go in eq_packet_structs.h. I will go through the SoD and UF clients and add the structs for those patch files as well in the next post.

Right now, there are still a couple of struct issues remaining due to how the variable sized packets for the Mercenary Data has variable sized arrays within it. To prevent it from breaking anything, I just hard set the variable sized structs that are inside the already variable sized structs. This only effects a few fields, but it is something that will need to be corrected to make these packets work exactly like they do on Live. For example, the MercName, MercTypes,and Stances fields are all hard set to values that should make them functional enough for now, but ideally those should all be able to vary in size. I am not really sure of the best way to do this and still allow the data to be sent to patch .cpp files so they can be encoded accordingly for each client.

Code:

// Used by MercenaryListEntry_Struct
struct MercenaryStance_Struct {
/*0000*/        int32        StanceIndex;        // Index of this stance (sometimes reverse reverse order - 3, 2, 1, 0 for 4 stances etc)
/*0004*/        int32        Stance;                        // From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
};

// Used by MercenaryMerchantList_Struct
struct MercenaryListEntry_Struct {
/*0000*/        int32        MercID;                                // ID unique to each type of mercenary (probably a DB id)
/*0004*/        int32        MercType;                        // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0008*/        int32        MercSubType;                // From dbstr_us.txt - 330020105^23^Race: Guktan<br>Type: Healer<br>Confidence: High<br>Proficiency: Apprentice, Tier V...
/*0012*/        int32        PurchaseCost;                // Purchase Cost (in gold)
/*0016*/        int32        UpkeepCost;                        // Upkeep Cost (in gold)
/*0020*/        int32        Status;                                // Required Account Status (Free = 0, Silver = 1, Gold = 2) at merchants - Seen 0 (suspended) or 1 (unsuspended) on hired mercs ?
/*0024*/        int32        AltCurrencyCost;        // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0
/*0028*/        int32        AltCurrencyUpkeep;        // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1
/*0032*/        int32        AltCurrencyType;        // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19
/*0036*/        int8        MercUnk01;                        // Unknown (always see 0)
/*0037*/        sint32        TimeLeft;                        // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc)
/*0041*/        int32        MerchantSlot;                // Merchant Slot? Increments, but not always by 1 - May be for Merc Window Options (Seen 5, 36, 1 for active mercs)?
/*0045*/        int32        MercUnk02;                        // Unknown (normally see 1, but sometimes 2 or 0)
/*0049*/        int32        StanceCount;                // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen
/*0053*/        int32        MercUnk03;                        // Unknown (always 0 at merchant) - Seen on active merc: 93 a4 03 77, b8 ed 2f 26, 88 d5 8b c3, and 93 a4 ad 77
/*0057*/        int8        MercUnk04;                        // Seen 1
/*0058*/        char        MercName[1];                // Null Terminated Mercenary Name (00 at merchants)
/*0000*/        MercenaryStance_Struct Stances[2];        // Count Varies, but hard set to 2 for now - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
};

// [OPCode: 0x27ac OP_MercenaryDataResponse] On Live as of April 2 2012 [Server->Client]
// Opcode should be renamed to something like OP_MercenaryMerchantShopResponse since the Data Response packet is different
// Sent by the server when browsing the Mercenary Merchant
struct MercenaryMerchantList_Struct {
/*0000*/        int32        MercTypeCount;                        // Number of Merc Types to follow
/*0004*/        int32        MercTypes[3];                        // Count varies, but hard set to 3 for now - From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0016*/        int32        MercCount;                                // Number of MercenaryInfo_Struct to follow
/*0020*/        MercenaryListEntry_Struct Mercs[0];        // Data for individual mercenaries in the Merchant List
};

// [OPCode: 0x4dd9 OP_MercenaryDataRequest] On Live as of April 2 2012 [Client->Server]
// Opcode should be renamed to something like OP_MercenaryMerchantShopRequest since the Data Request packet is different
// Right clicking merchant - shop request
struct MercenaryMerchantShopRequest_Struct {
/*0000*/        int32        MercMerchantID;                        // Entity ID of the Mercenary Merchant
/*0004*/
};

// Used by MercenaryDataUpdate_Struct
struct MercenaryData_Struct {
/*0000*/        int32        MercID;                                // ID unique to each type of mercenary (probably a DB id) - (if 1, do not send MercenaryData_Struct - No merc hired)
/*0004*/        int32        MercType;                        // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0008*/        int32        MercSubType;                // From dbstr_us.txt - 330020105^23^Race: Guktan<br>Type: Healer<br>Confidence: High<br>Proficiency: Apprentice, Tier V...
/*0012*/        int32        PurchaseCost;                // Purchase Cost (in gold)
/*0016*/        int32        UpkeepCost;                        // Upkeep Cost (in gold)
/*0020*/        int32        Status;                                // Required Account Status (Free = 0, Silver = 1, Gold = 2) at merchants - Seen 0 (suspended) or 1 (unsuspended) on hired mercs ?
/*0024*/        int32        AltCurrencyCost;        // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0
/*0028*/        int32        AltCurrencyUpkeep;        // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1
/*0032*/        int32        AltCurrencyType;        // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19
/*0036*/        int8        MercUnk01;                        // Unknown (always see 0)
/*0037*/        sint32        TimeLeft;                        // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc)
/*0041*/        int32        MerchantSlot;                // Merchant Slot? Increments, but not always by 1 - May be for Merc Window Options (Seen 5, 36, 1 for active mercs)?
/*0045*/        int32        MercUnk02;                        // Unknown (normally see 1, but sometimes 2 or 0)
/*0049*/        int32        StanceCount;                // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen
/*0053*/        int32        MercUnk03;                        // Unknown (always 0 at merchant) - Seen on active merc: 93 a4 03 77, b8 ed 2f 26, 88 d5 8b c3, and 93 a4 ad 77
/*0057*/        int8        MercUnk04;                        // Seen 1
/*0058*/        char        MercName[1];                // Null Terminated Mercenary Name (00 at merchants)
/*0000*/        MercenaryStance_Struct Stances[2];        // Count Varies, but hard set to 2 for now - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
/*0000*/        int32        MercUnk05;                        // Seen 1 - Extra Merc Data field that differs from MercenaryListEntry_Struct
// MercUnk05 may be a field that is at the end of the packet only, even if multiple mercs are listed (haven't seen examples of multiple mercs owned at once)
};

// [OPCode: 0x6537] On Live as of April 2 2012 [Server->Client]
// Should be named OP_MercenaryDataResponse, but the current opcode using that name should be renamed first
// Size varies if mercenary is hired or if browsing Mercenary Merchant
// This may also be the response for Client->Server 0x0327 (size 0) packet On Live as of April 2 2012
struct MercenaryDataUpdate_Struct {
/*0000*/        sint32        MercStatus;                                        // Seen 0 with merc and -1 with no merc hired
/*0004*/        int32        MercCount;                                        // Seen 1 with 1 merc hired and 0 with no merc hired
/*0008*/        MercenaryData_Struct MercData[0];        // Data for individual mercenaries in the Merchant List
};

// [OPCode: 0x6537] On Live as of April 2 2012 [Server->Client]
// Size 12 and sent on Zone-In if no mercenary is currently hired and when merc is dismissed
// (Same packet as MercAssign_Struct?)
struct NoMercenaryHired_Struct {
/*0000*/        sint32        MercStatus;                        // Seen -1 with no merc hired
/*0004*/        int32        MercCount;                        // Seen 0 with no merc hired
/*0008*/        int32        MercID;                                // Seen 1 when no merc is hired - ID unique to each type of mercenary
/*0012*/
};

// OP_MercenaryAssign (Same packet as NoMercenaryHired_Struct?)
struct MercenaryAssign_Struct {
/*0000*/        int32        MercEntityID;        // Seen 0 (no merc spawned) or 615843841 and 22779137
/*0004*/        int32        MercUnk01;                //
/*0008*/        int32        MercUnk02;                //
/*0012*/
};

// [OPCode: 0x495d OP_MercenaryTimer] On Live as of April 2 2012 [Server->Client] [Size: 20]
// Sent on Zone-In, or after Dismissing, Suspending, or Unsuspending Mercs
struct MercenaryStatus_Struct {
/*0000*/        int32        MercEntityID;        // Seen 0 (no merc spawned) or 615843841 and 22779137
/*0004*/        int32        UpdateInterval;        // Seen 900000 - Matches from 0x6537 packet (15 minutes in ms?)
/*0008*/        int32        MercUnk01;                // Seen 180000 - 3 minutes in milleseconds? Maybe next update interval?
/*0012*/        int32        MercState;                // Seen 5 (normal) or 1 (suspended)
/*0016*/        int32        SuspendedTime;        // Seen 0 (not suspended) or c9 c2 64 4f (suspended on Sat Mar 17 11:58:49 2012) - Unix Timestamp
/*0020*/
};

// [OPCode: 0x4c6c] On Live as of April 2 2012 [Client->Server] [Size: 8]
// Sent from the client when using the Mercenary Window
struct MercenaryCommand_Struct {
/*0000*/        int32        MercCommand;        // Seen 0 (zone in with no merc or suspended), 1 (dismiss merc), 5 (normal state), 36 (zone in with merc)
/*0004*/        sint32        Option;                        // Seen -1 (zone in with no merc), 0 (setting to passive stance), 1 (normal or setting to balanced stance)
/*0008*/
};

// [OPCode: 0x1a79] On Live as of April 2 2012 [Client->Server] [Size: 1]
// Requesting to suspend or unsuspend merc
struct SuspendMercenary_Struct {
/*0000*/        int8        SuspendMerc;        // Seen 30 (48) for suspending or unsuspending
/*0001*/
};

// [OPCode: 0x2528] On Live as of April 2 2012 [Server->Client] [Size: 4]
// Response to suspend merc with timestamp
struct SuspendMercenaryResponse_Struct {
/*0000*/        int32        SuspendTime;        // Unix Timestamp - Seen a9 11 78 4f
/*0004*/
};

// [OPCode: 0x5e78 (OP_MercenaryHire?)] On Live as of April 2 2012
// Sent by client when requesting to view Mercenary info or Hire a Mercenary
struct MercenaryMerchantRequest_Struct {
/*0000*/        int32        MercID;                        // Seen 399 and 400 for merc ID
/*0004*/        int32        MercUnk01;                // Seen 1
/*0008*/        int32        MercMerchantID;        // Entity ID for Mercenary Merchant
/*0012*/        int32        MercUnk02;                // Seen 65302016 (00 6e e4 03) - (probably actually individual int8 fields)
/*0016*/
};

// [OPCode: 0x5e78 (OP_MercenaryHire?)] On Live as of April 2 2012
// Sent by Server in response to requesting to view Mercenary info or Hire a Mercenary
struct MercenaryMerchantResponse_Struct {
/*0000*/        int32        ResponseType;        // Seen 0 for hire response, 6 for info response, and 9 for denied hire request
/*0004*/
};


trevius 10-12-2012 07:26 AM

Here are the only struct differences for UF and SoD that I know so far based on the packets bad_captain and Derision were generating for each client:

SoD
Code:

// Used by MercenaryMerchantList_Struct
struct MercenaryListEntry_Struct {
/*0000*/        int32        MercID;                                // ID unique to each type of mercenary (probably a DB id)
/*0004*/        int32        MercType;                        // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0008*/        int32        MercSubType;                // From dbstr_us.txt - 330020105^23^Race: Guktan<br>Type: Healer<br>Confidence: High<br>Proficiency: Apprentice, Tier V...
/*0012*/        int32        PurchaseCost;                // Purchase Cost (in gold)
/*0016*/        int32        UpkeepCost;                        // Upkeep Cost (in gold)
/*0020*/        int32        AltCurrencyCost;        // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0
/*0024*/        int32        AltCurrencyUpkeep;        // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1
/*0028*/        int32        AltCurrencyType;        // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19
/*0032*/        int32        StanceCount;                // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen
/*0036*/        sint32        TimeLeft;                        // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc)
/*0040*/        MercenaryStance_Struct Stances[2];        // Count Varies, but hard set to 2 for now - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
};

// Used by MercenaryDataUpdate_Struct
struct MercenaryData_Struct {
/*0000*/        int32        MercID;                                // ID unique to each type of mercenary (probably a DB id)
/*0004*/        int32        MercType;                        // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0008*/        int32        MercSubType;                // From dbstr_us.txt - 330020105^23^Race: Guktan<br>Type: Healer<br>Confidence: High<br>Proficiency: Apprentice, Tier V...
/*0012*/        int32        PurchaseCost;                // Purchase Cost (in gold)
/*0016*/        int32        UpkeepCost;                        // Upkeep Cost (in gold)
/*0020*/        int32        AltCurrencyCost;        // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0
/*0024*/        int32        AltCurrencyUpkeep;        // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1
/*0028*/        int32        AltCurrencyType;        // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19
/*0032*/        int32        StanceCount;                // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen
/*0036*/        sint32        TimeLeft;                        // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc)
/*0040*/        MercenaryStance_Struct Stances[2];        // Count Varies, but hard set to 2 for now - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
/*0000*/        int32        MercUnk05;                        // Seen 1 - Extra Merc Data field that differs from MercenaryListEntry_Struct
// MercUnk05 may be a field that is at the end of the packet only, even if multiple mercs are listed (haven't seen examples of multiple mercs owned at once)
};

Underfoot
Code:

// Used by MercenaryMerchantList_Struct
struct MercenaryListEntry_Struct {
/*0000*/        int32        MercID;                                // ID unique to each type of mercenary (probably a DB id)
/*0004*/        int32        MercType;                        // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0008*/        int32        MercSubType;                // From dbstr_us.txt - 330020105^23^Race: Guktan<br>Type: Healer<br>Confidence: High<br>Proficiency: Apprentice, Tier V...
/*0012*/        int32        PurchaseCost;                // Purchase Cost (in gold)
/*0016*/        int32        UpkeepCost;                        // Upkeep Cost (in gold)
/*0020*/        int32        AltCurrencyCost;        // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0
/*0024*/        int32        AltCurrencyUpkeep;        // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1
/*0028*/        int32        AltCurrencyType;        // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19
/*0032*/        int8        MercUnk01;                        // Unknown (always see 0)
/*0033*/        sint32        TimeLeft;                        // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc)
/*0037*/        int32        MerchantSlot;                // Merchant Slot? Increments, but not always by 1 - May be for Merc Window Options (Seen 5, 36, 1 for active mercs)?
/*0041*/        int32        MercUnk02;                        // Unknown (normally see 1, but sometimes 2 or 0)
/*0045*/        int32        StanceCount;                // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen
/*0049*/        int32        MercUnk03;                        // Unknown (always 0 at merchant) - Seen on active merc: 93 a4 03 77, b8 ed 2f 26, 88 d5 8b c3, and 93 a4 ad 77
/*0053*/        int8        MercUnk04;                        // Seen 1
/*0054*/        MercenaryStance_Struct Stances[2];        // Count Varies, but hard set to 2 for now - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
};

// Used by MercenaryDataUpdate_Struct
struct MercenaryData_Struct {
/*0000*/        int32        MercID;                                // ID unique to each type of mercenary (probably a DB id)
/*0004*/        int32        MercType;                        // From dbstr_us.txt - Apprentice (330000100), Journeyman (330000200), Master (330000300)
/*0008*/        int32        MercSubType;                // From dbstr_us.txt - 330020105^23^Race: Guktan<br>Type: Healer<br>Confidence: High<br>Proficiency: Apprentice, Tier V...
/*0012*/        int32        PurchaseCost;                // Purchase Cost (in gold)
/*0016*/        int32        UpkeepCost;                        // Upkeep Cost (in gold)
/*0020*/        int32        AltCurrencyCost;        // Alternate Currency Purchase Cost? (all seen costs show N/A Bayle Mark) - Seen 0
/*0024*/        int32        AltCurrencyUpkeep;        // Alternate Currency Upkeep Cost? (all seen costs show 1 Bayle Mark) - Seen 1
/*0028*/        int32        AltCurrencyType;        // Alternate Currency Type? - 19^17^Bayle Mark^0 - Seen 19
/*0032*/        int8        MercUnk01;                        // Unknown (always see 0)
/*0033*/        sint32        TimeLeft;                        // Unknown (always see -1 at merchant) - Seen 900000 (15 minutes in ms for newly hired merc)
/*0037*/        int32        MerchantSlot;                // Merchant Slot? Increments, but not always by 1 - May be for Merc Window Options (Seen 5, 36, 1 for active mercs)?
/*0041*/        int32        MercUnk02;                        // Unknown (normally see 1, but sometimes 2 or 0)
/*0045*/        int32        StanceCount;                // Iterations of MercenaryStance_Struct - Normally 2 to 4 seen
/*0049*/        int32        MercUnk03;                        // Unknown (always 0 at merchant) - Seen on active merc: 93 a4 03 77, b8 ed 2f 26, 88 d5 8b c3, and 93 a4 ad 77
/*0053*/        int8        MercUnk04;                        // Seen 1
/*0054*/        MercenaryStance_Struct Stances[2];        // Count Varies, but hard set to 2 for now - From dbstr_us.txt - 1^24^Passive^0, 2^24^Balanced^0, etc (1 to 9 as of April 2012)
/*0000*/        int32        MercUnk05;                        // Seen 1 - Extra Merc Data field that differs from MercenaryListEntry_Struct
// MercUnk05 may be a field that is at the end of the packet only, even if multiple mercs are listed (haven't seen examples of multiple mercs owned at once)
};

My guess is that most of the smaller packets have not changed much if at all.

Shiny151 10-12-2012 11:47 AM

Trev; will mercs piggyback off any of the bot code or are they standalone?

trevius 10-12-2012 08:29 PM

I will leave that type of thing up to the bot dev people like bad_captain. I assume they will get their own merc class that is basically just a copy of the bot class, but tweaked for mercs.

bad_captain 10-12-2012 10:44 PM

I had a conversation about 2 years ago with Wildcard, who did a lot of the work on bots before me, and he had planned to change bots to be inherited off of mercs when they were finished. After doing a little bit of work on mercs, I'm not sure how easy or beneficial that would be, but I guess we'll see. The one real problem with bots (that won't be an issue with mercs), is the option to build without them, meaning a lot of code has to be rewritten or copied to get bots to work and still compile when they aren't enabled. Mercs should be built into the actual build so that they work a little more seamlessly than bots, even if they are less flexible.

On the other hand, with some changes on the live client, switching between multiple mercs, and editing the dbstring files, I think a lot could be done to merge the two. Incorporating the upkeep system into bots would be a benefit as well.

Once mercs get closer to being viable, I think the decision will have to be made whether to keep bots as is or inherit off of mercs, but unless someone can find other advantages to doing so, I see bots remaining as is.

bad_captain 10-12-2012 10:53 PM

Note: your comment regarding the first field in the MercenaryMerchantRequest_Struct, is I believe the Merc ID, instead of RequestType.

trevius 10-13-2012 06:58 AM

Quote:

Originally Posted by bad_captain (Post 213282)
Note: your comment regarding the first field in the MercenaryMerchantRequest_Struct, is I believe the Merc ID, instead of RequestType.

Thanks, I corrected that one in the post.

KLS 10-13-2012 05:45 PM

Going to chime in: I think bots are a clusterfuck and if we're implementing mercs we should implement them as a new system and not shoehorn them into the gap we've made with bots(esp since they don't work 100% the same).

bad_captain 10-13-2012 08:02 PM

Maybe once Mercs are in, trunk drops support for bots, who are then maintained in the MercsAndBots branch. Seems like an acceptable solution to me.

trevius 10-15-2012 05:07 AM

Here are some more Mercenary related opcodes for SoD and UF:

SoD

Code:

OP_MercenaryDataUpdate=0x0786                #
OP_MercenaryCommand=0x167b                        #
OP_MercenarySuspendRequest=0x05f1        #
OP_MercenarySuspendResponse=0x57f2        #
OP_MercenaryDataUpdateRequest=0x390c        #

Underfoot

Code:

OP_MercenaryDataUpdate=0x57f2                #
OP_MercenaryCommand=0x6c36                        #
OP_MercenarySuspendRequest=0x3c58        #
OP_MercenarySuspendResponse=0x4b82        #
OP_MercenaryDataUpdateRequest=0x05f1        #

I will try to get some basic packet handling added for these and the code actually supporting them can be added later once more merc stuff is in place.

Also, it looks like OP_MercenaryAssign may actually just be OP_WeaponEquip1 according to the info I can find in my last collects. It is the same size packet and seems like the same struct. If we can verify this, it is one less thing to deal with for merc stuff.

Code:

// 0x7404 - OP_MercenaryAssign (Same packet as NoMercenaryHired_Struct?) [Server->Client]
struct MercenaryAssign_Struct {
/*0000*/ int32 MercEntityID; // Seen 0 (no merc spawned) or 615843841 and 22779137
/*0004*/ int32 MercUnk01; //
/*0008*/ int32 MercUnk02; //
/*0012*/
};

Code:

[OPCode: 0x7404] OP_WeaponEquip1 [Server->Client] [Size: 12]
000 | a4 59 00 00 01 00 00 00 8a 2b 00 00              | .Y.......+..

[OPCode: 0x7404] OP_WeaponEquip1 [Server->Client] [Size: 12]
000 | a4 59 00 00 00 00 00 00 dd 2a 00 00              | .Y.......*..


trevius 10-15-2012 07:29 AM

And here are some roughed in packet handling for mercs for client_packet.cpp. These are mostly just hard set with the basic packet responses so they can be corrected later with actual functions supporting them.

Code:

ConnectedOpcodes[OP_MercenaryCommand] = &Client::Handle_OP_MercenaryCommand;
ConnectedOpcodes[OP_MercenaryDataUpdateRequest] = &Client::Handle_OP_MercenaryDataUpdateRequest;
ConnectedOpcodes[OP_MercenarySuspendRequest] = &Client::Handle_OP_MercenarySuspendRequest;

Code:

void Client::Handle_OP_MercenarySuspendRequest(const EQApplicationPacket *app)
{
        if(app->size != sizeof(SuspendMercenary_Struct))
        {
                LogFile->write(EQEMuLog::Debug, "Size mismatch in OP_MercenarySuspendRequest expected %i got %i", sizeof(SuspendMercenary_Struct), app->size);
                DumpPacket(app);
                return;
        }

        SuspendMercenary_Struct* sm = (SuspendMercenary_Struct*) app->pBuffer;
        uint32 merc_suspend = sm->SuspendMerc;        // Seen 30 for suspending or unsuspending

        DumpPacket(app);
       
        // Handle the Command here...
        // Check if the merc is suspended and if so, unsuspend, otherwise suspend it
       
       
        // This response packet includes the timestamp of the suspend request
        EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenarySuspendResponse, sizeof(SuspendMercenaryResponse_Struct));
        SuspendMercenaryResponse_Struct* smr = (SuspendMercenaryResponse_Struct*)outapp->pBuffer;
        smr->SuspendTime = time();        // Unix Timestamp
       
        DumpPacket(outapp);
        FastQueuePacket(&outapp);
}

void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app)
{
        if(app->size != sizeof(MercenaryCommand_Struct))
        {
                LogFile->write(EQEMuLog::Debug, "Size mismatch in OP_MercenaryCommand expected %i got %i", sizeof(MercenaryCommand_Struct), app->size);
                DumpPacket(app);
                return;
        }

        MercenaryCommand_Struct* mc = (MercenaryCommand_Struct*) app->pBuffer;
        uint32 merc_command = mc->MercCommand;        // Seen 0 (zone in with no merc or suspended), 1 (dismiss merc), 5 (normal state), 36 (zone in with merc)
        sint32 option = mc->Option;        // Seen -1 (zone in with no merc), 0 (setting to passive stance), 1 (normal or setting to balanced stance)

        DumpPacket(app);
       
        // Handle the Command here...
        // Will need a list of what every type of command is supposed to do
        // Unsure if there is a server response to this packet
}

void Client::Handle_OP_MercenaryDataUpdateRequest(const EQApplicationPacket *app)
{
        // The payload is 0 bytes.
        if(app->size != 0)
        {
                LogFile->write(EQEMuLog::Debug, "Size mismatch in OP_MercenaryDataUpdateRequest expected 0 got %i", app->size);
                DumpPacket(app);
                return;
        }

        DumpPacket(app);
       
        // Hard setting some stuff until it can be coded to load properly from the DB
        int mercCount = 1;
        int stanceCount = 2;
        char mercName[32];        // This actually needs to be null terminated
        strcpy(mercName, GetRandPetName());
       
        uint32 packetSize = sizeof(MercenaryDataUpdate_Struct) + ( sizeof(MercenaryData_Struct) - 8 + sizeof(MercenaryStance_Struct) * stanceCount ) * mercCount + strlen(mercName);
       
        // This response packet seems to be sent on zoning or camping by client request
        // It is populated with owned merc data only
        EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, packetSize);
        MercenaryDataUpdate_Struct* mdu = (MercenaryDataUpdate_Struct*)outapp->pBuffer;

        mdu->MercStatus = 0;
        mdu->MercCount = mercCount;

        for(int i = 0; i < mercCount; i++)
        {
                mdu->Mercs[i].MercID = 400;
                mdu->Mercs[i].MercType = 330000100;
                mdu->Mercs[i].MercSubType = 330020105;
                mdu->Mercs[i].PurchaseCost = 4910;
                mdu->Mercs[i].UpkeepCost = 123;
                mdu->Mercs[i].Status = 0;
                mdu->Mercs[i].AltCurrencyCost = 0;
                mdu->Mercs[i].AltCurrencyUpkeep = 1;
                mdu->Mercs[i].AltCurrencyType = 19;
                mdu->Mercs[i].MercUnk01 = 0;
                mdu->Mercs[i].TimeLeft = 900000;
                mdu->Mercs[i].MerchantSlot = 1;
                mdu->Mercs[i].MercUnk02 = 1;
                mdu->Mercs[i].StanceCount = stanceCount;
                mdu->Mercs[i].MercUnk03 = 519044964;
                mdu->Mercs[i].MercUnk04 = 1;
                strcpy(mml->Mercs[i].MercName, mercName);
                for (int stanceindex = 0; stanceindex < stanceCount; stanceindex++)
                {
                        mdu->Mercs[i].Stances[stanceindex].StanceIndex = stanceindex;
                        mdu->Mercs[i].Stances[stanceindex].Stance = stanceindex + 1;
                }
                mdu->Mercs[i].MercUnk05 = 1;
                i++;
        }

        DumpPacket(outapp);
        FastQueuePacket(&outapp);
}

I haven't tested these yet, but the basics should be there and easy to get working. I think this is the last of the handling needed for packets coming from the client. There is still plenty to do to get this stuff actually working as intended though.

trevius 10-16-2012 06:23 AM

I think it may need some testing, but based on my VoA merc collects, I found a couple more opcodes that appear to be mercenary related:

SoD:
Code:

OP_MercenaryDismiss=0x319a #
OP_MercenaryTimerRequest=0x184e #

Underfoot:
Code:

OP_MercenaryDismiss=0x0bd0 #
OP_MercenaryTimerRequest=0x0924 #

These are both Client->Server packets, so they will require more handling. I am pretty sure OP_MercenaryDismiss is the right opcode and names based on what I was seeing in UF while watching my log files and dismissing a merc. I am not sure about OP_MercenaryTimerRequest yet, but in my collect from Live, the OP_MercenaryTimer packet comes in right after OP_MercenaryTimerRequest on initial zone in with a merc.

All of these new packets will probably take some playing around with to figure out which are required for what and which may not be required at all (if any).

I will work on some basic handling for these as well, which can be refined later.

trevius 10-16-2012 06:39 AM

I think this should be the basic handling for those 2 new opcodes:

client_packet.h
Code:

                void Handle_OP_MercenaryDismiss(const EQApplicationPacket *app);
                void Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app);

client_packet.cpp
Code:

ConnectedOpcodes[OP_MercenaryDismiss] = &Client::Handle_OP_MercenaryDismiss;
ConnectedOpcodes[OP_MercenaryTimerRequest] = &Client::Handle_OP_MercenaryTimerRequest;

Code:

void Client::Handle_OP_MercenaryDismiss(const EQApplicationPacket *app)
{
        // The payload is 0 bytes.
        if(app->size != 0)
        {
                Message(13, "Size mismatch in OP_MercenaryDismiss expected 0 got %i", app->size);
                LogFile->write(EQEMuLog::Debug, "Size mismatch in OP_MercenaryDismiss expected 0 got %i", app->size);
                DumpPacket(app);
                return;
        }

        DumpPacket(app);

        Message(7, "Mercenary Debug: Dismiss Request Recieved.");

        // Handle the dismiss here...
       
        // Unsure if there is a server response to this packet
       
}

void Client::Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app)
{
        // The payload is 0 bytes.
        if(app->size != 0)
        {
                Message(13, "Size mismatch in OP_MercenaryTimerRequest expected 0 got %i", app->size);
                LogFile->write(EQEMuLog::Debug, "Size mismatch in OP_MercenaryTimerRequest expected 0 got %i", app->size);
                DumpPacket(app);
                return;
        }
       
        DumpPacket(app);

        Message(7, "Mercenary Debug: Timer Request received.");

        // To Do: Load Mercenary Timer Data to properly populate this reply packet
        // All hard set values for now
       
        // Send Mercenary Status/Timer packet
        EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryTimer, sizeof(MercenaryStatus_Struct));
        MercenaryStatus_Struct* mss = (MercenaryStatus_Struct*)outapp->pBuffer;
        mss->MercEntityID = 1; // Seen 0 (no merc spawned) or 615843841 and 22779137
        mss->UpdateInterval = 900000; // Seen 900000 - Matches from 0x6537 packet (15 minutes in ms?)
        mss->MercUnk01 = 180000; // Seen 180000 - 3 minutes in milleseconds? Maybe next update interval?
        mss->MercState = 5; // Seen 5 (normal) or 1 (suspended)
        mss->SuspendedTime = 0; // Seen 0 (not suspended) or c9 c2 64 4f (suspended on Sat Mar 17 11:58:49 2012) - Unix Timestamp
       
        DumpPacket(outapp);
        FastQueuePacket(&outapp);
}


trevius 10-17-2012 05:26 AM

The last commit I did for Rev2234 is causing a zone crash when sending the mercenary merchant list. Simple fix is this:

client_packet.cpp in Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app)

Replace:
Code:

packetSize = sizeof(MercenaryMerchantList_Struct) - 12 + mercTypeCount * 4 + ( sizeof(MercenaryListEntry_Struct) - 40 + sizeof(MercenaryStance_Struct) * mercStanceCount ) * mercCount;
With:
Code:

packetSize = sizeof(MercenaryMerchantList_Struct) + sizeof(MercenaryListEntry_Struct) * mercCount;
There are 2 spots in that function where this needs to be replaced.

I don't have access to test this right now, but will check it in the morning and commit the fix. Just noting it here for anyone following the merc branch changes.

KLS 10-17-2012 12:34 PM

See this is why we need automatic packet encoding/decoding even at the application level. =/

bad_captain 10-19-2012 10:09 AM

I did some spawn work last night. I cleaned up some code in client_packet.cpp and tried to flesh out the hiring / spawning process.

I was able to get the merc when hired added to my group. I had added some code for the merc to follow me, but it doesn't work yet. I didn't get a chance to test it out other than seeing it didn't work.

I added some code for dismiss, but it didn't seem to work either. It may have been an issue with getting the merc owner, as I had a similar issue on spawning I was able to fix. I just ran out of time to test out why.

My plan is to clean up the spawning process a little more, get my merc to follow me, get suspend/unsuspending & dismiss working tonight. A little more work needs to be done before being able to save the merc to the database (definitely not in the player profile).

The merc templates are currently being stored in the zone, so there is duplication. It could be moved to EQSharedMem to eliminate that, but to get it up and running, that's where I put them. The shared memory stuff may be beyond my pay grade, but there's plenty of time before anyone needs to worry about it. I think it's around 150kb per zone if my math is close.

If anyone has a live paid account on EQ that has mercs, I have some things I need to check on that I can't on my account. If anyone is able and willing, I'd appreciate it.

bad_captain 10-19-2012 11:09 AM

Also, I think I have everything to put the correct stances in. Is there anything else that needs to be done besides modifying the packet size when creating it to account for the extra stances? Besides actually loading the correct stances, of course.. I'm in no hurry to add them, but wanted to check so I knew what changes would be needed. Passive and Balanced are fine for what we need to do yet.

Devincean 10-20-2012 12:23 AM

Quote:

Originally Posted by bad_captain (Post 213489)
I did some spawn work last night. I cleaned up some code in client_packet.cpp and tried to flesh out the hiring / spawning process.

I was able to get the merc when hired added to my group. I had added some code for the merc to follow me, but it doesn't work yet. I didn't get a chance to test it out other than seeing it didn't work.

I added some code for dismiss, but it didn't seem to work either. It may have been an issue with getting the merc owner, as I had a similar issue on spawning I was able to fix. I just ran out of time to test out why.

My plan is to clean up the spawning process a little more, get my merc to follow me, get suspend/unsuspending & dismiss working tonight. A little more work needs to be done before being able to save the merc to the database (definitely not in the player profile).

The merc templates are currently being stored in the zone, so there is duplication. It could be moved to EQSharedMem to eliminate that, but to get it up and running, that's where I put them. The shared memory stuff may be beyond my pay grade, but there's plenty of time before anyone needs to worry about it. I think it's around 150kb per zone if my math is close.

If anyone has a live paid account on EQ that has mercs, I have some things I need to check on that I can't on my account. If anyone is able and willing, I'd appreciate it.

I had mercs on my account even ended up putting in the work and getting high end tier 3 mercs so know all about them. Was also thinking of trying to help you guys out with any packet catching ya need since have guys at all levels and can solo most of the game since my mains on live are 90 druid i dual box with my 90 enchanter each with about 3000aa been awhile since I played well about VOA also have a entire guild city and a couple of houses wanted to see if I could help you guys get that data. If so let me know be glad to reactive my accounts for a month or two if it helps out.

trevius 10-20-2012 08:04 AM

Quote:

Originally Posted by bad_captain (Post 213493)
Also, I think I have everything to put the correct stances in. Is there anything else that needs to be done besides modifying the packet size when creating it to account for the extra stances? Besides actually loading the correct stances, of course.. I'm in no hurry to add them, but wanted to check so I knew what changes would be needed. Passive and Balanced are fine for what we need to do yet.

Nothing special needs to be done to the packets for stances to be added as long as you don't exceed 5 total stances. Right now, due to the variable sized packet issues, I just have it hard coded to globally load 5 stance iterations into the packet. Then, once it is encoded, it only uses the number of iterations that are set in the stance count field. I did the same thing with merc types. I have it currently set to load 3 of them, but only use as many as are set in the merc type counts when the encode happens. Everything else gets discarded and is not populated anyway.

If we need to increase the number of merc types or stances at some point, I think we just have to adjust the related structs in eq_packet_structs.h.

bad_captain 10-20-2012 10:18 AM

Okay, good to know.

5 stances should be okay, I believe. I'll have to check for any that might have more. Caster has the most - Passive, Balanced, Burn, and BurnAE for sure, maybe Efficient or Aggressive (I don't have them right in front of me). Healers have Passive, Balanced, Efficient and Reactive.

We will need to increase Merc Types, though. While I'm not even sure if they have any Master Mercenaries, there are a few Mercenary Merchants who have 2 races, so they will have at least 4 (6 if you include master).

I was able to get mercs to follow last night, and dismiss and suspend mostly working. Also, I fixed a couple of issues that allow the illusion packet to work (purchasing mercs from Guardian Norerd in PoK who needs to be changed to be a froglok now results in a froglok merc). I still need to add the SQL to fix the mercenary merchants, but i know him and Mercenary Mdjai in Crescent Reach work.

bad_captain 10-20-2012 04:39 PM

I apparently made a few changes before I committed that I forgot about. One is causing a crash when hiring a merc. To fix this, add the following to the Merc constructor:

Code:

p_depop = false;
I'll add it tonight and try to fix another issue when the merc is dismissed. He's dismissed all right, but apparently his group doesn't think so. I'll get it sorted out. Good news though is that it does dismiss him.

bad_captain 10-20-2012 04:42 PM

Quote:

Originally Posted by Devincean (Post 213518)
I had mercs on my account even ended up putting in the work and getting high end tier 3 mercs so know all about them. Was also thinking of trying to help you guys out with any packet catching ya need since have guys at all levels and can solo most of the game since my mains on live are 90 druid i dual box with my 90 enchanter each with about 3000aa been awhile since I played well about VOA also have a entire guild city and a couple of houses wanted to see if I could help you guys get that data. If so let me know be glad to reactive my accounts for a month or two if it helps out.

Well, I was reminded that the test server has access to the Journeyman mercs, so I was able to get some data that way. I wouldn't want you to do that yet, and only if no one else has easy access to higher tier of mercs. I will be coming up with a list of things to work on, as well as a list of data that's needed. Hopefully this weekend.

Devincean 10-20-2012 06:20 PM

Ok ya the high tier mercs t3 to t5 are the harder to get usually you have to know someone high enough to run you through the unlock quests or pay someone too run you through the quest and its not cheap from what I use to charge was about half a million plat plus also I made a mistake have the T5 mercs on my guys not the T3 like I said been awhile but just peaked at them yesterday here is the guide i used for the mercs. http://articles.eqresource.com/mercoverview.php

Also just FYI the diffrence between Tier 1 - Tier 4 and Tier 5 mercs is very huge btw the T5 mercs can solo raid targets that are outdoor zones since mercs don't work in closed raid zones example (can't do 2.5 epics with mercs since the Dreadspire Keep: Demi-Plane of Blood is indoor raid zone.)

Also some other useful links for mercs sure you could find them yourself but just to help out since information is fairly scattered. These links made coming back and learning how mercs work and what they could do really easy.

Everything about mercs stances/upgrades etc
http://almarsguides.com/eq/general/mercenaries.cfm

Bottom of page has most the race/class combos for mercs
http://everquest.allakhazam.com/wiki/EQ:Mercenaries

Only big things I am not sure how ya would figure out is T5 mercs obviously have AA bonuses the clerics heals amazingly and the tank merc hardly ever take a lot of damage even against raid targets so not sure if there is a way to figure that out also since merc armor auto upgrades as you level up (you can see the armor change per couple levels) not sure what armor and weapons they change to as they level up with you. I guess I could see if I took a alt and power leveled it up at what levels it changes and take pictures of it but not sure how to get the stats of the armor they are wearing or what they are wearing.

trevius 10-22-2012 03:21 AM

Unless we plan to allow mercs to be given items to equip like Bots (which might be a nice option for custom servers), then the easiest solution would just be to simulate it by changing armor textures and tint. We can also set them to use specific weapon models and attack types right in the npc_types table so we don't have to give them actual weapons. Then their stats just need to be adjusted to whatever we want. Unless they get racial benefits, we could probably save some effort by making a single npc_type entry for each merc and then adjusting the race at the time it is created. Otherwise you are going to end up with thousands of entries to do what could otherwise be done with a small percentage of that.

Also, bad_captain, we will probably need to remove the 2 assign mercenary packets from the hire handling, since those are actually just used for setting weapon models. Those won't be required if we set the weapon models on the npc_type. That, or we can just send normal wearchanges or whatever.

Mercs are looking pretty good so far. Since using them is optional, we could probably merge them into the trunk anytime now even though they are still being worked on. Can probably wait until at least the rest of the packet stuff is worked out I guess.

I will probably leave most of the merc supporting code up to you, since you probably know what is needed better than I due to your experience with Bots. I definitely want to keep helping to make sure all of the packet stuff is worked out though. It looks like we still need to get the timer stuff working, so maybe I will work on that next. I am willing to help with more though, if you want to divvy anything out.

bad_captain 10-22-2012 09:35 AM

I had planned to write up some stuff over the weekend, but was too busy to get to it. I started to work on stats last night and did give them an inventory, but could take it away just as easily. I would lean towards having it for customization reasons, and it allows for better code reuse from clients. But, I could be convinced otherwise. It would save the hassle of coming up with equipment sets, since they change weapons every 5 levels. They also change weapon types, as I had seen 1hs, 1hp, and 1hb all used by like level 30.

As far as race and npc_types, there is no different between races, and actually, they are all the same race (human?) with an illusion of their actual race. That is already in. I'm not sure I see the need for any entries in npc_types for a couple of reasons. First, everything needed is already in the current merc tables (most everything is dependent on class, proficiency (apprentice, journeyman) and tier). I think its very similar to pet power, which I believe was poorly implemented by having to use different records for each power for each pet. The rest just need to be handled in code based on those factors. Also, I think most fields in the npc_types table are not relevant to mercs (or at least won't vary among them) while there are also additional fields that aren't relevant to npcs but are for mercs.

Once I get a bit of time to write up what's done and what's not, I will have a better idea what can easily be delegated without us tripping over one another. I don't have a problem with others working on it, as another opinion from someone who doesn't work on bots may be beneficial, since I think of how to attack problems like they are bots. A fresh perspective is definitely helpful.

Once a little more work is done to handle the packets and most of the work is done that affects clients ( suspending, hiring, etc), I would feel better about merging. I don't want one of these big changes to mess anyone up. Once most of the work is just getting merc behavior correct, I say go ahead.

Also regarding equipment and stats. We need to decide on a way to scale spell casting as well as melee damage, especially if we choose not to give them an inventory. For journeyman healers, there can be almost a 100% increase in healing on a rank II spell at level 85. We need to determine if that holds true across the board, or if they also receive AA like bonuses that increase with levels (my assumption). I don't think my mercs currently heal for more than the base amount (level in mid 50s) but I would have to look through my logs.

trevius 10-23-2012 03:42 AM

Yeah, definitely not all fields in npc_types would be relevant for mercs. I was just thinking it would be a nice way for servers to be able to adjust merc stats so they aren't hard coded in the source. If it used npc_types, it would let servers adjust stats and min/max damage etc so you could scale them in any way you want. This would remove the issue of trying to have gear come into play for mercs. I think having a gearing option for mercs might be nice as well to make them more flexible, but it might also be nice to be able to just create them similar to creating a pet. Though, given that mercs can range to any level and there are quite a few variations of mercs, that could mean quite a few npc_types entries to do it that way.

One possibility might be to have it load the base stats, min/max damage, health/mana, regen, weapon models, and so on from the db along with maybe a scaling ratio or something right from the merc_types table with a few new fields. Just like NPCs, they could use the npc_types_tint table to load the armor colors. If material/texture was added to that table as well, it would make it easy to simulate the appearance of any armor set on live for mercs.

The main argument I would have for allowing mercs to use stats over armor sets is that stats are much easier to tweak than armor sets are. It seems pretty clear to me that mercs on Live don't reflect exactly what a character of the same class type (such as warrior compared to merc tank) is capable of. I leveled a trio on Live recently from 1 to 60 and had a tank merc that is able to well out tank my warrior that is fairly well geared for his level now. I don't know if it is just that his mitigation is higher or if he just has a ton more HPs, but he probably tanks 2 or 3 times as well as my warrior does. Unless he is geared far beyond the standard gear for that level, I assume Live uses different base stats and/or formulas for mercs from what player characters use. I am sure there is more solid data out there somewhere from the crazy number crunchers, but I haven't done enough research to find it yet.

It could just be that mercs on Live are wearing the same armor set until they reach the higher levels or maybe only the higher tier mercs. If the set has a recommended level on it, maybe the armor just scales as the merc levels, which makes sense for simplifying the process. If that is the case, armor sets might not be a bad option and then we would just need to adjust the weapons that are used, which is much less work. I am guessing we would have to add support to make sure gear scales to level for recommended level gear that mercs are wearing.

You are probably right that AAs are used to increase spell effects. I don't think it would be hard to get that working for mercs. The other possibility would be if they use focus effects on gear they wear. If using the same armor set as they level as mentioned above, the focus effects wouldn't kick in until they reached the recommended level I think.

I wasn't aware that they are all a single race with an illusion cast on them. That should simplify things a bit as far as DB entries go.

KLS 10-23-2012 05:55 AM

Just create a mercs table to store stats. A lot of the npc_types info is completely useless to mercs and it sucks having to give up valuable npc type ids.

bad_captain 10-23-2012 10:30 AM

That seems like a good idea to just maintain it all in a new table. I think it will be important to decide how to scale the stats based on level. Tier also must affect stats since otherwise, why get the highest tier tank, when the lower tier and cheaper one would work almost as well.

With regards to equipment, just for testing, I had planned to give them the defiant gear for their level, with it changing every 20 levels or so. Weapons are a different story, but they are already in with pretty easy to determine effective level ranges. But, that also adds in another level of complexity. But, then we still need to figure out a way to give the mercs bonuses.

Also, Trevius, I think a lot of the merc tank's ability to tank is its regen. I can't remember the exact numbers, but I know at least at lower levels, they would regen more than 10% (I think closer to 15%) of their hps every tick. They could easily tank 3-4 even con mobs at least through level 30-35 or so without a heal.

bad_captain 10-24-2012 06:13 PM

Below is a first attempt at breaking up the remaining work to be done for mercs. Some of the areas are very broad, but will get refined once work is done on them or in other areas. I have done some work on stats, but until the exact method of giving mercs stats and skills is decided, a lot of the other areas can't be worked on (such as combat). I will try to update this as work is done and further clarify the remaining items to do.

Packets
Merc Merchant List- send correct stances instead of hard coded ones
Merc Hire- check if client has enough coin, deduct purchase cost from client
Timer- send response packet, check if client has enough coin, if so- deduct upkeep from client; if not- dismiss merc
Merc Command- zone, change stance, etc
Remove most if not all of the hard coded values left
Finish extracting packet sending functions

Stats
NPC style stats or equipment based?
Weapons or Max/Min hit?
Stats db table
Skills stored in db table?
if using equipment, need equipment lists
stat scaling based on lvl, proficiency, tier

Spells
Spell & Skill lists per lvl & proficiency

Combat
Melee Attacks
Spell Casting
AI based on proximity
Group Roles
Flee based on confidence & situation

Out of Combat
Buffs
Resurrections

Misc
Save merc to DB

bad_captain 10-24-2012 10:48 PM

I may be tired and not thinking correctly, but was trying to figure out the upkeep part. I looked at a log I did in December on live, and was watching for when I had my upkeep deducted. Here are the only unknown packets arriving at that time. Note: I was charged the upkeep just before I said 'Upkeep' as shown in the last packet. I was charged 1 platinum, 9 gold. I'm having trouble getting 1 platinum, 9 gold out of that, as well as matching it up with one of the existing structs. Am I missing something?

Code:

12/8/2011 9:02:45 PM
[OPCode: 0x7062] OP_ClientUpdate [Client->Server] [Size: 42]
000 | 59 6b 00 00 ce 55 02 00 00 00 b6 24 59 44 b6 2f  | Yk...U.....$YD./
016 | a0 42 00 00 a1 c4 00 00 00 00 00 00 00 00 68 cb  | .B............h.
032 | 58 40 00 00 00 00 00 78 18 00                    | X@.....x..

12/8/2011 9:02:45 PM
[OPCode: 0x528f] OP_Unknown [Server->Client] [Size: 16]
000 | 2d 00 00 00 00 00 00 00 06 00 00 00 05 00 00 00  | -...............

12/8/2011 9:02:45 PM
[OPCode: 0x6537] OP_Unknown [Server->Client] [Size: 4]
000 | 0a 00 00 00                                      | ....

12/8/2011 9:02:46 PM
[OPCode: 0x2e79] OP_ChannelMessage [Client->Server] [Size: 51]
000 | XX XX XX XX XX XX 00 00 00 00 00 00 00 00 00 00  | MyName..........
016 | 08 00 00 00 00 00 00 00 00 64 00 00 00 75 70 6b  | .........d...upk
032 | 65 65 70 00 00 00 00 00 00 00 00 00 00 00 00 00  | eep.............
048 | 00 00 00


lerxst2112 10-24-2012 11:00 PM

Are there any AA or faction type mods that might change the amount you're charged?

Devincean 10-24-2012 11:09 PM

Quote:

Originally Posted by lerxst2112 (Post 213613)
Are there any AA or faction type mods that might change the amount you're charged?

no but you can have a marketplace tokenthat gets deducted rather then plat from your character and the amount per upkeep goes up with levels and merc tier type ... possibly the easiest way to see upkeep is to put away and recall your merc since every time you dismiss and recall mercs it charges a upkeep cost.

Code:

12/8/2011 9:02:45 PM
[OPCode: 0x7062] OP_ClientUpdate [Client->Server] [Size: 42]
000 | 59 6b 00 00 ce 55 02 00 00 00 b6 24 59 44 b6 2f  | Yk...U.....$YD./
016 | a0 42 00 00 a1 c4 00 00 00 00 00 00 00 00 68 cb  | .B............h.
032 | 58 40 00 00 00 00 00 78 18 00                    | X@.....x..

Could be totally off but this looks like during the upkeep it checks for diffrence currencies first.

Code:

12/8/2011 9:02:45 PM
[OPCode: 0x528f] OP_Unknown [Server->Client] [Size: 16]
000 | 2d 00 00 00 00 00 00 00 06 00 00 00 05 00 00 00  | -...............

12/8/2011 9:02:45 PM
[OPCode: 0x6537] OP_Unknown [Server->Client] [Size: 4]
000 | 0a 00 00 00                                      | ....

Then possibly how much of what to minus plat or token
Mind you thats really just a guess.


All times are GMT -4. The time now is 03:52 PM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.