mirror of
https://github.com/EQEmu/Server.git
synced 2026-03-27 14:42:25 +00:00
Merge branch 'master' into web_interface
This commit is contained in:
commit
598a4a6878
@ -1,5 +1,97 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 03/04/2015 ==
|
||||||
|
Akkadius: Fix Spell Book Deletion
|
||||||
|
|
||||||
|
== 03/03/2015 ==
|
||||||
|
Uleat: Fix for 'Invalid Slot ID' messages. Bag slot count is now enforced during database saves to eliminate existing 'hidden' duplicated items..sorry MQ2 users...
|
||||||
|
Uleat: Fix for Item loss during corpse looting and possible item loss when purchasing items from LDoN or Adventure merchants. (cursor-related)
|
||||||
|
|
||||||
|
== 02/27/2015 ==
|
||||||
|
Uleat: Final 'tweak' for light sources until a valid issue arises. Wearable equipment now matches client behavior. Stackable light sources are bugged in the client..but, the current timer update implementation alleviates this condition.
|
||||||
|
|
||||||
|
== 02/26/2015 ==
|
||||||
|
Uleat: Updated light source criteria to (hopefully) match what the client uses (still needs tweaking)
|
||||||
|
Uleat: Changed 'general' light source checks to accept the last valid light source (client behavior)
|
||||||
|
Notes:
|
||||||
|
- "Fire Beetle Eyes" are still causing issues in general slots (no item movement sound effect)
|
||||||
|
- Wearable equipment types still register as valid light sources when in general slots (needs exemption criteria)
|
||||||
|
|
||||||
|
== 02/23/2015 ==
|
||||||
|
Noudess: Allow for a rule to set starting swimming && SenseHeading value.
|
||||||
|
I moved the swimming override to char create instead of setting it
|
||||||
|
every time a char enters a zone.
|
||||||
|
|
||||||
|
Also added rules to not ignore, but rather forrce sense heading packets to be
|
||||||
|
used to train it instead of maxing it out like before.
|
||||||
|
|
||||||
|
Uleat: Fix for RoF+ clients showing active 'Return Home' button when action is not available (swapped 'GoHome' and 'Enabled' fields in RoF-era CharacterSelectEntry structs)
|
||||||
|
|
||||||
|
== 02/21/2015 ==
|
||||||
|
Noudess: Starting erudites that were supposed to start in paineel were landing in erudin on Titanium. Fixed to be paineel.
|
||||||
|
|
||||||
|
== 02/20/2015 ==
|
||||||
|
demonstar55: Implement claims for RoF/RoF2 (should no longer crash the client!)
|
||||||
|
- fixed bugs related to claims for the rest of the clients (woo infinite loops)
|
||||||
|
|
||||||
|
== 02/18/2015 ==
|
||||||
|
Trevius: Fix for potential recursive loops if using RemoveFromHateList() within EVENT_HATE_LIST.
|
||||||
|
|
||||||
|
== 02/17/2015 ==
|
||||||
|
Uleat: Implemented per-client character creation limiting. Caps are unknown atm..so, don't get over-zealous!
|
||||||
|
Notes:
|
||||||
|
- Titanium is hard-coded to min/max of 8 in both the server and client translator code (client doesn't support variations in available character count)
|
||||||
|
- SoF thru RoF2 have had their max characters raised to 12 from 10
|
||||||
|
- Changing the number of characters per account is accomplished by:
|
||||||
|
1) Setting consts::CHARACTER_CREATION_LIMIT to the desired count in the client's constants file in ../common/patches/
|
||||||
|
2) Ensuring that eq_dictionary's EmuConstants::CHARACTER_CREATION_LIMIT is equal-greater than the client's new value..referencing is good
|
||||||
|
3) Recompiling the server code
|
||||||
|
- A rules-based qualifier may be added at some point
|
||||||
|
|
||||||
|
== 02/16/2015 ==
|
||||||
|
Trevius: (RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional.
|
||||||
|
demonstar55: (RoF2) Send the bard focus effects, note custom servers will need to fix their items, server side we still use the old system, but RoF2 wasn't showing anything with not sending focus, so send them
|
||||||
|
|
||||||
|
== 02/14/2015 ==
|
||||||
|
Trevius: (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet.
|
||||||
|
Uleat: Implemented higher bandolier and potion belt counts for clients that support it..you will still need to activate them through the proper aa's, etc...
|
||||||
|
|
||||||
|
== 02/12/2015 ==
|
||||||
|
Akkadius: Implement zone based gravity, required SQL DB change
|
||||||
|
- To test `zone` table `gravity` values, change the value and use #zheader <zoneshortname> to test
|
||||||
|
|
||||||
|
== 02/11/2015 ==
|
||||||
|
Trevius: (RoF+) Bandolier no longer displays a Treasure Chest Icon when no Bandoliers are set.
|
||||||
|
|
||||||
|
== 02/09/2015 ==
|
||||||
|
Trevius: (RoF+) Setting Alt flag on characters in the Guild Management Window is now saved and functional for filtering.
|
||||||
|
Trevius: (RoF+) Guild Invites between RoF+ and previous Clients is now functional.
|
||||||
|
|
||||||
|
== 02/08/2015 ==
|
||||||
|
Kayen: Implemented npc specialability (44) COUNTER_AVOID_DAMAGE which when applied to the ATTACKING NPC will make their attacks more difficult to be avoided by riposte/dodge/parry/block.
|
||||||
|
Parama0: Negative modifer value that affects ALL avoid damage types dodge/parry/riposte/block) chance on defender. Ie (44,50 = 50 pct reduction to ALL)
|
||||||
|
Parama1: Negative modifer value that affects RIPOSTE chance on defender. Ie (44,1,0,50 = 50 pct reduction to riposte chance)
|
||||||
|
Parama2: Negative modifer value that affects PARRY chance on defender. Ie (44,1,0,0,50 = 50 pct reduction to parry chance)
|
||||||
|
Parama3: Negative modifer value that affects BLOCK chance on defender. Ie (44,1,0,0,0,50 = 50 pct reduction to block chance)
|
||||||
|
Parama4: Negative modifer value that affects DODGE chance on defender. e (44,1,0,0,0,0,50 = 50 pct reduction to dodge chance)
|
||||||
|
Example of usage: Player has Improved Dodge V (+50 pct dodge chance), you want to negate this bonus you would set 44,1,0,0,0,0,50 on your NPC.
|
||||||
|
|
||||||
|
== 02/07/2015 ==
|
||||||
|
Akkadius: Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few
|
||||||
|
See: https://www.youtube.com/watch?v=9kSFbyTBuAk
|
||||||
|
|
||||||
|
== 02/06/2015 ==
|
||||||
|
Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const)
|
||||||
|
Uleat: Replaced 'iter_inst' and 'iter_contents' typedefs with their stl definitions
|
||||||
|
Uleat: Removed 'limbo' from the 'HasItem' series of checks - including lore checks. The client excludes this range and it causes issues when performing item searches - dupe lore checks were added to account for this.
|
||||||
|
Uleat: Updated command #iteminfo to show light source information and a few other things
|
||||||
|
|
||||||
|
== 02/05/2015 ==
|
||||||
|
Trevius: Fixed Environmental Damage for RoF2.
|
||||||
|
|
||||||
|
== 02/03/2015 ==
|
||||||
|
Trevius: Crashfix for TempName() when numbers are passed at the end of the name.
|
||||||
|
Uleat: Tweaking of item type exclusions to alleviate strobing conditions with light sources
|
||||||
|
|
||||||
== 02/02/2015 ==
|
== 02/02/2015 ==
|
||||||
Akkadius: Implement Packet logs with dumps
|
Akkadius: Implement Packet logs with dumps
|
||||||
|
|||||||
@ -76,6 +76,24 @@ int GetSpellColumns(SharedDatabase *db) {
|
|||||||
return results.RowCount();
|
return results.RowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsStringField(int i) {
|
||||||
|
switch(i)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ImportSpells(SharedDatabase *db) {
|
void ImportSpells(SharedDatabase *db) {
|
||||||
Log.Out(Logs::General, Logs::Status, "Importing Spells...");
|
Log.Out(Logs::General, Logs::Status, "Importing Spells...");
|
||||||
FILE *f = fopen("import/spells_us.txt", "r");
|
FILE *f = fopen("import/spells_us.txt", "r");
|
||||||
@ -113,7 +131,12 @@ void ImportSpells(SharedDatabase *db) {
|
|||||||
sql += "'";
|
sql += "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
sql += split[i];
|
if(split[i].compare("") == 0 && !IsStringField(i)) {
|
||||||
|
sql += "0";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sql += split[i];
|
||||||
|
}
|
||||||
sql += "'";
|
sql += "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +151,12 @@ void ImportSpells(SharedDatabase *db) {
|
|||||||
sql += "'";
|
sql += "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
sql += split[i];
|
if(split[i].compare("") == 0 && !IsStringField(i)) {
|
||||||
|
sql += "0";
|
||||||
|
} else {
|
||||||
|
sql += split[i];
|
||||||
|
}
|
||||||
|
|
||||||
sql += "'";
|
sql += "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -63,6 +63,7 @@ public:
|
|||||||
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
|
void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); }
|
||||||
void WriteDouble(double value) { *(double *)(pBuffer + _wpos) = value; _wpos += sizeof(double); }
|
void WriteDouble(double value) { *(double *)(pBuffer + _wpos) = value; _wpos += sizeof(double); }
|
||||||
void WriteString(const char * str) { uint32 len = static_cast<uint32>(strlen(str)) + 1; memcpy(pBuffer + _wpos, str, len); _wpos += len; }
|
void WriteString(const char * str) { uint32 len = static_cast<uint32>(strlen(str)) + 1; memcpy(pBuffer + _wpos, str, len); _wpos += len; }
|
||||||
|
void WriteData(const void *ptr, size_t n) { memcpy(pBuffer + _wpos, ptr, n); _wpos += n; }
|
||||||
|
|
||||||
uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; }
|
uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; }
|
||||||
uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; }
|
uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; }
|
||||||
|
|||||||
@ -1,3 +1,24 @@
|
|||||||
|
/*
|
||||||
|
EQEMu: Everquest Server Emulator
|
||||||
|
|
||||||
|
Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net)
|
||||||
|
|
||||||
|
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; version 2 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||||
|
are required to give you total support for your newly bought product;
|
||||||
|
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 CLIENTVERSIONS_H
|
#ifndef CLIENTVERSIONS_H
|
||||||
#define CLIENTVERSIONS_H
|
#define CLIENTVERSIONS_H
|
||||||
|
|
||||||
@ -46,32 +67,87 @@ static const char* ClientVersionName(ClientVersion version)
|
|||||||
switch (version)
|
switch (version)
|
||||||
{
|
{
|
||||||
case ClientVersion::Unknown:
|
case ClientVersion::Unknown:
|
||||||
return "ClientVersion::Unknown";
|
return "Unknown";
|
||||||
case ClientVersion::Client62:
|
case ClientVersion::Client62:
|
||||||
return "ClientVersion::Client62";
|
return "Client62";
|
||||||
case ClientVersion::Titanium:
|
case ClientVersion::Titanium:
|
||||||
return "ClientVersion::Titanium";
|
return "Titanium";
|
||||||
case ClientVersion::SoF:
|
case ClientVersion::SoF:
|
||||||
return "ClientVersion::SoF";
|
return "SoF";
|
||||||
case ClientVersion::SoD:
|
case ClientVersion::SoD:
|
||||||
return "ClientVersion::SoD";
|
return "SoD";
|
||||||
case ClientVersion::UF:
|
case ClientVersion::UF:
|
||||||
return "ClientVersion::UF";
|
return "UF";
|
||||||
case ClientVersion::RoF:
|
case ClientVersion::RoF:
|
||||||
return "ClientVersion::RoF";
|
return "RoF";
|
||||||
case ClientVersion::RoF2:
|
case ClientVersion::RoF2:
|
||||||
return "ClientVersion::RoF2";
|
return "RoF2";
|
||||||
case ClientVersion::MobNPC:
|
case ClientVersion::MobNPC:
|
||||||
return "ClientVersion::MobNPC";
|
return "MobNPC";
|
||||||
case ClientVersion::MobMerc:
|
case ClientVersion::MobMerc:
|
||||||
return "ClientVersion::MobMerc";
|
return "MobMerc";
|
||||||
case ClientVersion::MobBot:
|
case ClientVersion::MobBot:
|
||||||
return "ClientVersion::MobBot";
|
return "MobBot";
|
||||||
case ClientVersion::MobPet:
|
case ClientVersion::MobPet:
|
||||||
return "ClientVersion::MobPet";
|
return "MobPet";
|
||||||
default:
|
default:
|
||||||
return "<ERROR> Invalid ClientVersion";
|
return "<ERROR> Invalid ClientVersion";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32 ClientBitFromVersion(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
|
switch (clientVersion)
|
||||||
|
{
|
||||||
|
case ClientVersion::Unknown:
|
||||||
|
case ClientVersion::Client62:
|
||||||
|
return 0;
|
||||||
|
case ClientVersion::Titanium:
|
||||||
|
case ClientVersion::SoF:
|
||||||
|
case ClientVersion::SoD:
|
||||||
|
case ClientVersion::UF:
|
||||||
|
case ClientVersion::RoF:
|
||||||
|
case ClientVersion::RoF2:
|
||||||
|
case ClientVersion::MobNPC:
|
||||||
|
case ClientVersion::MobMerc:
|
||||||
|
case ClientVersion::MobBot:
|
||||||
|
case ClientVersion::MobPet:
|
||||||
|
return ((uint32)1 << (static_cast<unsigned int>(clientVersion) - 1));
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ClientVersion ClientVersionFromBit(uint32 clientVersionBit)
|
||||||
|
{
|
||||||
|
switch (clientVersionBit)
|
||||||
|
{
|
||||||
|
case (uint32)static_cast<unsigned int>(ClientVersion::Unknown):
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::Client62) - 1)):
|
||||||
|
return ClientVersion::Unknown;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::Titanium) - 1)):
|
||||||
|
return ClientVersion::Titanium;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::SoF) - 1)):
|
||||||
|
return ClientVersion::SoF;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::SoD) - 1)):
|
||||||
|
return ClientVersion::SoD;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::UF) - 1)):
|
||||||
|
return ClientVersion::UF;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::RoF) - 1)):
|
||||||
|
return ClientVersion::RoF;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::RoF2) - 1)):
|
||||||
|
return ClientVersion::RoF2;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::MobNPC) - 1)):
|
||||||
|
return ClientVersion::MobNPC;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::MobMerc) - 1)):
|
||||||
|
return ClientVersion::MobMerc;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::MobBot) - 1)):
|
||||||
|
return ClientVersion::MobBot;
|
||||||
|
case ((uint32)1 << (static_cast<unsigned int>(ClientVersion::MobPet) - 1)):
|
||||||
|
return ClientVersion::MobPet;
|
||||||
|
default:
|
||||||
|
return ClientVersion::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CLIENTVERSIONS_H */
|
#endif /* CLIENTVERSIONS_H */
|
||||||
|
|||||||
@ -1984,7 +1984,7 @@ void Database::GetRaidLeadershipInfo(uint32 rid, char *maintank,
|
|||||||
|
|
||||||
void Database::SetRaidGroupLeaderInfo(uint32 gid, uint32 rid)
|
void Database::SetRaidGroupLeaderInfo(uint32 gid, uint32 rid)
|
||||||
{
|
{
|
||||||
std::string query = StringFormat("UPDATE raid_leaders SET leadershipaa = '', WHERE gid = %lu AND rid = %lu",
|
std::string query = StringFormat("UPDATE raid_leaders SET leadershipaa = '' WHERE gid = %lu AND rid = %lu",
|
||||||
(unsigned long)gid, (unsigned long)rid);
|
(unsigned long)gid, (unsigned long)rid);
|
||||||
auto results = QueryDatabase(query);
|
auto results = QueryDatabase(query);
|
||||||
|
|
||||||
@ -2172,4 +2172,4 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings)
|
|||||||
Log.file_logs_enabled = true;
|
Log.file_logs_enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -157,18 +157,29 @@ namespace Convert {
|
|||||||
/*84*/ uint32 Points;
|
/*84*/ uint32 Points;
|
||||||
/*88*/
|
/*88*/
|
||||||
} PVPStatsEntry_Struct;
|
} PVPStatsEntry_Struct;
|
||||||
|
|
||||||
|
static const size_t BANDOLIERS_SIZE = 4;
|
||||||
|
static const size_t BANDOLIER_ITEM_COUNT = 4;
|
||||||
struct BandolierItem_Struct {
|
struct BandolierItem_Struct {
|
||||||
uint32 item_id;
|
uint32 ID;
|
||||||
uint32 icon;
|
uint32 Icon;
|
||||||
char item_name[64];
|
char Name[64];
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
struct Bandolier_Struct {
|
||||||
char name[32];
|
char Name[32];
|
||||||
Convert::BandolierItem_Struct items[EmuConstants::BANDOLIER_SIZE];
|
Convert::BandolierItem_Struct Items[Convert::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t POTION_BELT_ITEM_COUNT = 4;
|
||||||
|
struct PotionBeltItem_Struct {
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
struct PotionBelt_Struct {
|
struct PotionBelt_Struct {
|
||||||
Convert::BandolierItem_Struct items[EmuConstants::POTION_BELT_SIZE];
|
Convert::PotionBeltItem_Struct Items[Convert::POTION_BELT_ITEM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SuspendedMinion_Struct
|
struct SuspendedMinion_Struct
|
||||||
{
|
{
|
||||||
/*000*/ uint16 SpellID;
|
/*000*/ uint16 SpellID;
|
||||||
@ -346,7 +357,7 @@ namespace Convert {
|
|||||||
/*12800*/ uint32 expAA;
|
/*12800*/ uint32 expAA;
|
||||||
/*12804*/ uint32 aapoints; //avaliable, unspent
|
/*12804*/ uint32 aapoints; //avaliable, unspent
|
||||||
/*12808*/ uint8 unknown12844[36];
|
/*12808*/ uint8 unknown12844[36];
|
||||||
/*12844*/ Convert::Bandolier_Struct bandoliers[EmuConstants::BANDOLIERS_COUNT];
|
/*12844*/ Convert::Bandolier_Struct bandoliers[Convert::BANDOLIERS_SIZE];
|
||||||
/*14124*/ uint8 unknown14160[4506];
|
/*14124*/ uint8 unknown14160[4506];
|
||||||
/*18630*/ Convert::SuspendedMinion_Struct SuspendedMinion; // No longer in use
|
/*18630*/ Convert::SuspendedMinion_Struct SuspendedMinion; // No longer in use
|
||||||
/*19240*/ uint32 timeentitledonaccount;
|
/*19240*/ uint32 timeentitledonaccount;
|
||||||
@ -1430,15 +1441,15 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
|||||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||||
/* Run Bandolier Convert */
|
/* Run Bandolier Convert */
|
||||||
first_entry = 0; rquery = "";
|
first_entry = 0; rquery = "";
|
||||||
for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++){
|
for (i = 0; i < Convert::BANDOLIERS_SIZE; i++){
|
||||||
if (strlen(pp->bandoliers[i].name) < 32) {
|
if (strlen(pp->bandoliers[i].Name) < 32) {
|
||||||
for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++){
|
for (int si = 0; si < Convert::BANDOLIER_ITEM_COUNT; si++){
|
||||||
if (pp->bandoliers[i].items[si].item_id > 0){
|
if (pp->bandoliers[i].Items[si].ID > 0){
|
||||||
if (first_entry != 1) {
|
if (first_entry != 1) {
|
||||||
rquery = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].items[si].item_id, pp->bandoliers[i].items[si].icon, pp->bandoliers[i].name);
|
rquery = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].Items[si].ID, pp->bandoliers[i].Items[si].Icon, pp->bandoliers[i].Name);
|
||||||
first_entry = 1;
|
first_entry = 1;
|
||||||
}
|
}
|
||||||
rquery = rquery + StringFormat(", (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].items[si].item_id, pp->bandoliers[i].items[si].icon, pp->bandoliers[i].name);
|
rquery = rquery + StringFormat(", (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].Items[si].ID, pp->bandoliers[i].Items[si].Icon, pp->bandoliers[i].Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1446,13 +1457,13 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
|||||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||||
/* Run Potion Belt Convert */
|
/* Run Potion Belt Convert */
|
||||||
first_entry = 0; rquery = "";
|
first_entry = 0; rquery = "";
|
||||||
for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){
|
for (i = 0; i < Convert::POTION_BELT_ITEM_COUNT; i++){
|
||||||
if (pp->potionbelt.items[i].item_id > 0){
|
if (pp->potionbelt.Items[i].ID > 0){
|
||||||
if (first_entry != 1){
|
if (first_entry != 1){
|
||||||
rquery = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%i, %u, %u, %u)", character_id, i, pp->potionbelt.items[i].item_id, pp->potionbelt.items[i].icon);
|
rquery = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%i, %u, %u, %u)", character_id, i, pp->potionbelt.Items[i].ID, pp->potionbelt.Items[i].Icon);
|
||||||
first_entry = 1;
|
first_entry = 1;
|
||||||
}
|
}
|
||||||
rquery = rquery + StringFormat(", (%i, %u, %u, %u)", character_id, i, pp->potionbelt.items[i].item_id, pp->potionbelt.items[i].icon);
|
rquery = rquery + StringFormat(", (%i, %u, %u, %u)", character_id, i, pp->potionbelt.Items[i].ID, pp->potionbelt.Items[i].Icon);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,53 @@
|
|||||||
#include "skills.h"
|
#include "skills.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Light Types
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
enum LightTypes
|
||||||
|
{
|
||||||
|
lightTypeNone = 0,
|
||||||
|
lightTypeCandle,
|
||||||
|
lightTypeTorch,
|
||||||
|
lightTypeTinyGlowingSkull,
|
||||||
|
lightTypeSmallLantern,
|
||||||
|
lightTypeSteinOfMoggok,
|
||||||
|
lightTypeLargeLantern,
|
||||||
|
lightTypeFlamelessLantern,
|
||||||
|
lightTypeGlobeOfStars,
|
||||||
|
lightTypeLightGlobe,
|
||||||
|
lightTypeLightstone,
|
||||||
|
lightTypeGreaterLightstone,
|
||||||
|
lightTypeFireBeetleEye,
|
||||||
|
lightTypeColdlight,
|
||||||
|
lightTypeUnknown1,
|
||||||
|
lightTypeUnknown2
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LIGHT_TYPES_COUNT 16
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Light Levels
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
enum LightLevels
|
||||||
|
{
|
||||||
|
lightLevelUnlit = 0,
|
||||||
|
lightLevelCandle,
|
||||||
|
lightLevelTorch,
|
||||||
|
lightLevelSmallMagic,
|
||||||
|
lightLevelRedLight,
|
||||||
|
lightLevelBlueLight,
|
||||||
|
lightLevelSmallLantern,
|
||||||
|
lightLevelMagicLantern,
|
||||||
|
lightLevelLargeLantern,
|
||||||
|
lightLevelLargeMagic,
|
||||||
|
lightLevelBrilliant
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LIGHT_LEVELS_COUNT 11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Item attributes
|
** Item attributes
|
||||||
**
|
**
|
||||||
@ -55,7 +102,7 @@ enum ItemClassTypes
|
|||||||
**
|
**
|
||||||
** (ref: database and eqstr_us.txt)
|
** (ref: database and eqstr_us.txt)
|
||||||
**
|
**
|
||||||
** (Looking at a recent database, it's possible that some of the item values may be off [10-27-2013] -U)
|
** (Looking at a recent database, it's possible that some of the item values may be off [10-27-2013])
|
||||||
*/
|
*/
|
||||||
enum ItemUseTypes : uint8
|
enum ItemUseTypes : uint8
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
EQEMu: Everquest Server Emulator
|
EQEMu: Everquest Server Emulator
|
||||||
|
|
||||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net)
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -25,8 +25,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
//
|
//
|
||||||
// class EmuConstants
|
// class EmuConstants
|
||||||
//
|
//
|
||||||
uint16 EmuConstants::InventoryMapSize(int16 indexMap) {
|
uint16 EmuConstants::InventoryMapSize(int16 indexMap)
|
||||||
switch (indexMap) {
|
{
|
||||||
|
switch (indexMap)
|
||||||
|
{
|
||||||
case MapPossessions:
|
case MapPossessions:
|
||||||
return MAP_POSSESSIONS_SIZE;
|
return MAP_POSSESSIONS_SIZE;
|
||||||
case MapBank:
|
case MapBank:
|
||||||
@ -83,7 +85,8 @@ uint16 EmuConstants::InventoryMapSize(int16 indexMap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
std::string EmuConstants::InventoryLocationName(Location_Struct location) {
|
std::string EmuConstants::InventoryLocationName(Location_Struct location)
|
||||||
|
{
|
||||||
// not ready for implementation...
|
// not ready for implementation...
|
||||||
std::string ret_str;
|
std::string ret_str;
|
||||||
StringFormat(ret_str, "%s, %s, %s, %s", InventoryMapName(location.map), InventoryMainName(location.main), InventorySubName(location.sub), InventoryAugName(location.aug));
|
StringFormat(ret_str, "%s, %s, %s, %s", InventoryMapName(location.map), InventoryMainName(location.main), InventorySubName(location.sub), InventoryAugName(location.aug));
|
||||||
@ -91,8 +94,10 @@ std::string EmuConstants::InventoryLocationName(Location_Struct location) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::string EmuConstants::InventoryMapName(int16 indexMap) {
|
std::string EmuConstants::InventoryMapName(int16 indexMap)
|
||||||
switch (indexMap) {
|
{
|
||||||
|
switch (indexMap)
|
||||||
|
{
|
||||||
case INVALID_INDEX:
|
case INVALID_INDEX:
|
||||||
return "Invalid Map";
|
return "Invalid Map";
|
||||||
case MapPossessions:
|
case MapPossessions:
|
||||||
@ -100,7 +105,7 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) {
|
|||||||
case MapBank:
|
case MapBank:
|
||||||
return "Bank";
|
return "Bank";
|
||||||
case MapSharedBank:
|
case MapSharedBank:
|
||||||
return "Shared Bank";
|
return "SharedBank";
|
||||||
case MapTrade:
|
case MapTrade:
|
||||||
return "Trade";
|
return "Trade";
|
||||||
case MapWorld:
|
case MapWorld:
|
||||||
@ -110,9 +115,9 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) {
|
|||||||
case MapTribute:
|
case MapTribute:
|
||||||
return "Tribute";
|
return "Tribute";
|
||||||
case MapTrophyTribute:
|
case MapTrophyTribute:
|
||||||
return "Trophy Tribute";
|
return "TrophyTribute";
|
||||||
case MapGuildTribute:
|
case MapGuildTribute:
|
||||||
return "Guild Tribute";
|
return "GuildTribute";
|
||||||
case MapMerchant:
|
case MapMerchant:
|
||||||
return "Merchant";
|
return "Merchant";
|
||||||
case MapDeleted:
|
case MapDeleted:
|
||||||
@ -124,23 +129,23 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) {
|
|||||||
case MapInspect:
|
case MapInspect:
|
||||||
return "Inspect";
|
return "Inspect";
|
||||||
case MapRealEstate:
|
case MapRealEstate:
|
||||||
return "Real Estate";
|
return "RealEstate";
|
||||||
case MapViewMODPC:
|
case MapViewMODPC:
|
||||||
return "View MOD PC";
|
return "ViewMODPC";
|
||||||
case MapViewMODBank:
|
case MapViewMODBank:
|
||||||
return "View MOD Bank";
|
return "ViewMODBank";
|
||||||
case MapViewMODSharedBank:
|
case MapViewMODSharedBank:
|
||||||
return "View MOD Shared Bank";
|
return "ViewMODSharedBank";
|
||||||
case MapViewMODLimbo:
|
case MapViewMODLimbo:
|
||||||
return "View MOD Limbo";
|
return "ViewMODLimbo";
|
||||||
case MapAltStorage:
|
case MapAltStorage:
|
||||||
return "Alt Storage";
|
return "AltStorage";
|
||||||
case MapArchived:
|
case MapArchived:
|
||||||
return "Archived";
|
return "Archived";
|
||||||
case MapMail:
|
case MapMail:
|
||||||
return "Mail";
|
return "Mail";
|
||||||
case MapGuildTrophyTribute:
|
case MapGuildTrophyTribute:
|
||||||
return "Guild Trophy Tribute";
|
return "GuildTrophyTribute";
|
||||||
case MapKrono:
|
case MapKrono:
|
||||||
return "Krono";
|
return "Krono";
|
||||||
case MapOther:
|
case MapOther:
|
||||||
@ -150,20 +155,22 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EmuConstants::InventoryMainName(int16 indexMain) {
|
std::string EmuConstants::InventoryMainName(int16 indexMain)
|
||||||
switch (indexMain) {
|
{
|
||||||
|
switch (indexMain)
|
||||||
|
{
|
||||||
case INVALID_INDEX:
|
case INVALID_INDEX:
|
||||||
return "Invalid Main";
|
return "Invalid Main";
|
||||||
case MainCharm:
|
case MainCharm:
|
||||||
return "Charm";
|
return "Charm";
|
||||||
case MainEar1:
|
case MainEar1:
|
||||||
return "Ear 1";
|
return "Ear1";
|
||||||
case MainHead:
|
case MainHead:
|
||||||
return "Head";
|
return "Head";
|
||||||
case MainFace:
|
case MainFace:
|
||||||
return "Face";
|
return "Face";
|
||||||
case MainEar2:
|
case MainEar2:
|
||||||
return "Ear 2";
|
return "Ear2";
|
||||||
case MainNeck:
|
case MainNeck:
|
||||||
return "Neck";
|
return "Neck";
|
||||||
case MainShoulders:
|
case MainShoulders:
|
||||||
@ -173,9 +180,9 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) {
|
|||||||
case MainBack:
|
case MainBack:
|
||||||
return "Back";
|
return "Back";
|
||||||
case MainWrist1:
|
case MainWrist1:
|
||||||
return "Wrist 1";
|
return "Wrist1";
|
||||||
case MainWrist2:
|
case MainWrist2:
|
||||||
return "Wrist 2";
|
return "Wrist2";
|
||||||
case MainRange:
|
case MainRange:
|
||||||
return "Range";
|
return "Range";
|
||||||
case MainHands:
|
case MainHands:
|
||||||
@ -185,9 +192,9 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) {
|
|||||||
case MainSecondary:
|
case MainSecondary:
|
||||||
return "Secondary";
|
return "Secondary";
|
||||||
case MainFinger1:
|
case MainFinger1:
|
||||||
return "Finger 1";
|
return "Finger1";
|
||||||
case MainFinger2:
|
case MainFinger2:
|
||||||
return "Finger 2";
|
return "Finger2";
|
||||||
case MainChest:
|
case MainChest:
|
||||||
return "Chest";
|
return "Chest";
|
||||||
case MainLegs:
|
case MainLegs:
|
||||||
@ -197,30 +204,30 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) {
|
|||||||
case MainWaist:
|
case MainWaist:
|
||||||
return "Waist";
|
return "Waist";
|
||||||
case MainPowerSource:
|
case MainPowerSource:
|
||||||
return "Power Source";
|
return "PowerSource";
|
||||||
case MainAmmo:
|
case MainAmmo:
|
||||||
return "Ammo";
|
return "Ammo";
|
||||||
case MainGeneral1:
|
case MainGeneral1:
|
||||||
return "General 1";
|
return "General1";
|
||||||
case MainGeneral2:
|
case MainGeneral2:
|
||||||
return "General 2";
|
return "General2";
|
||||||
case MainGeneral3:
|
case MainGeneral3:
|
||||||
return "General 3";
|
return "General3";
|
||||||
case MainGeneral4:
|
case MainGeneral4:
|
||||||
return "General 4";
|
return "General4";
|
||||||
case MainGeneral5:
|
case MainGeneral5:
|
||||||
return "General 5";
|
return "General5";
|
||||||
case MainGeneral6:
|
case MainGeneral6:
|
||||||
return "General 6";
|
return "General6";
|
||||||
case MainGeneral7:
|
case MainGeneral7:
|
||||||
return "General 7";
|
return "General7";
|
||||||
case MainGeneral8:
|
case MainGeneral8:
|
||||||
return "General 8";
|
return "General8";
|
||||||
/*
|
/*
|
||||||
case MainGeneral9:
|
case MainGeneral9:
|
||||||
return "General 9";
|
return "General9";
|
||||||
case MainGeneral10:
|
case MainGeneral10:
|
||||||
return "General 10";
|
return "General10";
|
||||||
*/
|
*/
|
||||||
case MainCursor:
|
case MainCursor:
|
||||||
return "Cursor";
|
return "Cursor";
|
||||||
@ -229,7 +236,8 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EmuConstants::InventorySubName(int16 indexSub) {
|
std::string EmuConstants::InventorySubName(int16 indexSub)
|
||||||
|
{
|
||||||
if (indexSub == INVALID_INDEX)
|
if (indexSub == INVALID_INDEX)
|
||||||
return "Invalid Sub";
|
return "Invalid Sub";
|
||||||
|
|
||||||
@ -237,12 +245,13 @@ std::string EmuConstants::InventorySubName(int16 indexSub) {
|
|||||||
return "Unknown Sub";
|
return "Unknown Sub";
|
||||||
|
|
||||||
std::string ret_str;
|
std::string ret_str;
|
||||||
ret_str = StringFormat("Container %i", (indexSub + 1)); // zero-based index..but, count starts at one
|
ret_str = StringFormat("Container%i", (indexSub + 1)); // zero-based index..but, count starts at one
|
||||||
|
|
||||||
return ret_str;
|
return ret_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EmuConstants::InventoryAugName(int16 indexAug) {
|
std::string EmuConstants::InventoryAugName(int16 indexAug)
|
||||||
|
{
|
||||||
if (indexAug == INVALID_INDEX)
|
if (indexAug == INVALID_INDEX)
|
||||||
return "Invalid Aug";
|
return "Invalid Aug";
|
||||||
|
|
||||||
@ -250,7 +259,7 @@ std::string EmuConstants::InventoryAugName(int16 indexAug) {
|
|||||||
return "Unknown Aug";
|
return "Unknown Aug";
|
||||||
|
|
||||||
std::string ret_str;
|
std::string ret_str;
|
||||||
ret_str = StringFormat("Augment %i", (indexAug + 1)); // zero-based index..but, count starts at one
|
ret_str = StringFormat("Augment%i", (indexAug + 1)); // zero-based index..but, count starts at one
|
||||||
|
|
||||||
return ret_str;
|
return ret_str;
|
||||||
}
|
}
|
||||||
@ -260,14 +269,16 @@ std::string EmuConstants::InventoryAugName(int16 indexAug) {
|
|||||||
// class EQLimits
|
// class EQLimits
|
||||||
//
|
//
|
||||||
// client validation
|
// client validation
|
||||||
bool EQLimits::IsValidPCClientVersion(ClientVersion clientVersion) {
|
bool EQLimits::IsValidPCClientVersion(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT)
|
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientVersion EQLimits::ValidatePCClientVersion(ClientVersion clientVersion) {
|
ClientVersion EQLimits::ValidatePCClientVersion(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT)
|
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT)
|
||||||
return clientVersion;
|
return clientVersion;
|
||||||
|
|
||||||
@ -275,14 +286,16 @@ ClientVersion EQLimits::ValidatePCClientVersion(ClientVersion clientVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// npc validation
|
// npc validation
|
||||||
bool EQLimits::IsValidNPCClientVersion(ClientVersion clientVersion) {
|
bool EQLimits::IsValidNPCClientVersion(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT)
|
if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientVersion EQLimits::ValidateNPCClientVersion(ClientVersion clientVersion) {
|
ClientVersion EQLimits::ValidateNPCClientVersion(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT)
|
if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT)
|
||||||
return clientVersion;
|
return clientVersion;
|
||||||
|
|
||||||
@ -290,22 +303,47 @@ ClientVersion EQLimits::ValidateNPCClientVersion(ClientVersion clientVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mob validation
|
// mob validation
|
||||||
bool EQLimits::IsValidMobClientVersion(ClientVersion clientVersion) {
|
bool EQLimits::IsValidMobClientVersion(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT)
|
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientVersion EQLimits::ValidateMobClientVersion(ClientVersion clientVersion) {
|
ClientVersion EQLimits::ValidateMobClientVersion(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT)
|
if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT)
|
||||||
return clientVersion;
|
return clientVersion;
|
||||||
|
|
||||||
return ClientVersion::Unknown;
|
return ClientVersion::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// database
|
||||||
|
size_t EQLimits::CharacterCreationLimit(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
|
static const size_t local[CLIENT_VERSION_COUNT] = {
|
||||||
|
/*Unknown*/ NOT_USED,
|
||||||
|
/*Client62*/ NOT_USED,
|
||||||
|
/*Titanium*/ Titanium::consts::CHARACTER_CREATION_LIMIT,
|
||||||
|
/*SoF*/ SoF::consts::CHARACTER_CREATION_LIMIT,
|
||||||
|
/*SoD*/ SoD::consts::CHARACTER_CREATION_LIMIT,
|
||||||
|
/*UF*/ UF::consts::CHARACTER_CREATION_LIMIT,
|
||||||
|
/*RoF*/ RoF::consts::CHARACTER_CREATION_LIMIT,
|
||||||
|
/*RoF2*/ RoF2::consts::CHARACTER_CREATION_LIMIT,
|
||||||
|
|
||||||
|
/*MobNPC*/ NOT_USED,
|
||||||
|
/*MobMerc*/ NOT_USED,
|
||||||
|
/*MobBot*/ NOT_USED,
|
||||||
|
/*MobPet*/ NOT_USED
|
||||||
|
};
|
||||||
|
|
||||||
|
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
|
}
|
||||||
|
|
||||||
// inventory
|
// inventory
|
||||||
uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion) {
|
uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion)
|
||||||
|
{
|
||||||
// not all maps will have an instantiated container..some are references for queue generators (i.e., bazaar, mail, etc...)
|
// not all maps will have an instantiated container..some are references for queue generators (i.e., bazaar, mail, etc...)
|
||||||
// a zero '0' indicates a needed value..otherwise, change to '_NOTUSED' for a null value so indices requiring research can be identified
|
// a zero '0' indicates a needed value..otherwise, change to '_NOTUSED' for a null value so indices requiring research can be identified
|
||||||
// ALL of these values need to be verified before pushing to live
|
// ALL of these values need to be verified before pushing to live
|
||||||
@ -704,7 +742,8 @@ uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion) {
|
|||||||
return NOT_USED;
|
return NOT_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 EQLimits::PossessionsBitmask(ClientVersion clientVersion) {
|
uint64 EQLimits::PossessionsBitmask(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
// these are for the new inventory system (RoF)..not the current (Ti) one...
|
// these are for the new inventory system (RoF)..not the current (Ti) one...
|
||||||
// 0x0000000000200000 is SlotPowerSource (SoF+)
|
// 0x0000000000200000 is SlotPowerSource (SoF+)
|
||||||
// 0x0000000080000000 is SlotGeneral9 (RoF+)
|
// 0x0000000080000000 is SlotGeneral9 (RoF+)
|
||||||
@ -730,7 +769,8 @@ uint64 EQLimits::PossessionsBitmask(ClientVersion clientVersion) {
|
|||||||
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 EQLimits::EquipmentBitmask(ClientVersion clientVersion) {
|
uint64 EQLimits::EquipmentBitmask(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const uint64 local[CLIENT_VERSION_COUNT] = {
|
static const uint64 local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ NOT_USED,
|
/*Unknown*/ NOT_USED,
|
||||||
/*62*/ 0x00000000005FFFFF,
|
/*62*/ 0x00000000005FFFFF,
|
||||||
@ -751,7 +791,8 @@ uint64 EQLimits::EquipmentBitmask(ClientVersion clientVersion) {
|
|||||||
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 EQLimits::GeneralBitmask(ClientVersion clientVersion) {
|
uint64 EQLimits::GeneralBitmask(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const uint64 local[CLIENT_VERSION_COUNT] = {
|
static const uint64 local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ NOT_USED,
|
/*Unknown*/ NOT_USED,
|
||||||
/*62*/ 0x000000007F800000,
|
/*62*/ 0x000000007F800000,
|
||||||
@ -772,7 +813,8 @@ uint64 EQLimits::GeneralBitmask(ClientVersion clientVersion) {
|
|||||||
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 EQLimits::CursorBitmask(ClientVersion clientVersion) {
|
uint64 EQLimits::CursorBitmask(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const uint64 local[CLIENT_VERSION_COUNT] = {
|
static const uint64 local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ NOT_USED,
|
/*Unknown*/ NOT_USED,
|
||||||
/*62*/ 0x0000000200000000,
|
/*62*/ 0x0000000200000000,
|
||||||
@ -793,7 +835,8 @@ uint64 EQLimits::CursorBitmask(ClientVersion clientVersion) {
|
|||||||
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EQLimits::AllowsEmptyBagInBag(ClientVersion clientVersion) {
|
bool EQLimits::AllowsEmptyBagInBag(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const bool local[CLIENT_VERSION_COUNT] = {
|
static const bool local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ false,
|
/*Unknown*/ false,
|
||||||
/*62*/ false,
|
/*62*/ false,
|
||||||
@ -814,7 +857,8 @@ bool EQLimits::AllowsEmptyBagInBag(ClientVersion clientVersion) {
|
|||||||
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
//return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EQLimits::AllowsClickCastFromBag(ClientVersion clientVersion) {
|
bool EQLimits::AllowsClickCastFromBag(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const bool local[CLIENT_VERSION_COUNT] = {
|
static const bool local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ false,
|
/*Unknown*/ false,
|
||||||
/*62*/ false,
|
/*62*/ false,
|
||||||
@ -835,7 +879,8 @@ bool EQLimits::AllowsClickCastFromBag(ClientVersion clientVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// items
|
// items
|
||||||
uint16 EQLimits::ItemCommonSize(ClientVersion clientVersion) {
|
uint16 EQLimits::ItemCommonSize(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const uint16 local[CLIENT_VERSION_COUNT] = {
|
static const uint16 local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ NOT_USED,
|
/*Unknown*/ NOT_USED,
|
||||||
/*62*/ EmuConstants::ITEM_COMMON_SIZE,
|
/*62*/ EmuConstants::ITEM_COMMON_SIZE,
|
||||||
@ -855,7 +900,8 @@ uint16 EQLimits::ItemCommonSize(ClientVersion clientVersion) {
|
|||||||
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 EQLimits::ItemContainerSize(ClientVersion clientVersion) {
|
uint16 EQLimits::ItemContainerSize(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const uint16 local[CLIENT_VERSION_COUNT] = {
|
static const uint16 local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ NOT_USED,
|
/*Unknown*/ NOT_USED,
|
||||||
/*62*/ EmuConstants::ITEM_CONTAINER_SIZE,
|
/*62*/ EmuConstants::ITEM_CONTAINER_SIZE,
|
||||||
@ -875,7 +921,8 @@ uint16 EQLimits::ItemContainerSize(ClientVersion clientVersion) {
|
|||||||
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EQLimits::CoinHasWeight(ClientVersion clientVersion) {
|
bool EQLimits::CoinHasWeight(ClientVersion clientVersion)
|
||||||
|
{
|
||||||
static const bool local[CLIENT_VERSION_COUNT] = {
|
static const bool local[CLIENT_VERSION_COUNT] = {
|
||||||
/*Unknown*/ true,
|
/*Unknown*/ true,
|
||||||
/*62*/ true,
|
/*62*/ true,
|
||||||
@ -894,63 +941,3 @@ bool EQLimits::CoinHasWeight(ClientVersion clientVersion) {
|
|||||||
|
|
||||||
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 EQLimits::BandoliersCount(ClientVersion clientVersion) {
|
|
||||||
static const uint32 local[CLIENT_VERSION_COUNT] = {
|
|
||||||
/*Unknown*/ NOT_USED,
|
|
||||||
/*62*/ EmuConstants::BANDOLIERS_COUNT,
|
|
||||||
/*Titanium*/ EmuConstants::BANDOLIERS_COUNT,
|
|
||||||
/*SoF*/ EmuConstants::BANDOLIERS_COUNT,
|
|
||||||
/*SoD*/ EmuConstants::BANDOLIERS_COUNT,
|
|
||||||
/*Underfoot*/ EmuConstants::BANDOLIERS_COUNT,
|
|
||||||
/*RoF*/ EmuConstants::BANDOLIERS_COUNT,
|
|
||||||
/*RoF2*/ EmuConstants::BANDOLIERS_COUNT,
|
|
||||||
|
|
||||||
/*NPC*/ NOT_USED,
|
|
||||||
/*Merc*/ NOT_USED,
|
|
||||||
/*Bot*/ NOT_USED,
|
|
||||||
/*Pet*/ NOT_USED
|
|
||||||
};
|
|
||||||
|
|
||||||
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 EQLimits::BandolierSize(ClientVersion clientVersion) {
|
|
||||||
static const uint32 local[CLIENT_VERSION_COUNT] = {
|
|
||||||
/*Unknown*/ NOT_USED,
|
|
||||||
/*62*/ EmuConstants::BANDOLIER_SIZE,
|
|
||||||
/*Titanium*/ EmuConstants::BANDOLIER_SIZE,
|
|
||||||
/*SoF*/ EmuConstants::BANDOLIER_SIZE,
|
|
||||||
/*SoD*/ EmuConstants::BANDOLIER_SIZE,
|
|
||||||
/*Underfoot*/ EmuConstants::BANDOLIER_SIZE,
|
|
||||||
/*RoF*/ EmuConstants::BANDOLIER_SIZE,
|
|
||||||
/*RoF2*/ EmuConstants::BANDOLIER_SIZE,
|
|
||||||
|
|
||||||
/*NPC*/ NOT_USED,
|
|
||||||
/*Merc*/ NOT_USED,
|
|
||||||
/*Bot*/ NOT_USED,
|
|
||||||
/*Pet*/ NOT_USED
|
|
||||||
};
|
|
||||||
|
|
||||||
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 EQLimits::PotionBeltSize(ClientVersion clientVersion) {
|
|
||||||
static const uint32 local[CLIENT_VERSION_COUNT] = {
|
|
||||||
/*Unknown*/ NOT_USED,
|
|
||||||
/*62*/ EmuConstants::POTION_BELT_SIZE,
|
|
||||||
/*Titanium*/ EmuConstants::POTION_BELT_SIZE,
|
|
||||||
/*SoF*/ EmuConstants::POTION_BELT_SIZE,
|
|
||||||
/*SoD*/ EmuConstants::POTION_BELT_SIZE,
|
|
||||||
/*Underfoot*/ EmuConstants::POTION_BELT_SIZE,
|
|
||||||
/*RoF*/ EmuConstants::POTION_BELT_SIZE,
|
|
||||||
/*RoF2*/ EmuConstants::POTION_BELT_SIZE,
|
|
||||||
|
|
||||||
/*NPC*/ NOT_USED,
|
|
||||||
/*Merc*/ NOT_USED,
|
|
||||||
/*Bot*/ NOT_USED,
|
|
||||||
/*Pet*/ NOT_USED
|
|
||||||
};
|
|
||||||
|
|
||||||
return local[static_cast<unsigned int>(ValidateMobClientVersion(clientVersion))];
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
EQEMu: Everquest Server Emulator
|
EQEMu: Everquest Server Emulator
|
||||||
|
|
||||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net)
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -42,12 +42,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
//using namespace RoF2::maps; // server inventory maps enumeration (code and database sync'd to reference)
|
//using namespace RoF2::maps; // server inventory maps enumeration (code and database sync'd to reference)
|
||||||
//using namespace RoF::slots; // server possessions slots enumeration (code and database sync'd to reference)
|
//using namespace RoF::slots; // server possessions slots enumeration (code and database sync'd to reference)
|
||||||
|
|
||||||
class EmuConstants {
|
class EmuConstants
|
||||||
|
{
|
||||||
// an immutable value is required to initialize arrays, etc... use this class as a repository for those
|
// an immutable value is required to initialize arrays, etc... use this class as a repository for those
|
||||||
public:
|
public:
|
||||||
// database
|
// database
|
||||||
static const ClientVersion CHARACTER_CREATION_CLIENT = ClientVersion::RoF2; // adjust according to starting item placement and target client
|
static const ClientVersion CHARACTER_CREATION_CLIENT = ClientVersion::RoF2; // adjust according to starting item placement and target client
|
||||||
|
|
||||||
|
static const size_t CHARACTER_CREATION_LIMIT = RoF2::consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
// inventory
|
// inventory
|
||||||
static uint16 InventoryMapSize(int16 indexMap);
|
static uint16 InventoryMapSize(int16 indexMap);
|
||||||
//static std::string InventoryLocationName(Location_Struct location);
|
//static std::string InventoryLocationName(Location_Struct location);
|
||||||
@ -140,23 +143,18 @@ public:
|
|||||||
static const uint16 ITEM_COMMON_SIZE = RoF::consts::ITEM_COMMON_SIZE;
|
static const uint16 ITEM_COMMON_SIZE = RoF::consts::ITEM_COMMON_SIZE;
|
||||||
static const uint16 ITEM_CONTAINER_SIZE = Titanium::consts::ITEM_CONTAINER_SIZE;
|
static const uint16 ITEM_CONTAINER_SIZE = Titanium::consts::ITEM_CONTAINER_SIZE;
|
||||||
|
|
||||||
// player profile
|
// BANDOLIERS_SIZE sets maximum limit..active limit will need to be handled by the appropriate AA or spell (or item?)
|
||||||
//static const uint32 CLASS_BITMASK = 0; // needs value
|
static const size_t BANDOLIERS_SIZE = RoF2::consts::BANDOLIERS_SIZE; // number of bandolier instances
|
||||||
//static const uint32 RACE_BITMASK = 0; // needs value
|
static const size_t BANDOLIER_ITEM_COUNT = RoF2::consts::BANDOLIER_ITEM_COUNT; // number of equipment slots in bandolier instance
|
||||||
|
|
||||||
// BANDOLIERS_COUNT sets maximum limit..active limit will need to be handled by the appropriate AA
|
// POTION_BELT_SIZE sets maximum limit..active limit will need to be handled by the appropriate AA or spell (or item?)
|
||||||
static const uint32 BANDOLIERS_COUNT = Titanium::consts::BANDOLIERS_COUNT; // count = number of bandolier instances
|
static const size_t POTION_BELT_ITEM_COUNT = RoF2::consts::POTION_BELT_ITEM_COUNT;
|
||||||
static const uint32 BANDOLIER_SIZE = Titanium::consts::BANDOLIER_SIZE; // size = number of equipment slots in bandolier instance
|
|
||||||
static const uint32 POTION_BELT_SIZE = Titanium::consts::POTION_BELT_SIZE;
|
|
||||||
|
|
||||||
static const size_t TEXT_LINK_BODY_LENGTH = 56;
|
static const size_t TEXT_LINK_BODY_LENGTH = RoF2::consts::TEXT_LINK_BODY_LENGTH;
|
||||||
|
|
||||||
// legacy-related functions
|
|
||||||
//static int ServerToPerlSlot(int slot); // encode
|
|
||||||
//static int PerlToServerSlot(int slot); // decode
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class EQLimits {
|
class EQLimits
|
||||||
|
{
|
||||||
// values should default to a non-beneficial value..unless value conflicts with intended operation
|
// values should default to a non-beneficial value..unless value conflicts with intended operation
|
||||||
//
|
//
|
||||||
// EmuConstants may be used as references..but, not every reference needs to be in EmuConstants (i.e., AllowsEmptyBagInBag(), CoinHasWeight(), etc...)
|
// EmuConstants may be used as references..but, not every reference needs to be in EmuConstants (i.e., AllowsEmptyBagInBag(), CoinHasWeight(), etc...)
|
||||||
@ -174,6 +172,9 @@ public:
|
|||||||
static bool IsValidMobClientVersion(ClientVersion clientVersion);
|
static bool IsValidMobClientVersion(ClientVersion clientVersion);
|
||||||
static ClientVersion ValidateMobClientVersion(ClientVersion clientVersion);
|
static ClientVersion ValidateMobClientVersion(ClientVersion clientVersion);
|
||||||
|
|
||||||
|
// database
|
||||||
|
static size_t CharacterCreationLimit(ClientVersion clientVersion);
|
||||||
|
|
||||||
// inventory
|
// inventory
|
||||||
static uint16 InventoryMapSize(int16 indexMap, ClientVersion clientVersion);
|
static uint16 InventoryMapSize(int16 indexMap, ClientVersion clientVersion);
|
||||||
static uint64 PossessionsBitmask(ClientVersion clientVersion);
|
static uint64 PossessionsBitmask(ClientVersion clientVersion);
|
||||||
@ -190,11 +191,6 @@ public:
|
|||||||
|
|
||||||
// player profile
|
// player profile
|
||||||
static bool CoinHasWeight(ClientVersion clientVersion);
|
static bool CoinHasWeight(ClientVersion clientVersion);
|
||||||
|
|
||||||
static uint32 BandoliersCount(ClientVersion clientVersion);
|
|
||||||
static uint32 BandolierSize(ClientVersion clientVersion);
|
|
||||||
|
|
||||||
static uint32 PotionBeltSize(ClientVersion clientVersion);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* EQ_DICTIONARY_H */
|
#endif /* EQ_DICTIONARY_H */
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef EQ_PACKET_STRUCTS_H
|
#ifndef EQ_PACKET_STRUCTS_H
|
||||||
#define EQ_PACKET_STRUCTS_H
|
#define EQ_PACKET_STRUCTS_H
|
||||||
|
|
||||||
@ -123,83 +124,81 @@ struct LDoNTrapTemplate
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
/*
|
// All clients translate the character select information to some degree
|
||||||
** Color_Struct
|
|
||||||
** Size: 4 bytes
|
|
||||||
** Used for convenience
|
|
||||||
** Merth: Gave struct a name so gcc 2.96 would compile
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
struct Color_Struct
|
struct Color_Struct
|
||||||
{
|
{
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
uint8 Blue;
|
||||||
{
|
uint8 Green;
|
||||||
uint8 blue;
|
uint8 Red;
|
||||||
uint8 green;
|
uint8 UseTint; // if there's a tint this is FF
|
||||||
uint8 red;
|
} RGB;
|
||||||
uint8 use_tint; // if there's a tint this is FF
|
uint32 Color;
|
||||||
} rgb;
|
|
||||||
uint32 color;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
struct EquipStruct
|
||||||
* Visible equiptment.
|
{
|
||||||
* Size: 20 Octets
|
uint32 Material;
|
||||||
*/
|
uint32 Unknown1;
|
||||||
struct EquipStruct {
|
uint32 EliteMaterial;
|
||||||
/*00*/ uint32 material;
|
uint32 HeroForgeModel;
|
||||||
/*04*/ uint32 unknown1;
|
uint32 Material2; // Same as material?
|
||||||
/*08*/ uint32 elitematerial;
|
|
||||||
/*12*/ uint32 heroforgemodel;
|
|
||||||
/*16*/ uint32 material2; // Same as material?
|
|
||||||
/*20*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharSelectEquip {
|
struct CharSelectEquip
|
||||||
uint32 material;
|
{
|
||||||
uint32 unknown1;
|
uint32 Material;
|
||||||
uint32 elitematerial;
|
uint32 Unknown1;
|
||||||
uint32 heroforgemodel;
|
uint32 EliteMaterial;
|
||||||
uint32 material2;
|
uint32 HeroForgeModel;
|
||||||
Color_Struct color;
|
uint32 Material2;
|
||||||
|
Color_Struct Color;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
// RoF2-based hybrid struct
|
||||||
** Character Selection Struct
|
struct CharacterSelectEntry_Struct
|
||||||
** Length: 1704 Bytes
|
{
|
||||||
**
|
char Name[64];
|
||||||
*/
|
uint8 Class;
|
||||||
struct CharacterSelect_Struct {
|
uint32 Race;
|
||||||
/*0000*/ uint32 race[10]; // Characters Race
|
uint8 Level;
|
||||||
/*0040*/ //Color_Struct cs_colors[10][9]; // Characters Equipment Colors
|
uint8 ShroudClass;
|
||||||
/*0400*/ uint8 beardcolor[10]; // Characters beard Color
|
uint32 ShroudRace;
|
||||||
/*0410*/ uint8 hairstyle[10]; // Characters hair style
|
uint16 Zone;
|
||||||
/*0420*/ //uint32 equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be)
|
uint16 Instance;
|
||||||
/*0000*/ CharSelectEquip equip[10][9];
|
uint8 Gender;
|
||||||
/*0780*/ uint32 secondary[10]; // Characters secondary IDFile number
|
uint8 Face;
|
||||||
/*0820*/ uint32 drakkin_heritage[10]; // added for SoF
|
CharSelectEquip Equip[9];
|
||||||
/*0860*/ uint32 drakkin_tattoo[10]; // added for SoF
|
uint8 Unknown15; // Seen FF
|
||||||
/*0900*/ uint32 drakkin_details[10]; // added for SoF
|
uint8 Unknown19; // Seen FF
|
||||||
/*0940*/ uint32 deity[10]; // Characters Deity
|
uint32 DrakkinTattoo;
|
||||||
/*0980*/ uint8 gohome[10]; // 1=Go Home available, 0=not
|
uint32 DrakkinDetails;
|
||||||
/*0990*/ uint8 tutorial[10]; // 1=Tutorial available, 0=not
|
uint32 Deity;
|
||||||
/*1000*/ uint8 beard[10]; // Characters Beard Type
|
uint32 PrimaryIDFile;
|
||||||
/*1010*/ uint8 unknown902[10]; // 10x ff
|
uint32 SecondaryIDFile;
|
||||||
/*1020*/ uint32 primary[10]; // Characters primary IDFile number
|
uint8 HairColor;
|
||||||
/*1060*/ uint8 haircolor[10]; // Characters Hair Color
|
uint8 BeardColor;
|
||||||
/*1070*/ uint8 unknown0962[2]; // 2x 00
|
uint8 EyeColor1;
|
||||||
/*1072*/ uint32 zone[10]; // Characters Current Zone
|
uint8 EyeColor2;
|
||||||
/*1112*/ uint8 class_[10]; // Characters Classes
|
uint8 HairStyle;
|
||||||
/*1022*/ uint8 face[10]; // Characters Face Type
|
uint8 Beard;
|
||||||
/*1032*/ char name[10][64]; // Characters Names
|
uint8 GoHome; // Seen 0 for new char and 1 for existing
|
||||||
/*1672*/ uint8 gender[10]; // Characters Gender
|
uint8 Tutorial; // Seen 1 for new char or 0 for existing
|
||||||
/*1682*/ uint8 eyecolor1[10]; // Characters Eye Color
|
uint32 DrakkinHeritage;
|
||||||
/*1692*/ uint8 eyecolor2[10]; // Characters Eye 2 Color
|
uint8 Unknown1; // Seen 0
|
||||||
/*1702*/ uint8 level[10]; // Characters Levels
|
uint8 Enabled; // Originally labeled as 'CharEnabled' - unknown purpose and setting
|
||||||
/*1712*/
|
uint32 LastLogin;
|
||||||
|
uint8 Unknown2; // Seen 0
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharacterSelect_Struct
|
||||||
|
{
|
||||||
|
uint32 CharCount; //number of chars in this packet
|
||||||
|
uint32 TotalChars; //total number of chars allowed?
|
||||||
|
CharacterSelectEntry_Struct Entries[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -756,29 +755,46 @@ struct Tribute_Struct {
|
|||||||
uint32 tier;
|
uint32 tier;
|
||||||
};
|
};
|
||||||
|
|
||||||
//len = 72
|
// Bandolier item positions
|
||||||
struct BandolierItem_Struct {
|
enum
|
||||||
uint32 item_id;
|
{
|
||||||
uint32 icon;
|
bandolierPrimary = 0,
|
||||||
char item_name[64];
|
bandolierSecondary,
|
||||||
};
|
|
||||||
|
|
||||||
//len = 320
|
|
||||||
enum { //bandolier item positions
|
|
||||||
bandolierMainHand = 0,
|
|
||||||
bandolierOffHand,
|
|
||||||
bandolierRange,
|
bandolierRange,
|
||||||
bandolierAmmo
|
bandolierAmmo
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
|
||||||
char name[32];
|
//len = 72
|
||||||
BandolierItem_Struct items[EmuConstants::BANDOLIER_SIZE];
|
struct BandolierItem_Struct
|
||||||
};
|
{
|
||||||
struct PotionBelt_Struct {
|
uint32 ID;
|
||||||
BandolierItem_Struct items[EmuConstants::POTION_BELT_SIZE];
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MovePotionToBelt_Struct {
|
//len = 320
|
||||||
|
struct Bandolier_Struct
|
||||||
|
{
|
||||||
|
char Name[32];
|
||||||
|
BandolierItem_Struct Items[EmuConstants::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 72
|
||||||
|
struct PotionBeltItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 288
|
||||||
|
struct PotionBelt_Struct
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct Items[EmuConstants::POTION_BELT_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MovePotionToBelt_Struct
|
||||||
|
{
|
||||||
uint32 Action;
|
uint32 Action;
|
||||||
uint32 SlotNumber;
|
uint32 SlotNumber;
|
||||||
uint32 ItemID;
|
uint32 ItemID;
|
||||||
@ -1103,7 +1119,7 @@ struct PlayerProfile_Struct
|
|||||||
/*12800*/ uint32 expAA;
|
/*12800*/ uint32 expAA;
|
||||||
/*12804*/ uint32 aapoints; //avaliable, unspent
|
/*12804*/ uint32 aapoints; //avaliable, unspent
|
||||||
/*12808*/ uint8 unknown12844[36];
|
/*12808*/ uint8 unknown12844[36];
|
||||||
/*12844*/ Bandolier_Struct bandoliers[EmuConstants::BANDOLIERS_COUNT];
|
/*12844*/ Bandolier_Struct bandoliers[EmuConstants::BANDOLIERS_SIZE];
|
||||||
/*14124*/ uint8 unknown14160[4506];
|
/*14124*/ uint8 unknown14160[4506];
|
||||||
/*18630*/ SuspendedMinion_Struct SuspendedMinion; // No longer in use
|
/*18630*/ SuspendedMinion_Struct SuspendedMinion; // No longer in use
|
||||||
/*19240*/ uint32 timeentitledonaccount;
|
/*19240*/ uint32 timeentitledonaccount;
|
||||||
@ -1249,7 +1265,7 @@ struct ZoneChange_Struct {
|
|||||||
|
|
||||||
// Whatever you send to the client in RequestClientZoneChange_Struct.type, the client will send back
|
// Whatever you send to the client in RequestClientZoneChange_Struct.type, the client will send back
|
||||||
// to the server in ZoneChange_Struct.zone_reason. My guess is this is a memo field of sorts.
|
// to the server in ZoneChange_Struct.zone_reason. My guess is this is a memo field of sorts.
|
||||||
// WildcardX 27 January 2008
|
// 27 January 2008
|
||||||
|
|
||||||
struct RequestClientZoneChange_Struct {
|
struct RequestClientZoneChange_Struct {
|
||||||
/*00*/ uint16 zone_id;
|
/*00*/ uint16 zone_id;
|
||||||
@ -2405,11 +2421,11 @@ struct InspectResponse_Struct {
|
|||||||
/*004*/ uint32 playerid;
|
/*004*/ uint32 playerid;
|
||||||
/*008*/ char itemnames[23][64];
|
/*008*/ char itemnames[23][64];
|
||||||
/*1480*/uint32 itemicons[23];
|
/*1480*/uint32 itemicons[23];
|
||||||
/*1572*/char text[288]; // Max number of chars in Inspect Window appears to be 254 // Msg struct property is 256 (254 + '\0' is my guess) -U
|
/*1572*/char text[288]; // Max number of chars in Inspect Window appears to be 254 // Msg struct property is 256 (254 + '\0' is my guess)
|
||||||
/*1860*/
|
/*1860*/
|
||||||
};
|
};
|
||||||
|
|
||||||
//OP_InspectMessageUpdate - Size: 256 (SoF+ clients after self-inspect window is closed) -U
|
//OP_InspectMessageUpdate - Size: 256 (SoF+ clients after self-inspect window is closed)
|
||||||
struct InspectMessage_Struct {
|
struct InspectMessage_Struct {
|
||||||
/*000*/ char text[256];
|
/*000*/ char text[256];
|
||||||
/*256*/
|
/*256*/
|
||||||
@ -2518,7 +2534,7 @@ struct BookRequest_Struct {
|
|||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct Object_Struct {
|
struct Object_Struct {
|
||||||
/*00*/ uint32 linked_list_addr[2];// <Zaphod> They are, get this, prev and next, ala linked list
|
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
|
||||||
/*08*/ uint16 unknown008; //
|
/*08*/ uint16 unknown008; //
|
||||||
/*10*/ uint16 unknown010; //
|
/*10*/ uint16 unknown010; //
|
||||||
/*12*/ uint32 drop_id; // Unique object id for zone
|
/*12*/ uint32 drop_id; // Unique object id for zone
|
||||||
@ -2537,8 +2553,8 @@ struct Object_Struct {
|
|||||||
/*88*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
/*88*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
||||||
/*92*/
|
/*92*/
|
||||||
};
|
};
|
||||||
//<Zaphod> 01 = generic drop, 02 = armor, 19 = weapon
|
// 01 = generic drop, 02 = armor, 19 = weapon
|
||||||
//[13:40] <Zaphod> and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
//[13:40] and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Click Object Struct
|
** Click Object Struct
|
||||||
@ -2595,7 +2611,7 @@ struct CloseContainer_Struct {
|
|||||||
*/
|
*/
|
||||||
struct Door_Struct
|
struct Door_Struct
|
||||||
{
|
{
|
||||||
/*0000*/ char name[32]; // Filename of Door // Was 10char long before... added the 6 in the next unknown to it: Daeken M. BlackBlade //changed both to 32: Trevius
|
/*0000*/ char name[32]; // Filename of Door // Was 10char long before... added the 6 in the next unknown to it //changed both to 32
|
||||||
/*0032*/ float yPos; // y loc
|
/*0032*/ float yPos; // y loc
|
||||||
/*0036*/ float xPos; // x loc
|
/*0036*/ float xPos; // x loc
|
||||||
/*0040*/ float zPos; // z loc
|
/*0040*/ float zPos; // z loc
|
||||||
@ -2761,7 +2777,8 @@ struct BazaarWelcome_Struct {
|
|||||||
BazaarWindowStart_Struct Beginning;
|
BazaarWindowStart_Struct Beginning;
|
||||||
uint32 Traders;
|
uint32 Traders;
|
||||||
uint32 Items;
|
uint32 Items;
|
||||||
uint8 Unknown012[8];
|
uint32 Unknown012;
|
||||||
|
uint32 Unknown016;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarSearch_Struct {
|
struct BazaarSearch_Struct {
|
||||||
@ -3146,6 +3163,7 @@ struct Trader_ShowItems_Struct{
|
|||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 Code;
|
||||||
/*004*/ uint32 TraderID;
|
/*004*/ uint32 TraderID;
|
||||||
/*008*/ uint32 Unknown08[3];
|
/*008*/ uint32 Unknown08[3];
|
||||||
|
/*020*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct{
|
struct TraderBuy_Struct{
|
||||||
@ -3191,9 +3209,10 @@ struct TraderDelItem_Struct{
|
|||||||
|
|
||||||
struct TraderClick_Struct{
|
struct TraderClick_Struct{
|
||||||
/*000*/ uint32 TraderID;
|
/*000*/ uint32 TraderID;
|
||||||
/*004*/ uint32 Unknown004;
|
/*004*/ uint32 Code;
|
||||||
/*008*/ uint32 Unknown008;
|
/*008*/ uint32 Unknown008;
|
||||||
/*012*/ uint32 Approval;
|
/*012*/ uint32 Approval;
|
||||||
|
/*016*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FormattedMessage_Struct{
|
struct FormattedMessage_Struct{
|
||||||
@ -4104,30 +4123,35 @@ struct DynamicWall_Struct {
|
|||||||
/*80*/
|
/*80*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { //bandolier actions
|
// Bandolier actions
|
||||||
BandolierCreate = 0,
|
enum
|
||||||
BandolierRemove = 1,
|
{
|
||||||
BandolierSet = 2
|
bandolierCreate = 0,
|
||||||
|
bandolierRemove,
|
||||||
|
bandolierSet
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierCreate_Struct {
|
struct BandolierCreate_Struct
|
||||||
/*00*/ uint32 action; //0 for create
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action; //0 for create
|
||||||
/*05*/ char name[32];
|
/*04*/ uint8 Number;
|
||||||
/*37*/ uint16 unknown37; //seen 0x93FD
|
/*05*/ char Name[32];
|
||||||
/*39*/ uint8 unknown39; //0
|
/*37*/ uint16 Unknown37; //seen 0x93FD
|
||||||
|
/*39*/ uint8 Unknown39; //0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierDelete_Struct {
|
struct BandolierDelete_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierSet_Struct {
|
struct BandolierSet_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arrow_Struct {
|
struct Arrow_Struct {
|
||||||
@ -4530,19 +4554,12 @@ struct InternalVeteranReward
|
|||||||
/*012*/ InternalVeteranRewardItem items[8];
|
/*012*/ InternalVeteranRewardItem items[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VeteranClaimReply
|
struct VeteranClaim
|
||||||
{
|
{
|
||||||
/*000*/ char name[64];
|
/*000*/ char name[64]; //name + other data
|
||||||
/*064*/ uint32 claim_id;
|
|
||||||
/*068*/ uint32 reject_field;
|
|
||||||
/*072*/ uint32 unknown072;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VeteranClaimRequest
|
|
||||||
{
|
|
||||||
/*000*/ char name_data[64]; //name + other data
|
|
||||||
/*064*/ uint32 claim_id;
|
/*064*/ uint32 claim_id;
|
||||||
/*068*/ uint32 unknown068;
|
/*068*/ uint32 unknown068;
|
||||||
|
/*072*/ uint32 action;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GMSearchCorpse_Struct
|
struct GMSearchCorpse_Struct
|
||||||
|
|||||||
158
common/item.cpp
158
common/item.cpp
@ -506,6 +506,7 @@ int16 Inventory::HasItem(uint32 item_id, uint8 quantity, uint8 where)
|
|||||||
return slot_id;
|
return slot_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Behavioral change - Limbo is no longer checked due to improper handling of return value
|
||||||
if (where & invWhereCursor) {
|
if (where & invWhereCursor) {
|
||||||
// Check cursor queue
|
// Check cursor queue
|
||||||
slot_id = _HasItem(m_cursor, item_id, quantity);
|
slot_id = _HasItem(m_cursor, item_id, quantity);
|
||||||
@ -552,6 +553,7 @@ int16 Inventory::HasItemByUse(uint8 use, uint8 quantity, uint8 where)
|
|||||||
return slot_id;
|
return slot_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Behavioral change - Limbo is no longer checked due to improper handling of return value
|
||||||
if (where & invWhereCursor) {
|
if (where & invWhereCursor) {
|
||||||
// Check cursor queue
|
// Check cursor queue
|
||||||
slot_id = _HasItemByUse(m_cursor, use, quantity);
|
slot_id = _HasItemByUse(m_cursor, use, quantity);
|
||||||
@ -597,6 +599,7 @@ int16 Inventory::HasItemByLoreGroup(uint32 loregroup, uint8 where)
|
|||||||
return slot_id;
|
return slot_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Behavioral change - Limbo is no longer checked due to improper handling of return value
|
||||||
if (where & invWhereCursor) {
|
if (where & invWhereCursor) {
|
||||||
// Check cursor queue
|
// Check cursor queue
|
||||||
slot_id = _HasItemByLoreGroup(m_cursor, loregroup);
|
slot_id = _HasItemByLoreGroup(m_cursor, loregroup);
|
||||||
@ -657,7 +660,7 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) {
|
|||||||
// Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade().
|
// Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade().
|
||||||
// If you have a need, use it..but, understand it is not a compatible replacement for Inventory::FindFreeSlot().
|
// If you have a need, use it..but, understand it is not a compatible replacement for Inventory::FindFreeSlot().
|
||||||
//
|
//
|
||||||
// I'll probably implement a bitmask in the new inventory system to avoid having to adjust stack bias -U
|
// I'll probably implement a bitmask in the new inventory system to avoid having to adjust stack bias
|
||||||
|
|
||||||
if (!inst || !inst->GetID())
|
if (!inst || !inst->GetID())
|
||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
@ -990,33 +993,43 @@ int Inventory::GetSlotByItemInst(ItemInst *inst) {
|
|||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 Inventory::FindHighestLightValue()
|
uint8 Inventory::FindBrightestLightType()
|
||||||
{
|
{
|
||||||
uint8 light_value = NOT_USED;
|
uint8 brightest_light_type = 0;
|
||||||
|
|
||||||
// NOTE: The client does not recognize augment light sources, applied or otherwise, and should not be parsed
|
|
||||||
for (auto iter = m_worn.begin(); iter != m_worn.end(); ++iter) {
|
for (auto iter = m_worn.begin(); iter != m_worn.end(); ++iter) {
|
||||||
if ((iter->first < EmuConstants::EQUIPMENT_BEGIN || iter->first > EmuConstants::EQUIPMENT_END) && iter->first != MainPowerSource) { continue; }
|
if ((iter->first < EmuConstants::EQUIPMENT_BEGIN || iter->first > EmuConstants::EQUIPMENT_END) && iter->first != MainPowerSource) { continue; }
|
||||||
|
if (iter->first == MainAmmo) { continue; }
|
||||||
|
|
||||||
auto inst = iter->second;
|
auto inst = iter->second;
|
||||||
if (inst == nullptr) { continue; }
|
if (inst == nullptr) { continue; }
|
||||||
auto item = inst->GetItem();
|
auto item = inst->GetItem();
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
if (item->Light & 0xF0) { continue; }
|
|
||||||
if (item->Light > light_value) { light_value = item->Light; }
|
if (LightProfile_Struct::IsLevelGreater(item->Light, brightest_light_type))
|
||||||
|
brightest_light_type = item->Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8 general_light_type = 0;
|
||||||
for (auto iter = m_inv.begin(); iter != m_inv.end(); ++iter) {
|
for (auto iter = m_inv.begin(); iter != m_inv.end(); ++iter) {
|
||||||
if (iter->first < EmuConstants::GENERAL_BEGIN || iter->first > EmuConstants::GENERAL_END) { continue; }
|
if (iter->first < EmuConstants::GENERAL_BEGIN || iter->first > EmuConstants::GENERAL_END) { continue; }
|
||||||
|
|
||||||
auto inst = iter->second;
|
auto inst = iter->second;
|
||||||
if (inst == nullptr) { continue; }
|
if (inst == nullptr) { continue; }
|
||||||
auto item = inst->GetItem();
|
auto item = inst->GetItem();
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
|
||||||
if (item->Light & 0xF0) { continue; }
|
if (item->ItemClass != ItemClassCommon) { continue; }
|
||||||
if (item->Light > light_value) { light_value = item->Light; }
|
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||||
|
|
||||||
|
if (LightProfile_Struct::TypeToLevel(item->Light))
|
||||||
|
general_light_type = item->Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
return light_value;
|
if (LightProfile_Struct::IsLevelGreater(general_light_type, brightest_light_type))
|
||||||
|
brightest_light_type = general_light_type;
|
||||||
|
|
||||||
|
return brightest_light_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inventory::dumpEntireInventory() {
|
void Inventory::dumpEntireInventory() {
|
||||||
@ -1059,7 +1072,7 @@ int Inventory::GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &col
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (t_inst && !t_inst->IsType(ItemClassContainer)) {
|
if (t_inst && !t_inst->IsType(ItemClassContainer)) {
|
||||||
for (auto b_iter = t_inst->_begin(); b_iter != t_inst->_end(); ++b_iter) {
|
for (auto b_iter = t_inst->_cbegin(); b_iter != t_inst->_cend(); ++b_iter) {
|
||||||
if (b_iter->second == inst) {
|
if (b_iter->second == inst) {
|
||||||
return Inventory::CalcSlotId(iter->first, b_iter->first);
|
return Inventory::CalcSlotId(iter->first, b_iter->first);
|
||||||
}
|
}
|
||||||
@ -1070,13 +1083,10 @@ int Inventory::GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &col
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection) {
|
void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection)
|
||||||
iter_inst it;
|
{
|
||||||
iter_contents itb;
|
for (auto it = collection.cbegin(); it != collection.cend(); ++it) {
|
||||||
ItemInst* inst = nullptr;
|
auto inst = it->second;
|
||||||
|
|
||||||
for (it = collection.begin(); it != collection.end(); ++it) {
|
|
||||||
inst = it->second;
|
|
||||||
if (!inst || !inst->GetItem())
|
if (!inst || !inst->GetItem())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1087,14 +1097,13 @@ void Inventory::dumpItemCollection(const std::map<int16, ItemInst*> &collection)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) {
|
void Inventory::dumpBagContents(ItemInst *inst, std::map<int16, ItemInst*>::const_iterator *it)
|
||||||
iter_contents itb;
|
{
|
||||||
|
|
||||||
if (!inst || !inst->IsType(ItemClassContainer))
|
if (!inst || !inst->IsType(ItemClassContainer))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Go through bag, if bag
|
// Go through bag, if bag
|
||||||
for (itb = inst->_begin(); itb != inst->_end(); ++itb) {
|
for (auto itb = inst->_cbegin(); itb != inst->_cend(); ++itb) {
|
||||||
ItemInst* baginst = itb->second;
|
ItemInst* baginst = itb->second;
|
||||||
if (!baginst || !baginst->GetItem())
|
if (!baginst || !baginst->GetItem())
|
||||||
continue;
|
continue;
|
||||||
@ -1109,7 +1118,7 @@ void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) {
|
|||||||
// Internal Method: Retrieves item within an inventory bucket
|
// Internal Method: Retrieves item within an inventory bucket
|
||||||
ItemInst* Inventory::_GetItem(const std::map<int16, ItemInst*>& bucket, int16 slot_id) const
|
ItemInst* Inventory::_GetItem(const std::map<int16, ItemInst*>& bucket, int16 slot_id) const
|
||||||
{
|
{
|
||||||
iter_inst it = bucket.find(slot_id);
|
auto it = bucket.find(slot_id);
|
||||||
if (it != bucket.end()) {
|
if (it != bucket.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
@ -1122,6 +1131,8 @@ ItemInst* Inventory::_GetItem(const std::map<int16, ItemInst*>& bucket, int16 sl
|
|||||||
// Assumes item has already been allocated
|
// Assumes item has already been allocated
|
||||||
int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst)
|
int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst)
|
||||||
{
|
{
|
||||||
|
// What happens here when we _PutItem(MainCursor)? Bad things..really bad things...
|
||||||
|
//
|
||||||
// If putting a nullptr into slot, we need to remove slot without memory delete
|
// If putting a nullptr into slot, we need to remove slot without memory delete
|
||||||
if (inst == nullptr) {
|
if (inst == nullptr) {
|
||||||
//Why do we not delete the poped item here????
|
//Why do we not delete the poped item here????
|
||||||
@ -1203,7 +1214,7 @@ int16 Inventory::_HasItem(std::map<int16, ItemInst*>& bucket, uint32 item_id, ui
|
|||||||
|
|
||||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||||
|
|
||||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||||
auto bag_inst = bag_iter->second;
|
auto bag_inst = bag_iter->second;
|
||||||
if (bag_inst == nullptr) { continue; }
|
if (bag_inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1230,11 +1241,11 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
|
|||||||
// found, it is presented as being available on the cursor. In cases of a parity check, this
|
// found, it is presented as being available on the cursor. In cases of a parity check, this
|
||||||
// is sufficient. However, in cases where referential criteria is considered, this can lead
|
// is sufficient. However, in cases where referential criteria is considered, this can lead
|
||||||
// to unintended results. Funtionality should be observed when referencing the return value
|
// to unintended results. Funtionality should be observed when referencing the return value
|
||||||
// of this query -U
|
// of this query
|
||||||
|
|
||||||
uint8 quantity_found = 0;
|
uint8 quantity_found = 0;
|
||||||
|
|
||||||
for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) {
|
for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) {
|
||||||
auto inst = *iter;
|
auto inst = *iter;
|
||||||
if (inst == nullptr) { continue; }
|
if (inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1251,7 +1262,7 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
|
|||||||
|
|
||||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||||
|
|
||||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||||
auto bag_inst = bag_iter->second;
|
auto bag_inst = bag_iter->second;
|
||||||
if (bag_inst == nullptr) { continue; }
|
if (bag_inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1266,6 +1277,9 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity)
|
|||||||
return legacy::SLOT_AUGMENT;
|
return legacy::SLOT_AUGMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
@ -1288,7 +1302,7 @@ int16 Inventory::_HasItemByUse(std::map<int16, ItemInst*>& bucket, uint8 use, ui
|
|||||||
|
|
||||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||||
|
|
||||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||||
auto bag_inst = bag_iter->second;
|
auto bag_inst = bag_iter->second;
|
||||||
if (bag_inst == nullptr) { continue; }
|
if (bag_inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1308,7 +1322,7 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity)
|
|||||||
{
|
{
|
||||||
uint8 quantity_found = 0;
|
uint8 quantity_found = 0;
|
||||||
|
|
||||||
for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) {
|
for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) {
|
||||||
auto inst = *iter;
|
auto inst = *iter;
|
||||||
if (inst == nullptr) { continue; }
|
if (inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1320,7 +1334,7 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity)
|
|||||||
|
|
||||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||||
|
|
||||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||||
auto bag_inst = bag_iter->second;
|
auto bag_inst = bag_iter->second;
|
||||||
if (bag_inst == nullptr) { continue; }
|
if (bag_inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1330,6 +1344,9 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity)
|
|||||||
return Inventory::CalcSlotId(MainCursor, bag_iter->first);
|
return Inventory::CalcSlotId(MainCursor, bag_iter->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
@ -1354,7 +1371,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
|
|||||||
|
|
||||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||||
|
|
||||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||||
auto bag_inst = bag_iter->second;
|
auto bag_inst = bag_iter->second;
|
||||||
if (bag_inst == nullptr) { continue; }
|
if (bag_inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1377,7 +1394,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map<int16, ItemInst*>& bucket, uint32
|
|||||||
// Internal Method: Checks an inventory queue type bucket for a particular item
|
// Internal Method: Checks an inventory queue type bucket for a particular item
|
||||||
int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
||||||
{
|
{
|
||||||
for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) {
|
for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) {
|
||||||
auto inst = *iter;
|
auto inst = *iter;
|
||||||
if (inst == nullptr) { continue; }
|
if (inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1394,7 +1411,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
|||||||
|
|
||||||
if (!inst->IsType(ItemClassContainer)) { continue; }
|
if (!inst->IsType(ItemClassContainer)) { continue; }
|
||||||
|
|
||||||
for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) {
|
for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) {
|
||||||
auto bag_inst = bag_iter->second;
|
auto bag_inst = bag_iter->second;
|
||||||
if (bag_inst == nullptr) { continue; }
|
if (bag_inst == nullptr) { continue; }
|
||||||
|
|
||||||
@ -1409,6 +1426,9 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup)
|
|||||||
return legacy::SLOT_AUGMENT;
|
return legacy::SLOT_AUGMENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return INVALID_INDEX;
|
return INVALID_INDEX;
|
||||||
@ -1504,8 +1524,7 @@ ItemInst::ItemInst(const ItemInst& copy)
|
|||||||
m_attuned=copy.m_attuned;
|
m_attuned=copy.m_attuned;
|
||||||
m_merchantcount=copy.m_merchantcount;
|
m_merchantcount=copy.m_merchantcount;
|
||||||
// Copy container contents
|
// Copy container contents
|
||||||
iter_contents it;
|
for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) {
|
||||||
for (it=copy.m_contents.begin(); it!=copy.m_contents.end(); ++it) {
|
|
||||||
ItemInst* inst_old = it->second;
|
ItemInst* inst_old = it->second;
|
||||||
ItemInst* inst_new = nullptr;
|
ItemInst* inst_new = nullptr;
|
||||||
|
|
||||||
@ -1675,7 +1694,7 @@ bool ItemInst::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
|
|||||||
// Retrieve item inside container
|
// Retrieve item inside container
|
||||||
ItemInst* ItemInst::GetItem(uint8 index) const
|
ItemInst* ItemInst::GetItem(uint8 index) const
|
||||||
{
|
{
|
||||||
iter_contents it = m_contents.find(index);
|
auto it = m_contents.find(index);
|
||||||
if (it != m_contents.end()) {
|
if (it != m_contents.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
@ -1738,7 +1757,7 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent)
|
|||||||
// TODO: This needs work...
|
// TODO: This needs work...
|
||||||
|
|
||||||
// Destroy container contents
|
// Destroy container contents
|
||||||
iter_contents cur, end, del;
|
std::map<uint8, ItemInst*>::const_iterator cur, end, del;
|
||||||
cur = m_contents.begin();
|
cur = m_contents.begin();
|
||||||
end = m_contents.end();
|
end = m_contents.end();
|
||||||
for (; cur != end;) {
|
for (; cur != end;) {
|
||||||
@ -2138,7 +2157,7 @@ ItemInst* ItemInst::Clone() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ItemInst::IsSlotAllowed(int16 slot_id) const {
|
bool ItemInst::IsSlotAllowed(int16 slot_id) const {
|
||||||
// 'SupportsContainers' and 'slot_id > 21' previously saw the reassigned PowerSource slot (9999 to 22) as valid -U
|
// 'SupportsContainers' and 'slot_id > 21' previously saw the reassigned PowerSource slot (9999 to 22) as valid
|
||||||
if (!m_item) { return false; }
|
if (!m_item) { return false; }
|
||||||
else if (Inventory::SupportsContainers(slot_id)) { return true; }
|
else if (Inventory::SupportsContainers(slot_id)) { return true; }
|
||||||
else if (m_item->Slots & (1 << slot_id)) { return true; }
|
else if (m_item->Slots & (1 << slot_id)) { return true; }
|
||||||
@ -2351,3 +2370,66 @@ bool Item_Struct::IsEquipable(uint16 Race, uint16 Class_) const
|
|||||||
|
|
||||||
return (IsRace && IsClass);
|
return (IsRace && IsClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// struct LightProfile_Struct
|
||||||
|
//
|
||||||
|
uint8 LightProfile_Struct::TypeToLevel(uint8 lightType)
|
||||||
|
{
|
||||||
|
switch (lightType) {
|
||||||
|
case lightTypeGlobeOfStars:
|
||||||
|
return lightLevelBrilliant; // 10
|
||||||
|
case lightTypeFlamelessLantern:
|
||||||
|
case lightTypeGreaterLightstone:
|
||||||
|
return lightLevelLargeMagic; // 9
|
||||||
|
case lightTypeLargeLantern:
|
||||||
|
return lightLevelLargeLantern; // 8
|
||||||
|
case lightTypeSteinOfMoggok:
|
||||||
|
case lightTypeLightstone:
|
||||||
|
return lightLevelMagicLantern; // 7
|
||||||
|
case lightTypeSmallLantern:
|
||||||
|
return lightLevelSmallLantern; // 6
|
||||||
|
case lightTypeColdlight:
|
||||||
|
case lightTypeUnknown2:
|
||||||
|
return lightLevelBlueLight; // 5
|
||||||
|
case lightTypeFireBeetleEye:
|
||||||
|
case lightTypeUnknown1:
|
||||||
|
return lightLevelRedLight; // 4
|
||||||
|
case lightTypeTinyGlowingSkull:
|
||||||
|
case lightTypeLightGlobe:
|
||||||
|
return lightLevelSmallMagic; // 3
|
||||||
|
case lightTypeTorch:
|
||||||
|
return lightLevelTorch; // 2
|
||||||
|
case lightLevelCandle:
|
||||||
|
return lightLevelCandle; // 1
|
||||||
|
default:
|
||||||
|
return lightLevelUnlit; // 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LightProfile_Struct::IsLevelGreater(uint8 leftType, uint8 rightType)
|
||||||
|
{
|
||||||
|
static const uint8 light_levels[LIGHT_TYPES_COUNT] = {
|
||||||
|
lightLevelUnlit, /* lightTypeNone */
|
||||||
|
lightLevelCandle, /* lightTypeCandle */
|
||||||
|
lightLevelTorch, /* lightTypeTorch */
|
||||||
|
lightLevelSmallMagic, /* lightTypeTinyGlowingSkull */
|
||||||
|
lightLevelSmallLantern, /* lightTypeSmallLantern */
|
||||||
|
lightLevelMagicLantern, /* lightTypeSteinOfMoggok */
|
||||||
|
lightLevelLargeLantern, /* lightTypeLargeLantern */
|
||||||
|
lightLevelLargeMagic, /* lightTypeFlamelessLantern */
|
||||||
|
lightLevelBrilliant, /* lightTypeGlobeOfStars */
|
||||||
|
lightLevelSmallMagic, /* lightTypeLightGlobe */
|
||||||
|
lightLevelMagicLantern, /* lightTypeLightstone */
|
||||||
|
lightLevelLargeMagic, /* lightTypeGreaterLightstone */
|
||||||
|
lightLevelRedLight, /* lightTypeFireBeetleEye */
|
||||||
|
lightLevelBlueLight, /* lightTypeColdlight */
|
||||||
|
lightLevelRedLight, /* lightTypeUnknown1 */
|
||||||
|
lightLevelBlueLight /* lightTypeUnknown2 */
|
||||||
|
};
|
||||||
|
|
||||||
|
if (leftType >= LIGHT_TYPES_COUNT) { leftType = lightTypeNone; }
|
||||||
|
if (rightType >= LIGHT_TYPES_COUNT) { rightType = lightTypeNone; }
|
||||||
|
|
||||||
|
return (light_levels[leftType] > light_levels[rightType]);
|
||||||
|
}
|
||||||
|
|||||||
@ -33,9 +33,6 @@ class EvolveInfo; // Stores information about an evolving item family
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
// Helper typedefs
|
|
||||||
typedef std::map<int16, ItemInst*>::const_iterator iter_inst;
|
|
||||||
typedef std::map<uint8, ItemInst*>::const_iterator iter_contents;
|
|
||||||
|
|
||||||
namespace ItemField
|
namespace ItemField
|
||||||
{
|
{
|
||||||
@ -86,8 +83,8 @@ public:
|
|||||||
// Public Methods
|
// Public Methods
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
|
||||||
inline std::list<ItemInst*>::const_iterator begin() { return m_list.begin(); }
|
inline std::list<ItemInst*>::const_iterator cbegin() { return m_list.cbegin(); }
|
||||||
inline std::list<ItemInst*>::const_iterator end() { return m_list.end(); }
|
inline std::list<ItemInst*>::const_iterator cend() { return m_list.cend(); }
|
||||||
|
|
||||||
inline int size() { return static_cast<int>(m_list.size()); } // TODO: change to size_t
|
inline int size() { return static_cast<int>(m_list.size()); } // TODO: change to size_t
|
||||||
inline bool empty() { return m_list.empty(); }
|
inline bool empty() { return m_list.empty(); }
|
||||||
@ -140,8 +137,8 @@ public:
|
|||||||
ItemInst* GetItem(int16 slot_id) const;
|
ItemInst* GetItem(int16 slot_id) const;
|
||||||
ItemInst* GetItem(int16 slot_id, uint8 bagidx) const;
|
ItemInst* GetItem(int16 slot_id, uint8 bagidx) const;
|
||||||
|
|
||||||
inline std::list<ItemInst*>::const_iterator cursor_begin() { return m_cursor.begin(); }
|
inline std::list<ItemInst*>::const_iterator cursor_cbegin() { return m_cursor.cbegin(); }
|
||||||
inline std::list<ItemInst*>::const_iterator cursor_end() { return m_cursor.end(); }
|
inline std::list<ItemInst*>::const_iterator cursor_cend() { return m_cursor.cend(); }
|
||||||
|
|
||||||
inline int CursorSize() { return m_cursor.size(); }
|
inline int CursorSize() { return m_cursor.size(); }
|
||||||
inline bool CursorEmpty() { return m_cursor.empty(); }
|
inline bool CursorEmpty() { return m_cursor.empty(); }
|
||||||
@ -207,7 +204,7 @@ public:
|
|||||||
|
|
||||||
int GetSlotByItemInst(ItemInst *inst);
|
int GetSlotByItemInst(ItemInst *inst);
|
||||||
|
|
||||||
uint8 FindHighestLightValue();
|
uint8 FindBrightestLightType();
|
||||||
|
|
||||||
void dumpEntireInventory();
|
void dumpEntireInventory();
|
||||||
void dumpWornItems();
|
void dumpWornItems();
|
||||||
@ -227,7 +224,7 @@ protected:
|
|||||||
|
|
||||||
int GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &collection, ItemInst *inst);
|
int GetSlotByItemInstCollection(const std::map<int16, ItemInst*> &collection, ItemInst *inst);
|
||||||
void dumpItemCollection(const std::map<int16, ItemInst*> &collection);
|
void dumpItemCollection(const std::map<int16, ItemInst*> &collection);
|
||||||
void dumpBagContents(ItemInst *inst, iter_inst *it);
|
void dumpBagContents(ItemInst *inst, std::map<int16, ItemInst*>::const_iterator *it);
|
||||||
|
|
||||||
// Retrieves item within an inventory bucket
|
// Retrieves item within an inventory bucket
|
||||||
ItemInst* _GetItem(const std::map<int16, ItemInst*>& bucket, int16 slot_id) const;
|
ItemInst* _GetItem(const std::map<int16, ItemInst*>& bucket, int16 slot_id) const;
|
||||||
@ -425,8 +422,8 @@ protected:
|
|||||||
//////////////////////////
|
//////////////////////////
|
||||||
// Protected Members
|
// Protected Members
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
iter_contents _begin() { return m_contents.begin(); }
|
std::map<uint8, ItemInst*>::const_iterator _cbegin() { return m_contents.cbegin(); }
|
||||||
iter_contents _end() { return m_contents.end(); }
|
std::map<uint8, ItemInst*>::const_iterator _cend() { return m_contents.cend(); }
|
||||||
|
|
||||||
friend class Inventory;
|
friend class Inventory;
|
||||||
|
|
||||||
@ -475,4 +472,43 @@ public:
|
|||||||
~EvolveInfo();
|
~EvolveInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LightProfile_Struct
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Current criteria (light types):
|
||||||
|
Equipment: { 0 .. 15 }
|
||||||
|
General: { 9 .. 13 }
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Initial character load and item movement updates use different light source update behaviors
|
||||||
|
-- Server procedure matches the item movement behavior since most updates occur post-character load
|
||||||
|
- MainAmmo is not considered when determining light sources
|
||||||
|
- No 'Sub' or 'Aug' items are recognized as light sources
|
||||||
|
- Light types '< 9' and '> 13' are not considered for general (carried) light sources
|
||||||
|
- If values > 0x0F are valid, then assignment limiters will need to be removed
|
||||||
|
- MainCursor 'appears' to be a valid light source update slot..but, have not experienced updates during debug sessions
|
||||||
|
- All clients have a bug regarding stackable items (light and sound updates are not processed when picking up an item)
|
||||||
|
-- The timer-based update cancels out the invalid light source
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint8 TypeToLevel(uint8 lightType);
|
||||||
|
static bool IsLevelGreater(uint8 leftType, uint8 rightType);
|
||||||
|
|
||||||
|
// Light types (classifications)
|
||||||
|
struct {
|
||||||
|
uint8 Innate; // Defined by db field `npc_types`.`light` - where appropriate
|
||||||
|
uint8 Equipment; // Item_Struct::light value of worn/carried equipment
|
||||||
|
uint8 Spell; // Set value of any light-producing spell (can be modded to mimic equip_light behavior)
|
||||||
|
uint8 Active; // Highest value of all light sources
|
||||||
|
} Type;
|
||||||
|
|
||||||
|
// Light levels (intensities) - used to determine which light source should be active
|
||||||
|
struct {
|
||||||
|
uint8 Innate;
|
||||||
|
uint8 Equipment;
|
||||||
|
uint8 Spell;
|
||||||
|
uint8 Active;
|
||||||
|
} Level;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // #define __ITEM_H
|
#endif // #define __ITEM_H
|
||||||
|
|||||||
@ -180,7 +180,7 @@ IN(OP_GMLastName, GMLastName_Struct);
|
|||||||
IN(OP_GMToggle, GMToggle_Struct);
|
IN(OP_GMToggle, GMToggle_Struct);
|
||||||
IN(OP_LFGCommand, LFG_Struct);
|
IN(OP_LFGCommand, LFG_Struct);
|
||||||
IN(OP_GMGoto, GMSummon_Struct);
|
IN(OP_GMGoto, GMSummon_Struct);
|
||||||
IN(OP_TraderShop, TraderClick_Struct);
|
INv(OP_TraderShop, TraderClick_Struct);
|
||||||
IN(OP_ShopRequest, Merchant_Click_Struct);
|
IN(OP_ShopRequest, Merchant_Click_Struct);
|
||||||
IN(OP_Bazaar, BazaarSearch_Struct);
|
IN(OP_Bazaar, BazaarSearch_Struct);
|
||||||
//alt:IN(OP_Bazaar, BazaarWelcome_Struct); //alternate structure for OP_Bazaar
|
//alt:IN(OP_Bazaar, BazaarWelcome_Struct); //alternate structure for OP_Bazaar
|
||||||
@ -399,7 +399,7 @@ OUT(OP_Weather, Weather_Struct);
|
|||||||
OUT(OP_ZoneChange, ZoneChange_Struct);
|
OUT(OP_ZoneChange, ZoneChange_Struct);
|
||||||
OUT(OP_ZoneInUnknown, ZoneInUnknown_Struct);
|
OUT(OP_ZoneInUnknown, ZoneInUnknown_Struct);
|
||||||
|
|
||||||
//this is the set of opcodes which are allready listed
|
//this is the set of opcodes which are already listed
|
||||||
//in the IN section above, but are also sent OUT
|
//in the IN section above, but are also sent OUT
|
||||||
#ifdef DISJOINT_DIRECTIONS
|
#ifdef DISJOINT_DIRECTIONS
|
||||||
OUTz(OP_ClientReady); //follows OP_SetServerFilter
|
OUTz(OP_ClientReady); //follows OP_SetServerFilter
|
||||||
@ -449,7 +449,7 @@ OUT(OP_Trader, TraderBuy_Struct); //3 possible lengths
|
|||||||
//alt:OUT(OP_Trader, Trader_ShowItems_Struct);
|
//alt:OUT(OP_Trader, Trader_ShowItems_Struct);
|
||||||
//alt:OUT(OP_Trader, Trader_Struct);
|
//alt:OUT(OP_Trader, Trader_Struct);
|
||||||
OUT(OP_TraderBuy, TraderBuy_Struct);
|
OUT(OP_TraderBuy, TraderBuy_Struct);
|
||||||
OUT(OP_TraderShop, TraderClick_Struct);
|
OUTv(OP_TraderShop, TraderClick_Struct);
|
||||||
OUT(OP_WearChange, WearChange_Struct);
|
OUT(OP_WearChange, WearChange_Struct);
|
||||||
OUT(OP_ZoneEntry, ServerZoneEntry_Struct);
|
OUT(OP_ZoneEntry, ServerZoneEntry_Struct);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <numeric>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace RoF
|
namespace RoF
|
||||||
{
|
{
|
||||||
@ -2043,7 +2045,7 @@ namespace RoF
|
|||||||
|
|
||||||
for (int r = 0; r < 7; r++)
|
for (int r = 0; r < 7; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(emu->item_tint[r].color);
|
outapp->WriteUInt32(emu->item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// Write zeroes for extra two tint values
|
// Write zeroes for extra two tint values
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
@ -2053,7 +2055,7 @@ namespace RoF
|
|||||||
|
|
||||||
for (int r = 0; r < 7; r++)
|
for (int r = 0; r < 7; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(emu->item_tint[r].color);
|
outapp->WriteUInt32(emu->item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// Write zeroes for extra two tint values
|
// Write zeroes for extra two tint values
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
@ -2286,46 +2288,52 @@ namespace RoF
|
|||||||
outapp->WriteUInt8(0); // Unknown
|
outapp->WriteUInt8(0); // Unknown
|
||||||
outapp->WriteUInt8(0); // Unknown
|
outapp->WriteUInt8(0); // Unknown
|
||||||
|
|
||||||
outapp->WriteUInt32(structs::MAX_PLAYER_BANDOLIER);
|
outapp->WriteUInt32(consts::BANDOLIERS_SIZE);
|
||||||
|
|
||||||
for (uint32 r = 0; r < EmuConstants::BANDOLIERS_COUNT; r++)
|
// Copy bandoliers where server and client indexes converge
|
||||||
{
|
for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
outapp->WriteString(emu->bandoliers[r].name);
|
outapp->WriteString(emu->bandoliers[r].Name);
|
||||||
|
for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true
|
||||||
for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j)
|
outapp->WriteString(emu->bandoliers[r].Items[j].Name);
|
||||||
{
|
outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID);
|
||||||
outapp->WriteString(emu->bandoliers[r].items[j].item_name);
|
if (emu->bandoliers[r].Items[j].Icon) {
|
||||||
outapp->WriteUInt32(emu->bandoliers[r].items[j].item_id);
|
outapp->WriteSInt32(emu->bandoliers[r].Items[j].Icon);
|
||||||
outapp->WriteUInt32(emu->bandoliers[r].items[j].icon);
|
}
|
||||||
|
else {
|
||||||
|
// If no icon, it must send -1 or Treasure Chest Icon (836) is displayed
|
||||||
|
outapp->WriteSInt32(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||||
for (uint32 r = 0; r < structs::MAX_PLAYER_BANDOLIER - EmuConstants::BANDOLIERS_COUNT; r++)
|
for (uint32 r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
{
|
|
||||||
outapp->WriteString("");
|
outapp->WriteString("");
|
||||||
|
for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true
|
||||||
for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j)
|
|
||||||
{
|
|
||||||
outapp->WriteString("");
|
outapp->WriteString("");
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteSInt32(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteUInt32(structs::MAX_POTIONS_IN_BELT);
|
outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT);
|
||||||
|
|
||||||
for (uint32 r = 0; r < EmuConstants::POTION_BELT_SIZE; r++)
|
// Copy potion belt where server and client indexes converge
|
||||||
{
|
for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
outapp->WriteString(emu->potionbelt.items[r].item_name);
|
outapp->WriteString(emu->potionbelt.Items[r].Name);
|
||||||
outapp->WriteUInt32(emu->potionbelt.items[r].item_id);
|
outapp->WriteUInt32(emu->potionbelt.Items[r].ID);
|
||||||
outapp->WriteUInt32(emu->potionbelt.items[r].icon);
|
if (emu->potionbelt.Items[r].Icon) {
|
||||||
|
outapp->WriteSInt32(emu->potionbelt.Items[r].Icon);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If no icon, it must send -1 or Treasure Chest Icon (836) is displayed
|
||||||
|
outapp->WriteSInt32(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||||
for (uint32 r = 0; r < structs::MAX_POTIONS_IN_BELT - EmuConstants::POTION_BELT_SIZE; r++)
|
for (uint32 r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
{
|
|
||||||
outapp->WriteString("");
|
outapp->WriteString("");
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteSInt32(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteSInt32(-1); // Unknown;
|
outapp->WriteSInt32(-1); // Unknown;
|
||||||
@ -2418,7 +2426,7 @@ namespace RoF
|
|||||||
outapp->WriteUInt32(emu->silver_bank);
|
outapp->WriteUInt32(emu->silver_bank);
|
||||||
outapp->WriteUInt32(emu->copper_bank);
|
outapp->WriteUInt32(emu->copper_bank);
|
||||||
|
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(emu->platinum_shared);
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(0); // Unknown
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(0); // Unknown
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(0); // Unknown
|
||||||
@ -2891,85 +2899,99 @@ namespace RoF
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
if (emu->CharCount == 0) {
|
||||||
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
||||||
|
eq->CharCount = emu->CharCount;
|
||||||
|
|
||||||
int char_count;
|
FINISH_ENCODE();
|
||||||
int namelen = 0;
|
return;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->name[char_count][0] == '\0')
|
|
||||||
break;
|
|
||||||
if (strcmp(emu->name[char_count], "<none>") == 0)
|
|
||||||
break;
|
|
||||||
namelen += strlen(emu->name[char_count]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
|
size_t names_length = 0;
|
||||||
|
size_t character_count = 0;
|
||||||
|
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
|
||||||
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
|
names_length += strlen(emu_cse->Name);
|
||||||
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total_length = sizeof(structs::CharacterSelect_Struct)
|
||||||
|
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
|
||||||
|
+ names_length;
|
||||||
|
|
||||||
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
||||||
|
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
//unsigned char *eq_buffer = new unsigned char[total_length];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
//eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->char_count = char_count;
|
//if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
//eq->total_chars = 10;
|
// eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1);
|
|
||||||
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
strcpy(eq_cse->Name, emu_cse->Name);
|
||||||
|
eq_ptr += strlen(eq_cse->Name);
|
||||||
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
eq_cse->Class = emu_cse->Class;
|
||||||
|
eq_cse->Race = emu_cse->Race;
|
||||||
|
eq_cse->Level = emu_cse->Level;
|
||||||
|
eq_cse->ShroudClass = emu_cse->ShroudClass;
|
||||||
|
eq_cse->ShroudRace = emu_cse->ShroudRace;
|
||||||
|
eq_cse->Zone = emu_cse->Zone;
|
||||||
|
eq_cse->Instance = emu_cse->Instance;
|
||||||
|
eq_cse->Gender = emu_cse->Gender;
|
||||||
|
eq_cse->Face = emu_cse->Face;
|
||||||
|
|
||||||
|
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
|
||||||
|
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
|
||||||
|
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
|
||||||
|
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
|
||||||
|
eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel;
|
||||||
|
eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2;
|
||||||
|
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
|
||||||
}
|
}
|
||||||
//adjust for name.
|
|
||||||
bufptr += strlen(emu->name[r]);
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
{ //post-name section...
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->class_ = emu->class_[r];
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->race = emu->race[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->level = emu->level[r];
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
eq2->class_2 = emu->class_[r];
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
eq2->race2 = emu->race[r];
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
eq2->zone = emu->zone[r];
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
eq2->instance = 0;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->gender = emu->gender[r];
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->face = emu->face[r];
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
int k;
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->equip[k].material = emu->equip[r][k].material;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->equip[k].unknown1 = emu->equip[r][k].unknown1;
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial;
|
eq_cse->Unknown1 = emu_cse->Unknown1;
|
||||||
eq2->equip[k].heroforgemodel = emu->equip[r][k].heroforgemodel;
|
eq_cse->Enabled = emu_cse->Enabled;
|
||||||
eq2->equip[k].material2 = emu->equip[r][k].material2;
|
eq_cse->LastLogin = emu_cse->LastLogin;
|
||||||
eq2->equip[k].color.color = emu->equip[r][k].color.color;
|
eq_cse->Unknown2 = emu_cse->Unknown2;
|
||||||
}
|
|
||||||
eq2->u15 = 0xff;
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->u19 = 0xFF;
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
eq2->drakkin_tattoo = emu->drakkin_tattoo[r];
|
|
||||||
eq2->drakkin_details = emu->drakkin_details[r];
|
|
||||||
eq2->deity = emu->deity[r];
|
|
||||||
eq2->primary = emu->primary[r];
|
|
||||||
eq2->secondary = emu->secondary[r];
|
|
||||||
eq2->haircolor = emu->haircolor[r];
|
|
||||||
eq2->beardcolor = emu->beardcolor[r];
|
|
||||||
eq2->eyecolor1 = emu->eyecolor1[r];
|
|
||||||
eq2->eyecolor2 = emu->eyecolor2[r];
|
|
||||||
eq2->hairstyle = emu->hairstyle[r];
|
|
||||||
eq2->beard = emu->beard[r];
|
|
||||||
eq2->char_enabled = 1;
|
|
||||||
eq2->tutorial = emu->tutorial[r];
|
|
||||||
eq2->drakkin_heritage = emu->drakkin_heritage[r];
|
|
||||||
eq2->unknown1 = 0;
|
|
||||||
eq2->gohome = emu->gohome[r];
|
|
||||||
eq2->LastLogin = 1212696584;
|
|
||||||
eq2->unknown2 = 0;
|
|
||||||
}
|
|
||||||
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -3588,37 +3610,71 @@ namespace RoF
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_VetClaimReply)
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(VeteranClaim);
|
||||||
|
SETUP_DIRECT_ENCODE(VeteranClaim, structs::VeteranClaim);
|
||||||
|
|
||||||
|
memcpy(eq->name, emu->name, sizeof(emu->name));
|
||||||
|
OUT(claim_id);
|
||||||
|
OUT(action);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_VetRewardsAvaliable)
|
ENCODE(OP_VetRewardsAvaliable)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *inapp = *p;
|
EQApplicationPacket *inapp = *p;
|
||||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
auto __emu_buffer = inapp->pBuffer;
|
||||||
|
|
||||||
uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward));
|
uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward));
|
||||||
*p = nullptr;
|
|
||||||
|
|
||||||
EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count));
|
// calculate size of names, note the packet DOES NOT have null termed c-strings
|
||||||
uchar *old_data = __emu_buffer;
|
std::vector<uint32> name_lengths;
|
||||||
uchar *data = outapp_create->pBuffer;
|
for (int i = 0; i < count; ++i) {
|
||||||
for (unsigned int i = 0; i < count; ++i)
|
InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer;
|
||||||
{
|
|
||||||
structs::VeteranReward *vr = (structs::VeteranReward*)data;
|
|
||||||
InternalVeteranReward *ivr = (InternalVeteranReward*)old_data;
|
|
||||||
|
|
||||||
vr->claim_count = ivr->claim_count;
|
for (int i = 0; i < ivr->claim_count; i++) {
|
||||||
vr->claim_id = ivr->claim_id;
|
uint32 length = strnlen(ivr->items[i].item_name, 63);
|
||||||
vr->number_available = ivr->number_available;
|
if (length)
|
||||||
for (int x = 0; x < 8; ++x)
|
name_lengths.push_back(length);
|
||||||
{
|
|
||||||
vr->items[x].item_id = ivr->items[x].item_id;
|
|
||||||
strncpy(vr->items[x].item_name, ivr->items[x].item_name, sizeof(vr->items[x].item_name));
|
|
||||||
vr->items[x].charges = ivr->items[x].charges;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
old_data += sizeof(InternalVeteranReward);
|
__emu_buffer += sizeof(InternalVeteranReward);
|
||||||
data += sizeof(structs::VeteranReward);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dest->FastQueuePacket(&outapp_create);
|
uint32 packet_size = std::accumulate(name_lengths.begin(), name_lengths.end(), 0) +
|
||||||
|
sizeof(structs::VeteranReward) + (sizeof(structs::VeteranRewardEntry) * count) +
|
||||||
|
// size of name_lengths is the same as item count
|
||||||
|
(sizeof(structs::VeteranRewardItem) * name_lengths.size());
|
||||||
|
|
||||||
|
// build packet now!
|
||||||
|
auto outapp = new EQApplicationPacket(OP_VetRewardsAvaliable, packet_size);
|
||||||
|
__emu_buffer = inapp->pBuffer;
|
||||||
|
|
||||||
|
outapp->WriteUInt32(count);
|
||||||
|
auto name_itr = name_lengths.begin();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer;
|
||||||
|
|
||||||
|
outapp->WriteUInt32(ivr->claim_id);
|
||||||
|
outapp->WriteUInt32(ivr->number_available);
|
||||||
|
outapp->WriteUInt32(ivr->claim_count);
|
||||||
|
outapp->WriteUInt8(1); // enabled
|
||||||
|
|
||||||
|
for (int j = 0; j < ivr->claim_count; j++) {
|
||||||
|
assert(name_itr != name_lengths.end()); // the way it's written, it should never happen, so just assert
|
||||||
|
outapp->WriteUInt32(*name_itr);
|
||||||
|
outapp->WriteData(ivr->items[j].item_name, *name_itr);
|
||||||
|
outapp->WriteUInt32(ivr->items[j].item_id);
|
||||||
|
outapp->WriteUInt32(ivr->items[j].charges);
|
||||||
|
++name_itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
__emu_buffer += sizeof(InternalVeteranReward);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
delete inapp;
|
delete inapp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3633,7 +3689,7 @@ namespace RoF
|
|||||||
OUT(elite_material);
|
OUT(elite_material);
|
||||||
OUT(hero_forge_model);
|
OUT(hero_forge_model);
|
||||||
OUT(unknown18);
|
OUT(unknown18);
|
||||||
OUT(color.color);
|
OUT(color.Color);
|
||||||
OUT(wear_slot_id);
|
OUT(wear_slot_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -3724,42 +3780,23 @@ namespace RoF
|
|||||||
|
|
||||||
ENCODE(OP_ZonePlayerToBind)
|
ENCODE(OP_ZonePlayerToBind)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct);
|
SETUP_VAR_ENCODE(ZonePlayerToBind_Struct);
|
||||||
|
ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name));
|
||||||
|
|
||||||
ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer;
|
__packet->SetWritePosition(0);
|
||||||
|
__packet->WriteUInt16(emu->bind_zone_id);
|
||||||
|
__packet->WriteUInt16(emu->bind_instance_id);
|
||||||
|
__packet->WriteFloat(emu->x);
|
||||||
|
__packet->WriteFloat(emu->y);
|
||||||
|
__packet->WriteFloat(emu->z);
|
||||||
|
__packet->WriteFloat(emu->heading);
|
||||||
|
__packet->WriteString(emu->zone_name);
|
||||||
|
__packet->WriteUInt8(1); // save items
|
||||||
|
__packet->WriteUInt32(0); // hp
|
||||||
|
__packet->WriteUInt32(0); // mana
|
||||||
|
__packet->WriteUInt32(0); // endurance
|
||||||
|
|
||||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
FINISH_ENCODE();
|
||||||
|
|
||||||
unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)];
|
|
||||||
structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1;
|
|
||||||
unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)];
|
|
||||||
structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2;
|
|
||||||
|
|
||||||
zph->x = zps->x;
|
|
||||||
zph->y = zps->y;
|
|
||||||
zph->z = zps->z;
|
|
||||||
zph->heading = zps->heading;
|
|
||||||
zph->bind_zone_id = 0;
|
|
||||||
zph->bind_instance_id = zps->bind_instance_id;
|
|
||||||
strncpy(zph->zone_name, zps->zone_name, sizeof(zph->zone_name));
|
|
||||||
|
|
||||||
zpf->unknown021 = 1;
|
|
||||||
zpf->unknown022 = 0;
|
|
||||||
zpf->unknown023 = 0;
|
|
||||||
zpf->unknown024 = 0;
|
|
||||||
|
|
||||||
ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)));
|
|
||||||
ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct));
|
|
||||||
|
|
||||||
delete[] buffer1;
|
|
||||||
delete[] buffer2;
|
|
||||||
delete[](*p)->pBuffer;
|
|
||||||
|
|
||||||
(*p)->pBuffer = new unsigned char[ss.str().size()];
|
|
||||||
(*p)->size = ss.str().size();
|
|
||||||
|
|
||||||
memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size());
|
|
||||||
dest->FastQueuePacket(&(*p));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_ZoneServerInfo)
|
ENCODE(OP_ZoneServerInfo)
|
||||||
@ -3807,8 +3844,8 @@ namespace RoF
|
|||||||
PacketSize += strlen(emu->name);
|
PacketSize += strlen(emu->name);
|
||||||
PacketSize += strlen(emu->lastName);
|
PacketSize += strlen(emu->lastName);
|
||||||
|
|
||||||
emu->title[0] = 0;
|
emu->title[31] = 0;
|
||||||
emu->suffix[0] = 0;
|
emu->suffix[31] = 0;
|
||||||
|
|
||||||
if (strlen(emu->title))
|
if (strlen(emu->title))
|
||||||
PacketSize += strlen(emu->title) + 1;
|
PacketSize += strlen(emu->title) + 1;
|
||||||
@ -3963,18 +4000,18 @@ namespace RoF
|
|||||||
for (k = 0; k < 9; ++k)
|
for (k = 0; k < 9; ++k)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
||||||
|
|
||||||
for (k = 0; k < 9; k++) {
|
for (k = 0; k < 9; k++) {
|
||||||
Equipment[k].material = emu->equipment[k].material;
|
Equipment[k].Material = emu->equipment[k].Material;
|
||||||
Equipment[k].unknown1 = emu->equipment[k].unknown1;
|
Equipment[k].Unknown1 = emu->equipment[k].Unknown1;
|
||||||
Equipment[k].elitematerial = emu->equipment[k].elitematerial;
|
Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial;
|
||||||
Equipment[k].heroforgemodel = emu->equipment[k].heroforgemodel;
|
Equipment[k].HeroForgeModel = emu->equipment[k].HeroForgeModel;
|
||||||
Equipment[k].material2 = emu->equipment[k].material2;
|
Equipment[k].Material2 = emu->equipment[k].Material2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer += (sizeof(structs::EquipStruct) * 9);
|
Buffer += (sizeof(structs::EquipStruct) * 9);
|
||||||
@ -3987,13 +4024,13 @@ namespace RoF
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
@ -4888,7 +4925,7 @@ namespace RoF
|
|||||||
slot_id = legacy::SLOT_TRADESKILL; // 1000
|
slot_id = legacy::SLOT_TRADESKILL; // 1000
|
||||||
}
|
}
|
||||||
emu->container_slot = slot_id;
|
emu->container_slot = slot_id;
|
||||||
emu->guildtribute_slot = RoFToServerSlot(eq->guildtribute_slot); // this should only return INVALID_INDEX until implemented -U
|
emu->guildtribute_slot = RoFToServerSlot(eq->guildtribute_slot); // this should only return INVALID_INDEX until implemented
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
@ -4923,6 +4960,16 @@ namespace RoF
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_VetClaimRequest)
|
||||||
|
{
|
||||||
|
DECODE_LENGTH_EXACT(structs::VeteranClaim);
|
||||||
|
SETUP_DIRECT_DECODE(VeteranClaim, structs::VeteranClaim);
|
||||||
|
|
||||||
|
IN(claim_id);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_ZoneChange)
|
DECODE(OP_ZoneChange)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::ZoneChange_Struct);
|
DECODE_LENGTH_EXACT(structs::ZoneChange_Struct);
|
||||||
@ -4983,7 +5030,7 @@ namespace RoF
|
|||||||
|
|
||||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
||||||
|
|
||||||
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%012d", item->ID);
|
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
|
||||||
|
|
||||||
hdr.stacksize = stackable ? charges : 1;
|
hdr.stacksize = stackable ? charges : 1;
|
||||||
hdr.unknown004 = 0;
|
hdr.unknown004 = 0;
|
||||||
|
|||||||
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <numeric>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace RoF2
|
namespace RoF2
|
||||||
{
|
{
|
||||||
@ -104,7 +106,7 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
//all opcodes default to passthrough.
|
//all opcodes default to passthrough.
|
||||||
#include "ss_register.h"
|
#include "ss_register.h"
|
||||||
#include "rof_ops.h"
|
#include "rof2_ops.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Strategy::Describe() const
|
std::string Strategy::Describe() const
|
||||||
@ -2118,7 +2120,7 @@ namespace RoF2
|
|||||||
|
|
||||||
for (int r = 0; r < 7; r++)
|
for (int r = 0; r < 7; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(emu->item_tint[r].color);
|
outapp->WriteUInt32(emu->item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// Write zeroes for extra two tint values
|
// Write zeroes for extra two tint values
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
@ -2128,7 +2130,7 @@ namespace RoF2
|
|||||||
|
|
||||||
for (int r = 0; r < 7; r++)
|
for (int r = 0; r < 7; r++)
|
||||||
{
|
{
|
||||||
outapp->WriteUInt32(emu->item_tint[r].color);
|
outapp->WriteUInt32(emu->item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// Write zeroes for extra two tint values
|
// Write zeroes for extra two tint values
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
@ -2360,46 +2362,52 @@ namespace RoF2
|
|||||||
outapp->WriteUInt8(0); // Unknown
|
outapp->WriteUInt8(0); // Unknown
|
||||||
outapp->WriteUInt8(0); // Unknown
|
outapp->WriteUInt8(0); // Unknown
|
||||||
|
|
||||||
outapp->WriteUInt32(structs::MAX_PLAYER_BANDOLIER);
|
outapp->WriteUInt32(consts::BANDOLIERS_SIZE);
|
||||||
|
|
||||||
for (uint32 r = 0; r < EmuConstants::BANDOLIERS_COUNT; r++)
|
// Copy bandoliers where server and client indexes converge
|
||||||
{
|
for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
outapp->WriteString(emu->bandoliers[r].name);
|
outapp->WriteString(emu->bandoliers[r].Name);
|
||||||
|
for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true
|
||||||
for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j)
|
outapp->WriteString(emu->bandoliers[r].Items[j].Name);
|
||||||
{
|
outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID);
|
||||||
outapp->WriteString(emu->bandoliers[r].items[j].item_name);
|
if (emu->bandoliers[r].Items[j].Icon) {
|
||||||
outapp->WriteUInt32(emu->bandoliers[r].items[j].item_id);
|
outapp->WriteSInt32(emu->bandoliers[r].Items[j].Icon);
|
||||||
outapp->WriteUInt32(emu->bandoliers[r].items[j].icon);
|
}
|
||||||
}
|
else {
|
||||||
}
|
// If no icon, it must send -1 or Treasure Chest Icon (836) is displayed
|
||||||
|
outapp->WriteSInt32(-1);
|
||||||
for (uint32 r = 0; r < structs::MAX_PLAYER_BANDOLIER - EmuConstants::BANDOLIERS_COUNT; r++)
|
}
|
||||||
{
|
}
|
||||||
outapp->WriteString("");
|
}
|
||||||
|
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||||
for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j)
|
for (uint32 r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
{
|
outapp->WriteString("");
|
||||||
outapp->WriteString("");
|
for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteString("");
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
}
|
outapp->WriteSInt32(-1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
outapp->WriteUInt32(structs::MAX_POTIONS_IN_BELT);
|
|
||||||
|
outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT);
|
||||||
for (uint32 r = 0; r < EmuConstants::POTION_BELT_SIZE; r++)
|
|
||||||
{
|
// Copy potion belt where server and client indexes converge
|
||||||
outapp->WriteString(emu->potionbelt.items[r].item_name);
|
for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
outapp->WriteUInt32(emu->potionbelt.items[r].item_id);
|
outapp->WriteString(emu->potionbelt.Items[r].Name);
|
||||||
outapp->WriteUInt32(emu->potionbelt.items[r].icon);
|
outapp->WriteUInt32(emu->potionbelt.Items[r].ID);
|
||||||
}
|
if (emu->potionbelt.Items[r].Icon) {
|
||||||
|
outapp->WriteSInt32(emu->potionbelt.Items[r].Icon);
|
||||||
for (uint32 r = 0; r < structs::MAX_POTIONS_IN_BELT - EmuConstants::POTION_BELT_SIZE; r++)
|
}
|
||||||
{
|
else {
|
||||||
|
// If no icon, it must send -1 or Treasure Chest Icon (836) is displayed
|
||||||
|
outapp->WriteSInt32(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||||
|
for (uint32 r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
outapp->WriteString("");
|
outapp->WriteString("");
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteSInt32(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
outapp->WriteSInt32(-1); // Unknown;
|
outapp->WriteSInt32(-1); // Unknown;
|
||||||
@ -2493,7 +2501,7 @@ namespace RoF2
|
|||||||
outapp->WriteUInt32(emu->silver_bank);
|
outapp->WriteUInt32(emu->silver_bank);
|
||||||
outapp->WriteUInt32(emu->copper_bank);
|
outapp->WriteUInt32(emu->copper_bank);
|
||||||
|
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(emu->platinum_shared);
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(0); // Unknown
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(0); // Unknown
|
||||||
outapp->WriteUInt32(0); // Unknown
|
outapp->WriteUInt32(0); // Unknown
|
||||||
@ -2975,85 +2983,99 @@ namespace RoF2
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
if (emu->CharCount == 0) {
|
||||||
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
||||||
|
eq->CharCount = emu->CharCount;
|
||||||
|
|
||||||
int char_count;
|
FINISH_ENCODE();
|
||||||
int namelen = 0;
|
return;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->name[char_count][0] == '\0')
|
|
||||||
break;
|
|
||||||
if (strcmp(emu->name[char_count], "<none>") == 0)
|
|
||||||
break;
|
|
||||||
namelen += strlen(emu->name[char_count]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
|
size_t names_length = 0;
|
||||||
|
size_t character_count = 0;
|
||||||
|
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
|
||||||
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
|
names_length += strlen(emu_cse->Name);
|
||||||
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total_length = sizeof(structs::CharacterSelect_Struct)
|
||||||
|
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
|
||||||
|
+ names_length;
|
||||||
|
|
||||||
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
||||||
|
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
//unsigned char *eq_buffer = new unsigned char[total_length];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
//eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->char_count = char_count;
|
//if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
//eq->total_chars = 10;
|
// eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1);
|
|
||||||
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
strcpy(eq_cse->Name, emu_cse->Name);
|
||||||
|
eq_ptr += strlen(eq_cse->Name);
|
||||||
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
eq_cse->Class = emu_cse->Class;
|
||||||
|
eq_cse->Race = emu_cse->Race;
|
||||||
|
eq_cse->Level = emu_cse->Level;
|
||||||
|
eq_cse->ShroudClass = emu_cse->ShroudClass;
|
||||||
|
eq_cse->ShroudRace = emu_cse->ShroudRace;
|
||||||
|
eq_cse->Zone = emu_cse->Zone;
|
||||||
|
eq_cse->Instance = emu_cse->Instance;
|
||||||
|
eq_cse->Gender = emu_cse->Gender;
|
||||||
|
eq_cse->Face = emu_cse->Face;
|
||||||
|
|
||||||
|
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
|
||||||
|
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
|
||||||
|
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
|
||||||
|
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
|
||||||
|
eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel;
|
||||||
|
eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2;
|
||||||
|
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
|
||||||
}
|
}
|
||||||
//adjust for name.
|
|
||||||
bufptr += strlen(emu->name[r]);
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
{ //post-name section...
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->class_ = emu->class_[r];
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->race = emu->race[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->level = emu->level[r];
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
eq2->class_2 = emu->class_[r];
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
eq2->race2 = emu->race[r];
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
eq2->zone = emu->zone[r];
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
eq2->instance = 0;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->gender = emu->gender[r];
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->face = emu->face[r];
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
int k;
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->equip[k].material = emu->equip[r][k].material;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->equip[k].unknown1 = emu->equip[r][k].unknown1;
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial;
|
eq_cse->Unknown1 = emu_cse->Unknown1;
|
||||||
eq2->equip[k].heroforgemodel = emu->equip[r][k].heroforgemodel;
|
eq_cse->Enabled = emu_cse->Enabled;
|
||||||
eq2->equip[k].material2 = emu->equip[r][k].material2;
|
eq_cse->LastLogin = emu_cse->LastLogin;
|
||||||
eq2->equip[k].color.color = emu->equip[r][k].color.color;
|
eq_cse->Unknown2 = emu_cse->Unknown2;
|
||||||
}
|
|
||||||
eq2->u15 = 0xff;
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->u19 = 0xFF;
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
eq2->drakkin_tattoo = emu->drakkin_tattoo[r];
|
|
||||||
eq2->drakkin_details = emu->drakkin_details[r];
|
|
||||||
eq2->deity = emu->deity[r];
|
|
||||||
eq2->primary = emu->primary[r];
|
|
||||||
eq2->secondary = emu->secondary[r];
|
|
||||||
eq2->haircolor = emu->haircolor[r];
|
|
||||||
eq2->beardcolor = emu->beardcolor[r];
|
|
||||||
eq2->eyecolor1 = emu->eyecolor1[r];
|
|
||||||
eq2->eyecolor2 = emu->eyecolor2[r];
|
|
||||||
eq2->hairstyle = emu->hairstyle[r];
|
|
||||||
eq2->beard = emu->beard[r];
|
|
||||||
eq2->char_enabled = 1;
|
|
||||||
eq2->tutorial = emu->tutorial[r];
|
|
||||||
eq2->drakkin_heritage = emu->drakkin_heritage[r];
|
|
||||||
eq2->unknown1 = 0;
|
|
||||||
eq2->gohome = emu->gohome[r];
|
|
||||||
eq2->LastLogin = 1212696584;
|
|
||||||
eq2->unknown2 = 0;
|
|
||||||
}
|
|
||||||
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -3563,12 +3585,13 @@ namespace RoF2
|
|||||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
||||||
for (uint32 i = 0; i < 200; i++)
|
for (uint32 i = 0; i < 200; i++)
|
||||||
{
|
{
|
||||||
strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber));
|
|
||||||
eq->items[i].Unknown18 = 0;
|
eq->items[i].Unknown18 = 0;
|
||||||
if (i < 80) {
|
if (i < 80) {
|
||||||
|
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", emu->SerialNumber[i]);
|
||||||
eq->ItemCost[i] = emu->ItemCost[i];
|
eq->ItemCost[i] = emu->ItemCost[i];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0);
|
||||||
eq->ItemCost[i] = 0;
|
eq->ItemCost[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3581,10 +3604,11 @@ namespace RoF2
|
|||||||
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
|
|
||||||
eq->Code = emu->Code;
|
eq->Code = emu->Code;
|
||||||
strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
|
//strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber));
|
||||||
|
//snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", 0);
|
||||||
eq->TraderID = emu->TraderID;
|
eq->TraderID = emu->TraderID;
|
||||||
eq->Stacksize = 0;
|
//eq->Stacksize = 0;
|
||||||
eq->Price = 0;
|
//eq->Price = 0;
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
@ -3619,6 +3643,78 @@ namespace RoF2
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_TraderDelItem)
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(TraderDelItem_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct);
|
||||||
|
|
||||||
|
OUT(TraderID);
|
||||||
|
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderDelItem): TraderID %d, SerialNumber: %d", emu->TraderID, emu->ItemID);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_TraderShop)
|
||||||
|
{
|
||||||
|
uint32 psize = (*p)->size;
|
||||||
|
if (psize == sizeof(TraderClick_Struct))
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
|
||||||
|
eq->Code = 28; // Seen on Live
|
||||||
|
OUT(TraderID);
|
||||||
|
OUT(Approval);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
else if (psize == sizeof(BazaarWelcome_Struct))
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(BazaarWelcome_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct);
|
||||||
|
|
||||||
|
eq->Code = emu->Beginning.Action;
|
||||||
|
eq->EntityID = emu->Unknown012;
|
||||||
|
OUT(Traders);
|
||||||
|
OUT(Items);
|
||||||
|
eq->Traders2 = emu->Traders;
|
||||||
|
eq->Items2 = emu->Items;
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): BazaarWelcome_Struct Code %d, Traders %d, Items %d",
|
||||||
|
eq->Code, eq->Traders, eq->Items);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
else if (psize == sizeof(TraderBuy_Struct))
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
||||||
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
|
||||||
|
OUT(Action);
|
||||||
|
OUT(TraderID);
|
||||||
|
|
||||||
|
//memcpy(eq->BuyerName, emu->BuyerName, sizeof(eq->BuyerName));
|
||||||
|
//memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName));
|
||||||
|
|
||||||
|
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
||||||
|
OUT(ItemID);
|
||||||
|
OUT(AlreadySold);
|
||||||
|
OUT(Price);
|
||||||
|
OUT(Quantity);
|
||||||
|
snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID);
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||||
|
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, emu->ItemName);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Encode Size Unknown (%d)", psize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_TributeInfo)
|
ENCODE(OP_TributeInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_ATLEAST(TributeAbility_Struct);
|
ENCODE_LENGTH_ATLEAST(TributeAbility_Struct);
|
||||||
@ -3655,37 +3751,71 @@ namespace RoF2
|
|||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ENCODE(OP_VetClaimReply)
|
||||||
|
{
|
||||||
|
ENCODE_LENGTH_EXACT(VeteranClaim);
|
||||||
|
SETUP_DIRECT_ENCODE(VeteranClaim, structs::VeteranClaim);
|
||||||
|
|
||||||
|
memcpy(eq->name, emu->name, sizeof(emu->name));
|
||||||
|
OUT(claim_id);
|
||||||
|
OUT(action);
|
||||||
|
|
||||||
|
FINISH_ENCODE();
|
||||||
|
}
|
||||||
|
|
||||||
ENCODE(OP_VetRewardsAvaliable)
|
ENCODE(OP_VetRewardsAvaliable)
|
||||||
{
|
{
|
||||||
EQApplicationPacket *inapp = *p;
|
EQApplicationPacket *inapp = *p;
|
||||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
auto __emu_buffer = inapp->pBuffer;
|
||||||
|
|
||||||
uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward));
|
uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward));
|
||||||
*p = nullptr;
|
|
||||||
|
|
||||||
EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count));
|
// calculate size of names, note the packet DOES NOT have null termed c-strings
|
||||||
uchar *old_data = __emu_buffer;
|
std::vector<uint32> name_lengths;
|
||||||
uchar *data = outapp_create->pBuffer;
|
for (int i = 0; i < count; ++i) {
|
||||||
for (unsigned int i = 0; i < count; ++i)
|
InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer;
|
||||||
{
|
|
||||||
structs::VeteranReward *vr = (structs::VeteranReward*)data;
|
|
||||||
InternalVeteranReward *ivr = (InternalVeteranReward*)old_data;
|
|
||||||
|
|
||||||
vr->claim_count = ivr->claim_count;
|
for (int i = 0; i < ivr->claim_count; i++) {
|
||||||
vr->claim_id = ivr->claim_id;
|
uint32 length = strnlen(ivr->items[i].item_name, 63);
|
||||||
vr->number_available = ivr->number_available;
|
if (length)
|
||||||
for (int x = 0; x < 8; ++x)
|
name_lengths.push_back(length);
|
||||||
{
|
|
||||||
vr->items[x].item_id = ivr->items[x].item_id;
|
|
||||||
strncpy(vr->items[x].item_name, ivr->items[x].item_name, sizeof(vr->items[x].item_name));
|
|
||||||
vr->items[x].charges = ivr->items[x].charges;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
old_data += sizeof(InternalVeteranReward);
|
__emu_buffer += sizeof(InternalVeteranReward);
|
||||||
data += sizeof(structs::VeteranReward);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dest->FastQueuePacket(&outapp_create);
|
uint32 packet_size = std::accumulate(name_lengths.begin(), name_lengths.end(), 0) +
|
||||||
|
sizeof(structs::VeteranReward) + (sizeof(structs::VeteranRewardEntry) * count) +
|
||||||
|
// size of name_lengths is the same as item count
|
||||||
|
(sizeof(structs::VeteranRewardItem) * name_lengths.size());
|
||||||
|
|
||||||
|
// build packet now!
|
||||||
|
auto outapp = new EQApplicationPacket(OP_VetRewardsAvaliable, packet_size);
|
||||||
|
__emu_buffer = inapp->pBuffer;
|
||||||
|
|
||||||
|
outapp->WriteUInt32(count);
|
||||||
|
auto name_itr = name_lengths.begin();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer;
|
||||||
|
|
||||||
|
outapp->WriteUInt32(ivr->claim_id);
|
||||||
|
outapp->WriteUInt32(ivr->number_available);
|
||||||
|
outapp->WriteUInt32(ivr->claim_count);
|
||||||
|
outapp->WriteUInt8(1); // enabled
|
||||||
|
|
||||||
|
for (int j = 0; j < ivr->claim_count; j++) {
|
||||||
|
assert(name_itr != name_lengths.end()); // the way it's written, it should never happen, so just assert
|
||||||
|
outapp->WriteUInt32(*name_itr);
|
||||||
|
outapp->WriteData(ivr->items[j].item_name, *name_itr);
|
||||||
|
outapp->WriteUInt32(ivr->items[j].item_id);
|
||||||
|
outapp->WriteUInt32(ivr->items[j].charges);
|
||||||
|
++name_itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
__emu_buffer += sizeof(InternalVeteranReward);
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->FastQueuePacket(&outapp);
|
||||||
delete inapp;
|
delete inapp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3700,7 +3830,7 @@ namespace RoF2
|
|||||||
OUT(elite_material);
|
OUT(elite_material);
|
||||||
OUT(hero_forge_model);
|
OUT(hero_forge_model);
|
||||||
OUT(unknown18);
|
OUT(unknown18);
|
||||||
OUT(color.color);
|
OUT(color.Color);
|
||||||
OUT(wear_slot_id);
|
OUT(wear_slot_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -3791,42 +3921,23 @@ namespace RoF2
|
|||||||
|
|
||||||
ENCODE(OP_ZonePlayerToBind)
|
ENCODE(OP_ZonePlayerToBind)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct);
|
SETUP_VAR_ENCODE(ZonePlayerToBind_Struct);
|
||||||
|
ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name));
|
||||||
|
|
||||||
ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer;
|
__packet->SetWritePosition(0);
|
||||||
|
__packet->WriteUInt16(emu->bind_zone_id);
|
||||||
|
__packet->WriteUInt16(emu->bind_instance_id);
|
||||||
|
__packet->WriteFloat(emu->x);
|
||||||
|
__packet->WriteFloat(emu->y);
|
||||||
|
__packet->WriteFloat(emu->z);
|
||||||
|
__packet->WriteFloat(emu->heading);
|
||||||
|
__packet->WriteString(emu->zone_name);
|
||||||
|
__packet->WriteUInt8(1); // save items
|
||||||
|
__packet->WriteUInt32(0); // hp
|
||||||
|
__packet->WriteUInt32(0); // mana
|
||||||
|
__packet->WriteUInt32(0); // endurance
|
||||||
|
|
||||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
FINISH_ENCODE();
|
||||||
|
|
||||||
unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)];
|
|
||||||
structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1;
|
|
||||||
unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)];
|
|
||||||
structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2;
|
|
||||||
|
|
||||||
zph->x = zps->x;
|
|
||||||
zph->y = zps->y;
|
|
||||||
zph->z = zps->z;
|
|
||||||
zph->heading = zps->heading;
|
|
||||||
zph->bind_zone_id = 0;
|
|
||||||
zph->bind_instance_id = zps->bind_instance_id;
|
|
||||||
strncpy(zph->zone_name, zps->zone_name, sizeof(zph->zone_name));
|
|
||||||
|
|
||||||
zpf->unknown021 = 1;
|
|
||||||
zpf->unknown022 = 0;
|
|
||||||
zpf->unknown023 = 0;
|
|
||||||
zpf->unknown024 = 0;
|
|
||||||
|
|
||||||
ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)));
|
|
||||||
ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct));
|
|
||||||
|
|
||||||
delete[] buffer1;
|
|
||||||
delete[] buffer2;
|
|
||||||
delete[](*p)->pBuffer;
|
|
||||||
|
|
||||||
(*p)->pBuffer = new unsigned char[ss.str().size()];
|
|
||||||
(*p)->size = ss.str().size();
|
|
||||||
|
|
||||||
memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size());
|
|
||||||
dest->FastQueuePacket(&(*p));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_ZoneServerInfo)
|
ENCODE(OP_ZoneServerInfo)
|
||||||
@ -3874,8 +3985,8 @@ namespace RoF2
|
|||||||
PacketSize += strlen(emu->name);
|
PacketSize += strlen(emu->name);
|
||||||
PacketSize += strlen(emu->lastName);
|
PacketSize += strlen(emu->lastName);
|
||||||
|
|
||||||
emu->title[0] = 0;
|
emu->title[31] = 0;
|
||||||
emu->suffix[0] = 0;
|
emu->suffix[31] = 0;
|
||||||
|
|
||||||
if (strlen(emu->title))
|
if (strlen(emu->title))
|
||||||
PacketSize += strlen(emu->title) + 1;
|
PacketSize += strlen(emu->title) + 1;
|
||||||
@ -4034,18 +4145,18 @@ namespace RoF2
|
|||||||
for (k = 0; k < 9; ++k)
|
for (k = 0; k < 9; ++k)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
||||||
|
|
||||||
for (k = 0; k < 9; k++) {
|
for (k = 0; k < 9; k++) {
|
||||||
Equipment[k].material = emu->equipment[k].material;
|
Equipment[k].Material = emu->equipment[k].Material;
|
||||||
Equipment[k].unknown1 = emu->equipment[k].unknown1;
|
Equipment[k].Unknown1 = emu->equipment[k].Unknown1;
|
||||||
Equipment[k].elitematerial = emu->equipment[k].elitematerial;
|
Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial;
|
||||||
Equipment[k].heroforgemodel = emu->equipment[k].heroforgemodel;
|
Equipment[k].HeroForgeModel = emu->equipment[k].HeroForgeModel;
|
||||||
Equipment[k].material2 = emu->equipment[k].material2;
|
Equipment[k].Material2 = emu->equipment[k].Material2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer += (sizeof(structs::EquipStruct) * 9);
|
Buffer += (sizeof(structs::EquipStruct) * 9);
|
||||||
@ -4058,13 +4169,13 @@ namespace RoF2
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
@ -4200,7 +4311,6 @@ namespace RoF2
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct);
|
SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct);
|
||||||
MEMSET_IN(structs::NewBazaarInspect_Struct);
|
|
||||||
|
|
||||||
IN(Beginning.Action);
|
IN(Beginning.Action);
|
||||||
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
|
memcpy(emu->Name, eq->Name, sizeof(emu->Name));
|
||||||
@ -4897,7 +5007,6 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::ClickTrader_Struct);
|
DECODE_LENGTH_EXACT(structs::ClickTrader_Struct);
|
||||||
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct);
|
||||||
MEMSET_IN(ClickTrader_Struct);
|
|
||||||
|
|
||||||
emu->Code = eq->Code;
|
emu->Code = eq->Code;
|
||||||
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
// Live actually has 200 items now, but 80 is the most our internal struct supports
|
||||||
@ -4913,7 +5022,6 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct);
|
||||||
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct);
|
||||||
MEMSET_IN(Trader_ShowItems_Struct);
|
|
||||||
|
|
||||||
emu->Code = eq->Code;
|
emu->Code = eq->Code;
|
||||||
emu->TraderID = eq->TraderID;
|
emu->TraderID = eq->TraderID;
|
||||||
@ -4924,9 +5032,8 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::TraderStatus_Struct);
|
DECODE_LENGTH_EXACT(structs::TraderStatus_Struct);
|
||||||
SETUP_DIRECT_DECODE(TraderStatus_Struct, structs::TraderStatus_Struct);
|
SETUP_DIRECT_DECODE(TraderStatus_Struct, structs::TraderStatus_Struct);
|
||||||
MEMSET_IN(TraderStatus_Struct);
|
|
||||||
|
|
||||||
emu->Code = eq->Code;
|
emu->Code = eq->Code; // 11 = Start Trader, 2 = End Trader, 22 = ? - Guessing
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
@ -4936,7 +5043,6 @@ namespace RoF2
|
|||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||||
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
MEMSET_IN(TraderBuy_Struct);
|
|
||||||
|
|
||||||
IN(Action);
|
IN(Action);
|
||||||
IN(Price);
|
IN(Price);
|
||||||
@ -4948,6 +5054,65 @@ namespace RoF2
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_TraderShop)
|
||||||
|
{
|
||||||
|
uint32 psize = __packet->size;
|
||||||
|
if (psize == sizeof(structs::TraderClick_Struct))
|
||||||
|
{
|
||||||
|
DECODE_LENGTH_EXACT(structs::TraderClick_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct);
|
||||||
|
|
||||||
|
IN(Code);
|
||||||
|
IN(TraderID);
|
||||||
|
IN(Approval);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderClick_Struct Code %d, TraderID %d, Approval %d",
|
||||||
|
eq->Code, eq->TraderID, eq->Approval);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
else if (psize == sizeof(structs::BazaarWelcome_Struct))
|
||||||
|
{
|
||||||
|
// Don't think this size gets used in RoF+ - Leaving for now...
|
||||||
|
DECODE_LENGTH_EXACT(structs::BazaarWelcome_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct);
|
||||||
|
|
||||||
|
emu->Beginning.Action = eq->Code;
|
||||||
|
IN(Traders);
|
||||||
|
IN(Items);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): BazaarWelcome_Struct Code %d, Traders %d, Items %d",
|
||||||
|
eq->Code, eq->Traders, eq->Items);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
else if (psize == sizeof(structs::TraderBuy_Struct))
|
||||||
|
{
|
||||||
|
|
||||||
|
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
||||||
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
||||||
|
|
||||||
|
IN(Action);
|
||||||
|
IN(Price);
|
||||||
|
IN(TraderID);
|
||||||
|
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
||||||
|
IN(ItemID);
|
||||||
|
IN(Quantity);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d",
|
||||||
|
eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||||
|
eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
else if (psize == 4)
|
||||||
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Forwarding packet as-is with size 4");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Unknown (%d)", psize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_TradeSkillCombine)
|
DECODE(OP_TradeSkillCombine)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::NewCombine_Struct);
|
DECODE_LENGTH_EXACT(structs::NewCombine_Struct);
|
||||||
@ -4958,7 +5123,7 @@ namespace RoF2
|
|||||||
slot_id = legacy::SLOT_TRADESKILL; // 1000
|
slot_id = legacy::SLOT_TRADESKILL; // 1000
|
||||||
}
|
}
|
||||||
emu->container_slot = slot_id;
|
emu->container_slot = slot_id;
|
||||||
emu->guildtribute_slot = RoF2ToServerSlot(eq->guildtribute_slot); // this should only return INVALID_INDEX until implemented -U
|
emu->guildtribute_slot = RoF2ToServerSlot(eq->guildtribute_slot); // this should only return INVALID_INDEX until implemented
|
||||||
|
|
||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
@ -4993,6 +5158,16 @@ namespace RoF2
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DECODE(OP_VetClaimRequest)
|
||||||
|
{
|
||||||
|
DECODE_LENGTH_EXACT(structs::VeteranClaim);
|
||||||
|
SETUP_DIRECT_DECODE(VeteranClaim, structs::VeteranClaim);
|
||||||
|
|
||||||
|
IN(claim_id);
|
||||||
|
|
||||||
|
FINISH_DIRECT_DECODE();
|
||||||
|
}
|
||||||
|
|
||||||
DECODE(OP_ZoneChange)
|
DECODE(OP_ZoneChange)
|
||||||
{
|
{
|
||||||
DECODE_LENGTH_EXACT(structs::ZoneChange_Struct);
|
DECODE_LENGTH_EXACT(structs::ZoneChange_Struct);
|
||||||
@ -5053,7 +5228,7 @@ namespace RoF2
|
|||||||
|
|
||||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
||||||
|
|
||||||
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%012d", item->ID);
|
snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID);
|
||||||
|
|
||||||
hdr.stacksize = stackable ? charges : 1;
|
hdr.stacksize = stackable ? charges : 1;
|
||||||
hdr.unknown004 = 0;
|
hdr.unknown004 = 0;
|
||||||
@ -5464,10 +5639,10 @@ namespace RoF2
|
|||||||
RoF2::structs::WornEffectStruct ibes;
|
RoF2::structs::WornEffectStruct ibes;
|
||||||
memset(&ibes, 0, sizeof(RoF2::structs::WornEffectStruct));
|
memset(&ibes, 0, sizeof(RoF2::structs::WornEffectStruct));
|
||||||
|
|
||||||
ibes.effect = 0xffffffff;
|
ibes.effect = item->Bard.Effect;
|
||||||
ibes.level2 = 0;
|
ibes.level2 = item->Bard.Level2;
|
||||||
ibes.type = 0;
|
ibes.type = item->Bard.Type;
|
||||||
ibes.level = 0;
|
ibes.level = item->Bard.Level;
|
||||||
//ibes.unknown6 = 0xffffffff;
|
//ibes.unknown6 = 0xffffffff;
|
||||||
|
|
||||||
ss.write((const char*)&ibes, sizeof(RoF2::structs::WornEffectStruct));
|
ss.write((const char*)&ibes, sizeof(RoF2::structs::WornEffectStruct));
|
||||||
|
|||||||
@ -103,6 +103,8 @@ namespace RoF2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
namespace consts {
|
||||||
|
static const size_t CHARACTER_CREATION_LIMIT = 12;
|
||||||
|
|
||||||
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
||||||
@ -178,9 +180,10 @@ namespace RoF2 {
|
|||||||
static const uint16 ITEM_COMMON_SIZE = 6;
|
static const uint16 ITEM_COMMON_SIZE = 6;
|
||||||
static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test)
|
static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test)
|
||||||
|
|
||||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances
|
||||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
|
||||||
static const uint32 POTION_BELT_SIZE = 5;
|
|
||||||
|
static const size_t POTION_BELT_ITEM_COUNT = 5;
|
||||||
|
|
||||||
static const size_t TEXT_LINK_BODY_LENGTH = 56;
|
static const size_t TEXT_LINK_BODY_LENGTH = 56;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,14 @@
|
|||||||
// Begin RoF2 Encodes
|
// Begin RoF2 Encodes
|
||||||
|
|
||||||
E(OP_SendMembershipDetails)
|
E(OP_SendMembershipDetails)
|
||||||
|
E(OP_TraderShop)
|
||||||
|
E(OP_TraderDelItem)
|
||||||
|
|
||||||
// incoming packets that require a DECODE translation:
|
// incoming packets that require a DECODE translation:
|
||||||
// Begin RoF2 Decodes
|
// Begin RoF2 Decodes
|
||||||
|
|
||||||
|
D(OP_TraderShop)
|
||||||
|
|
||||||
// End RoF2 Encodes/Decodes
|
// End RoF2 Encodes/Decodes
|
||||||
|
|
||||||
// These require Encodes/Decodes for RoF, so they do for RoF2 as well
|
// These require Encodes/Decodes for RoF, so they do for RoF2 as well
|
||||||
@ -107,6 +111,7 @@ E(OP_Trader)
|
|||||||
E(OP_TraderBuy)
|
E(OP_TraderBuy)
|
||||||
E(OP_TributeInfo)
|
E(OP_TributeInfo)
|
||||||
E(OP_TributeItem)
|
E(OP_TributeItem)
|
||||||
|
E(OP_VetClaimReply)
|
||||||
E(OP_VetRewardsAvaliable)
|
E(OP_VetRewardsAvaliable)
|
||||||
E(OP_WearChange)
|
E(OP_WearChange)
|
||||||
E(OP_WhoAllResponse)
|
E(OP_WhoAllResponse)
|
||||||
@ -170,6 +175,7 @@ D(OP_Trader)
|
|||||||
D(OP_TraderBuy)
|
D(OP_TraderBuy)
|
||||||
D(OP_TradeSkillCombine)
|
D(OP_TradeSkillCombine)
|
||||||
D(OP_TributeItem)
|
D(OP_TributeItem)
|
||||||
|
D(OP_VetClaimRequest)
|
||||||
D(OP_WhoAllRequest)
|
D(OP_WhoAllRequest)
|
||||||
D(OP_ZoneChange)
|
D(OP_ZoneChange)
|
||||||
D(OP_ZoneEntry)
|
D(OP_ZoneEntry)
|
||||||
|
|||||||
@ -97,11 +97,6 @@ static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
|||||||
static const uint32 MAX_TRIBUTE_TIERS = 10;
|
static const uint32 MAX_TRIBUTE_TIERS = 10;
|
||||||
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
||||||
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER = 20;
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4;
|
|
||||||
|
|
||||||
static const uint32 MAX_POTIONS_IN_BELT = 5;
|
|
||||||
|
|
||||||
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
||||||
static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16;
|
||||||
static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY);
|
static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY);
|
||||||
@ -114,7 +109,7 @@ static const uint32 MAX_PP_SPELLBOOK = 720; // was 480
|
|||||||
static const uint32 MAX_PP_MEMSPELL = 16; // was 12
|
static const uint32 MAX_PP_MEMSPELL = 16; // was 12
|
||||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||||
static const uint32 MAX_PP_AA_ARRAY = 300;
|
static const uint32 MAX_PP_AA_ARRAY = 300;
|
||||||
static const uint32 MAX_PP_DISCIPLINES = 200; // was 100
|
static const uint32 MAX_PP_DISCIPLINES = 300; // was 200
|
||||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||||
static const uint32 MAX_RECAST_TYPES = 20;
|
static const uint32 MAX_RECAST_TYPES = 20;
|
||||||
|
|
||||||
@ -147,84 +142,87 @@ struct AdventureInfo {
|
|||||||
*/
|
*/
|
||||||
struct Color_Struct
|
struct Color_Struct
|
||||||
{
|
{
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
uint8 Blue;
|
||||||
{
|
uint8 Green;
|
||||||
uint8 blue;
|
uint8 Red;
|
||||||
uint8 green;
|
uint8 UseTint; // if there's a tint this is FF
|
||||||
uint8 red;
|
} RGB;
|
||||||
uint8 use_tint; // if there's a tint this is FF
|
uint32 Color;
|
||||||
} rgb;
|
|
||||||
uint32 color;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
struct CharSelectEquip
|
||||||
* Visible equiptment.
|
{
|
||||||
* Size: 20 Octets
|
uint32 Material;
|
||||||
*/
|
uint32 Unknown1;
|
||||||
struct EquipStruct {
|
uint32 EliteMaterial;
|
||||||
/*00*/ uint32 material;
|
uint32 HeroForgeModel;
|
||||||
/*04*/ uint32 unknown1;
|
uint32 Material2;
|
||||||
/*08*/ uint32 elitematerial;
|
Color_Struct Color;
|
||||||
/*12*/ uint32 heroforgemodel;
|
|
||||||
/*16*/ uint32 material2; // Same as material?
|
|
||||||
/*20*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharSelectEquip {
|
struct CharacterSelectEntry_Struct
|
||||||
uint32 material;
|
{
|
||||||
uint32 unknown1;
|
/*0000*/ char Name[1]; // Name null terminated
|
||||||
uint32 elitematerial;
|
/*0000*/ uint8 Class;
|
||||||
uint32 heroforgemodel;
|
/*0000*/ uint32 Race;
|
||||||
uint32 material2;
|
/*0000*/ uint8 Level;
|
||||||
Color_Struct color;
|
/*0000*/ uint8 ShroudClass;
|
||||||
};
|
/*0000*/ uint32 ShroudRace;
|
||||||
|
/*0000*/ uint16 Zone;
|
||||||
struct CharacterSelectEntry_Struct {
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ char name[1]; // Name null terminated
|
/*0000*/ uint8 Gender;
|
||||||
/*0000*/ uint8 class_;
|
/*0000*/ uint8 Face;
|
||||||
/*0000*/ uint32 race;
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint8 level;
|
/*0000*/ uint8 Unknown15; // Seen FF
|
||||||
/*0000*/ uint8 class_2;
|
/*0000*/ uint8 Unknown19; // Seen FF
|
||||||
/*0000*/ uint32 race2;
|
/*0000*/ uint32 DrakkinTattoo;
|
||||||
/*0000*/ uint16 zone;
|
/*0000*/ uint32 DrakkinDetails;
|
||||||
/*0000*/ uint16 instance;
|
/*0000*/ uint32 Deity;
|
||||||
/*0000*/ uint8 gender;
|
/*0000*/ uint32 PrimaryIDFile;
|
||||||
/*0000*/ uint8 face;
|
/*0000*/ uint32 SecondaryIDFile;
|
||||||
/*0000*/ CharSelectEquip equip[9];
|
/*0000*/ uint8 HairColor;
|
||||||
/*0000*/ uint8 u15; // Seen FF
|
/*0000*/ uint8 BeardColor;
|
||||||
/*0000*/ uint8 u19; // Seen FF
|
/*0000*/ uint8 EyeColor1;
|
||||||
/*0000*/ uint32 drakkin_tattoo;
|
/*0000*/ uint8 EyeColor2;
|
||||||
/*0000*/ uint32 drakkin_details;
|
/*0000*/ uint8 HairStyle;
|
||||||
/*0000*/ uint32 deity;
|
/*0000*/ uint8 Beard;
|
||||||
/*0000*/ uint32 primary;
|
/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing
|
||||||
/*0000*/ uint32 secondary;
|
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
|
||||||
/*0000*/ uint8 haircolor;
|
/*0000*/ uint32 DrakkinHeritage;
|
||||||
/*0000*/ uint8 beardcolor;
|
/*0000*/ uint8 Unknown1; // Seen 0
|
||||||
/*0000*/ uint8 eyecolor1;
|
/*0000*/ uint8 Enabled; // Swapped position with 'GoHome' 02/23/2015
|
||||||
/*0000*/ uint8 eyecolor2;
|
|
||||||
/*0000*/ uint8 hairstyle;
|
|
||||||
/*0000*/ uint8 beard;
|
|
||||||
/*0000*/ uint8 char_enabled;
|
|
||||||
/*0000*/ uint8 tutorial; // Seen 1 for new char or 0 for existing
|
|
||||||
/*0000*/ uint32 drakkin_heritage;
|
|
||||||
/*0000*/ uint8 unknown1; // Seen 0
|
|
||||||
/*0000*/ uint8 gohome; // Seen 0 for new char and 1 for existing
|
|
||||||
/*0000*/ uint32 LastLogin;
|
/*0000*/ uint32 LastLogin;
|
||||||
/*0000*/ uint8 unknown2; // Seen 0
|
/*0000*/ uint8 Unknown2; // Seen 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Character Selection Struct
|
** Character Selection Struct
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct CharacterSelect_Struct {
|
struct CharacterSelect_Struct
|
||||||
/*000*/ uint32 char_count; //number of chars in this packet
|
{
|
||||||
/*004*/ CharacterSelectEntry_Struct entries[0];
|
/*000*/ uint32 CharCount; //number of chars in this packet
|
||||||
|
/*004*/ CharacterSelectEntry_Struct Entries[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Visible equiptment.
|
||||||
|
* Size: 20 Octets
|
||||||
|
*/
|
||||||
|
struct EquipStruct
|
||||||
|
{
|
||||||
|
/*00*/ uint32 Material;
|
||||||
|
/*04*/ uint32 Unknown1;
|
||||||
|
/*08*/ uint32 EliteMaterial;
|
||||||
|
/*12*/ uint32 HeroForgeModel;
|
||||||
|
/*16*/ uint32 Material2; // Same as material?
|
||||||
|
/*20*/
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Membership_Entry_Struct
|
struct Membership_Entry_Struct
|
||||||
{
|
{
|
||||||
/*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300
|
/*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300
|
||||||
@ -896,38 +894,66 @@ struct Tribute_Struct {
|
|||||||
uint32 tier;
|
uint32 tier;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierItem_Struct {
|
// Bandolier item positions
|
||||||
char item_name[1]; // Variable Length
|
enum
|
||||||
uint32 item_id;
|
{
|
||||||
uint32 icon;
|
bandolierPrimary = 0,
|
||||||
};
|
bandolierSecondary,
|
||||||
|
|
||||||
//len = 72
|
|
||||||
struct BandolierItem_Struct_Old {
|
|
||||||
uint32 item_id;
|
|
||||||
uint32 icon;
|
|
||||||
char item_name[64];
|
|
||||||
};
|
|
||||||
|
|
||||||
//len = 320
|
|
||||||
enum { //bandolier item positions
|
|
||||||
bandolierMainHand = 0,
|
|
||||||
bandolierOffHand,
|
|
||||||
bandolierRange,
|
bandolierRange,
|
||||||
bandolierAmmo
|
bandolierAmmo
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
|
||||||
char name[1]; // Variable Length
|
struct BandolierItem_Struct
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
{
|
||||||
|
char Name[1]; // Variable Length
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bandolier_Struct_Old {
|
//len = 72
|
||||||
char name[32];
|
struct BandolierItem_Struct_Old
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PotionBelt_Struct {
|
//len = 320
|
||||||
BandolierItem_Struct items[MAX_POTIONS_IN_BELT];
|
struct Bandolier_Struct
|
||||||
|
{
|
||||||
|
char Name[1]; // Variable Length
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Bandolier_Struct_Old
|
||||||
|
{
|
||||||
|
char Name[32];
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PotionBeltItem_Struct
|
||||||
|
{
|
||||||
|
char Name[1]; // Variable Length
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 72
|
||||||
|
struct PotionBeltItem_Struct_Old
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PotionBelt_Struct
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PotionBelt_Struct_Old
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct_Old Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GroupLeadershipAA_Struct {
|
struct GroupLeadershipAA_Struct {
|
||||||
@ -1137,7 +1163,7 @@ union
|
|||||||
/*12949*/ uint32 aapoints; // Unspent AA points - Seen 1
|
/*12949*/ uint32 aapoints; // Unspent AA points - Seen 1
|
||||||
/*12953*/ uint16 unknown_rof20; //
|
/*12953*/ uint16 unknown_rof20; //
|
||||||
/*12955*/ uint32 bandolier_count; // Seen 20
|
/*12955*/ uint32 bandolier_count; // Seen 20
|
||||||
/*12959*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents
|
/*12959*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents
|
||||||
/*13699*/ uint32 potionbelt_count; // Seen 5
|
/*13699*/ uint32 potionbelt_count; // Seen 5
|
||||||
/*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes)
|
/*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes)
|
||||||
/*13748*/ int32 unknown_rof21; // Seen -1
|
/*13748*/ int32 unknown_rof21; // Seen -1
|
||||||
@ -2865,7 +2891,7 @@ struct SetRunMode_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// EnvDamage is EnvDamage2 without a few bytes at the end.
|
// EnvDamage is EnvDamage2 without a few bytes at the end.
|
||||||
// Size: 37 bytes
|
// Size: 39 bytes
|
||||||
struct EnvDamage2_Struct {
|
struct EnvDamage2_Struct {
|
||||||
/*0000*/ uint32 id;
|
/*0000*/ uint32 id;
|
||||||
/*0004*/ uint16 unknown4;
|
/*0004*/ uint16 unknown4;
|
||||||
@ -2877,7 +2903,8 @@ struct EnvDamage2_Struct {
|
|||||||
/*0031*/ uint16 unknown31; // New to Underfoot - Seen 66
|
/*0031*/ uint16 unknown31; // New to Underfoot - Seen 66
|
||||||
/*0033*/ uint16 constant; // Always FFFF
|
/*0033*/ uint16 constant; // Always FFFF
|
||||||
/*0035*/ uint16 unknown35;
|
/*0035*/ uint16 unknown35;
|
||||||
/*0037*/
|
/*0037*/ uint16 unknown37;
|
||||||
|
/*0039*/
|
||||||
};
|
};
|
||||||
|
|
||||||
//Bazaar Stuff
|
//Bazaar Stuff
|
||||||
@ -2913,10 +2940,12 @@ struct BazaarWindowStart_Struct {
|
|||||||
|
|
||||||
|
|
||||||
struct BazaarWelcome_Struct {
|
struct BazaarWelcome_Struct {
|
||||||
BazaarWindowStart_Struct Beginning;
|
uint32 Code;
|
||||||
uint32 Traders;
|
uint32 EntityID;
|
||||||
uint32 Items;
|
uint32 Traders;
|
||||||
uint8 Unknown012[8];
|
uint32 Items;
|
||||||
|
uint32 Traders2;
|
||||||
|
uint32 Items2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BazaarSearch_Struct {
|
struct BazaarSearch_Struct {
|
||||||
@ -3199,6 +3228,13 @@ struct BecomeTrader_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Trader_ShowItems_Struct {
|
struct Trader_ShowItems_Struct {
|
||||||
|
/*000*/ uint32 Code;
|
||||||
|
/*004*/ uint16 TraderID;
|
||||||
|
/*008*/ uint32 Unknown08;
|
||||||
|
/*012*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Trader_ShowItems_Struct_WIP {
|
||||||
/*000*/ uint32 Code;
|
/*000*/ uint32 Code;
|
||||||
/*004*/ char SerialNumber[17];
|
/*004*/ char SerialNumber[17];
|
||||||
/*021*/ uint8 Unknown21;
|
/*021*/ uint8 Unknown21;
|
||||||
@ -3216,6 +3252,26 @@ struct TraderStatus_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TraderBuy_Struct {
|
struct TraderBuy_Struct {
|
||||||
|
/*000*/ uint32 Action;
|
||||||
|
/*004*/ uint32 Unknown004;
|
||||||
|
/*008*/ uint32 Unknown008;
|
||||||
|
/*012*/ uint32 Unknown012;
|
||||||
|
/*016*/ uint32 TraderID;
|
||||||
|
/*020*/ char BuyerName[64];
|
||||||
|
/*084*/ char SellerName[64];
|
||||||
|
/*148*/ char Unknown148[32];
|
||||||
|
/*180*/ char ItemName[64];
|
||||||
|
/*244*/ char SerialNumber[16];
|
||||||
|
/*260*/ uint32 Unknown076;
|
||||||
|
/*264*/ uint32 ItemID;
|
||||||
|
/*268*/ uint32 Price;
|
||||||
|
/*272*/ uint32 AlreadySold;
|
||||||
|
/*276*/ uint32 Unknown276;
|
||||||
|
/*280*/ uint32 Quantity;
|
||||||
|
/*284*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TraderBuy_Struct_OLD {
|
||||||
/*000*/ uint32 Action;
|
/*000*/ uint32 Action;
|
||||||
/*004*/ uint32 Unknown004;
|
/*004*/ uint32 Unknown004;
|
||||||
/*008*/ uint32 Price;
|
/*008*/ uint32 Price;
|
||||||
@ -3245,25 +3301,19 @@ struct MoneyUpdate_Struct{
|
|||||||
int32 copper;
|
int32 copper;
|
||||||
};
|
};
|
||||||
|
|
||||||
//struct MoneyUpdate_Struct
|
|
||||||
//{
|
|
||||||
//*0000*/ uint32 spawn_id; // ***Placeholder
|
|
||||||
//*0004*/ uint32 cointype; // Coin Type
|
|
||||||
//*0008*/ uint32 amount; // Amount
|
|
||||||
//*0012*/
|
|
||||||
//};
|
|
||||||
|
|
||||||
|
|
||||||
struct TraderDelItem_Struct{
|
struct TraderDelItem_Struct{
|
||||||
uint32 slotid;
|
/*000*/ uint32 Unknown000;
|
||||||
uint32 quantity;
|
/*004*/ uint32 TraderID;
|
||||||
uint32 unknown;
|
/*008*/ char SerialNumber[16];
|
||||||
|
/*024*/ uint32 Unknown012;
|
||||||
|
/*028*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TraderClick_Struct{
|
struct TraderClick_Struct{
|
||||||
uint32 traderid;
|
/*000*/ uint32 Code;
|
||||||
uint32 unknown4[2];
|
/*004*/ uint32 TraderID;
|
||||||
uint32 approval;
|
/*008*/ uint32 Approval;
|
||||||
|
/*012*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FormattedMessage_Struct{
|
struct FormattedMessage_Struct{
|
||||||
@ -3566,7 +3616,7 @@ struct Split_Struct
|
|||||||
*/
|
*/
|
||||||
struct NewCombine_Struct {
|
struct NewCombine_Struct {
|
||||||
/*00*/ ItemSlotStruct container_slot;
|
/*00*/ ItemSlotStruct container_slot;
|
||||||
/*12*/ ItemSlotStruct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8 -U)
|
/*12*/ ItemSlotStruct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8)
|
||||||
/*24*/
|
/*24*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4087,30 +4137,35 @@ struct DynamicWall_Struct {
|
|||||||
/*80*/
|
/*80*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { //bandolier actions
|
// Bandolier actions
|
||||||
BandolierCreate = 0,
|
enum
|
||||||
BandolierRemove = 1,
|
{
|
||||||
BandolierSet = 2
|
bandolierCreate = 0,
|
||||||
|
bandolierRemove,
|
||||||
|
bandolierSet
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierCreate_Struct {
|
struct BandolierCreate_Struct
|
||||||
/*00*/ uint32 action; //0 for create
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action; //0 for create
|
||||||
/*05*/ char name[32];
|
/*04*/ uint8 Number;
|
||||||
/*37*/ uint16 unknown37; //seen 0x93FD
|
/*05*/ char Name[32];
|
||||||
/*39*/ uint8 unknown39; //0
|
/*37*/ uint16 Unknown37; //seen 0x93FD
|
||||||
|
/*39*/ uint8 Unknown39; //0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierDelete_Struct {
|
struct BandolierDelete_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierSet_Struct {
|
struct BandolierSet_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arrow_Struct {
|
struct Arrow_Struct {
|
||||||
@ -4352,7 +4407,7 @@ struct RoF2SlotStruct
|
|||||||
|
|
||||||
struct ItemSerializationHeader
|
struct ItemSerializationHeader
|
||||||
{
|
{
|
||||||
/*000*/ char unknown000[13]; // New for HoT. Looks like a string.
|
/*000*/ char unknown000[17]; // New for HoT. Looks like a string.
|
||||||
/*017*/ uint32 stacksize;
|
/*017*/ uint32 stacksize;
|
||||||
/*021*/ uint32 unknown004;
|
/*021*/ uint32 unknown004;
|
||||||
/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ?
|
/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ?
|
||||||
@ -4497,7 +4552,7 @@ struct ItemSecondaryBodyStruct
|
|||||||
uint32 augtype;
|
uint32 augtype;
|
||||||
// swapped augrestrict and augdistiller positions
|
// swapped augrestrict and augdistiller positions
|
||||||
// (this swap does show the proper augment restrictions in Item Information window now)
|
// (this swap does show the proper augment restrictions in Item Information window now)
|
||||||
// unsure what the purpose of augdistiller is at this time -U 3/17/2014
|
// unsure what the purpose of augdistiller is at this time 3/17/2014
|
||||||
int32 augrestrict2; // New to December 10th 2012 client - Hidden Aug Restriction
|
int32 augrestrict2; // New to December 10th 2012 client - Hidden Aug Restriction
|
||||||
uint32 augrestrict;
|
uint32 augrestrict;
|
||||||
AugSlotStruct augslots[6];
|
AugSlotStruct augslots[6];
|
||||||
@ -4672,17 +4727,33 @@ struct AugmentInfo_Struct
|
|||||||
|
|
||||||
struct VeteranRewardItem
|
struct VeteranRewardItem
|
||||||
{
|
{
|
||||||
/*000*/ uint32 item_id;
|
/*000*/ uint32 name_length;
|
||||||
/*004*/ uint32 charges;
|
/*004*/ //char item_name[0]; // THIS IS NOT NULL TERMED
|
||||||
/*008*/ char item_name[64];
|
/*???*/ uint32 item_id;
|
||||||
|
/*???*/ uint32 charges;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VeteranRewardEntry
|
||||||
|
{
|
||||||
|
/*000*/ uint32 claim_id; // guessed
|
||||||
|
/*004*/ uint32 avaliable_count;
|
||||||
|
/*008*/ uint32 claim_count;
|
||||||
|
/*012*/ char enabled;
|
||||||
|
/*013*/ //VeteranRewardItem items[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VeteranReward
|
struct VeteranReward
|
||||||
{
|
{
|
||||||
/*000*/ uint32 claim_id;
|
/*000*/ uint32 claim_count;
|
||||||
/*004*/ uint32 number_available;
|
/*004*/ //VeteranRewardEntry entries[0];
|
||||||
/*008*/ uint32 claim_count;
|
};
|
||||||
/*012*/ VeteranRewardItem items[8];
|
|
||||||
|
struct VeteranClaim
|
||||||
|
{
|
||||||
|
/*000*/ char name[68]; //name + other data
|
||||||
|
/*068*/ uint32 claim_id;
|
||||||
|
/*072*/ uint32 unknown072;
|
||||||
|
/*076*/ uint32 action;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExpeditionEntryHeader_Struct
|
struct ExpeditionEntryHeader_Struct
|
||||||
|
|||||||
@ -102,6 +102,8 @@ namespace RoF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
namespace consts {
|
||||||
|
static const size_t CHARACTER_CREATION_LIMIT = 12;
|
||||||
|
|
||||||
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
||||||
@ -177,9 +179,10 @@ namespace RoF {
|
|||||||
static const uint16 ITEM_COMMON_SIZE = 6;
|
static const uint16 ITEM_COMMON_SIZE = 6;
|
||||||
static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test)
|
static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test)
|
||||||
|
|
||||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances
|
||||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
|
||||||
static const uint32 POTION_BELT_SIZE = 5;
|
|
||||||
|
static const size_t POTION_BELT_ITEM_COUNT = 5;
|
||||||
|
|
||||||
static const size_t TEXT_LINK_BODY_LENGTH = 55;
|
static const size_t TEXT_LINK_BODY_LENGTH = 55;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,6 +96,7 @@ E(OP_Trader)
|
|||||||
E(OP_TraderBuy)
|
E(OP_TraderBuy)
|
||||||
E(OP_TributeInfo)
|
E(OP_TributeInfo)
|
||||||
E(OP_TributeItem)
|
E(OP_TributeItem)
|
||||||
|
E(OP_VetClaimReply)
|
||||||
E(OP_VetRewardsAvaliable)
|
E(OP_VetRewardsAvaliable)
|
||||||
E(OP_WearChange)
|
E(OP_WearChange)
|
||||||
E(OP_WhoAllResponse)
|
E(OP_WhoAllResponse)
|
||||||
@ -159,6 +160,7 @@ D(OP_Trader)
|
|||||||
D(OP_TraderBuy)
|
D(OP_TraderBuy)
|
||||||
D(OP_TradeSkillCombine)
|
D(OP_TradeSkillCombine)
|
||||||
D(OP_TributeItem)
|
D(OP_TributeItem)
|
||||||
|
D(OP_VetClaimRequest)
|
||||||
D(OP_WhoAllRequest)
|
D(OP_WhoAllRequest)
|
||||||
D(OP_ZoneChange)
|
D(OP_ZoneChange)
|
||||||
D(OP_ZoneEntry)
|
D(OP_ZoneEntry)
|
||||||
|
|||||||
@ -97,11 +97,6 @@ static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
|||||||
static const uint32 MAX_TRIBUTE_TIERS = 10;
|
static const uint32 MAX_TRIBUTE_TIERS = 10;
|
||||||
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
||||||
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER = 20;
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4;
|
|
||||||
|
|
||||||
static const uint32 MAX_POTIONS_IN_BELT = 5;
|
|
||||||
|
|
||||||
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
||||||
static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16;
|
||||||
static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY);
|
static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY);
|
||||||
@ -147,71 +142,87 @@ struct AdventureInfo {
|
|||||||
*/
|
*/
|
||||||
struct Color_Struct
|
struct Color_Struct
|
||||||
{
|
{
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
uint8 Blue;
|
||||||
{
|
uint8 Green;
|
||||||
uint8 blue;
|
uint8 Red;
|
||||||
uint8 green;
|
uint8 UseTint; // if there's a tint this is FF
|
||||||
uint8 red;
|
} RGB;
|
||||||
uint8 use_tint; // if there's a tint this is FF
|
uint32 Color;
|
||||||
} rgb;
|
|
||||||
uint32 color;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharSelectEquip {
|
struct CharSelectEquip
|
||||||
uint32 material;
|
{
|
||||||
uint32 unknown1;
|
uint32 Material;
|
||||||
uint32 elitematerial;
|
uint32 Unknown1;
|
||||||
uint32 heroforgemodel;
|
uint32 EliteMaterial;
|
||||||
uint32 material2;
|
uint32 HeroForgeModel;
|
||||||
Color_Struct color;
|
uint32 Material2;
|
||||||
|
Color_Struct Color;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharacterSelectEntry_Struct {
|
struct CharacterSelectEntry_Struct
|
||||||
/*0000*/ char name[1]; // Name null terminated
|
{
|
||||||
/*0000*/ uint8 class_;
|
/*0000*/ char Name[1]; // Name null terminated
|
||||||
/*0000*/ uint32 race;
|
/*0000*/ uint8 Class;
|
||||||
/*0000*/ uint8 level;
|
/*0000*/ uint32 Race;
|
||||||
/*0000*/ uint8 class_2;
|
/*0000*/ uint8 Level;
|
||||||
/*0000*/ uint32 race2;
|
/*0000*/ uint8 ShroudClass;
|
||||||
/*0000*/ uint16 zone;
|
/*0000*/ uint32 ShroudRace;
|
||||||
/*0000*/ uint16 instance;
|
/*0000*/ uint16 Zone;
|
||||||
/*0000*/ uint8 gender;
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ uint8 face;
|
/*0000*/ uint8 Gender;
|
||||||
/*0000*/ CharSelectEquip equip[9];
|
/*0000*/ uint8 Face;
|
||||||
/*0000*/ uint8 u15; // Seen FF
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint8 u19; // Seen FF
|
/*0000*/ uint8 Unknown15; // Seen FF
|
||||||
/*0000*/ uint32 drakkin_tattoo;
|
/*0000*/ uint8 Unknown19; // Seen FF
|
||||||
/*0000*/ uint32 drakkin_details;
|
/*0000*/ uint32 DrakkinTattoo;
|
||||||
/*0000*/ uint32 deity;
|
/*0000*/ uint32 DrakkinDetails;
|
||||||
/*0000*/ uint32 primary;
|
/*0000*/ uint32 Deity;
|
||||||
/*0000*/ uint32 secondary;
|
/*0000*/ uint32 PrimaryIDFile;
|
||||||
/*0000*/ uint8 haircolor;
|
/*0000*/ uint32 SecondaryIDFile;
|
||||||
/*0000*/ uint8 beardcolor;
|
/*0000*/ uint8 HairColor;
|
||||||
/*0000*/ uint8 eyecolor1;
|
/*0000*/ uint8 BeardColor;
|
||||||
/*0000*/ uint8 eyecolor2;
|
/*0000*/ uint8 EyeColor1;
|
||||||
/*0000*/ uint8 hairstyle;
|
/*0000*/ uint8 EyeColor2;
|
||||||
/*0000*/ uint8 beard;
|
/*0000*/ uint8 HairStyle;
|
||||||
/*0000*/ uint8 char_enabled;
|
/*0000*/ uint8 Beard;
|
||||||
/*0000*/ uint8 tutorial; // Seen 1 for new char or 0 for existing
|
/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing
|
||||||
/*0000*/ uint32 drakkin_heritage;
|
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
|
||||||
/*0000*/ uint8 unknown1; // Seen 0
|
/*0000*/ uint32 DrakkinHeritage;
|
||||||
/*0000*/ uint8 gohome; // Seen 0 for new char and 1 for existing
|
/*0000*/ uint8 Unknown1; // Seen 0
|
||||||
|
/*0000*/ uint8 Enabled; // Swapped position with 'GoHome' 02/23/2015
|
||||||
/*0000*/ uint32 LastLogin;
|
/*0000*/ uint32 LastLogin;
|
||||||
/*0000*/ uint8 unknown2; // Seen 0
|
/*0000*/ uint8 Unknown2; // Seen 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Character Selection Struct
|
** Character Selection Struct
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct CharacterSelect_Struct {
|
struct CharacterSelect_Struct
|
||||||
/*000*/ uint32 char_count; //number of chars in this packet
|
{
|
||||||
/*004*/ CharacterSelectEntry_Struct entries[0];
|
/*000*/ uint32 CharCount; //number of chars in this packet
|
||||||
|
/*004*/ CharacterSelectEntry_Struct Entries[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Visible equiptment.
|
||||||
|
* Size: 20 Octets
|
||||||
|
*/
|
||||||
|
struct EquipStruct
|
||||||
|
{
|
||||||
|
/*00*/ uint32 Material;
|
||||||
|
/*04*/ uint32 Unknown1;
|
||||||
|
/*08*/ uint32 EliteMaterial;
|
||||||
|
/*12*/ uint32 HeroForgeModel;
|
||||||
|
/*16*/ uint32 Material2; // Same as material?
|
||||||
|
/*20*/
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Membership_Entry_Struct
|
struct Membership_Entry_Struct
|
||||||
{
|
{
|
||||||
/*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300
|
/*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300
|
||||||
@ -252,20 +263,6 @@ struct Membership_Struct
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Visible equiptment.
|
|
||||||
* Size: 20 Octets
|
|
||||||
*/
|
|
||||||
struct EquipStruct {
|
|
||||||
/*00*/ uint32 material;
|
|
||||||
/*04*/ uint32 unknown1;
|
|
||||||
/*08*/ uint32 elitematerial;
|
|
||||||
/*12*/ uint32 heroforgemodel;
|
|
||||||
/*16*/ uint32 material2; // Same as material?
|
|
||||||
/*20*/
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generic Spawn Struct
|
** Generic Spawn Struct
|
||||||
** Length: 897 Octets
|
** Length: 897 Octets
|
||||||
@ -880,38 +877,66 @@ struct Tribute_Struct {
|
|||||||
uint32 tier;
|
uint32 tier;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierItem_Struct {
|
// Bandolier item positions
|
||||||
char item_name[1]; // Variable Length
|
enum
|
||||||
uint32 item_id;
|
{
|
||||||
uint32 icon;
|
bandolierPrimary = 0,
|
||||||
};
|
bandolierSecondary,
|
||||||
|
|
||||||
//len = 72
|
|
||||||
struct BandolierItem_Struct_Old {
|
|
||||||
uint32 item_id;
|
|
||||||
uint32 icon;
|
|
||||||
char item_name[64];
|
|
||||||
};
|
|
||||||
|
|
||||||
//len = 320
|
|
||||||
enum { //bandolier item positions
|
|
||||||
bandolierMainHand = 0,
|
|
||||||
bandolierOffHand,
|
|
||||||
bandolierRange,
|
bandolierRange,
|
||||||
bandolierAmmo
|
bandolierAmmo
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
|
||||||
char name[1]; // Variable Length
|
struct BandolierItem_Struct
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
{
|
||||||
|
char Name[1]; // Variable Length
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bandolier_Struct_Old {
|
//len = 72
|
||||||
char name[32];
|
struct BandolierItem_Struct_Old
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PotionBelt_Struct {
|
//len = 320
|
||||||
BandolierItem_Struct items[MAX_POTIONS_IN_BELT];
|
struct Bandolier_Struct
|
||||||
|
{
|
||||||
|
char Name[1]; // Variable Length
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Bandolier_Struct_Old
|
||||||
|
{
|
||||||
|
char Name[32];
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PotionBeltItem_Struct
|
||||||
|
{
|
||||||
|
char Name[1]; // Variable Length
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 72
|
||||||
|
struct PotionBeltItem_Struct_Old
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PotionBelt_Struct
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PotionBelt_Struct_Old
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct_Old Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GroupLeadershipAA_Struct {
|
struct GroupLeadershipAA_Struct {
|
||||||
@ -1121,7 +1146,7 @@ union
|
|||||||
/*12949*/ uint32 aapoints; // Unspent AA points - Seen 1
|
/*12949*/ uint32 aapoints; // Unspent AA points - Seen 1
|
||||||
/*12953*/ uint16 unknown_rof20; //
|
/*12953*/ uint16 unknown_rof20; //
|
||||||
/*12955*/ uint32 bandolier_count; // Seen 20
|
/*12955*/ uint32 bandolier_count; // Seen 20
|
||||||
/*12959*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents
|
/*12959*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents
|
||||||
/*13699*/ uint32 potionbelt_count; // Seen 5
|
/*13699*/ uint32 potionbelt_count; // Seen 5
|
||||||
/*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes)
|
/*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes)
|
||||||
/*13748*/ int32 unknown_rof21; // Seen -1
|
/*13748*/ int32 unknown_rof21; // Seen -1
|
||||||
@ -3592,7 +3617,7 @@ struct Split_Struct
|
|||||||
*/
|
*/
|
||||||
struct NewCombine_Struct {
|
struct NewCombine_Struct {
|
||||||
/*00*/ ItemSlotStruct container_slot;
|
/*00*/ ItemSlotStruct container_slot;
|
||||||
/*12*/ ItemSlotStruct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8 -U)
|
/*12*/ ItemSlotStruct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8)
|
||||||
/*24*/
|
/*24*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4113,30 +4138,35 @@ struct DynamicWall_Struct {
|
|||||||
/*80*/
|
/*80*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { //bandolier actions
|
// Bandolier actions
|
||||||
BandolierCreate = 0,
|
enum
|
||||||
BandolierRemove = 1,
|
{
|
||||||
BandolierSet = 2
|
bandolierCreate = 0,
|
||||||
|
bandolierRemove,
|
||||||
|
bandolierSet
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierCreate_Struct {
|
struct BandolierCreate_Struct
|
||||||
/*00*/ uint32 action; //0 for create
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action; //0 for create
|
||||||
/*05*/ char name[32];
|
/*04*/ uint8 Number;
|
||||||
/*37*/ uint16 unknown37; //seen 0x93FD
|
/*05*/ char Name[32];
|
||||||
/*39*/ uint8 unknown39; //0
|
/*37*/ uint16 Unknown37; //seen 0x93FD
|
||||||
|
/*39*/ uint8 Unknown39; //0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierDelete_Struct {
|
struct BandolierDelete_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierSet_Struct {
|
struct BandolierSet_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arrow_Struct {
|
struct Arrow_Struct {
|
||||||
@ -4378,7 +4408,7 @@ struct RoFSlotStruct
|
|||||||
|
|
||||||
struct ItemSerializationHeader
|
struct ItemSerializationHeader
|
||||||
{
|
{
|
||||||
/*000*/ char unknown000[13]; // New for HoT. Looks like a string.
|
/*000*/ char unknown000[17]; // New for HoT. Looks like a string.
|
||||||
/*017*/ uint32 stacksize;
|
/*017*/ uint32 stacksize;
|
||||||
/*021*/ uint32 unknown004;
|
/*021*/ uint32 unknown004;
|
||||||
/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ?
|
/*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ?
|
||||||
@ -4524,7 +4554,7 @@ struct ItemSecondaryBodyStruct
|
|||||||
uint32 augtype;
|
uint32 augtype;
|
||||||
// swapped augrestrict and augdistiller positions
|
// swapped augrestrict and augdistiller positions
|
||||||
// (this swap does show the proper augment restrictions in Item Information window now)
|
// (this swap does show the proper augment restrictions in Item Information window now)
|
||||||
// unsure what the purpose of augdistiller is at this time -U 3/17/2014
|
// unsure what the purpose of augdistiller is at this time 3/17/2014
|
||||||
uint32 augdistiller; // New to December 10th 2012 client - NEW
|
uint32 augdistiller; // New to December 10th 2012 client - NEW
|
||||||
uint32 augrestrict;
|
uint32 augrestrict;
|
||||||
AugSlotStruct augslots[6];
|
AugSlotStruct augslots[6];
|
||||||
@ -4688,17 +4718,33 @@ struct AugmentInfo_Struct
|
|||||||
|
|
||||||
struct VeteranRewardItem
|
struct VeteranRewardItem
|
||||||
{
|
{
|
||||||
/*000*/ uint32 item_id;
|
/*000*/ uint32 name_length;
|
||||||
/*004*/ uint32 charges;
|
/*004*/ //char item_name[0]; // THIS IS NOT NULL TERMED
|
||||||
/*008*/ char item_name[64];
|
/*???*/ uint32 item_id;
|
||||||
|
/*???*/ uint32 charges;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VeteranRewardEntry
|
||||||
|
{
|
||||||
|
/*000*/ uint32 claim_id; // guessed
|
||||||
|
/*004*/ uint32 avaliable_count;
|
||||||
|
/*008*/ uint32 claim_count;
|
||||||
|
/*012*/ char enabled;
|
||||||
|
/*013*/ //VeteranRewardItem items[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VeteranReward
|
struct VeteranReward
|
||||||
{
|
{
|
||||||
/*000*/ uint32 claim_id;
|
/*000*/ uint32 claim_count;
|
||||||
/*004*/ uint32 number_available;
|
/*004*/ //VeteranRewardEntry entries[0];
|
||||||
/*008*/ uint32 claim_count;
|
};
|
||||||
/*012*/ VeteranRewardItem items[8];
|
|
||||||
|
struct VeteranClaim
|
||||||
|
{
|
||||||
|
/*000*/ char name[68]; //name + other data
|
||||||
|
/*068*/ uint32 claim_id;
|
||||||
|
/*072*/ uint32 unknown072;
|
||||||
|
/*076*/ uint32 action;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExpeditionEntryHeader_Struct
|
struct ExpeditionEntryHeader_Struct
|
||||||
|
|||||||
@ -1542,13 +1542,13 @@ namespace SoD
|
|||||||
OUT(beard);
|
OUT(beard);
|
||||||
// OUT(unknown00178[10]);
|
// OUT(unknown00178[10]);
|
||||||
for (r = 0; r < 9; r++) {
|
for (r = 0; r < 9; r++) {
|
||||||
eq->equipment[r].material = emu->item_material[r];
|
eq->equipment[r].Material = emu->item_material[r];
|
||||||
eq->equipment[r].unknown1 = 0;
|
eq->equipment[r].Unknown1 = 0;
|
||||||
eq->equipment[r].elitematerial = 0;
|
eq->equipment[r].EliteMaterial = 0;
|
||||||
//eq->colors[r].color = emu->colors[r].color;
|
//eq->colors[r].color = emu->colors[r].color;
|
||||||
}
|
}
|
||||||
for (r = 0; r < 7; r++) {
|
for (r = 0; r < 7; r++) {
|
||||||
OUT(item_tint[r].color);
|
OUT(item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// OUT(unknown00224[48]);
|
// OUT(unknown00224[48]);
|
||||||
//NOTE: new client supports 300 AAs, our internal rep/PP
|
//NOTE: new client supports 300 AAs, our internal rep/PP
|
||||||
@ -1606,26 +1606,46 @@ namespace SoD
|
|||||||
OUT(endurance);
|
OUT(endurance);
|
||||||
OUT(aapoints_spent);
|
OUT(aapoints_spent);
|
||||||
OUT(aapoints);
|
OUT(aapoints);
|
||||||
|
|
||||||
// OUT(unknown06160[4]);
|
// OUT(unknown06160[4]);
|
||||||
//NOTE: new client supports 20 bandoliers, our internal rep
|
|
||||||
//only supports 4..
|
// Copy bandoliers where server and client indexes converge
|
||||||
for (r = 0; r < 4; r++) {
|
for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
OUT_str(bandoliers[r].name);
|
OUT_str(bandoliers[r].Name);
|
||||||
uint32 k;
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) {
|
OUT(bandoliers[r].Items[k].ID);
|
||||||
OUT(bandoliers[r].items[k].item_id);
|
OUT(bandoliers[r].Items[k].Icon);
|
||||||
OUT(bandoliers[r].items[k].icon);
|
OUT_str(bandoliers[r].Items[k].Name);
|
||||||
OUT_str(bandoliers[r].items[k].item_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// OUT(unknown07444[5120]);
|
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||||
for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) {
|
for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
OUT(potionbelt.items[r].item_id);
|
eq->bandoliers[r].Name[0] = '\0';
|
||||||
OUT(potionbelt.items[r].icon);
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
OUT_str(potionbelt.items[r].item_name);
|
eq->bandoliers[r].Items[k].ID = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Icon = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Name[0] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OUT(unknown07444[5120]);
|
||||||
|
|
||||||
|
// Copy potion belt where server and client indexes converge
|
||||||
|
for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
OUT(potionbelt.Items[r].ID);
|
||||||
|
OUT(potionbelt.Items[r].Icon);
|
||||||
|
OUT_str(potionbelt.Items[r].Name);
|
||||||
|
}
|
||||||
|
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||||
|
for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
eq->potionbelt.Items[r].ID = 0;
|
||||||
|
eq->potionbelt.Items[r].Icon = 0;
|
||||||
|
eq->potionbelt.Items[r].Name[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// OUT(unknown12852[8]);
|
// OUT(unknown12852[8]);
|
||||||
// OUT(unknown12864[76]);
|
// OUT(unknown12864[76]);
|
||||||
|
|
||||||
OUT_str(name);
|
OUT_str(name);
|
||||||
OUT_str(last_name);
|
OUT_str(last_name);
|
||||||
OUT(guild_id);
|
OUT(guild_id);
|
||||||
@ -1891,76 +1911,95 @@ namespace SoD
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
if (emu->CharCount == 0) {
|
||||||
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
||||||
|
eq->CharCount = emu->CharCount;
|
||||||
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
int char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
int namelen = 0;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->name[char_count][0] == '\0')
|
FINISH_ENCODE();
|
||||||
break;
|
return;
|
||||||
if (strcmp(emu->name[char_count], "<none>") == 0)
|
|
||||||
break;
|
|
||||||
namelen += strlen(emu->name[char_count]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
|
size_t names_length = 0;
|
||||||
|
size_t character_count = 0;
|
||||||
|
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
|
||||||
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
|
names_length += strlen(emu_cse->Name);
|
||||||
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total_length = sizeof(structs::CharacterSelect_Struct)
|
||||||
|
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
|
||||||
|
+ names_length;
|
||||||
|
|
||||||
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
||||||
|
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
//unsigned char *eq_buffer = new unsigned char[total_length];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->char_count = char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
eq->total_chars = 10;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
eq2->level = emu->level[r];
|
|
||||||
eq2->hairstyle = emu->hairstyle[r];
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
eq2->gender = emu->gender[r];
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1);
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
eq_cse->Level = emu_cse->Level;
|
||||||
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
|
eq_cse->Gender = emu_cse->Gender;
|
||||||
|
|
||||||
|
strcpy(eq_cse->Name, emu_cse->Name);
|
||||||
|
eq_ptr += strlen(eq_cse->Name);
|
||||||
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
|
eq_cse->Face = emu_cse->Face;
|
||||||
|
|
||||||
|
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
|
||||||
|
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
|
||||||
|
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
|
||||||
|
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
|
||||||
|
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
|
||||||
}
|
}
|
||||||
//adjust for name.
|
|
||||||
bufptr += strlen(emu->name[r]);
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
{ //post-name section...
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->beard = emu->beard[r];
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
eq2->haircolor = emu->haircolor[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->face = emu->face[r];
|
eq_cse->Zone = emu_cse->Zone;
|
||||||
int k;
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->Race = emu_cse->Race;
|
||||||
eq2->equip[k].material = emu->equip[r][k].material;
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->equip[k].unknown1 = emu->equip[r][k].unknown1;
|
eq_cse->Class = emu_cse->Class;
|
||||||
eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->equip[k].color.color = emu->equip[r][k].color.color;
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
}
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->primary = emu->primary[r];
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->secondary = emu->secondary[r];
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->tutorial = emu->tutorial[r]; // was u15
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->u15 = 0xff;
|
|
||||||
eq2->deity = emu->deity[r];
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->zone = emu->zone[r];
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
eq2->u19 = 0xFF;
|
|
||||||
eq2->race = emu->race[r];
|
|
||||||
eq2->gohome = emu->gohome[r];
|
|
||||||
eq2->class_ = emu->class_[r];
|
|
||||||
eq2->eyecolor1 = emu->eyecolor1[r];
|
|
||||||
eq2->beardcolor = emu->beardcolor[r];
|
|
||||||
eq2->eyecolor2 = emu->eyecolor2[r];
|
|
||||||
eq2->drakkin_heritage = emu->drakkin_heritage[r];
|
|
||||||
eq2->drakkin_tattoo = emu->drakkin_tattoo[r];
|
|
||||||
eq2->drakkin_details = emu->drakkin_details[r];
|
|
||||||
}
|
|
||||||
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -2355,7 +2394,7 @@ namespace SoD
|
|||||||
OUT(material);
|
OUT(material);
|
||||||
OUT(unknown06);
|
OUT(unknown06);
|
||||||
OUT(elite_material);
|
OUT(elite_material);
|
||||||
OUT(color.color);
|
OUT(color.Color);
|
||||||
OUT(wear_slot_id);
|
OUT(wear_slot_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -2427,42 +2466,23 @@ namespace SoD
|
|||||||
|
|
||||||
ENCODE(OP_ZonePlayerToBind)
|
ENCODE(OP_ZonePlayerToBind)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct);
|
SETUP_VAR_ENCODE(ZonePlayerToBind_Struct);
|
||||||
|
ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name));
|
||||||
|
|
||||||
ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer;
|
__packet->SetWritePosition(0);
|
||||||
|
__packet->WriteUInt16(emu->bind_zone_id);
|
||||||
|
__packet->WriteUInt16(emu->bind_instance_id);
|
||||||
|
__packet->WriteFloat(emu->x);
|
||||||
|
__packet->WriteFloat(emu->y);
|
||||||
|
__packet->WriteFloat(emu->z);
|
||||||
|
__packet->WriteFloat(emu->heading);
|
||||||
|
__packet->WriteString(emu->zone_name);
|
||||||
|
__packet->WriteUInt8(1); // save items
|
||||||
|
__packet->WriteUInt32(0); // hp
|
||||||
|
__packet->WriteUInt32(0); // mana
|
||||||
|
__packet->WriteUInt32(0); // endurance
|
||||||
|
|
||||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
FINISH_ENCODE();
|
||||||
|
|
||||||
unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)];
|
|
||||||
structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1;
|
|
||||||
unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)];
|
|
||||||
structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2;
|
|
||||||
|
|
||||||
zph->x = zps->x;
|
|
||||||
zph->y = zps->y;
|
|
||||||
zph->z = zps->z;
|
|
||||||
zph->heading = zps->heading;
|
|
||||||
zph->bind_zone_id = zps->bind_zone_id;
|
|
||||||
zph->bind_instance_id = zps->bind_instance_id;
|
|
||||||
strcpy(zph->zone_name, zps->zone_name);
|
|
||||||
|
|
||||||
zpf->unknown021 = 1;
|
|
||||||
zpf->unknown022 = 0;
|
|
||||||
zpf->unknown023 = 0;
|
|
||||||
zpf->unknown024 = 0;
|
|
||||||
|
|
||||||
ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)));
|
|
||||||
ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct));
|
|
||||||
|
|
||||||
delete[] buffer1;
|
|
||||||
delete[] buffer2;
|
|
||||||
delete[](*p)->pBuffer;
|
|
||||||
|
|
||||||
(*p)->pBuffer = new unsigned char[ss.str().size()];
|
|
||||||
(*p)->size = ss.str().size();
|
|
||||||
|
|
||||||
memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size());
|
|
||||||
dest->FastQueuePacket(&(*p));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_ZoneServerInfo)
|
ENCODE(OP_ZoneServerInfo)
|
||||||
@ -2742,7 +2762,7 @@ namespace SoD
|
|||||||
for (k = 0; k < 9; ++k)
|
for (k = 0; k < 9; ++k)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2752,11 +2772,11 @@ namespace SoD
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
}
|
}
|
||||||
@ -2767,9 +2787,9 @@ namespace SoD
|
|||||||
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
||||||
|
|
||||||
for (k = 0; k < 9; k++) {
|
for (k = 0; k < 9; k++) {
|
||||||
Equipment[k].material = emu->equipment[k].material;
|
Equipment[k].Material = emu->equipment[k].Material;
|
||||||
Equipment[k].unknown1 = emu->equipment[k].unknown1;
|
Equipment[k].Unknown1 = emu->equipment[k].Unknown1;
|
||||||
Equipment[k].elitematerial = emu->equipment[k].elitematerial;
|
Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer += (sizeof(structs::EquipStruct) * 9);
|
Buffer += (sizeof(structs::EquipStruct) * 9);
|
||||||
@ -3484,7 +3504,7 @@ namespace SoD
|
|||||||
IN(material);
|
IN(material);
|
||||||
IN(unknown06);
|
IN(unknown06);
|
||||||
IN(elite_material);
|
IN(elite_material);
|
||||||
IN(color.color);
|
IN(color.Color);
|
||||||
IN(wear_slot_id);
|
IN(wear_slot_id);
|
||||||
emu->hero_forge_model = 0;
|
emu->hero_forge_model = 0;
|
||||||
emu->unknown18 = 0;
|
emu->unknown18 = 0;
|
||||||
|
|||||||
@ -101,6 +101,8 @@ namespace SoD {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
namespace consts {
|
||||||
|
static const size_t CHARACTER_CREATION_LIMIT = 12;
|
||||||
|
|
||||||
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
||||||
@ -174,9 +176,10 @@ namespace SoD {
|
|||||||
static const uint16 ITEM_COMMON_SIZE = 5;
|
static const uint16 ITEM_COMMON_SIZE = 5;
|
||||||
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
||||||
|
|
||||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances
|
||||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
|
||||||
static const uint32 POTION_BELT_SIZE = 5;
|
|
||||||
|
static const size_t POTION_BELT_ITEM_COUNT = 5;
|
||||||
|
|
||||||
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,54 +103,53 @@ struct AdventureInfo {
|
|||||||
*/
|
*/
|
||||||
struct Color_Struct
|
struct Color_Struct
|
||||||
{
|
{
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
uint8 Blue;
|
||||||
{
|
uint8 Green;
|
||||||
uint8 blue;
|
uint8 Red;
|
||||||
uint8 green;
|
uint8 UseTint; // if there's a tint this is FF
|
||||||
uint8 red;
|
} RGB;
|
||||||
uint8 use_tint; // if there's a tint this is FF
|
uint32 Color;
|
||||||
} rgb;
|
|
||||||
uint32 color;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharSelectEquip {
|
struct CharSelectEquip
|
||||||
//totally guessed;
|
{
|
||||||
uint32 material;
|
uint32 Material;
|
||||||
uint32 unknown1;
|
uint32 Unknown1;
|
||||||
uint32 elitematerial;
|
uint32 EliteMaterial;
|
||||||
Color_Struct color;
|
Color_Struct Color;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharacterSelectEntry_Struct {
|
struct CharacterSelectEntry_Struct
|
||||||
/*0000*/ uint8 level; //
|
{
|
||||||
/*0000*/ uint8 hairstyle; //
|
/*0000*/ uint8 Level; //
|
||||||
/*0002*/ uint8 gender; //
|
/*0000*/ uint8 HairStyle; //
|
||||||
/*0003*/ char name[1]; //variable length, edi+0
|
/*0002*/ uint8 Gender; //
|
||||||
/*0000*/ uint8 beard; //
|
/*0003*/ char Name[1]; // variable length, edi+0
|
||||||
/*0001*/ uint8 haircolor; //
|
/*0000*/ uint8 Beard; //
|
||||||
/*0000*/ uint8 face; //
|
/*0001*/ uint8 HairColor; //
|
||||||
/*0000*/ CharSelectEquip equip[9];
|
/*0000*/ uint8 Face; //
|
||||||
/*0000*/ uint32 primary; //
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint32 secondary; //
|
/*0000*/ uint32 PrimaryIDFile; //
|
||||||
/*0000*/ uint8 u15; // 0xff
|
/*0000*/ uint32 SecondaryIDFile; //
|
||||||
/*0000*/ uint32 deity; //
|
/*0000*/ uint8 Unknown15; // 0xff
|
||||||
/*0000*/ uint16 zone; //
|
/*0000*/ uint32 Deity; //
|
||||||
/*0000*/ uint16 instance;
|
/*0000*/ uint16 Zone; //
|
||||||
/*0000*/ uint8 gohome; //
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ uint8 u19; // 0xff
|
/*0000*/ uint8 GoHome; //
|
||||||
/*0000*/ uint32 race; //
|
/*0000*/ uint8 Unknown19; // 0xff
|
||||||
/*0000*/ uint8 tutorial; //
|
/*0000*/ uint32 Race; //
|
||||||
/*0000*/ uint8 class_; //
|
/*0000*/ uint8 Tutorial; //
|
||||||
/*0000*/ uint8 eyecolor1; //
|
/*0000*/ uint8 Class; //
|
||||||
/*0000*/ uint8 beardcolor; //
|
/*0000*/ uint8 EyeColor1; //
|
||||||
/*0000*/ uint8 eyecolor2; //
|
/*0000*/ uint8 BeardColor; //
|
||||||
/*0000*/ uint32 drakkin_heritage; // Drakkin Heritage
|
/*0000*/ uint8 EyeColor2; //
|
||||||
/*0000*/ uint32 drakkin_tattoo; // Drakkin Tattoo
|
/*0000*/ uint32 DrakkinHeritage; // Drakkin Heritage
|
||||||
/*0000*/ uint32 drakkin_details; // Drakkin Details (Facial Spikes)
|
/*0000*/ uint32 DrakkinTattoo; // Drakkin Tattoo
|
||||||
/*0000*/ uint8 unknown; // New field to SoD
|
/*0000*/ uint32 DrakkinDetails; // Drakkin Details (Facial Spikes)
|
||||||
|
/*0000*/ uint8 Unknown; // New field to SoD
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -158,20 +157,22 @@ struct CharacterSelectEntry_Struct {
|
|||||||
** Character Selection Struct
|
** Character Selection Struct
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct CharacterSelect_Struct {
|
struct CharacterSelect_Struct
|
||||||
/*0000*/ uint32 char_count; //number of chars in this packet
|
{
|
||||||
/*0004*/ uint32 total_chars; //total number of chars allowed?
|
/*0000*/ uint32 CharCount; //number of chars in this packet
|
||||||
/*0008*/ CharacterSelectEntry_Struct entries[0];
|
/*0004*/ uint32 TotalChars; //total number of chars allowed?
|
||||||
|
/*0008*/ CharacterSelectEntry_Struct Entries[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Visible equiptment.
|
* Visible equiptment.
|
||||||
* Size: 12 Octets
|
* Size: 12 Octets
|
||||||
*/
|
*/
|
||||||
struct EquipStruct {
|
struct EquipStruct
|
||||||
/*00*/ uint32 material;
|
{
|
||||||
/*04*/ uint32 unknown1;
|
/*00*/ uint32 Material;
|
||||||
/*08*/ uint32 elitematerial;
|
/*04*/ uint32 Unknown1;
|
||||||
|
/*08*/ uint32 EliteMaterial;
|
||||||
/*12*/
|
/*12*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -676,9 +677,6 @@ struct Disciplines_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER = 20;
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4;
|
|
||||||
static const uint32 MAX_POTIONS_IN_BELT = 5;
|
|
||||||
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
||||||
|
|
||||||
struct Tribute_Struct {
|
struct Tribute_Struct {
|
||||||
@ -686,26 +684,42 @@ struct Tribute_Struct {
|
|||||||
uint32 tier;
|
uint32 tier;
|
||||||
};
|
};
|
||||||
|
|
||||||
//len = 72
|
// Bandolier item positions
|
||||||
struct BandolierItem_Struct {
|
enum
|
||||||
uint32 item_id;
|
{
|
||||||
uint32 icon;
|
bandolierPrimary = 0,
|
||||||
char item_name[64];
|
bandolierSecondary,
|
||||||
};
|
|
||||||
|
|
||||||
//len = 320
|
|
||||||
enum { //bandolier item positions
|
|
||||||
bandolierMainHand = 0,
|
|
||||||
bandolierOffHand,
|
|
||||||
bandolierRange,
|
bandolierRange,
|
||||||
bandolierAmmo
|
bandolierAmmo
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
|
||||||
char name[32];
|
//len = 72
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
struct BandolierItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
struct PotionBelt_Struct {
|
|
||||||
BandolierItem_Struct items[MAX_POTIONS_IN_BELT];
|
//len = 320
|
||||||
|
struct Bandolier_Struct
|
||||||
|
{
|
||||||
|
char Name[32];
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 72
|
||||||
|
struct PotionBeltItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 288
|
||||||
|
struct PotionBelt_Struct
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
||||||
@ -925,7 +939,7 @@ struct PlayerProfile_Struct
|
|||||||
/*08288*/ uint32 aapoints_spent; // Number of spent AA points
|
/*08288*/ uint32 aapoints_spent; // Number of spent AA points
|
||||||
/*08292*/ uint32 aapoints; // Unspent AA points
|
/*08292*/ uint32 aapoints; // Unspent AA points
|
||||||
/*08296*/ uint8 unknown06160[4];
|
/*08296*/ uint8 unknown06160[4];
|
||||||
/*08300*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [6400] bandolier contents
|
/*08300*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents
|
||||||
/*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot
|
/*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot
|
||||||
/*15060*/ uint8 unknown12852[8];
|
/*15060*/ uint8 unknown12852[8];
|
||||||
/*15068*/ uint32 available_slots;
|
/*15068*/ uint32 available_slots;
|
||||||
@ -2357,7 +2371,7 @@ struct BookRequest_Struct {
|
|||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct Object_Struct {
|
struct Object_Struct {
|
||||||
/*00*/ uint32 linked_list_addr[2];// <Zaphod> They are, get this, prev and next, ala linked list
|
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
|
||||||
/*08*/ uint32 unknown008; // Something related to the linked list?
|
/*08*/ uint32 unknown008; // Something related to the linked list?
|
||||||
/*12*/ uint32 drop_id; // Unique object id for zone
|
/*12*/ uint32 drop_id; // Unique object id for zone
|
||||||
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
||||||
@ -2377,8 +2391,8 @@ struct Object_Struct {
|
|||||||
/*100*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
/*100*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
||||||
/*104*/
|
/*104*/
|
||||||
};
|
};
|
||||||
//<Zaphod> 01 = generic drop, 02 = armor, 19 = weapon
|
//01 = generic drop, 02 = armor, 19 = weapon
|
||||||
//[13:40] <Zaphod> and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
//[13:40] and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Click Object Struct
|
** Click Object Struct
|
||||||
@ -3686,30 +3700,35 @@ struct DynamicWall_Struct {
|
|||||||
/*80*/
|
/*80*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { //bandolier actions
|
// Bandolier actions
|
||||||
BandolierCreate = 0,
|
enum
|
||||||
BandolierRemove = 1,
|
{
|
||||||
BandolierSet = 2
|
bandolierCreate = 0,
|
||||||
|
bandolierRemove,
|
||||||
|
bandolierSet
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierCreate_Struct {
|
struct BandolierCreate_Struct
|
||||||
/*00*/ uint32 action; //0 for create
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action; //0 for create
|
||||||
/*05*/ char name[32];
|
/*04*/ uint8 Number;
|
||||||
/*37*/ uint16 unknown37; //seen 0x93FD
|
/*05*/ char Name[32];
|
||||||
/*39*/ uint8 unknown39; //0
|
/*37*/ uint16 Unknown37; //seen 0x93FD
|
||||||
|
/*39*/ uint8 Unknown39; //0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierDelete_Struct {
|
struct BandolierDelete_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierSet_Struct {
|
struct BandolierSet_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arrow_Struct {
|
struct Arrow_Struct {
|
||||||
|
|||||||
@ -1200,13 +1200,13 @@ namespace SoF
|
|||||||
OUT(beard);
|
OUT(beard);
|
||||||
// OUT(unknown00178[10]);
|
// OUT(unknown00178[10]);
|
||||||
for (r = 0; r < 9; r++) {
|
for (r = 0; r < 9; r++) {
|
||||||
eq->equipment[r].material = emu->item_material[r];
|
eq->equipment[r].Material = emu->item_material[r];
|
||||||
eq->equipment[r].unknown1 = 0;
|
eq->equipment[r].Unknown1 = 0;
|
||||||
eq->equipment[r].elitematerial = 0;
|
eq->equipment[r].EliteMaterial = 0;
|
||||||
//eq->colors[r].color = emu->colors[r].color;
|
//eq->colors[r].color = emu->colors[r].color;
|
||||||
}
|
}
|
||||||
for (r = 0; r < 7; r++) {
|
for (r = 0; r < 7; r++) {
|
||||||
OUT(item_tint[r].color);
|
OUT(item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// OUT(unknown00224[48]);
|
// OUT(unknown00224[48]);
|
||||||
//NOTE: new client supports 300 AAs, our internal rep/PP
|
//NOTE: new client supports 300 AAs, our internal rep/PP
|
||||||
@ -1264,26 +1264,46 @@ namespace SoF
|
|||||||
OUT(endurance);
|
OUT(endurance);
|
||||||
OUT(aapoints_spent);
|
OUT(aapoints_spent);
|
||||||
OUT(aapoints);
|
OUT(aapoints);
|
||||||
|
|
||||||
// OUT(unknown06160[4]);
|
// OUT(unknown06160[4]);
|
||||||
//NOTE: new client supports 20 bandoliers, our internal rep
|
|
||||||
//only supports 4..
|
// Copy bandoliers where server and client indexes converge
|
||||||
for (r = 0; r < 4; r++) {
|
for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
OUT_str(bandoliers[r].name);
|
OUT_str(bandoliers[r].Name);
|
||||||
uint32 k;
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) {
|
OUT(bandoliers[r].Items[k].ID);
|
||||||
OUT(bandoliers[r].items[k].item_id);
|
OUT(bandoliers[r].Items[k].Icon);
|
||||||
OUT(bandoliers[r].items[k].icon);
|
OUT_str(bandoliers[r].Items[k].Name);
|
||||||
OUT_str(bandoliers[r].items[k].item_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// OUT(unknown07444[5120]);
|
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||||
for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) {
|
for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
OUT(potionbelt.items[r].item_id);
|
eq->bandoliers[r].Name[0] = '\0';
|
||||||
OUT(potionbelt.items[r].icon);
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
OUT_str(potionbelt.items[r].item_name);
|
eq->bandoliers[r].Items[k].ID = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Icon = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Name[0] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OUT(unknown07444[5120]);
|
||||||
|
|
||||||
|
// Copy potion belt where server and client indexes converge
|
||||||
|
for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
OUT(potionbelt.Items[r].ID);
|
||||||
|
OUT(potionbelt.Items[r].Icon);
|
||||||
|
OUT_str(potionbelt.Items[r].Name);
|
||||||
|
}
|
||||||
|
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||||
|
for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
eq->potionbelt.Items[r].ID = 0;
|
||||||
|
eq->potionbelt.Items[r].Icon = 0;
|
||||||
|
eq->potionbelt.Items[r].Name[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// OUT(unknown12852[8]);
|
// OUT(unknown12852[8]);
|
||||||
// OUT(unknown12864[76]);
|
// OUT(unknown12864[76]);
|
||||||
|
|
||||||
OUT_str(name);
|
OUT_str(name);
|
||||||
OUT_str(last_name);
|
OUT_str(last_name);
|
||||||
OUT(guild_id);
|
OUT(guild_id);
|
||||||
@ -1550,76 +1570,95 @@ namespace SoF
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
if (emu->CharCount == 0) {
|
||||||
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
||||||
|
eq->CharCount = emu->CharCount;
|
||||||
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
int char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
int namelen = 0;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->name[char_count][0] == '\0')
|
FINISH_ENCODE();
|
||||||
break;
|
return;
|
||||||
if (strcmp(emu->name[char_count], "<none>") == 0)
|
|
||||||
break;
|
|
||||||
namelen += strlen(emu->name[char_count]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
|
size_t names_length = 0;
|
||||||
|
size_t character_count = 0;
|
||||||
|
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
|
||||||
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
|
names_length += strlen(emu_cse->Name);
|
||||||
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total_length = sizeof(structs::CharacterSelect_Struct)
|
||||||
|
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
|
||||||
|
+ names_length;
|
||||||
|
|
||||||
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
||||||
|
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
//unsigned char *eq_buffer = new unsigned char[total_length];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->char_count = char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
eq->total_chars = 10;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
eq2->level = emu->level[r];
|
|
||||||
eq2->hairstyle = emu->hairstyle[r];
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
eq2->gender = emu->gender[r];
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1);
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
eq_cse->Level = emu_cse->Level;
|
||||||
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
|
eq_cse->Gender = emu_cse->Gender;
|
||||||
|
|
||||||
|
strcpy(eq_cse->Name, emu_cse->Name);
|
||||||
|
eq_ptr += strlen(eq_cse->Name);
|
||||||
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
|
|
||||||
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
|
eq_cse->Face = emu_cse->Face;
|
||||||
|
|
||||||
|
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
|
||||||
|
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
|
||||||
|
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
|
||||||
|
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
|
||||||
|
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
|
||||||
}
|
}
|
||||||
//adjust for name.
|
|
||||||
bufptr += strlen(emu->name[r]);
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
{ //post-name section...
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->beard = emu->beard[r];
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
eq2->haircolor = emu->haircolor[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->face = emu->face[r];
|
eq_cse->Zone = emu_cse->Zone;
|
||||||
int k;
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->Race = emu_cse->Race;
|
||||||
eq2->equip[k].material = emu->equip[r][k].material;
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->equip[k].unknown1 = emu->equip[r][k].unknown1;
|
eq_cse->Class = emu_cse->Class;
|
||||||
eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->equip[k].color.color = emu->equip[r][k].color.color;
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
}
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->primary = emu->primary[r];
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->secondary = emu->secondary[r];
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->tutorial = emu->tutorial[r]; // was u15
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->u15 = 0xff;
|
|
||||||
eq2->deity = emu->deity[r];
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->zone = emu->zone[r];
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
eq2->u19 = 0xFF;
|
|
||||||
eq2->race = emu->race[r];
|
|
||||||
eq2->gohome = emu->gohome[r];
|
|
||||||
eq2->class_ = emu->class_[r];
|
|
||||||
eq2->eyecolor1 = emu->eyecolor1[r];
|
|
||||||
eq2->beardcolor = emu->beardcolor[r];
|
|
||||||
eq2->eyecolor2 = emu->eyecolor2[r];
|
|
||||||
eq2->drakkin_heritage = emu->drakkin_heritage[r];
|
|
||||||
eq2->drakkin_tattoo = emu->drakkin_tattoo[r];
|
|
||||||
eq2->drakkin_details = emu->drakkin_details[r];
|
|
||||||
}
|
|
||||||
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -1941,7 +1980,7 @@ namespace SoF
|
|||||||
OUT(material);
|
OUT(material);
|
||||||
OUT(unknown06);
|
OUT(unknown06);
|
||||||
OUT(elite_material);
|
OUT(elite_material);
|
||||||
OUT(color.color);
|
OUT(color.Color);
|
||||||
OUT(wear_slot_id);
|
OUT(wear_slot_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -1951,42 +1990,23 @@ namespace SoF
|
|||||||
|
|
||||||
ENCODE(OP_ZonePlayerToBind)
|
ENCODE(OP_ZonePlayerToBind)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct);
|
SETUP_VAR_ENCODE(ZonePlayerToBind_Struct);
|
||||||
|
ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name));
|
||||||
|
|
||||||
ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer;
|
__packet->SetWritePosition(0);
|
||||||
|
__packet->WriteUInt16(emu->bind_zone_id);
|
||||||
|
__packet->WriteUInt16(emu->bind_instance_id);
|
||||||
|
__packet->WriteFloat(emu->x);
|
||||||
|
__packet->WriteFloat(emu->y);
|
||||||
|
__packet->WriteFloat(emu->z);
|
||||||
|
__packet->WriteFloat(emu->heading);
|
||||||
|
__packet->WriteString(emu->zone_name);
|
||||||
|
__packet->WriteUInt8(1); // save items
|
||||||
|
__packet->WriteUInt32(0); // hp
|
||||||
|
__packet->WriteUInt32(0); // mana
|
||||||
|
__packet->WriteUInt32(0); // endurance
|
||||||
|
|
||||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
FINISH_ENCODE();
|
||||||
|
|
||||||
unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)];
|
|
||||||
structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1;
|
|
||||||
unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)];
|
|
||||||
structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2;
|
|
||||||
|
|
||||||
zph->x = zps->x;
|
|
||||||
zph->y = zps->y;
|
|
||||||
zph->z = zps->z;
|
|
||||||
zph->heading = zps->heading;
|
|
||||||
zph->bind_zone_id = zps->bind_zone_id;
|
|
||||||
zph->bind_instance_id = zps->bind_instance_id;
|
|
||||||
strcpy(zph->zone_name, zps->zone_name);
|
|
||||||
|
|
||||||
zpf->unknown021 = 1;
|
|
||||||
zpf->unknown022 = 0;
|
|
||||||
zpf->unknown023 = 0;
|
|
||||||
zpf->unknown024 = 0;
|
|
||||||
|
|
||||||
ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)));
|
|
||||||
ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct));
|
|
||||||
|
|
||||||
delete[] buffer1;
|
|
||||||
delete[] buffer2;
|
|
||||||
delete[](*p)->pBuffer;
|
|
||||||
|
|
||||||
(*p)->pBuffer = new unsigned char[ss.str().size()];
|
|
||||||
(*p)->size = ss.str().size();
|
|
||||||
|
|
||||||
memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size());
|
|
||||||
dest->FastQueuePacket(&(*p));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_ZoneServerInfo)
|
ENCODE(OP_ZoneServerInfo)
|
||||||
@ -2044,10 +2064,10 @@ namespace SoF
|
|||||||
eq->drakkin_heritage = emu->drakkin_heritage;
|
eq->drakkin_heritage = emu->drakkin_heritage;
|
||||||
eq->gender = emu->gender;
|
eq->gender = emu->gender;
|
||||||
for (k = 0; k < 9; k++) {
|
for (k = 0; k < 9; k++) {
|
||||||
eq->equipment[k].material = emu->equipment[k].material;
|
eq->equipment[k].Material = emu->equipment[k].Material;
|
||||||
eq->equipment[k].unknown1 = emu->equipment[k].unknown1;
|
eq->equipment[k].Unknown1 = emu->equipment[k].Unknown1;
|
||||||
eq->equipment[k].elitematerial = emu->equipment[k].elitematerial;
|
eq->equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial;
|
||||||
eq->colors[k].color = emu->colors[k].color;
|
eq->colors[k].Color = emu->colors[k].Color;
|
||||||
}
|
}
|
||||||
eq->StandState = emu->StandState;
|
eq->StandState = emu->StandState;
|
||||||
eq->guildID = emu->guildID;
|
eq->guildID = emu->guildID;
|
||||||
@ -2109,7 +2129,7 @@ namespace SoF
|
|||||||
eq->petOwnerId = emu->petOwnerId;
|
eq->petOwnerId = emu->petOwnerId;
|
||||||
eq->pvp = 0; // 0 = non-pvp colored name, 1 = red pvp name
|
eq->pvp = 0; // 0 = non-pvp colored name, 1 = red pvp name
|
||||||
for (k = 0; k < 9; k++) {
|
for (k = 0; k < 9; k++) {
|
||||||
eq->colors[k].color = emu->colors[k].color;
|
eq->colors[k].Color = emu->colors[k].Color;
|
||||||
}
|
}
|
||||||
eq->anon = emu->anon;
|
eq->anon = emu->anon;
|
||||||
eq->face = emu->face;
|
eq->face = emu->face;
|
||||||
@ -2808,7 +2828,7 @@ namespace SoF
|
|||||||
IN(material);
|
IN(material);
|
||||||
IN(unknown06);
|
IN(unknown06);
|
||||||
IN(elite_material);
|
IN(elite_material);
|
||||||
IN(color.color);
|
IN(color.Color);
|
||||||
IN(wear_slot_id);
|
IN(wear_slot_id);
|
||||||
emu->hero_forge_model = 0;
|
emu->hero_forge_model = 0;
|
||||||
emu->unknown18 = 0;
|
emu->unknown18 = 0;
|
||||||
|
|||||||
@ -101,6 +101,8 @@ namespace SoF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
namespace consts {
|
||||||
|
static const size_t CHARACTER_CREATION_LIMIT = 12;
|
||||||
|
|
||||||
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
||||||
@ -174,9 +176,10 @@ namespace SoF {
|
|||||||
static const uint16 ITEM_COMMON_SIZE = 5;
|
static const uint16 ITEM_COMMON_SIZE = 5;
|
||||||
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
||||||
|
|
||||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances
|
||||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
|
||||||
static const uint32 POTION_BELT_SIZE = 5;
|
|
||||||
|
static const size_t POTION_BELT_ITEM_COUNT = 5;
|
||||||
|
|
||||||
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,72 +103,74 @@ struct AdventureInfo {
|
|||||||
*/
|
*/
|
||||||
struct Color_Struct
|
struct Color_Struct
|
||||||
{
|
{
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
uint8 Blue;
|
||||||
{
|
uint8 Green;
|
||||||
uint8 blue;
|
uint8 Red;
|
||||||
uint8 green;
|
uint8 UseTint; // if there's a tint this is FF
|
||||||
uint8 red;
|
} RGB;
|
||||||
uint8 use_tint; // if there's a tint this is FF
|
uint32 Color;
|
||||||
} rgb;
|
|
||||||
uint32 color;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharSelectEquip {
|
struct CharSelectEquip
|
||||||
uint32 material;
|
{
|
||||||
uint32 unknown1;
|
uint32 Material;
|
||||||
uint32 elitematerial;
|
uint32 Unknown1;
|
||||||
Color_Struct color;
|
uint32 EliteMaterial;
|
||||||
|
Color_Struct Color;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharacterSelectEntry_Struct {
|
struct CharacterSelectEntry_Struct
|
||||||
/*0000*/ uint8 level; //
|
{
|
||||||
/*0000*/ uint8 hairstyle; //
|
/*0000*/ uint8 Level; //
|
||||||
/*0002*/ uint8 gender; //
|
/*0000*/ uint8 HairStyle; //
|
||||||
/*0003*/ char name[1]; //variable length, edi+0
|
/*0002*/ uint8 Gender; //
|
||||||
/*0000*/ uint8 beard; //
|
/*0003*/ char Name[1]; // variable length, edi+0
|
||||||
/*0001*/ uint8 haircolor; //
|
/*0000*/ uint8 Beard; //
|
||||||
/*0000*/ uint8 face; //
|
/*0001*/ uint8 HairColor; //
|
||||||
/*0000*/ CharSelectEquip equip[9];
|
/*0000*/ uint8 Face; //
|
||||||
/*0000*/ uint32 primary; //
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint32 secondary; //
|
/*0000*/ uint32 PrimaryIDFile; //
|
||||||
/*0000*/ uint8 u15; // 0xff
|
/*0000*/ uint32 SecondaryIDFile; //
|
||||||
/*0000*/ uint32 deity; //
|
/*0000*/ uint8 Unknown15; // 0xff
|
||||||
/*0000*/ uint16 zone; //
|
/*0000*/ uint32 Deity; //
|
||||||
/*0000*/ uint16 instance;
|
/*0000*/ uint16 Zone; //
|
||||||
/*0000*/ uint8 gohome; //
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ uint8 u19; // 0xff
|
/*0000*/ uint8 GoHome; //
|
||||||
/*0000*/ uint32 race; //
|
/*0000*/ uint8 Unknown19; // 0xff
|
||||||
/*0000*/ uint8 tutorial; //
|
/*0000*/ uint32 Race; //
|
||||||
/*0000*/ uint8 class_; //
|
/*0000*/ uint8 Tutorial; //
|
||||||
/*0000*/ uint8 eyecolor1; //
|
/*0000*/ uint8 Class; //
|
||||||
/*0000*/ uint8 beardcolor; //
|
/*0000*/ uint8 EyeColor1; //
|
||||||
/*0000*/ uint8 eyecolor2; //
|
/*0000*/ uint8 BeardColor; //
|
||||||
/*0000*/ uint32 drakkin_heritage; // Drakkin Heritage
|
/*0000*/ uint8 EyeColor2; //
|
||||||
/*0000*/ uint32 drakkin_tattoo; // Drakkin Tattoo
|
/*0000*/ uint32 DrakkinHeritage; // Drakkin Heritage
|
||||||
/*0000*/ uint32 drakkin_details; // Drakkin Details (Facial Spikes)
|
/*0000*/ uint32 DrakkinTattoo; // Drakkin Tattoo
|
||||||
|
/*0000*/ uint32 DrakkinDetails; // Drakkin Details (Facial Spikes)
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Character Selection Struct
|
** Character Selection Struct
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct CharacterSelect_Struct {
|
struct CharacterSelect_Struct
|
||||||
/*0000*/ uint32 char_count; //number of chars in this packet
|
{
|
||||||
/*0004*/ uint32 total_chars; //total number of chars allowed?
|
/*0000*/ uint32 CharCount; //number of chars in this packet
|
||||||
/*0008*/ CharacterSelectEntry_Struct entries[0];
|
/*0004*/ uint32 TotalChars; //total number of chars allowed?
|
||||||
|
/*0008*/ CharacterSelectEntry_Struct Entries[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Visible equiptment.
|
* Visible equiptment.
|
||||||
* Size: 12 Octets
|
* Size: 12 Octets
|
||||||
*/
|
*/
|
||||||
struct EquipStruct {
|
struct EquipStruct
|
||||||
/*00*/ uint32 material;
|
{
|
||||||
/*04*/ uint32 unknown1;
|
/*00*/ uint32 Material;
|
||||||
/*08*/ uint32 elitematerial;
|
/*04*/ uint32 Unknown1;
|
||||||
|
/*08*/ uint32 EliteMaterial;
|
||||||
/*12*/
|
/*12*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -653,9 +655,6 @@ struct Disciplines_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER = 20;
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4;
|
|
||||||
static const uint32 MAX_POTIONS_IN_BELT = 5;
|
|
||||||
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
||||||
|
|
||||||
struct Tribute_Struct {
|
struct Tribute_Struct {
|
||||||
@ -663,26 +662,42 @@ struct Tribute_Struct {
|
|||||||
uint32 tier;
|
uint32 tier;
|
||||||
};
|
};
|
||||||
|
|
||||||
//len = 72
|
// Bandolier item positions
|
||||||
struct BandolierItem_Struct {
|
enum
|
||||||
uint32 item_id;
|
{
|
||||||
uint32 icon;
|
bandolierPrimary = 0,
|
||||||
char item_name[64];
|
bandolierSecondary,
|
||||||
};
|
|
||||||
|
|
||||||
//len = 320
|
|
||||||
enum { //bandolier item positions
|
|
||||||
bandolierMainHand = 0,
|
|
||||||
bandolierOffHand,
|
|
||||||
bandolierRange,
|
bandolierRange,
|
||||||
bandolierAmmo
|
bandolierAmmo
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
|
||||||
char name[32];
|
//len = 72
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
struct BandolierItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
struct PotionBelt_Struct {
|
|
||||||
BandolierItem_Struct items[MAX_POTIONS_IN_BELT];
|
//len = 320
|
||||||
|
struct Bandolier_Struct
|
||||||
|
{
|
||||||
|
char Name[32];
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 72
|
||||||
|
struct PotionBeltItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 288
|
||||||
|
struct PotionBelt_Struct
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
||||||
@ -901,7 +916,7 @@ struct PlayerProfile_Struct //23576 Octets
|
|||||||
/*08288*/ uint32 aapoints_spent; // Number of spent AA points
|
/*08288*/ uint32 aapoints_spent; // Number of spent AA points
|
||||||
/*08292*/ uint32 aapoints; // Unspent AA points
|
/*08292*/ uint32 aapoints; // Unspent AA points
|
||||||
/*08296*/ uint8 unknown06160[4];
|
/*08296*/ uint8 unknown06160[4];
|
||||||
/*08300*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [6400] bandolier contents
|
/*08300*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents
|
||||||
/*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot
|
/*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot
|
||||||
/*15060*/ uint8 unknown12852[8];
|
/*15060*/ uint8 unknown12852[8];
|
||||||
/*15068*/ uint32 available_slots;
|
/*15068*/ uint32 available_slots;
|
||||||
@ -2290,7 +2305,7 @@ struct BookRequest_Struct {
|
|||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct Object_Struct {
|
struct Object_Struct {
|
||||||
/*00*/ uint32 linked_list_addr[2];// <Zaphod> They are, get this, prev and next, ala linked list
|
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
|
||||||
/*08*/ uint32 unknown008; // Something related to the linked list?
|
/*08*/ uint32 unknown008; // Something related to the linked list?
|
||||||
/*12*/ uint32 drop_id; // Unique object id for zone
|
/*12*/ uint32 drop_id; // Unique object id for zone
|
||||||
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
||||||
@ -2310,8 +2325,8 @@ struct Object_Struct {
|
|||||||
/*100*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
/*100*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
||||||
/*104*/
|
/*104*/
|
||||||
};
|
};
|
||||||
//<Zaphod> 01 = generic drop, 02 = armor, 19 = weapon
|
//01 = generic drop, 02 = armor, 19 = weapon
|
||||||
//[13:40] <Zaphod> and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
//[13:40] and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Click Object Struct
|
** Click Object Struct
|
||||||
@ -3548,30 +3563,35 @@ struct DynamicWall_Struct {
|
|||||||
/*80*/
|
/*80*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { //bandolier actions
|
// Bandolier actions
|
||||||
BandolierCreate = 0,
|
enum
|
||||||
BandolierRemove = 1,
|
{
|
||||||
BandolierSet = 2
|
bandolierCreate = 0,
|
||||||
|
bandolierRemove,
|
||||||
|
bandolierSet
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierCreate_Struct {
|
struct BandolierCreate_Struct
|
||||||
/*00*/ uint32 action; //0 for create
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action; //0 for create
|
||||||
/*05*/ char name[32];
|
/*04*/ uint8 Number;
|
||||||
/*37*/ uint16 unknown37; //seen 0x93FD
|
/*05*/ char Name[32];
|
||||||
/*39*/ uint8 unknown39; //0
|
/*37*/ uint16 Unknown37; //seen 0x93FD
|
||||||
|
/*39*/ uint8 Unknown39; //0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierDelete_Struct {
|
struct BandolierDelete_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierSet_Struct {
|
struct BandolierSet_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arrow_Struct {
|
struct Arrow_Struct {
|
||||||
|
|||||||
@ -41,6 +41,11 @@
|
|||||||
memset(__packet->pBuffer, 0, len); \
|
memset(__packet->pBuffer, 0, len); \
|
||||||
eq_struct *eq = (eq_struct *) __packet->pBuffer; \
|
eq_struct *eq = (eq_struct *) __packet->pBuffer; \
|
||||||
|
|
||||||
|
#define ALLOC_LEN_ENCODE(len) \
|
||||||
|
__packet->pBuffer = new unsigned char[len]; \
|
||||||
|
__packet->size = len; \
|
||||||
|
memset(__packet->pBuffer, 0, len); \
|
||||||
|
|
||||||
//a shorter assignment for direct mode
|
//a shorter assignment for direct mode
|
||||||
#undef OUT
|
#undef OUT
|
||||||
#define OUT(x) eq->x = emu->x;
|
#define OUT(x) eq->x = emu->x;
|
||||||
@ -124,14 +129,14 @@
|
|||||||
//check length of packet before decoding. Call before setup.
|
//check length of packet before decoding. Call before setup.
|
||||||
#define DECODE_LENGTH_EXACT(struct_) \
|
#define DECODE_LENGTH_EXACT(struct_) \
|
||||||
if(__packet->size != sizeof(struct_)) { \
|
if(__packet->size != sizeof(struct_)) { \
|
||||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \
|
|
||||||
Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
||||||
|
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
#define DECODE_LENGTH_ATLEAST(struct_) \
|
#define DECODE_LENGTH_ATLEAST(struct_) \
|
||||||
if(__packet->size < sizeof(struct_)) { \
|
if(__packet->size < sizeof(struct_)) { \
|
||||||
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \
|
|
||||||
Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected at least %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected at least %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \
|
||||||
|
__packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -865,7 +865,7 @@ namespace Titanium
|
|||||||
// OUT(unknown00178[10]);
|
// OUT(unknown00178[10]);
|
||||||
for (r = 0; r < 9; r++) {
|
for (r = 0; r < 9; r++) {
|
||||||
OUT(item_material[r]);
|
OUT(item_material[r]);
|
||||||
OUT(item_tint[r].color);
|
OUT(item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// OUT(unknown00224[48]);
|
// OUT(unknown00224[48]);
|
||||||
for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) {
|
for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) {
|
||||||
@ -922,24 +922,46 @@ namespace Titanium
|
|||||||
OUT(endurance);
|
OUT(endurance);
|
||||||
OUT(aapoints_spent);
|
OUT(aapoints_spent);
|
||||||
OUT(aapoints);
|
OUT(aapoints);
|
||||||
|
|
||||||
// OUT(unknown06160[4]);
|
// OUT(unknown06160[4]);
|
||||||
for (r = 0; r < structs::MAX_PLAYER_BANDOLIER; r++) {
|
|
||||||
OUT_str(bandoliers[r].name);
|
// Copy bandoliers where server and client indexes converge
|
||||||
uint32 k;
|
for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) {
|
OUT_str(bandoliers[r].Name);
|
||||||
OUT(bandoliers[r].items[k].item_id);
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
OUT(bandoliers[r].items[k].icon);
|
OUT(bandoliers[r].Items[k].ID);
|
||||||
OUT_str(bandoliers[r].items[k].item_name);
|
OUT(bandoliers[r].Items[k].Icon);
|
||||||
|
OUT_str(bandoliers[r].Items[k].Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// OUT(unknown07444[5120]);
|
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||||
for (r = 0; r < structs::MAX_PLAYER_BANDOLIER_ITEMS; r++) {
|
for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
OUT(potionbelt.items[r].item_id);
|
eq->bandoliers[r].Name[0] = '\0';
|
||||||
OUT(potionbelt.items[r].icon);
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
OUT_str(potionbelt.items[r].item_name);
|
eq->bandoliers[r].Items[k].ID = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Icon = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Name[0] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OUT(unknown07444[5120]);
|
||||||
|
|
||||||
|
// Copy potion belt where server and client indexes converge
|
||||||
|
for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
OUT(potionbelt.Items[r].ID);
|
||||||
|
OUT(potionbelt.Items[r].Icon);
|
||||||
|
OUT_str(potionbelt.Items[r].Name);
|
||||||
|
}
|
||||||
|
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||||
|
for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
eq->potionbelt.Items[r].ID = 0;
|
||||||
|
eq->potionbelt.Items[r].Icon = 0;
|
||||||
|
eq->potionbelt.Items[r].Name[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// OUT(unknown12852[8]);
|
// OUT(unknown12852[8]);
|
||||||
// OUT(unknown12864[76]);
|
// OUT(unknown12864[76]);
|
||||||
|
|
||||||
OUT_str(name);
|
OUT_str(name);
|
||||||
OUT_str(last_name);
|
OUT_str(last_name);
|
||||||
OUT(guild_id);
|
OUT(guild_id);
|
||||||
@ -1048,7 +1070,7 @@ namespace Titanium
|
|||||||
|
|
||||||
ENCODE(OP_ReadBook)
|
ENCODE(OP_ReadBook)
|
||||||
{
|
{
|
||||||
// no apparent slot translation needed -U
|
// no apparent slot translation needed
|
||||||
EQApplicationPacket *in = *p;
|
EQApplicationPacket *in = *p;
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
|
|
||||||
@ -1133,39 +1155,98 @@ namespace Titanium
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_DIRECT_ENCODE(CharacterSelect_Struct, structs::CharacterSelect_Struct);
|
SETUP_DIRECT_ENCODE(CharacterSelect_Struct, structs::CharacterSelect_Struct);
|
||||||
|
|
||||||
int r;
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
for (r = 0; r < 10; r++) {
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
OUT(zone[r]);
|
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
|
||||||
OUT(eyecolor1[r]);
|
|
||||||
OUT(eyecolor2[r]);
|
for (size_t index = 0; index < 10; ++index) {
|
||||||
OUT(hairstyle[r]);
|
memset(eq->Name[index], 0, 64);
|
||||||
OUT(primary[r]);
|
}
|
||||||
if (emu->race[r] > 473)
|
|
||||||
eq->race[r] = 1;
|
// Non character-indexed packet fields
|
||||||
else
|
eq->Unknown830[0] = 0;
|
||||||
eq->race[r] = emu->race[r];
|
eq->Unknown830[1] = 0;
|
||||||
OUT(class_[r]);
|
eq->Unknown0962[0] = 0;
|
||||||
OUT_str(name[r]);
|
eq->Unknown0962[1] = 0;
|
||||||
OUT(gender[r]);
|
|
||||||
OUT(level[r]);
|
size_t char_index = 0;
|
||||||
OUT(secondary[r]);
|
for (; char_index < emu->CharCount && char_index < 8; ++char_index) {
|
||||||
OUT(face[r]);
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
OUT(beard[r]);
|
|
||||||
int k;
|
eq->Race[char_index] = emu_cse->Race;
|
||||||
for (k = 0; k < 9; k++) {
|
if (eq->Race[char_index] > 473)
|
||||||
eq->equip[r][k] = emu->equip[r][k].material;
|
eq->Race[char_index] = 1;
|
||||||
eq->cs_colors[r][k].color = emu->equip[r][k].color.color;
|
|
||||||
|
for (int index = 0; index < _MaterialCount; ++index) {
|
||||||
|
eq->CS_Colors[char_index][index].Color = emu_cse->Equip[index].Color.Color;
|
||||||
}
|
}
|
||||||
OUT(haircolor[r]);
|
|
||||||
OUT(gohome[r]);
|
eq->BeardColor[char_index] = emu_cse->BeardColor;
|
||||||
OUT(tutorial[r]);
|
eq->HairStyle[char_index] = emu_cse->HairStyle;
|
||||||
OUT(deity[r]);
|
|
||||||
OUT(beardcolor[r]);
|
for (int index = 0; index < _MaterialCount; ++index) {
|
||||||
eq->unknown820[r] = 0xFF;
|
eq->Equip[char_index][index] = emu_cse->Equip[index].Material;
|
||||||
eq->unknown902[r] = 0xFF;
|
}
|
||||||
|
|
||||||
|
eq->SecondaryIDFile[char_index] = emu_cse->SecondaryIDFile;
|
||||||
|
eq->Unknown820[char_index] = (uint8)0xFF;
|
||||||
|
eq->Deity[char_index] = emu_cse->Deity;
|
||||||
|
eq->GoHome[char_index] = emu_cse->GoHome;
|
||||||
|
eq->Tutorial[char_index] = emu_cse->Tutorial;
|
||||||
|
eq->Beard[char_index] = emu_cse->Beard;
|
||||||
|
eq->Unknown902[char_index] = (uint8)0xFF;
|
||||||
|
eq->PrimaryIDFile[char_index] = emu_cse->PrimaryIDFile;
|
||||||
|
eq->HairColor[char_index] = emu_cse->HairColor;
|
||||||
|
eq->Zone[char_index] = emu_cse->Zone;
|
||||||
|
eq->Class[char_index] = emu_cse->Class;
|
||||||
|
eq->Face[char_index] = emu_cse->Face;
|
||||||
|
|
||||||
|
memcpy(eq->Name[char_index], emu_cse->Name, 64);
|
||||||
|
|
||||||
|
eq->Gender[char_index] = emu_cse->Gender;
|
||||||
|
eq->EyeColor1[char_index] = emu_cse->EyeColor1;
|
||||||
|
eq->EyeColor2[char_index] = emu_cse->EyeColor2;
|
||||||
|
eq->Level[char_index] = emu_cse->Level;
|
||||||
|
|
||||||
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; char_index < 10; ++char_index) {
|
||||||
|
eq->Race[char_index] = 0;
|
||||||
|
|
||||||
|
for (int index = 0; index < _MaterialCount; ++index) {
|
||||||
|
eq->CS_Colors[char_index][index].Color = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
eq->BeardColor[char_index] = 0;
|
||||||
|
eq->HairStyle[char_index] = 0;
|
||||||
|
|
||||||
|
for (int index = 0; index < _MaterialCount; ++index) {
|
||||||
|
eq->Equip[char_index][index] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
eq->SecondaryIDFile[char_index] = 0;
|
||||||
|
eq->Unknown820[char_index] = (uint8)0xFF;
|
||||||
|
eq->Deity[char_index] = 0;
|
||||||
|
eq->GoHome[char_index] = 0;
|
||||||
|
eq->Tutorial[char_index] = 0;
|
||||||
|
eq->Beard[char_index] = 0;
|
||||||
|
eq->Unknown902[char_index] = (uint8)0xFF;
|
||||||
|
eq->PrimaryIDFile[char_index] = 0;
|
||||||
|
eq->HairColor[char_index] = 0;
|
||||||
|
eq->Zone[char_index] = 0;
|
||||||
|
eq->Class[char_index] = 0;
|
||||||
|
eq->Face[char_index] = 0;
|
||||||
|
|
||||||
|
strncpy(eq->Name[char_index], "<none>", 6);
|
||||||
|
|
||||||
|
eq->Gender[char_index] = 0;
|
||||||
|
eq->EyeColor1[char_index] = 0;
|
||||||
|
eq->EyeColor2[char_index] = 0;
|
||||||
|
eq->Level[char_index] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -1383,7 +1464,7 @@ namespace Titanium
|
|||||||
|
|
||||||
OUT(spawn_id);
|
OUT(spawn_id);
|
||||||
OUT(material);
|
OUT(material);
|
||||||
OUT(color.color);
|
OUT(color.Color);
|
||||||
OUT(wear_slot_id);
|
OUT(wear_slot_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -1475,8 +1556,8 @@ namespace Titanium
|
|||||||
eq->guildrank = emu->guildrank;
|
eq->guildrank = emu->guildrank;
|
||||||
// eq->unknown0194[3] = emu->unknown0194[3];
|
// eq->unknown0194[3] = emu->unknown0194[3];
|
||||||
for (k = 0; k < 9; k++) {
|
for (k = 0; k < 9; k++) {
|
||||||
eq->equipment[k] = emu->equipment[k].material;
|
eq->equipment[k] = emu->equipment[k].Material;
|
||||||
eq->colors[k].color = emu->colors[k].color;
|
eq->colors[k].Color = emu->colors[k].Color;
|
||||||
}
|
}
|
||||||
for (k = 0; k < 8; k++) {
|
for (k = 0; k < 8; k++) {
|
||||||
eq->set_to_0xFF[k] = 0xFF;
|
eq->set_to_0xFF[k] = 0xFF;
|
||||||
@ -1868,7 +1949,7 @@ namespace Titanium
|
|||||||
|
|
||||||
DECODE(OP_ReadBook)
|
DECODE(OP_ReadBook)
|
||||||
{
|
{
|
||||||
// no apparent slot translation needed -U
|
// no apparent slot translation needed
|
||||||
DECODE_LENGTH_ATLEAST(structs::BookRequest_Struct);
|
DECODE_LENGTH_ATLEAST(structs::BookRequest_Struct);
|
||||||
SETUP_DIRECT_DECODE(BookRequest_Struct, structs::BookRequest_Struct);
|
SETUP_DIRECT_DECODE(BookRequest_Struct, structs::BookRequest_Struct);
|
||||||
|
|
||||||
@ -1952,7 +2033,7 @@ namespace Titanium
|
|||||||
|
|
||||||
IN(spawn_id);
|
IN(spawn_id);
|
||||||
IN(material);
|
IN(material);
|
||||||
IN(color.color);
|
IN(color.Color);
|
||||||
IN(wear_slot_id);
|
IN(wear_slot_id);
|
||||||
emu->unknown06 = 0;
|
emu->unknown06 = 0;
|
||||||
emu->elite_material = 0;
|
emu->elite_material = 0;
|
||||||
|
|||||||
@ -100,6 +100,8 @@ namespace Titanium {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
namespace consts {
|
||||||
|
static const size_t CHARACTER_CREATION_LIMIT = 8; // Hard-coded in client - DO NOT ALTER
|
||||||
|
|
||||||
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 16;
|
static const uint16 MAP_BANK_SIZE = 16;
|
||||||
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
||||||
@ -173,9 +175,10 @@ namespace Titanium {
|
|||||||
static const uint16 ITEM_COMMON_SIZE = 5;
|
static const uint16 ITEM_COMMON_SIZE = 5;
|
||||||
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
||||||
|
|
||||||
static const uint32 BANDOLIERS_COUNT = 4; // count = number of bandolier instances
|
static const size_t BANDOLIERS_SIZE = 4; // number of bandolier instances
|
||||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
|
||||||
static const uint32 POTION_BELT_SIZE = 4;
|
|
||||||
|
static const size_t POTION_BELT_ITEM_COUNT = 4;
|
||||||
|
|
||||||
static const size_t TEXT_LINK_BODY_LENGTH = 45;
|
static const size_t TEXT_LINK_BODY_LENGTH = 45;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,16 +99,14 @@ struct AdventureInfo {
|
|||||||
*/
|
*/
|
||||||
struct Color_Struct
|
struct Color_Struct
|
||||||
{
|
{
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
uint8 Blue;
|
||||||
{
|
uint8 Green;
|
||||||
uint8 blue;
|
uint8 Red;
|
||||||
uint8 green;
|
uint8 UseTint; // if there's a tint this is FF
|
||||||
uint8 red;
|
} RGB;
|
||||||
uint8 use_tint; // if there's a tint this is FF
|
uint32 Color;
|
||||||
} rgb;
|
|
||||||
uint32 color;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,31 +115,32 @@ struct Color_Struct
|
|||||||
** Length: 1704 Bytes
|
** Length: 1704 Bytes
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct CharacterSelect_Struct {
|
struct CharacterSelect_Struct
|
||||||
/*0000*/ uint32 race[10]; // Characters Race
|
{
|
||||||
/*0040*/ Color_Struct cs_colors[10][9]; // Characters Equipment Colors
|
/*0000*/ uint32 Race[10]; // Characters Race
|
||||||
/*0400*/ uint8 beardcolor[10]; // Characters beard Color
|
/*0040*/ Color_Struct CS_Colors[10][9]; // Characters Equipment Colors
|
||||||
/*0410*/ uint8 hairstyle[10]; // Characters hair style
|
/*0400*/ uint8 BeardColor[10]; // Characters beard Color
|
||||||
/*0420*/ uint32 equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be)
|
/*0410*/ uint8 HairStyle[10]; // Characters hair style
|
||||||
/*0780*/ uint32 secondary[10]; // Characters secondary IDFile number
|
/*0420*/ uint32 Equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be)
|
||||||
/*0820*/ uint8 unknown820[10]; // 10x ff
|
/*0780*/ uint32 SecondaryIDFile[10]; // Characters secondary IDFile number
|
||||||
/*0830*/ uint8 unknown830[2]; // 2x 00
|
/*0820*/ uint8 Unknown820[10]; // 10x ff
|
||||||
/*0832*/ uint32 deity[10]; // Characters Deity
|
/*0830*/ uint8 Unknown830[2]; // 2x 00
|
||||||
/*0872*/ uint8 gohome[10]; // 1=Go Home available, 0=not
|
/*0832*/ uint32 Deity[10]; // Characters Deity
|
||||||
/*0882*/ uint8 tutorial[10]; // 1=Tutorial available, 0=not
|
/*0872*/ uint8 GoHome[10]; // 1=Go Home available, 0=not
|
||||||
/*0892*/ uint8 beard[10]; // Characters Beard Type
|
/*0882*/ uint8 Tutorial[10]; // 1=Tutorial available, 0=not
|
||||||
/*0902*/ uint8 unknown902[10]; // 10x ff
|
/*0892*/ uint8 Beard[10]; // Characters Beard Type
|
||||||
/*0912*/ uint32 primary[10]; // Characters primary IDFile number
|
/*0902*/ uint8 Unknown902[10]; // 10x ff
|
||||||
/*0952*/ uint8 haircolor[10]; // Characters Hair Color
|
/*0912*/ uint32 PrimaryIDFile[10]; // Characters primary IDFile number
|
||||||
/*0962*/ uint8 unknown0962[2]; // 2x 00
|
/*0952*/ uint8 HairColor[10]; // Characters Hair Color
|
||||||
/*0964*/ uint32 zone[10]; // Characters Current Zone
|
/*0962*/ uint8 Unknown0962[2]; // 2x 00
|
||||||
/*1004*/ uint8 class_[10]; // Characters Classes
|
/*0964*/ uint32 Zone[10]; // Characters Current Zone
|
||||||
/*1014*/ uint8 face[10]; // Characters Face Type
|
/*1004*/ uint8 Class[10]; // Characters Classes
|
||||||
/*1024*/ char name[10][64]; // Characters Names
|
/*1014*/ uint8 Face[10]; // Characters Face Type
|
||||||
/*1664*/ uint8 gender[10]; // Characters Gender
|
/*1024*/ char Name[10][64]; // Characters Names
|
||||||
/*1674*/ uint8 eyecolor1[10]; // Characters Eye Color
|
/*1664*/ uint8 Gender[10]; // Characters Gender
|
||||||
/*1684*/ uint8 eyecolor2[10]; // Characters Eye 2 Color
|
/*1674*/ uint8 EyeColor1[10]; // Characters Eye Color
|
||||||
/*1694*/ uint8 level[10]; // Characters Levels
|
/*1684*/ uint8 EyeColor2[10]; // Characters Eye 2 Color
|
||||||
|
/*1694*/ uint8 Level[10]; // Characters Levels
|
||||||
/*1704*/
|
/*1704*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -586,34 +585,48 @@ struct Disciplines_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER = 4;
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4;
|
|
||||||
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
||||||
struct Tribute_Struct {
|
struct Tribute_Struct {
|
||||||
uint32 tribute;
|
uint32 tribute;
|
||||||
uint32 tier;
|
uint32 tier;
|
||||||
};
|
};
|
||||||
|
|
||||||
//len = 72
|
// Bandolier item positions
|
||||||
struct BandolierItem_Struct {
|
enum
|
||||||
uint32 item_id;
|
{
|
||||||
uint32 icon;
|
bandolierPrimary = 0,
|
||||||
char item_name[64];
|
bandolierSecondary,
|
||||||
};
|
|
||||||
|
|
||||||
//len = 320
|
|
||||||
enum { //bandolier item positions
|
|
||||||
bandolierMainHand = 0,
|
|
||||||
bandolierOffHand,
|
|
||||||
bandolierRange,
|
bandolierRange,
|
||||||
bandolierAmmo
|
bandolierAmmo
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
|
||||||
char name[32];
|
//len = 72
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
struct BandolierItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
struct PotionBelt_Struct {
|
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
//len = 320
|
||||||
|
struct Bandolier_Struct
|
||||||
|
{
|
||||||
|
char Name[32];
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 72
|
||||||
|
struct PotionBeltItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 288
|
||||||
|
struct PotionBelt_Struct
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
||||||
@ -817,7 +830,7 @@ struct PlayerProfile_Struct
|
|||||||
/*06152*/ uint32 aapoints_spent; // Number of spent AA points
|
/*06152*/ uint32 aapoints_spent; // Number of spent AA points
|
||||||
/*06156*/ uint32 aapoints; // Unspent AA points
|
/*06156*/ uint32 aapoints; // Unspent AA points
|
||||||
/*06160*/ uint8 unknown06160[4];
|
/*06160*/ uint8 unknown06160[4];
|
||||||
/*06164*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // bandolier contents
|
/*06164*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // bandolier contents
|
||||||
/*07444*/ uint8 unknown07444[5120];
|
/*07444*/ uint8 unknown07444[5120];
|
||||||
/*12564*/ PotionBelt_Struct potionbelt; // potion belt
|
/*12564*/ PotionBelt_Struct potionbelt; // potion belt
|
||||||
/*12852*/ uint8 unknown12852[8];
|
/*12852*/ uint8 unknown12852[8];
|
||||||
@ -1997,7 +2010,7 @@ struct BookRequest_Struct {
|
|||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct Object_Struct {
|
struct Object_Struct {
|
||||||
/*00*/ uint32 linked_list_addr[2];// <Zaphod> They are, get this, prev and next, ala linked list
|
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
|
||||||
/*08*/ uint16 unknown008[2]; //
|
/*08*/ uint16 unknown008[2]; //
|
||||||
/*12*/ uint32 drop_id; // Unique object id for zone
|
/*12*/ uint32 drop_id; // Unique object id for zone
|
||||||
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
||||||
@ -2016,8 +2029,8 @@ struct Object_Struct {
|
|||||||
/*88*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
/*88*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
||||||
/*92*/
|
/*92*/
|
||||||
};
|
};
|
||||||
//<Zaphod> 01 = generic drop, 02 = armor, 19 = weapon
|
//01 = generic drop, 02 = armor, 19 = weapon
|
||||||
//[13:40] <Zaphod> and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
//[13:40] and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Click Object Struct
|
** Click Object Struct
|
||||||
@ -3030,30 +3043,35 @@ struct DynamicWall_Struct {
|
|||||||
/*80*/
|
/*80*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { //bandolier actions
|
// Bandolier actions
|
||||||
BandolierCreate = 0,
|
enum
|
||||||
BandolierRemove = 1,
|
{
|
||||||
BandolierSet = 2
|
bandolierCreate = 0,
|
||||||
|
bandolierRemove,
|
||||||
|
bandolierSet
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierCreate_Struct {
|
struct BandolierCreate_Struct
|
||||||
/*00*/ uint32 action; //0 for create
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action; //0 for create
|
||||||
/*05*/ char name[32];
|
/*04*/ uint8 Number;
|
||||||
/*37*/ uint16 unknown37; //seen 0x93FD
|
/*05*/ char Name[32];
|
||||||
/*39*/ uint8 unknown39; //0
|
/*37*/ uint16 Unknown37; //seen 0x93FD
|
||||||
|
/*39*/ uint8 Unknown39; //0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierDelete_Struct {
|
struct BandolierDelete_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierSet_Struct {
|
struct BandolierSet_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arrow_Struct {
|
struct Arrow_Struct {
|
||||||
|
|||||||
@ -1791,13 +1791,13 @@ namespace UF
|
|||||||
OUT(beard);
|
OUT(beard);
|
||||||
// OUT(unknown00178[10]);
|
// OUT(unknown00178[10]);
|
||||||
for (r = 0; r < 9; r++) {
|
for (r = 0; r < 9; r++) {
|
||||||
eq->equipment[r].material = emu->item_material[r];
|
eq->equipment[r].Material = emu->item_material[r];
|
||||||
eq->equipment[r].unknown1 = 0;
|
eq->equipment[r].Unknown1 = 0;
|
||||||
eq->equipment[r].elitematerial = 0;
|
eq->equipment[r].EliteMaterial = 0;
|
||||||
//eq->colors[r].color = emu->colors[r].color;
|
//eq->colors[r].color = emu->colors[r].color;
|
||||||
}
|
}
|
||||||
for (r = 0; r < 7; r++) {
|
for (r = 0; r < 7; r++) {
|
||||||
OUT(item_tint[r].color);
|
OUT(item_tint[r].Color);
|
||||||
}
|
}
|
||||||
// OUT(unknown00224[48]);
|
// OUT(unknown00224[48]);
|
||||||
//NOTE: new client supports 300 AAs, our internal rep/PP
|
//NOTE: new client supports 300 AAs, our internal rep/PP
|
||||||
@ -1868,26 +1868,46 @@ namespace UF
|
|||||||
OUT(endurance);
|
OUT(endurance);
|
||||||
OUT(aapoints_spent);
|
OUT(aapoints_spent);
|
||||||
OUT(aapoints);
|
OUT(aapoints);
|
||||||
|
|
||||||
// OUT(unknown06160[4]);
|
// OUT(unknown06160[4]);
|
||||||
//NOTE: new client supports 20 bandoliers, our internal rep
|
|
||||||
//only supports 4..
|
// Copy bandoliers where server and client indexes converge
|
||||||
for (r = 0; r < 4; r++) {
|
for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
OUT_str(bandoliers[r].name);
|
OUT_str(bandoliers[r].Name);
|
||||||
uint32 k;
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) {
|
OUT(bandoliers[r].Items[k].ID);
|
||||||
OUT(bandoliers[r].items[k].item_id);
|
OUT(bandoliers[r].Items[k].Icon);
|
||||||
OUT(bandoliers[r].items[k].icon);
|
OUT_str(bandoliers[r].Items[k].Name);
|
||||||
OUT_str(bandoliers[r].items[k].item_name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// OUT(unknown07444[5120]);
|
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||||
for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) {
|
for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) {
|
||||||
OUT(potionbelt.items[r].item_id);
|
eq->bandoliers[r].Name[0] = '\0';
|
||||||
OUT(potionbelt.items[r].icon);
|
for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||||
OUT_str(potionbelt.items[r].item_name);
|
eq->bandoliers[r].Items[k].ID = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Icon = 0;
|
||||||
|
eq->bandoliers[r].Items[k].Name[0] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OUT(unknown07444[5120]);
|
||||||
|
|
||||||
|
// Copy potion belt where server and client indexes converge
|
||||||
|
for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
OUT(potionbelt.Items[r].ID);
|
||||||
|
OUT(potionbelt.Items[r].Icon);
|
||||||
|
OUT_str(potionbelt.Items[r].Name);
|
||||||
|
}
|
||||||
|
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||||
|
for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) {
|
||||||
|
eq->potionbelt.Items[r].ID = 0;
|
||||||
|
eq->potionbelt.Items[r].Icon = 0;
|
||||||
|
eq->potionbelt.Items[r].Name[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
// OUT(unknown12852[8]);
|
// OUT(unknown12852[8]);
|
||||||
// OUT(unknown12864[76]);
|
// OUT(unknown12864[76]);
|
||||||
|
|
||||||
OUT_str(name);
|
OUT_str(name);
|
||||||
OUT_str(last_name);
|
OUT_str(last_name);
|
||||||
OUT(guild_id);
|
OUT(guild_id);
|
||||||
@ -2174,77 +2194,103 @@ namespace UF
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
if (emu->CharCount == 0) {
|
||||||
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
||||||
|
eq->CharCount = emu->CharCount;
|
||||||
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
int char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
int namelen = 0;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->name[char_count][0] == '\0')
|
// Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars'
|
||||||
break;
|
uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field
|
||||||
if (strcmp(emu->name[char_count], "<none>") == 0)
|
eq->TotalChars = adjusted_total;
|
||||||
break;
|
|
||||||
namelen += strlen(emu->name[char_count]);
|
FINISH_ENCODE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
|
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
|
size_t names_length = 0;
|
||||||
|
size_t character_count = 0;
|
||||||
|
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
|
||||||
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
|
names_length += strlen(emu_cse->Name);
|
||||||
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
size_t total_length = sizeof(structs::CharacterSelect_Struct)
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
|
||||||
+ namelen;
|
+ names_length;
|
||||||
|
|
||||||
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
||||||
|
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
|
||||||
|
|
||||||
//unsigned char *eq_buffer = new unsigned char[total_length];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->char_count = char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
eq->total_chars = 10;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->entries;
|
// Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars' in this client
|
||||||
int r;
|
uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field
|
||||||
for (r = 0; r < char_count; r++) {
|
eq->TotalChars = adjusted_total;
|
||||||
{ //pre-name section...
|
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
emu_ptr = __emu_buffer;
|
||||||
eq2->level = emu->level[r];
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
eq2->hairstyle = emu->hairstyle[r];
|
|
||||||
eq2->gender = emu->gender[r];
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1);
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
}
|
|
||||||
//adjust for name.
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
bufptr += strlen(emu->name[r]);
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
{ //post-name section...
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
|
||||||
eq2->beard = emu->beard[r];
|
eq_cse->Level = emu_cse->Level;
|
||||||
eq2->haircolor = emu->haircolor[r];
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
eq2->face = emu->face[r];
|
eq_cse->Gender = emu_cse->Gender;
|
||||||
int k;
|
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
strcpy(eq_cse->Name, emu_cse->Name);
|
||||||
eq2->equip[k].material = emu->equip[r][k].material;
|
eq_ptr += strlen(eq_cse->Name);
|
||||||
eq2->equip[k].unknown1 = emu->equip[r][k].unknown1;
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial;
|
|
||||||
eq2->equip[k].color.color = emu->equip[r][k].color.color;
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
}
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
eq2->primary = emu->primary[r];
|
eq_cse->Face = emu_cse->Face;
|
||||||
eq2->secondary = emu->secondary[r];
|
|
||||||
eq2->tutorial = emu->tutorial[r]; // was u15
|
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
|
||||||
eq2->u15 = 0xff;
|
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
|
||||||
eq2->deity = emu->deity[r];
|
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
|
||||||
eq2->zone = emu->zone[r];
|
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
|
||||||
eq2->u19 = 0xFF;
|
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
|
||||||
eq2->race = emu->race[r];
|
|
||||||
eq2->gohome = emu->gohome[r];
|
|
||||||
eq2->class_ = emu->class_[r];
|
|
||||||
eq2->eyecolor1 = emu->eyecolor1[r];
|
|
||||||
eq2->beardcolor = emu->beardcolor[r];
|
|
||||||
eq2->eyecolor2 = emu->eyecolor2[r];
|
|
||||||
eq2->drakkin_heritage = emu->drakkin_heritage[r];
|
|
||||||
eq2->drakkin_tattoo = emu->drakkin_tattoo[r];
|
|
||||||
eq2->drakkin_details = emu->drakkin_details[r];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
|
eq_cse->Zone = emu_cse->Zone;
|
||||||
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
|
eq_cse->Race = emu_cse->Race;
|
||||||
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
|
eq_cse->Class = emu_cse->Class;
|
||||||
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
|
|
||||||
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -2621,7 +2667,7 @@ namespace UF
|
|||||||
OUT(material);
|
OUT(material);
|
||||||
OUT(unknown06);
|
OUT(unknown06);
|
||||||
OUT(elite_material);
|
OUT(elite_material);
|
||||||
OUT(color.color);
|
OUT(color.Color);
|
||||||
OUT(wear_slot_id);
|
OUT(wear_slot_id);
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
@ -2693,42 +2739,23 @@ namespace UF
|
|||||||
|
|
||||||
ENCODE(OP_ZonePlayerToBind)
|
ENCODE(OP_ZonePlayerToBind)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct);
|
SETUP_VAR_ENCODE(ZonePlayerToBind_Struct);
|
||||||
|
ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name));
|
||||||
|
|
||||||
ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer;
|
__packet->SetWritePosition(0);
|
||||||
|
__packet->WriteUInt16(emu->bind_zone_id);
|
||||||
|
__packet->WriteUInt16(emu->bind_instance_id);
|
||||||
|
__packet->WriteFloat(emu->x);
|
||||||
|
__packet->WriteFloat(emu->y);
|
||||||
|
__packet->WriteFloat(emu->z);
|
||||||
|
__packet->WriteFloat(emu->heading);
|
||||||
|
__packet->WriteString(emu->zone_name);
|
||||||
|
__packet->WriteUInt8(1); // save items
|
||||||
|
__packet->WriteUInt32(0); // hp
|
||||||
|
__packet->WriteUInt32(0); // mana
|
||||||
|
__packet->WriteUInt32(0); // endurance
|
||||||
|
|
||||||
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
FINISH_ENCODE();
|
||||||
|
|
||||||
unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)];
|
|
||||||
structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1;
|
|
||||||
unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)];
|
|
||||||
structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2;
|
|
||||||
|
|
||||||
zph->x = zps->x;
|
|
||||||
zph->y = zps->y;
|
|
||||||
zph->z = zps->z;
|
|
||||||
zph->heading = zps->heading;
|
|
||||||
zph->bind_zone_id = zps->bind_zone_id;
|
|
||||||
zph->bind_instance_id = zps->bind_instance_id;
|
|
||||||
strcpy(zph->zone_name, zps->zone_name);
|
|
||||||
|
|
||||||
zpf->unknown021 = 1;
|
|
||||||
zpf->unknown022 = 0;
|
|
||||||
zpf->unknown023 = 0;
|
|
||||||
zpf->unknown024 = 0;
|
|
||||||
|
|
||||||
ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)));
|
|
||||||
ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct));
|
|
||||||
|
|
||||||
delete[] buffer1;
|
|
||||||
delete[] buffer2;
|
|
||||||
delete[](*p)->pBuffer;
|
|
||||||
|
|
||||||
(*p)->pBuffer = new unsigned char[ss.str().size()];
|
|
||||||
(*p)->size = ss.str().size();
|
|
||||||
|
|
||||||
memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size());
|
|
||||||
dest->FastQueuePacket(&(*p));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ENCODE(OP_ZoneServerInfo)
|
ENCODE(OP_ZoneServerInfo)
|
||||||
@ -3002,7 +3029,7 @@ namespace UF
|
|||||||
for (k = 0; k < 9; ++k)
|
for (k = 0; k < 9; ++k)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3012,11 +3039,11 @@ namespace UF
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
|
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
|
||||||
}
|
}
|
||||||
@ -3026,9 +3053,9 @@ namespace UF
|
|||||||
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer;
|
||||||
|
|
||||||
for (k = 0; k < 9; k++) {
|
for (k = 0; k < 9; k++) {
|
||||||
Equipment[k].material = emu->equipment[k].material;
|
Equipment[k].Material = emu->equipment[k].Material;
|
||||||
Equipment[k].unknown1 = emu->equipment[k].unknown1;
|
Equipment[k].Unknown1 = emu->equipment[k].Unknown1;
|
||||||
Equipment[k].elitematerial = emu->equipment[k].elitematerial;
|
Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer += (sizeof(structs::EquipStruct) * 9);
|
Buffer += (sizeof(structs::EquipStruct) * 9);
|
||||||
@ -3728,7 +3755,7 @@ namespace UF
|
|||||||
IN(material);
|
IN(material);
|
||||||
IN(unknown06);
|
IN(unknown06);
|
||||||
IN(elite_material);
|
IN(elite_material);
|
||||||
IN(color.color);
|
IN(color.Color);
|
||||||
IN(wear_slot_id);
|
IN(wear_slot_id);
|
||||||
emu->hero_forge_model = 0;
|
emu->hero_forge_model = 0;
|
||||||
emu->unknown18 = 0;
|
emu->unknown18 = 0;
|
||||||
|
|||||||
@ -101,6 +101,8 @@ namespace UF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
namespace consts {
|
||||||
|
static const size_t CHARACTER_CREATION_LIMIT = 12;
|
||||||
|
|
||||||
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
static const uint16 MAP_SHARED_BANK_SIZE = 2;
|
||||||
@ -174,9 +176,10 @@ namespace UF {
|
|||||||
static const uint16 ITEM_COMMON_SIZE = 5;
|
static const uint16 ITEM_COMMON_SIZE = 5;
|
||||||
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
static const uint16 ITEM_CONTAINER_SIZE = 10;
|
||||||
|
|
||||||
static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances
|
static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances
|
||||||
static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance
|
static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance
|
||||||
static const uint32 POTION_BELT_SIZE = 5;
|
|
||||||
|
static const size_t POTION_BELT_ITEM_COUNT = 5;
|
||||||
|
|
||||||
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
static const size_t TEXT_LINK_BODY_LENGTH = 50;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,53 +103,53 @@ struct AdventureInfo {
|
|||||||
*/
|
*/
|
||||||
struct Color_Struct
|
struct Color_Struct
|
||||||
{
|
{
|
||||||
union
|
union {
|
||||||
{
|
struct {
|
||||||
struct
|
uint8 blue;
|
||||||
{
|
uint8 Green;
|
||||||
uint8 blue;
|
uint8 Red;
|
||||||
uint8 green;
|
uint8 UseTint; // if there's a tint this is FF
|
||||||
uint8 red;
|
} RGB;
|
||||||
uint8 use_tint; // if there's a tint this is FF
|
uint32 Color;
|
||||||
} rgb;
|
|
||||||
uint32 color;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharSelectEquip {
|
struct CharSelectEquip
|
||||||
uint32 material;
|
{
|
||||||
uint32 unknown1;
|
uint32 Material;
|
||||||
uint32 elitematerial;
|
uint32 Unknown1;
|
||||||
Color_Struct color;
|
uint32 EliteMaterial;
|
||||||
|
Color_Struct Color;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharacterSelectEntry_Struct {
|
struct CharacterSelectEntry_Struct
|
||||||
/*0000*/ uint8 level; //
|
{
|
||||||
/*0000*/ uint8 hairstyle; //
|
/*0000*/ uint8 Level; //
|
||||||
/*0002*/ uint8 gender; //
|
/*0000*/ uint8 HairStyle; //
|
||||||
/*0003*/ char name[1]; //variable length, edi+0
|
/*0002*/ uint8 Gender; //
|
||||||
/*0000*/ uint8 beard; //
|
/*0003*/ char Name[1]; // variable length, edi+0
|
||||||
/*0001*/ uint8 haircolor; //
|
/*0000*/ uint8 Beard; //
|
||||||
/*0000*/ uint8 face; //
|
/*0001*/ uint8 HairColor; //
|
||||||
/*0000*/ CharSelectEquip equip[9];
|
/*0000*/ uint8 Face; //
|
||||||
/*0000*/ uint32 primary; //
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint32 secondary; //
|
/*0000*/ uint32 PrimaryIDFile; //
|
||||||
/*0000*/ uint8 u15; // 0xff
|
/*0000*/ uint32 SecondaryIDFile; //
|
||||||
/*0000*/ uint32 deity; //
|
/*0000*/ uint8 Unknown15; // 0xff
|
||||||
/*0000*/ uint16 zone; //
|
/*0000*/ uint32 Deity; //
|
||||||
/*0000*/ uint16 instance;
|
/*0000*/ uint16 Zone; //
|
||||||
/*0000*/ uint8 gohome; //
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ uint8 u19; // 0xff
|
/*0000*/ uint8 GoHome; //
|
||||||
/*0000*/ uint32 race; //
|
/*0000*/ uint8 Unknown19; // 0xff
|
||||||
/*0000*/ uint8 tutorial; //
|
/*0000*/ uint32 Race; //
|
||||||
/*0000*/ uint8 class_; //
|
/*0000*/ uint8 Tutorial; //
|
||||||
/*0000*/ uint8 eyecolor1; //
|
/*0000*/ uint8 Class; //
|
||||||
/*0000*/ uint8 beardcolor; //
|
/*0000*/ uint8 EyeColor1; //
|
||||||
/*0000*/ uint8 eyecolor2; //
|
/*0000*/ uint8 BeardColor; //
|
||||||
/*0000*/ uint32 drakkin_heritage; // Drakkin Heritage
|
/*0000*/ uint8 EyeColor2; //
|
||||||
/*0000*/ uint32 drakkin_tattoo; // Drakkin Tattoo
|
/*0000*/ uint32 DrakkinHeritage; // Drakkin Heritage
|
||||||
/*0000*/ uint32 drakkin_details; // Drakkin Details (Facial Spikes)
|
/*0000*/ uint32 DrakkinTattoo; // Drakkin Tattoo
|
||||||
/*0000*/ uint8 unknown; // New field to Underfoot
|
/*0000*/ uint32 DrakkinDetails; // Drakkin Details (Facial Spikes)
|
||||||
|
/*0000*/ uint8 Unknown; // New field to Underfoot
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,20 +157,22 @@ struct CharacterSelectEntry_Struct {
|
|||||||
** Character Selection Struct
|
** Character Selection Struct
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct CharacterSelect_Struct {
|
struct CharacterSelect_Struct
|
||||||
/*0000*/ uint32 char_count; //number of chars in this packet
|
{
|
||||||
/*0004*/ uint32 total_chars; //total number of chars allowed?
|
/*0000*/ uint32 CharCount; //number of chars in this packet
|
||||||
/*0008*/ CharacterSelectEntry_Struct entries[0];
|
/*0004*/ uint32 TotalChars; //total number of chars allowed?
|
||||||
|
/*0008*/ CharacterSelectEntry_Struct Entries[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Visible equiptment.
|
* Visible equiptment.
|
||||||
* Size: 12 Octets
|
* Size: 12 Octets
|
||||||
*/
|
*/
|
||||||
struct EquipStruct {
|
struct EquipStruct
|
||||||
/*00*/ uint32 material;
|
{
|
||||||
/*04*/ uint32 unknown1;
|
/*00*/ uint32 Material;
|
||||||
/*08*/ uint32 elitematerial;
|
/*04*/ uint32 Unknown1;
|
||||||
|
/*08*/ uint32 EliteMaterial;
|
||||||
/*12*/
|
/*12*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -722,9 +724,6 @@ struct Disciplines_Struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
static const uint32 MAX_PLAYER_TRIBUTES = 5;
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER = 20;
|
|
||||||
static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4;
|
|
||||||
static const uint32 MAX_POTIONS_IN_BELT = 5;
|
|
||||||
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
static const uint32 TRIBUTE_NONE = 0xFFFFFFFF;
|
||||||
|
|
||||||
struct Tribute_Struct {
|
struct Tribute_Struct {
|
||||||
@ -732,26 +731,42 @@ struct Tribute_Struct {
|
|||||||
uint32 tier;
|
uint32 tier;
|
||||||
};
|
};
|
||||||
|
|
||||||
//len = 72
|
// Bandolier item positions
|
||||||
struct BandolierItem_Struct {
|
enum
|
||||||
uint32 item_id;
|
{
|
||||||
uint32 icon;
|
bandolierPrimary = 0,
|
||||||
char item_name[64];
|
bandolierSecondary,
|
||||||
};
|
|
||||||
|
|
||||||
//len = 320
|
|
||||||
enum { //bandolier item positions
|
|
||||||
bandolierMainHand = 0,
|
|
||||||
bandolierOffHand,
|
|
||||||
bandolierRange,
|
bandolierRange,
|
||||||
bandolierAmmo
|
bandolierAmmo
|
||||||
};
|
};
|
||||||
struct Bandolier_Struct {
|
|
||||||
char name[32];
|
//len = 72
|
||||||
BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS];
|
struct BandolierItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
};
|
};
|
||||||
struct PotionBelt_Struct {
|
|
||||||
BandolierItem_Struct items[MAX_POTIONS_IN_BELT];
|
//len = 320
|
||||||
|
struct Bandolier_Struct
|
||||||
|
{
|
||||||
|
char Name[32];
|
||||||
|
BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 72
|
||||||
|
struct PotionBeltItem_Struct
|
||||||
|
{
|
||||||
|
uint32 ID;
|
||||||
|
uint32 Icon;
|
||||||
|
char Name[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
//len = 288
|
||||||
|
struct PotionBelt_Struct
|
||||||
|
{
|
||||||
|
PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16;
|
||||||
@ -974,7 +989,7 @@ struct PlayerProfile_Struct
|
|||||||
/*11236*/ uint32 aapoints_spent; // Number of spent AA points
|
/*11236*/ uint32 aapoints_spent; // Number of spent AA points
|
||||||
/*11240*/ uint32 aapoints; // Unspent AA points
|
/*11240*/ uint32 aapoints; // Unspent AA points
|
||||||
/*11244*/ uint8 unknown11244[4];
|
/*11244*/ uint8 unknown11244[4];
|
||||||
/*11248*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [6400] bandolier contents
|
/*11248*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents
|
||||||
/*17648*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot
|
/*17648*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot
|
||||||
/*18008*/ uint8 unknown18008[8];
|
/*18008*/ uint8 unknown18008[8];
|
||||||
/*18016*/ uint32 available_slots;
|
/*18016*/ uint32 available_slots;
|
||||||
@ -2425,7 +2440,7 @@ struct BookRequest_Struct {
|
|||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
struct Object_Struct {
|
struct Object_Struct {
|
||||||
/*00*/ uint32 linked_list_addr[2];// <Zaphod> They are, get this, prev and next, ala linked list
|
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
|
||||||
/*08*/ uint32 unknown008; // Something related to the linked list?
|
/*08*/ uint32 unknown008; // Something related to the linked list?
|
||||||
/*12*/ uint32 drop_id; // Unique object id for zone
|
/*12*/ uint32 drop_id; // Unique object id for zone
|
||||||
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
||||||
@ -2445,8 +2460,8 @@ struct Object_Struct {
|
|||||||
/*100*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
/*100*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
||||||
/*104*/
|
/*104*/
|
||||||
};
|
};
|
||||||
//<Zaphod> 01 = generic drop, 02 = armor, 19 = weapon
|
//01 = generic drop, 02 = armor, 19 = weapon
|
||||||
//[13:40] <Zaphod> and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
//[13:40] and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Click Object Struct
|
** Click Object Struct
|
||||||
@ -3758,30 +3773,35 @@ struct DynamicWall_Struct {
|
|||||||
/*80*/
|
/*80*/
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { //bandolier actions
|
// Bandolier actions
|
||||||
BandolierCreate = 0,
|
enum
|
||||||
BandolierRemove = 1,
|
{
|
||||||
BandolierSet = 2
|
bandolierCreate = 0,
|
||||||
|
bandolierRemove,
|
||||||
|
bandolierSet
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierCreate_Struct {
|
struct BandolierCreate_Struct
|
||||||
/*00*/ uint32 action; //0 for create
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action; //0 for create
|
||||||
/*05*/ char name[32];
|
/*04*/ uint8 Number;
|
||||||
/*37*/ uint16 unknown37; //seen 0x93FD
|
/*05*/ char Name[32];
|
||||||
/*39*/ uint8 unknown39; //0
|
/*37*/ uint16 Unknown37; //seen 0x93FD
|
||||||
|
/*39*/ uint8 Unknown39; //0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierDelete_Struct {
|
struct BandolierDelete_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BandolierSet_Struct {
|
struct BandolierSet_Struct
|
||||||
/*00*/ uint32 action;
|
{
|
||||||
/*04*/ uint8 number;
|
/*00*/ uint32 Action;
|
||||||
/*05*/ uint8 unknown05[35];
|
/*04*/ uint8 Number;
|
||||||
|
/*05*/ uint8 Unknown05[35];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Not 100% sure on this struct. Live as of 1/1/11 is different than UF. Seems to work 'OK'
|
// Not 100% sure on this struct. Live as of 1/1/11 is different than UF. Seems to work 'OK'
|
||||||
|
|||||||
@ -133,6 +133,9 @@ RULE_INT ( Skills, MaxTrainTradeskills, 21 )
|
|||||||
RULE_BOOL ( Skills, UseLimitTradeskillSearchSkillDiff, true )
|
RULE_BOOL ( Skills, UseLimitTradeskillSearchSkillDiff, true )
|
||||||
RULE_INT ( Skills, MaxTradeskillSearchSkillDiff, 50 )
|
RULE_INT ( Skills, MaxTradeskillSearchSkillDiff, 50 )
|
||||||
RULE_INT ( Skills, MaxTrainSpecializations, 50 ) // Max level a GM trainer will train casting specializations
|
RULE_INT ( Skills, MaxTrainSpecializations, 50 ) // Max level a GM trainer will train casting specializations
|
||||||
|
RULE_INT ( Skills, SwimmingStartValue, 100 )
|
||||||
|
RULE_BOOL ( Skills, TrainSenseHeading, false )
|
||||||
|
RULE_INT ( Skills, SenseHeadingStartValue, 200 )
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY( Pets )
|
RULE_CATEGORY( Pets )
|
||||||
@ -300,7 +303,7 @@ RULE_INT ( Spells, MaxCastTimeReduction, 50) //Max percent your spell cast time
|
|||||||
RULE_INT ( Spells, RootBreakFromSpells, 55) //Chance for root to break when cast on.
|
RULE_INT ( Spells, RootBreakFromSpells, 55) //Chance for root to break when cast on.
|
||||||
RULE_INT ( Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effects chance of death save firing.
|
RULE_INT ( Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effects chance of death save firing.
|
||||||
RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount.
|
RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount.
|
||||||
RULE_BOOL ( Spells, AdditiveBonusValues, false) //Allow certain bonuses to be calculated by adding together the value from each item, instead of taking the highest value. (ie Add together all Cleave Effects)
|
RULE_INT ( Spells, AdditiveBonusWornType, 0) //Calc worn bonuses to add together (instead of taking highest) if set to THIS worn type. (2=Will covert live items automatically)
|
||||||
RULE_BOOL ( Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this?
|
RULE_BOOL ( Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this?
|
||||||
RULE_BOOL ( Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live
|
RULE_BOOL ( Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live
|
||||||
RULE_INT ( Spells, RootBreakCheckChance, 70) //Determines chance for a root break check to occur each buff tick.
|
RULE_INT ( Spells, RootBreakCheckChance, 70) //Determines chance for a root break check to occur each buff tick.
|
||||||
@ -329,6 +332,7 @@ RULE_BOOL ( Spells, Jun182014HundredHandsRevamp, false) // this should be true f
|
|||||||
RULE_BOOL ( Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning.
|
RULE_BOOL ( Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning.
|
||||||
RULE_BOOL ( Spells, NPC_UseFocusFromSpells, true) // Allow npcs to use most spell derived focus effects.
|
RULE_BOOL ( Spells, NPC_UseFocusFromSpells, true) // Allow npcs to use most spell derived focus effects.
|
||||||
RULE_BOOL ( Spells, NPC_UseFocusFromItems, false) // Allow npcs to use most item derived focus effects.
|
RULE_BOOL ( Spells, NPC_UseFocusFromItems, false) // Allow npcs to use most item derived focus effects.
|
||||||
|
RULE_BOOL ( Spells, UseAdditiveFocusFromWornSlot, false) // Allows an additive focus effect to be calculated from worn slot.
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY( Combat )
|
RULE_CATEGORY( Combat )
|
||||||
|
|||||||
@ -151,28 +151,31 @@ bool SharedDatabase::VerifyInventory(uint32 account_id, int16 slot_id, const Ite
|
|||||||
|
|
||||||
bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 slot_id) {
|
bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 slot_id) {
|
||||||
|
|
||||||
// If we never save tribute slots..how are we to ever benefit from them!!? The client
|
|
||||||
// object is destroyed upon zoning - including its inventory object..and if tributes
|
|
||||||
// don't exist in the database, then they will never be loaded when the new client
|
|
||||||
// object is created in the new zone object... Something to consider... -U
|
|
||||||
//
|
|
||||||
// (we could add them to the 'NoRent' checks and dispose of after 30 minutes offline)
|
|
||||||
|
|
||||||
//never save tribute slots:
|
//never save tribute slots:
|
||||||
if(slot_id >= EmuConstants::TRIBUTE_BEGIN && slot_id <= EmuConstants::TRIBUTE_END)
|
if(slot_id >= EmuConstants::TRIBUTE_BEGIN && slot_id <= EmuConstants::TRIBUTE_END)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) {
|
if (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) {
|
||||||
// Shared bank inventory
|
// Shared bank inventory
|
||||||
if (!inst)
|
if (!inst) {
|
||||||
return DeleteSharedBankSlot(char_id, slot_id);
|
return DeleteSharedBankSlot(char_id, slot_id);
|
||||||
else
|
}
|
||||||
return UpdateSharedBankSlot(char_id, inst, slot_id);
|
else {
|
||||||
|
// Needed to clear out bag slots that 'REPLACE' in UpdateSharedBankSlot does not overwrite..otherwise, duplication occurs
|
||||||
|
// (This requires that parent then child items be sent..which should be how they are currently passed)
|
||||||
|
if (Inventory::SupportsContainers(slot_id))
|
||||||
|
DeleteSharedBankSlot(char_id, slot_id);
|
||||||
|
return UpdateSharedBankSlot(char_id, inst, slot_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!inst) { // All other inventory
|
else if (!inst) { // All other inventory
|
||||||
return DeleteInventorySlot(char_id, slot_id);
|
return DeleteInventorySlot(char_id, slot_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed to clear out bag slots that 'REPLACE' in UpdateInventorySlot does not overwrite..otherwise, duplication occurs
|
||||||
|
// (This requires that parent then child items be sent..which should be how they are currently passed)
|
||||||
|
if (Inventory::SupportsContainers(slot_id))
|
||||||
|
DeleteInventorySlot(char_id, slot_id);
|
||||||
return UpdateInventorySlot(char_id, inst, slot_id);
|
return UpdateInventorySlot(char_id, inst, slot_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +212,9 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i
|
|||||||
|
|
||||||
// Save bag contents, if slot supports bag contents
|
// Save bag contents, if slot supports bag contents
|
||||||
if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id))
|
if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id))
|
||||||
for (uint8 idx = SUB_BEGIN; idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) {
|
// Limiting to bag slot count will get rid of 'hidden' duplicated items and 'Invalid Slot ID'
|
||||||
|
// messages through attrition (and the modded code in SaveInventory)
|
||||||
|
for (uint8 idx = SUB_BEGIN; idx < inst->GetItem()->BagSlots && idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) {
|
||||||
const ItemInst* baginst = inst->GetItem(idx);
|
const ItemInst* baginst = inst->GetItem(idx);
|
||||||
SaveInventory(char_id, baginst, Inventory::CalcSlotId(slot_id, idx));
|
SaveInventory(char_id, baginst, Inventory::CalcSlotId(slot_id, idx));
|
||||||
}
|
}
|
||||||
@ -253,7 +258,9 @@ bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst,
|
|||||||
|
|
||||||
// Save bag contents, if slot supports bag contents
|
// Save bag contents, if slot supports bag contents
|
||||||
if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id)) {
|
if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id)) {
|
||||||
for (uint8 idx = SUB_BEGIN; idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) {
|
// Limiting to bag slot count will get rid of 'hidden' duplicated items and 'Invalid Slot ID'
|
||||||
|
// messages through attrition (and the modded code in SaveInventory)
|
||||||
|
for (uint8 idx = SUB_BEGIN; idx < inst->GetItem()->BagSlots && idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) {
|
||||||
const ItemInst* baginst = inst->GetItem(idx);
|
const ItemInst* baginst = inst->GetItem(idx);
|
||||||
SaveInventory(char_id, baginst, Inventory::CalcSlotId(slot_id, idx));
|
SaveInventory(char_id, baginst, Inventory::CalcSlotId(slot_id, idx));
|
||||||
}
|
}
|
||||||
@ -1158,7 +1165,7 @@ void SharedDatabase::GetFactionListInfo(uint32 &list_count, uint32 &max_lists) {
|
|||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
list_count = static_cast<uint32>(atoul(row[0]));
|
list_count = static_cast<uint32>(atoul(row[0]));
|
||||||
max_lists = static_cast<uint32>(atoul(row[1]));
|
max_lists = static_cast<uint32>(atoul(row[1] ? row[1] : "0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const NPCFactionList* SharedDatabase::GetNPCFactionEntry(uint32 id) {
|
const NPCFactionList* SharedDatabase::GetNPCFactionEntry(uint32 id) {
|
||||||
@ -1235,9 +1242,6 @@ bool SharedDatabase::LoadNPCFactionLists() {
|
|||||||
uint32 list_count = 0;
|
uint32 list_count = 0;
|
||||||
uint32 max_lists = 0;
|
uint32 max_lists = 0;
|
||||||
GetFactionListInfo(list_count, max_lists);
|
GetFactionListInfo(list_count, max_lists);
|
||||||
if(list_count == 0) {
|
|
||||||
EQ_EXCEPT("SharedDatabase", "Database returned no result");
|
|
||||||
}
|
|
||||||
uint32 size = static_cast<uint32>(EQEmu::FixedMemoryHashSet<NPCFactionList>::estimated_size(
|
uint32 size = static_cast<uint32>(EQEmu::FixedMemoryHashSet<NPCFactionList>::estimated_size(
|
||||||
list_count, max_lists));
|
list_count, max_lists));
|
||||||
|
|
||||||
@ -1837,7 +1841,7 @@ void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot
|
|||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
loot_table_count = static_cast<uint32>(atoul(row[0]));
|
loot_table_count = static_cast<uint32>(atoul(row[0]));
|
||||||
max_loot_table = static_cast<uint32>(atoul(row[1]));
|
max_loot_table = static_cast<uint32>(atoul(row[1] ? row[1] : "0"));
|
||||||
loot_table_entries = static_cast<uint32>(atoul(row[2]));
|
loot_table_entries = static_cast<uint32>(atoul(row[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1858,7 +1862,7 @@ void SharedDatabase::GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_d
|
|||||||
auto row =results.begin();
|
auto row =results.begin();
|
||||||
|
|
||||||
loot_drop_count = static_cast<uint32>(atoul(row[0]));
|
loot_drop_count = static_cast<uint32>(atoul(row[0]));
|
||||||
max_loot_drop = static_cast<uint32>(atoul(row[1]));
|
max_loot_drop = static_cast<uint32>(atoul(row[1] ? row[1] : "0"));
|
||||||
loot_drop_entries = static_cast<uint32>(atoul(row[2]));
|
loot_drop_entries = static_cast<uint32>(atoul(row[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2074,4 +2078,4 @@ bool SharedDatabase::VerifyToken(std::string token, int& status) {
|
|||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
status = atoi(row[0]);
|
status = atoi(row[0]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -171,6 +171,8 @@ enum SkillUseTypes
|
|||||||
|
|
||||||
// temporary until it can be sorted out...
|
// temporary until it can be sorted out...
|
||||||
#define HIGHEST_SKILL SkillFrenzy
|
#define HIGHEST_SKILL SkillFrenzy
|
||||||
|
// Spell Effects use this value to determine if an effect applies to all skills.
|
||||||
|
#define ALL_SKILLS -1
|
||||||
|
|
||||||
// server profile does not reflect this yet..so, prefixed with 'PACKET_'
|
// server profile does not reflect this yet..so, prefixed with 'PACKET_'
|
||||||
#define PACKET_SKILL_ARRAY_SIZE 100
|
#define PACKET_SKILL_ARRAY_SIZE 100
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
#define LOGIN_VERSION "0.8.0"
|
#define LOGIN_VERSION "0.8.0"
|
||||||
#define EQEMU_PROTOCOL_VERSION "0.3.10"
|
#define EQEMU_PROTOCOL_VERSION "0.3.10"
|
||||||
|
|
||||||
#define CURRENT_VERSION "1.0.0"
|
#define CURRENT_VERSION "1.1.3"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Everytime a Database SQL is added to Github,
|
Everytime a Database SQL is added to Github,
|
||||||
@ -30,7 +30,7 @@
|
|||||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9075
|
#define CURRENT_BINARY_DATABASE_VERSION 9077
|
||||||
#define COMPILE_DATE __DATE__
|
#define COMPILE_DATE __DATE__
|
||||||
#define COMPILE_TIME __TIME__
|
#define COMPILE_TIME __TIME__
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
|||||||
@ -306,7 +306,7 @@ void Database::LogPlayerMove(QSPlayerLogMove_Struct* QS, uint32 items) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 items) {
|
void Database::LogMerchantTransaction(QSMerchantLogTransaction_Struct* QS, uint32 items) {
|
||||||
/* Merchant transactions are from the perspective of the merchant, not the player -U */
|
/* Merchant transactions are from the perspective of the merchant, not the player */
|
||||||
std::string query = StringFormat("INSERT INTO `qs_merchant_transaction_record` SET `time` = NOW(), "
|
std::string query = StringFormat("INSERT INTO `qs_merchant_transaction_record` SET `time` = NOW(), "
|
||||||
"`zone_id` = '%i', `merchant_id` = '%i', `merchant_pp` = '%i', "
|
"`zone_id` = '%i', `merchant_id` = '%i', `merchant_pp` = '%i', "
|
||||||
"`merchant_gp` = '%i', `merchant_sp` = '%i', `merchant_cp` = '%i', "
|
"`merchant_gp` = '%i', `merchant_sp` = '%i', `merchant_cp` = '%i', "
|
||||||
|
|||||||
@ -31,9 +31,6 @@ void LoadFactions(SharedDatabase *database) {
|
|||||||
uint32 lists = 0;
|
uint32 lists = 0;
|
||||||
uint32 max_list = 0;
|
uint32 max_list = 0;
|
||||||
database->GetFactionListInfo(lists, max_list);
|
database->GetFactionListInfo(lists, max_list);
|
||||||
if(lists == 0) {
|
|
||||||
EQ_EXCEPT("Shared Memory", "Unable to get any factions from the database.");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 size = static_cast<uint32>(EQEmu::FixedMemoryHashSet<NPCFactionList>::estimated_size(lists, max_list));
|
uint32 size = static_cast<uint32>(EQEmu::FixedMemoryHashSet<NPCFactionList>::estimated_size(lists, max_list));
|
||||||
EQEmu::MemoryMappedFile mmf("shared/faction", size);
|
EQEmu::MemoryMappedFile mmf("shared/faction", size);
|
||||||
|
|||||||
@ -129,7 +129,7 @@ OP_GuildInviteAccept=0x78a5
|
|||||||
OP_GuildDemote=0x3100
|
OP_GuildDemote=0x3100
|
||||||
OP_GuildPromote=0x2945
|
OP_GuildPromote=0x2945
|
||||||
OP_GuildPublicNote=0x3c2c
|
OP_GuildPublicNote=0x3c2c
|
||||||
OP_GuildManageBanker=0x096d # Was 0x0737
|
OP_GuildManageBanker=0x389c # Was 0x096d
|
||||||
OP_GuildBank=0x2ab0 # Was 0x10c3
|
OP_GuildBank=0x2ab0 # Was 0x10c3
|
||||||
OP_SetGuildRank=0x3599
|
OP_SetGuildRank=0x3599
|
||||||
OP_GuildUpdateURLAndChannel=0x7851
|
OP_GuildUpdateURLAndChannel=0x7851
|
||||||
|
|||||||
@ -128,7 +128,7 @@ OP_GuildInviteAccept=0x7053
|
|||||||
OP_GuildDemote=0x2d4e
|
OP_GuildDemote=0x2d4e
|
||||||
OP_GuildPromote=0x6a98
|
OP_GuildPromote=0x6a98
|
||||||
OP_GuildPublicNote=0x5053
|
OP_GuildPublicNote=0x5053
|
||||||
OP_GuildManageBanker=0x748f
|
OP_GuildManageBanker=0x3f35
|
||||||
OP_GuildBank=0x5134
|
OP_GuildBank=0x5134
|
||||||
OP_SetGuildRank=0x0b9c
|
OP_SetGuildRank=0x0b9c
|
||||||
OP_GuildUpdateURLAndChannel=0x2958
|
OP_GuildUpdateURLAndChannel=0x2958
|
||||||
@ -353,21 +353,22 @@ OP_Marquee=0x502e
|
|||||||
OP_ItemRecastDelay=0x15a9
|
OP_ItemRecastDelay=0x15a9
|
||||||
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
|
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
|
||||||
|
|
||||||
OP_DzQuit=0x205f
|
# Expeditions
|
||||||
OP_DzListTimers=0x0398
|
OP_DzAddPlayer=0x4701
|
||||||
OP_DzAddPlayer=0x59ca
|
OP_DzRemovePlayer=0x1abc
|
||||||
OP_DzRemovePlayer=0x4701
|
OP_DzSwapPlayer=0x405b
|
||||||
OP_DzSwapPlayer=0x1abc
|
OP_DzMakeLeader=0x543d
|
||||||
OP_DzMakeLeader=0x405b
|
OP_DzPlayerList=0x14c6
|
||||||
OP_DzPlayerList=0x543d
|
OP_DzJoinExpeditionConfirm=0x7f4b
|
||||||
OP_DzJoinExpeditionConfirm=0x14c6
|
OP_DzJoinExpeditionReply=0x1950
|
||||||
OP_DzJoinExpeditionReply=0x7f4b
|
OP_DzListTimers=0x7b68
|
||||||
OP_DzExpeditionInfo=0x4f7e
|
OP_DzExpeditionInfo=0x9119
|
||||||
OP_DzExpeditionList=0x9119
|
OP_DzExpeditionList=0x205f
|
||||||
OP_DzMemberStatus=0xb2e3
|
OP_DzQuit=0xb2e3
|
||||||
OP_DzLeaderStatus=0x32f0
|
OP_DzMemberStatus=0x32f0
|
||||||
|
OP_DzLeaderStatus=0x3de9
|
||||||
|
OP_DzMemberList=0x5ae4
|
||||||
OP_DzExpeditionEndsWarning=0x383c
|
OP_DzExpeditionEndsWarning=0x383c
|
||||||
OP_DzMemberList=0x3de9
|
|
||||||
OP_DzCompass=0x3e0e
|
OP_DzCompass=0x3e0e
|
||||||
OP_DzChooseZone=0x0b7d
|
OP_DzChooseZone=0x0b7d
|
||||||
|
|
||||||
@ -401,12 +402,12 @@ OP_LootComplete=0x55c4
|
|||||||
|
|
||||||
# bazaar trader stuff:
|
# bazaar trader stuff:
|
||||||
OP_BazaarSearch=0x39d6
|
OP_BazaarSearch=0x39d6
|
||||||
OP_TraderDelItem=0x0000
|
OP_TraderDelItem=0x5829
|
||||||
OP_BecomeTrader=0x61b3
|
OP_BecomeTrader=0x61b3
|
||||||
OP_TraderShop=0x31df
|
OP_TraderShop=0x31df
|
||||||
OP_Trader=0x4ef5
|
OP_Trader=0x4ef5
|
||||||
OP_TraderBuy=0x0000
|
|
||||||
OP_Barter=0x243a
|
OP_Barter=0x243a
|
||||||
|
OP_TraderBuy=0x0000
|
||||||
OP_ShopItem=0x0000
|
OP_ShopItem=0x0000
|
||||||
OP_BazaarInspect=0x0000
|
OP_BazaarInspect=0x0000
|
||||||
OP_Bazaar=0x0000
|
OP_Bazaar=0x0000
|
||||||
|
|||||||
@ -525,7 +525,7 @@ OP_KnowledgeBase=0x0000
|
|||||||
OP_SlashAdventure=0x571a # /adventure
|
OP_SlashAdventure=0x571a # /adventure
|
||||||
OP_VetRewardsAvaliable=0x0557
|
OP_VetRewardsAvaliable=0x0557
|
||||||
OP_VetClaimRequest=0x6ba0
|
OP_VetClaimRequest=0x6ba0
|
||||||
OP_VetClaimReply=0x0000
|
OP_VetClaimReply=0x407e
|
||||||
OP_BecomePVPPrompt=0x36B2 #guessed from ASM
|
OP_BecomePVPPrompt=0x36B2 #guessed from ASM
|
||||||
OP_PVPStats=0x5cc0
|
OP_PVPStats=0x5cc0
|
||||||
OP_PVPLeaderBoardRequest=0x61d2
|
OP_PVPLeaderBoardRequest=0x61d2
|
||||||
|
|||||||
@ -329,6 +329,8 @@
|
|||||||
9073|2015_01_31_character_item_recast.sql|SHOW TABLES LIKE 'character_item_recast'|empty|
|
9073|2015_01_31_character_item_recast.sql|SHOW TABLES LIKE 'character_item_recast'|empty|
|
||||||
9074|2015_02_01_logsys_packet_logs.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client'|empty|
|
9074|2015_02_01_logsys_packet_logs.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client'|empty|
|
||||||
9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty|
|
9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty|
|
||||||
|
9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint
|
||||||
|
9077|2015_02_12_zone_gravity.sql|SHOW COLUMNS FROM `zone` LIKE 'gravity'|empty|
|
||||||
|
|
||||||
# Upgrade conditions:
|
# Upgrade conditions:
|
||||||
# This won't be needed after this system is implemented, but it is used database that are not
|
# This won't be needed after this system is implemented, but it is used database that are not
|
||||||
|
|||||||
50
utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql
Normal file
50
utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
-- Updates live pets who should be type (5) - Pet locks onto target until dead.
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_74_";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_67_";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumSword";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer4";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumHammer";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "Burnout";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumSword";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumHammer";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_67_";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk3";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk1";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk2";
|
||||||
|
UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk3";
|
||||||
@ -0,0 +1 @@
|
|||||||
|
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:UseAdditiveFocusFromWornSlot', 'false', '[Not live like] If a focus effect is placed in a worn slot the base value will calculated as an additive bonus to regular focus effects.');
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:AdditiveBonusWornType', '0', 'Calcs worn bonuses to add together (instead of taking highest) if item set to THIS worn type. Will stack with regular worn bonuses. (2=Will cause all live items to use this behavior)');
|
||||||
|
|
||||||
|
-- This is no longer used - Set the above value equal to 2 to achieve the same effect.
|
||||||
|
DELETE FROM `rule_values` WHERE rule_name LIKE "Spells:AdditiveBonusValues";
|
||||||
2
utils/sql/git/required/2015_02_04_average_coin.sql
Normal file
2
utils/sql/git/required/2015_02_04_average_coin.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE `loottable` CHANGE COLUMN `avgcoin` `avgcoin` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `maxcash`;
|
||||||
|
UPDATE `loottable` SET avgcoin = 0;
|
||||||
2
utils/sql/git/required/2015_02_12_zone_gravity.sql
Normal file
2
utils/sql/git/required/2015_02_12_zone_gravity.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE `zone`
|
||||||
|
ADD COLUMN `gravity` float NOT NULL DEFAULT .4 AFTER `snow_duration4`;
|
||||||
168
world/client.cpp
168
world/client.cpp
@ -16,6 +16,7 @@
|
|||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
#include "../common/clientversions.h"
|
#include "../common/clientversions.h"
|
||||||
#include "../common/random.h"
|
#include "../common/random.h"
|
||||||
|
#include "../common/shareddb.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "worlddb.h"
|
#include "worlddb.h"
|
||||||
@ -86,11 +87,11 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
charid = 0;
|
charid = 0;
|
||||||
pwaitingforbootup = 0;
|
pwaitingforbootup = 0;
|
||||||
StartInTutorial = false;
|
StartInTutorial = false;
|
||||||
ClientVersionBit = 0;
|
|
||||||
numclients++;
|
|
||||||
|
|
||||||
if (eqs->GetClientVersion() != ClientVersion::Unknown)
|
m_ClientVersion = eqs->GetClientVersion();
|
||||||
ClientVersionBit = 1 << (static_cast<unsigned int>(eqs->GetClientVersion()) - 1);
|
m_ClientVersionBit = ClientBitFromVersion(m_ClientVersion);
|
||||||
|
|
||||||
|
numclients++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client() {
|
Client::~Client() {
|
||||||
@ -161,32 +162,34 @@ void Client::SendCharInfo() {
|
|||||||
cle->SetOnline(CLE_Status_CharSelect);
|
cle->SetOnline(CLE_Status_CharSelect);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ClientVersionBit & BIT_RoFAndLater)
|
if (m_ClientVersionBit & BIT_RoFAndLater) {
|
||||||
{
|
SendMaxCharCreate();
|
||||||
// Can make max char per account into a rule - New to VoA
|
|
||||||
SendMaxCharCreate(10);
|
|
||||||
SendMembership();
|
SendMembership();
|
||||||
SendMembershipSettings();
|
SendMembershipSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
seencharsel = true;
|
seencharsel = true;
|
||||||
|
|
||||||
|
|
||||||
// Send OP_SendCharInfo
|
// Send OP_SendCharInfo
|
||||||
auto outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
EQApplicationPacket *outapp = nullptr;
|
||||||
CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer;
|
database.GetCharSelectInfo(GetAccountID(), &outapp, m_ClientVersionBit);
|
||||||
|
|
||||||
database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit);
|
if (outapp) {
|
||||||
|
QueuePacket(outapp);
|
||||||
QueuePacket(outapp);
|
}
|
||||||
|
else {
|
||||||
|
Log.Out(Logs::General, Logs::World_Server, "[Error] Database did not return an OP_SendCharInfo packet for account %u", GetAccountID());
|
||||||
|
}
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendMaxCharCreate(int max_chars) {
|
void Client::SendMaxCharCreate() {
|
||||||
auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct));
|
auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct));
|
||||||
MaxCharacters_Struct* mc = (MaxCharacters_Struct*)outapp->pBuffer;
|
MaxCharacters_Struct* mc = (MaxCharacters_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
mc->max_chars = max_chars;
|
mc->max_chars = EQLimits::CharacterCreationLimit(m_ClientVersion);
|
||||||
|
if (mc->max_chars > EmuConstants::CHARACTER_CREATION_LIMIT)
|
||||||
|
mc->max_chars = EmuConstants::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@ -671,7 +674,7 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(ClientVersionBit & BIT_TitaniumAndEarlier)
|
if (m_ClientVersionBit & BIT_TitaniumAndEarlier)
|
||||||
StartInTutorial = true;
|
StartInTutorial = true;
|
||||||
SendCharInfo();
|
SendCharInfo();
|
||||||
}
|
}
|
||||||
@ -716,66 +719,72 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pZoning && ew->return_home && !ew->tutorial) {
|
// This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above)
|
||||||
auto cs = new CharacterSelect_Struct;
|
// (This is a literal translation of the original process..I don't see why it can't be changed to a single-target query over account iteration)
|
||||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
if (!pZoning) {
|
||||||
database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit);
|
size_t character_limit = EQLimits::CharacterCreationLimit(eqs->GetClientVersion());
|
||||||
bool home_enabled = false;
|
if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) { character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; }
|
||||||
|
if (eqs->GetClientVersion() == ClientVersion::Titanium) { character_limit = 8; }
|
||||||
|
|
||||||
for(int x = 0; x < 10; ++x)
|
std::string tgh_query = StringFormat(
|
||||||
{
|
"SELECT "
|
||||||
if(strcasecmp(cs->name[x], char_name) == 0)
|
"`id`, "
|
||||||
{
|
"name, "
|
||||||
if(cs->gohome[x] == 1)
|
"`level`, "
|
||||||
{
|
"last_login "
|
||||||
home_enabled = true;
|
"FROM "
|
||||||
break;
|
"character_data "
|
||||||
|
"WHERE `account_id` = %i ORDER BY `name` LIMIT %u", GetAccountID(), character_limit);
|
||||||
|
auto tgh_results = database.QueryDatabase(tgh_query);
|
||||||
|
|
||||||
|
/* Check GoHome */
|
||||||
|
if (ew->return_home && !ew->tutorial) {
|
||||||
|
bool home_enabled = false;
|
||||||
|
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||||
|
if (strcasecmp(row[1], char_name) == 0) {
|
||||||
|
if (RuleB(World, EnableReturnHomeButton)) {
|
||||||
|
int now = time(nullptr);
|
||||||
|
if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) {
|
||||||
|
home_enabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
safe_delete(cs);
|
|
||||||
|
|
||||||
if(home_enabled) {
|
if (home_enabled) {
|
||||||
zoneID = database.MoveCharacterToBind(charid,4);
|
zoneID = database.MoveCharacterToBind(charid, 4);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go home before they're able...",char_name);
|
Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go home before they're able...", char_name);
|
||||||
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
||||||
eqs->Close();
|
eqs->Close();
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) {
|
|
||||||
auto cs = new CharacterSelect_Struct;
|
|
||||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
|
||||||
database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit);
|
|
||||||
bool tutorial_enabled = false;
|
|
||||||
|
|
||||||
for(int x = 0; x < 10; ++x)
|
|
||||||
{
|
|
||||||
if(strcasecmp(cs->name[x], char_name) == 0)
|
|
||||||
{
|
|
||||||
if(cs->tutorial[x] == 1)
|
|
||||||
{
|
|
||||||
tutorial_enabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
safe_delete(cs);
|
|
||||||
|
|
||||||
if(tutorial_enabled)
|
/* Check Tutorial*/
|
||||||
{
|
if (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial)) {
|
||||||
zoneID = RuleI(World, TutorialZoneID);
|
bool tutorial_enabled = false;
|
||||||
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
|
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||||
}
|
if (strcasecmp(row[1], char_name) == 0) {
|
||||||
else
|
if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) {
|
||||||
{
|
tutorial_enabled = true;
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go to tutorial but are not allowed...",char_name);
|
break;
|
||||||
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
}
|
||||||
eqs->Close();
|
}
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
if (tutorial_enabled) {
|
||||||
|
zoneID = RuleI(World, TutorialZoneID);
|
||||||
|
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go to tutorial but are not allowed...", char_name);
|
||||||
|
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
||||||
|
eqs->Close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,9 +855,9 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
|||||||
|
|
||||||
char ConnectionType;
|
char ConnectionType;
|
||||||
|
|
||||||
if(ClientVersionBit & BIT_UFAndLater)
|
if (m_ClientVersionBit & BIT_UFAndLater)
|
||||||
ConnectionType = 'U';
|
ConnectionType = 'U';
|
||||||
else if(ClientVersionBit & BIT_SoFAndLater)
|
else if (m_ClientVersionBit & BIT_SoFAndLater)
|
||||||
ConnectionType = 'S';
|
ConnectionType = 'S';
|
||||||
else
|
else
|
||||||
ConnectionType = 'C';
|
ConnectionType = 'C';
|
||||||
@ -872,7 +881,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
|||||||
|
|
||||||
outapp2 = new EQApplicationPacket(OP_SetChatServer2);
|
outapp2 = new EQApplicationPacket(OP_SetChatServer2);
|
||||||
|
|
||||||
if(ClientVersionBit & BIT_TitaniumAndEarlier)
|
if (m_ClientVersionBit & BIT_TitaniumAndEarlier)
|
||||||
ConnectionType = 'M';
|
ConnectionType = 'M';
|
||||||
|
|
||||||
sprintf(buffer,"%s,%i,%s.%s,%c%08X",
|
sprintf(buffer,"%s,%i,%s.%s,%c%08X",
|
||||||
@ -906,7 +915,7 @@ bool Client::HandleDeleteCharacterPacket(const EQApplicationPacket *app) {
|
|||||||
|
|
||||||
bool Client::HandleZoneChangePacket(const EQApplicationPacket *app) {
|
bool Client::HandleZoneChangePacket(const EQApplicationPacket *app) {
|
||||||
// HoT sends this to world while zoning and wants it echoed back.
|
// HoT sends this to world while zoning and wants it echoed back.
|
||||||
if(ClientVersionBit & BIT_RoFAndLater)
|
if (m_ClientVersionBit & BIT_RoFAndLater)
|
||||||
{
|
{
|
||||||
QueuePacket(app);
|
QueuePacket(app);
|
||||||
}
|
}
|
||||||
@ -1370,7 +1379,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
|||||||
Log.Out(Logs::Detail, Logs::World_Server, "Beard: %d Beardcolor: %d", cc->beard, cc->beardcolor);
|
Log.Out(Logs::Detail, Logs::World_Server, "Beard: %d Beardcolor: %d", cc->beard, cc->beardcolor);
|
||||||
|
|
||||||
/* Validate the char creation struct */
|
/* Validate the char creation struct */
|
||||||
if (ClientVersionBit & BIT_SoFAndLater) {
|
if (m_ClientVersionBit & BIT_SoFAndLater) {
|
||||||
if (!CheckCharCreateInfoSoF(cc)) {
|
if (!CheckCharCreateInfoSoF(cc)) {
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
Log.Out(Logs::Detail, Logs::World_Server,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
||||||
return false;
|
return false;
|
||||||
@ -1421,7 +1430,10 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
|||||||
SetRaceStartingSkills(&pp);
|
SetRaceStartingSkills(&pp);
|
||||||
SetClassStartingSkills(&pp);
|
SetClassStartingSkills(&pp);
|
||||||
SetClassLanguages(&pp);
|
SetClassLanguages(&pp);
|
||||||
pp.skills[SkillSenseHeading] = 200;
|
|
||||||
|
pp.skills[SkillSwimming] = RuleI(Skills, SwimmingStartValue);
|
||||||
|
pp.skills[SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue);
|
||||||
|
|
||||||
// strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
|
// strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
|
||||||
|
|
||||||
|
|
||||||
@ -1438,7 +1450,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
|||||||
pp.pvp = database.GetServerType() == 1 ? 1 : 0;
|
pp.pvp = database.GetServerType() == 1 ? 1 : 0;
|
||||||
|
|
||||||
/* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */
|
/* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */
|
||||||
if (ClientVersionBit & BIT_SoFAndLater) {
|
if (m_ClientVersionBit & BIT_SoFAndLater) {
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"Found 'SoFStartZoneID' rule setting: %i", RuleI(World, SoFStartZoneID));
|
Log.Out(Logs::Detail, Logs::World_Server,"Found 'SoFStartZoneID' rule setting: %i", RuleI(World, SoFStartZoneID));
|
||||||
if (RuleI(World, SoFStartZoneID) > 0) {
|
if (RuleI(World, SoFStartZoneID) > 0) {
|
||||||
pp.zone_id = RuleI(World, SoFStartZoneID);
|
pp.zone_id = RuleI(World, SoFStartZoneID);
|
||||||
@ -1454,7 +1466,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/
|
/* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/
|
||||||
bool ValidStartZone = database.GetStartZone(&pp, cc, ClientVersionBit & BIT_TitaniumAndEarlier);
|
bool ValidStartZone = database.GetStartZone(&pp, cc, m_ClientVersionBit & BIT_TitaniumAndEarlier);
|
||||||
|
|
||||||
if (!ValidStartZone){
|
if (!ValidStartZone){
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public:
|
|||||||
bool Process();
|
bool Process();
|
||||||
void ReceiveData(uchar* buf, int len);
|
void ReceiveData(uchar* buf, int len);
|
||||||
void SendCharInfo();
|
void SendCharInfo();
|
||||||
void SendMaxCharCreate(int max_chars);
|
void SendMaxCharCreate();
|
||||||
void SendMembership();
|
void SendMembership();
|
||||||
void SendMembershipSettings();
|
void SendMembershipSettings();
|
||||||
void EnterWorld(bool TryBootup = true);
|
void EnterWorld(bool TryBootup = true);
|
||||||
@ -84,7 +84,8 @@ private:
|
|||||||
uint32 pwaitingforbootup;
|
uint32 pwaitingforbootup;
|
||||||
|
|
||||||
bool StartInTutorial;
|
bool StartInTutorial;
|
||||||
uint32 ClientVersionBit;
|
ClientVersion m_ClientVersion;
|
||||||
|
uint32 m_ClientVersionBit;
|
||||||
bool OPCharCreate(char *name, CharCreate_Struct *cc);
|
bool OPCharCreate(char *name, CharCreate_Struct *cc);
|
||||||
|
|
||||||
void SetClassStartingSkills( PlayerProfile_Struct *pp );
|
void SetClassStartingSkills( PlayerProfile_Struct *pp );
|
||||||
|
|||||||
@ -33,20 +33,20 @@ extern std::vector<RaceClassCombos> character_create_race_class_combos;
|
|||||||
|
|
||||||
|
|
||||||
// the current stuff is at the bottom of this function
|
// the current stuff is at the bottom of this function
|
||||||
void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* cs, uint32 ClientVersion) {
|
void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit)
|
||||||
Inventory *inv;
|
{
|
||||||
uint8 has_home = 0;
|
/* Set Character Creation Limit */
|
||||||
uint8 has_bind = 0;
|
ClientVersion client_version = ClientVersionFromBit(clientVersionBit);
|
||||||
|
size_t character_limit = EQLimits::CharacterCreationLimit(client_version);
|
||||||
/* Initialize Variables */
|
|
||||||
for (int i=0; i<10; i++) {
|
// Validate against absolute server max
|
||||||
strcpy(cs->name[i], "<none>");
|
if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT)
|
||||||
cs->zone[i] = 0;
|
character_limit = EmuConstants::CHARACTER_CREATION_LIMIT;
|
||||||
cs->level[i] = 0;
|
|
||||||
cs->tutorial[i] = 0;
|
|
||||||
cs->gohome[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Force Titanium clients to use '8'
|
||||||
|
if (client_version == ClientVersion::Titanium)
|
||||||
|
character_limit = 8;
|
||||||
|
|
||||||
/* Get Character Info */
|
/* Get Character Info */
|
||||||
std::string cquery = StringFormat(
|
std::string cquery = StringFormat(
|
||||||
"SELECT "
|
"SELECT "
|
||||||
@ -72,52 +72,102 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
|
|||||||
"zone_id " // 19
|
"zone_id " // 19
|
||||||
"FROM "
|
"FROM "
|
||||||
"character_data "
|
"character_data "
|
||||||
"WHERE `account_id` = %i ORDER BY `name` LIMIT 10 ", account_id);
|
"WHERE `account_id` = %i ORDER BY `name` LIMIT %u", accountID, character_limit);
|
||||||
auto results = database.QueryDatabase(cquery); int char_num = 0;
|
auto results = database.QueryDatabase(cquery);
|
||||||
|
|
||||||
|
size_t character_count = results.RowCount();
|
||||||
|
if (character_count == 0) {
|
||||||
|
*outApp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
||||||
|
CharacterSelect_Struct *cs = (CharacterSelect_Struct *)(*outApp)->pBuffer;
|
||||||
|
cs->CharCount = 0;
|
||||||
|
cs->TotalChars = character_limit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t packet_size = sizeof(CharacterSelect_Struct) + (sizeof(CharacterSelectEntry_Struct) * character_count);
|
||||||
|
*outApp = new EQApplicationPacket(OP_SendCharInfo, packet_size);
|
||||||
|
|
||||||
|
unsigned char *buff_ptr = (*outApp)->pBuffer;
|
||||||
|
CharacterSelect_Struct *cs = (CharacterSelect_Struct *)buff_ptr;
|
||||||
|
|
||||||
|
cs->CharCount = character_count;
|
||||||
|
cs->TotalChars = character_limit;
|
||||||
|
|
||||||
|
buff_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
CharacterSelectEntry_Struct *cse = (CharacterSelectEntry_Struct *)buff_ptr;
|
||||||
PlayerProfile_Struct pp;
|
PlayerProfile_Struct pp;
|
||||||
|
Inventory inv;
|
||||||
|
uint32 character_id = (uint32)atoi(row[0]);
|
||||||
|
uint8 has_home = 0;
|
||||||
|
uint8 has_bind = 0;
|
||||||
|
|
||||||
memset(&pp, 0, sizeof(PlayerProfile_Struct));
|
memset(&pp, 0, sizeof(PlayerProfile_Struct));
|
||||||
|
|
||||||
|
/* Fill CharacterSelectEntry_Struct */
|
||||||
|
strcpy(cse->Name, row[1]);
|
||||||
|
cse->Class = (uint8)atoi(row[4]);
|
||||||
|
cse->Race = (uint32)atoi(row[3]);
|
||||||
|
cse->Level = (uint8)atoi(row[5]);
|
||||||
|
cse->ShroudClass = cse->Class;
|
||||||
|
cse->ShroudRace = cse->Race;
|
||||||
|
cse->Zone = (uint16)atoi(row[19]);
|
||||||
|
cse->Instance = 0;
|
||||||
|
cse->Gender = (uint8)atoi(row[2]);
|
||||||
|
cse->Face = (uint8)atoi(row[15]);
|
||||||
|
|
||||||
uint32 character_id = atoi(row[0]);
|
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) { // Processed below
|
||||||
strcpy(cs->name[char_num], row[1]);
|
cse->Equip[matslot].Material = 0;
|
||||||
uint8 lvl = atoi(row[5]);
|
cse->Equip[matslot].Unknown1 = 0;
|
||||||
cs->level[char_num] = lvl;
|
cse->Equip[matslot].EliteMaterial = 0;
|
||||||
cs->class_[char_num] = atoi(row[4]);
|
cse->Equip[matslot].HeroForgeModel = 0;
|
||||||
cs->race[char_num] = atoi(row[3]);
|
cse->Equip[matslot].Material2 = 0;
|
||||||
cs->gender[char_num] = atoi(row[2]);
|
cse->Equip[matslot].Color.Color = 0;
|
||||||
cs->deity[char_num] = atoi(row[6]);
|
}
|
||||||
cs->zone[char_num] = atoi(row[19]);
|
|
||||||
cs->face[char_num] = atoi(row[15]);
|
|
||||||
cs->haircolor[char_num] = atoi(row[9]);
|
|
||||||
cs->beardcolor[char_num] = atoi(row[10]);
|
|
||||||
cs->eyecolor2[char_num] = atoi(row[12]);
|
|
||||||
cs->eyecolor1[char_num] = atoi(row[11]);
|
|
||||||
cs->hairstyle[char_num] = atoi(row[13]);
|
|
||||||
cs->beard[char_num] = atoi(row[14]);
|
|
||||||
cs->drakkin_heritage[char_num] = atoi(row[16]);
|
|
||||||
cs->drakkin_tattoo[char_num] = atoi(row[17]);
|
|
||||||
cs->drakkin_details[char_num] = atoi(row[18]);
|
|
||||||
|
|
||||||
if (RuleB(World, EnableTutorialButton) && (lvl <= RuleI(World, MaxLevelForTutorial)))
|
cse->Unknown15 = 0xFF;
|
||||||
cs->tutorial[char_num] = 1;
|
cse->Unknown19 = 0xFF;
|
||||||
|
cse->DrakkinTattoo = (uint32)atoi(row[17]);
|
||||||
|
cse->DrakkinDetails = (uint32)atoi(row[18]);
|
||||||
|
cse->Deity = (uint32)atoi(row[6]);
|
||||||
|
cse->PrimaryIDFile = 0; // Processed Below
|
||||||
|
cse->SecondaryIDFile = 0; // Processed Below
|
||||||
|
cse->HairColor = (uint8)atoi(row[9]);
|
||||||
|
cse->BeardColor = (uint8)atoi(row[10]);
|
||||||
|
cse->EyeColor1 = (uint8)atoi(row[11]);
|
||||||
|
cse->EyeColor2 = (uint8)atoi(row[12]);
|
||||||
|
cse->HairStyle = (uint8)atoi(row[13]);
|
||||||
|
cse->Beard = (uint8)atoi(row[14]);
|
||||||
|
cse->GoHome = 0; // Processed Below
|
||||||
|
cse->Tutorial = 0; // Processed Below
|
||||||
|
cse->DrakkinHeritage = (uint32)atoi(row[16]);
|
||||||
|
cse->Unknown1 = 0;
|
||||||
|
cse->Enabled = 1;
|
||||||
|
cse->LastLogin = (uint32)atoi(row[7]); // RoF2 value: 1212696584
|
||||||
|
cse->Unknown2 = 0;
|
||||||
|
/* Fill End */
|
||||||
|
|
||||||
if (RuleB(World, EnableReturnHomeButton)) {
|
if (RuleB(World, EnableReturnHomeButton)) {
|
||||||
int now = time(nullptr);
|
int now = time(nullptr);
|
||||||
if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome))
|
if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome))
|
||||||
cs->gohome[char_num] = 1;
|
cse->GoHome = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuleB(World, EnableTutorialButton) && (cse->Level <= RuleI(World, MaxLevelForTutorial))) {
|
||||||
|
cse->Tutorial = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set Bind Point Data for any character that may possibly be missing it for any reason */
|
/* Set Bind Point Data for any character that may possibly be missing it for any reason */
|
||||||
cquery = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %i LIMIT 2", character_id);
|
cquery = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %i LIMIT 2", character_id);
|
||||||
auto results_bind = database.QueryDatabase(cquery); has_home = 0; has_bind = 0;
|
auto results_bind = database.QueryDatabase(cquery);
|
||||||
for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) {
|
for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) {
|
||||||
if (row_b[6] && atoi(row_b[6]) == 1){ has_home = 1; }
|
if (row_b[6] && atoi(row_b[6]) == 1){ has_home = 1; }
|
||||||
if (row_b[6] && atoi(row_b[6]) == 0){ has_bind = 1; }
|
if (row_b[6] && atoi(row_b[6]) == 0){ has_bind = 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_home == 0 || has_bind == 0){
|
if (has_home == 0 || has_bind == 0) {
|
||||||
cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i",
|
cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i",
|
||||||
cs->class_[char_num], cs->deity[char_num], cs->race[char_num]);
|
cse->Class, cse->Deity, cse->Race);
|
||||||
auto results_bind = database.QueryDatabase(cquery);
|
auto results_bind = database.QueryDatabase(cquery);
|
||||||
for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) {
|
for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) {
|
||||||
/* If a bind_id is specified, make them start there */
|
/* If a bind_id is specified, make them start there */
|
||||||
@ -133,23 +183,22 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
|
|||||||
float z = atof(row_d[4]);
|
float z = atof(row_d[4]);
|
||||||
if (x == 0 && y == 0 && z == 0){ GetSafePoints(pp.binds[4].zoneId, 0, &x, &y, &z); }
|
if (x == 0 && y == 0 && z == 0){ GetSafePoints(pp.binds[4].zoneId, 0, &x, &y, &z); }
|
||||||
pp.binds[4].x = x; pp.binds[4].y = y; pp.binds[4].z = z;
|
pp.binds[4].x = x; pp.binds[4].y = y; pp.binds[4].z = z;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pp.binds[0] = pp.binds[4];
|
pp.binds[0] = pp.binds[4];
|
||||||
/* If no home bind set, set it */
|
/* If no home bind set, set it */
|
||||||
if (has_home == 0){
|
if (has_home == 0) {
|
||||||
std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
||||||
character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, 1);
|
character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, 1);
|
||||||
auto results_bset = QueryDatabase(query);
|
auto results_bset = QueryDatabase(query);
|
||||||
}
|
}
|
||||||
/* If no regular bind set, set it */
|
/* If no regular bind set, set it */
|
||||||
if (has_bind == 0){
|
if (has_bind == 0) {
|
||||||
std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
||||||
character_id, pp.binds[0].zoneId, 0, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z, pp.binds[0].heading, 0);
|
character_id, pp.binds[0].zoneId, 0, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z, pp.binds[0].heading, 0);
|
||||||
auto results_bset = QueryDatabase(query);
|
auto results_bset = QueryDatabase(query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Bind End */
|
/* Bind End */
|
||||||
@ -157,97 +206,78 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
|
|||||||
/* Load Character Material Data for Char Select */
|
/* Load Character Material Data for Char Select */
|
||||||
cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id);
|
cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id);
|
||||||
auto results_b = database.QueryDatabase(cquery); uint8 slot = 0;
|
auto results_b = database.QueryDatabase(cquery); uint8 slot = 0;
|
||||||
for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b)
|
for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) {
|
||||||
{
|
|
||||||
slot = atoi(row_b[0]);
|
slot = atoi(row_b[0]);
|
||||||
pp.item_tint[slot].rgb.red = atoi(row_b[1]);
|
pp.item_tint[slot].RGB.Red = atoi(row_b[1]);
|
||||||
pp.item_tint[slot].rgb.green = atoi(row_b[2]);
|
pp.item_tint[slot].RGB.Green = atoi(row_b[2]);
|
||||||
pp.item_tint[slot].rgb.blue = atoi(row_b[3]);
|
pp.item_tint[slot].RGB.Blue = atoi(row_b[3]);
|
||||||
pp.item_tint[slot].rgb.use_tint = atoi(row_b[4]);
|
pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]);
|
||||||
}
|
}
|
||||||
|
/* Character Material Data End */
|
||||||
|
|
||||||
/* Load Inventory */
|
/* Load Inventory */
|
||||||
inv = new Inventory;
|
// If we ensure that the material data is updated appropriately, we can do away with inventory loads
|
||||||
if (GetInventory(account_id, cs->name[char_num], inv))
|
if (GetInventory(accountID, cse->Name, &inv)) {
|
||||||
{
|
|
||||||
const Item_Struct* item = nullptr;
|
const Item_Struct* item = nullptr;
|
||||||
const ItemInst* inst = nullptr;
|
const ItemInst* inst = nullptr;
|
||||||
int16 invslot = 0;
|
int16 invslot = 0;
|
||||||
|
|
||||||
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++)
|
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) {
|
||||||
{
|
|
||||||
invslot = Inventory::CalcSlotFromMaterial(matslot);
|
invslot = Inventory::CalcSlotFromMaterial(matslot);
|
||||||
if (invslot == INVALID_INDEX) { continue; }
|
if (invslot == INVALID_INDEX) { continue; }
|
||||||
|
inst = inv.GetItem(invslot);
|
||||||
inst = inv->GetItem(invslot);
|
|
||||||
if (inst == nullptr) { continue; }
|
if (inst == nullptr) { continue; }
|
||||||
|
|
||||||
item = inst->GetItem();
|
item = inst->GetItem();
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
|
|
||||||
if (matslot > 6)
|
if (matslot > 6) {
|
||||||
{
|
|
||||||
uint32 idfile = 0;
|
uint32 idfile = 0;
|
||||||
// Weapon Models
|
// Weapon Models
|
||||||
if (inst->GetOrnamentationIDFile() != 0)
|
if (inst->GetOrnamentationIDFile() != 0) {
|
||||||
{
|
|
||||||
idfile = inst->GetOrnamentationIDFile();
|
idfile = inst->GetOrnamentationIDFile();
|
||||||
cs->equip[char_num][matslot].material = idfile;
|
cse->Equip[matslot].Material = idfile;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if (strlen(item->IDFile) > 2) {
|
||||||
if (strlen(item->IDFile) > 2)
|
|
||||||
{
|
|
||||||
idfile = atoi(&item->IDFile[2]);
|
idfile = atoi(&item->IDFile[2]);
|
||||||
cs->equip[char_num][matslot].material = idfile;
|
cse->Equip[matslot].Material = idfile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (matslot == MaterialPrimary)
|
if (matslot == MaterialPrimary) {
|
||||||
{
|
cse->PrimaryIDFile = idfile;
|
||||||
cs->primary[char_num] = idfile;
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
cse->SecondaryIDFile = idfile;
|
||||||
cs->secondary[char_num] = idfile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
uint32 color = 0;
|
uint32 color = 0;
|
||||||
if (pp.item_tint[matslot].rgb.use_tint)
|
if (pp.item_tint[matslot].RGB.UseTint) {
|
||||||
{
|
color = pp.item_tint[matslot].Color;
|
||||||
color = pp.item_tint[matslot].color;
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
color = inst->GetColor();
|
color = inst->GetColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Armor Materials/Models
|
// Armor Materials/Models
|
||||||
cs->equip[char_num][matslot].material = item->Material;
|
cse->Equip[matslot].Material = item->Material;
|
||||||
cs->equip[char_num][matslot].elitematerial = item->EliteMaterial;
|
cse->Equip[matslot].EliteMaterial = item->EliteMaterial;
|
||||||
cs->equip[char_num][matslot].heroforgemodel = inst->GetOrnamentHeroModel(matslot);
|
cse->Equip[matslot].HeroForgeModel = inst->GetOrnamentHeroModel(matslot);
|
||||||
cs->equip[char_num][matslot].color.color = color;
|
cse->Equip[matslot].Color.Color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
printf("Error loading inventory for %s\n", cse->Name);
|
||||||
printf("Error loading inventory for %s\n", cs->name[char_num]);
|
|
||||||
}
|
}
|
||||||
|
/* Load Inventory End */
|
||||||
|
|
||||||
safe_delete(inv);
|
buff_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
|
|
||||||
if (++char_num > 10)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) {
|
int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum)
|
||||||
|
{
|
||||||
/* if an invalid bind point is specified, use the primary bind */
|
/* if an invalid bind point is specified, use the primary bind */
|
||||||
if (bindnum > 4)
|
if (bindnum > 4)
|
||||||
{
|
{
|
||||||
@ -330,6 +360,7 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct*
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldDatabase::SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc){
|
void WorldDatabase::SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc){
|
||||||
if (in_cc->start_zone == RuleI(World, TutorialZoneID)) {
|
if (in_cc->start_zone == RuleI(World, TutorialZoneID)) {
|
||||||
in_pp->zone_id = in_cc->start_zone;
|
in_pp->zone_id = in_cc->start_zone;
|
||||||
@ -348,8 +379,16 @@ void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, Cha
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
in_pp->zone_id = 24; // erudnext
|
if (in_cc->deity == 203) // Cazic-Thule Erudites go to Paineel
|
||||||
in_pp->binds[0].zoneId = 38; // tox
|
{
|
||||||
|
in_pp->zone_id = 75; // paineel
|
||||||
|
in_pp->binds[0].zoneId = 75;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
in_pp->zone_id = 24; // erudnext
|
||||||
|
in_pp->binds[0].zoneId = 38; // tox
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
@ -432,6 +471,7 @@ void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, Cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldDatabase::GetLauncherList(std::vector<std::string> &rl) {
|
void WorldDatabase::GetLauncherList(std::vector<std::string> &rl) {
|
||||||
rl.clear();
|
rl.clear();
|
||||||
|
|
||||||
@ -447,8 +487,8 @@ void WorldDatabase::GetLauncherList(std::vector<std::string> &rl) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldDatabase::SetMailKey(int CharID, int IPAddress, int MailKey) {
|
void WorldDatabase::SetMailKey(int CharID, int IPAddress, int MailKey)
|
||||||
|
{
|
||||||
char MailKeyString[17];
|
char MailKeyString[17];
|
||||||
|
|
||||||
if(RuleB(Chat, EnableMailKeyIPVerification) == true)
|
if(RuleB(Chat, EnableMailKeyIPVerification) == true)
|
||||||
@ -482,7 +522,8 @@ bool WorldDatabase::GetCharacterLevel(const char *name, int &level)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldDatabase::LoadCharacterCreateAllocations() {
|
bool WorldDatabase::LoadCharacterCreateAllocations()
|
||||||
|
{
|
||||||
character_create_allocations.clear();
|
character_create_allocations.clear();
|
||||||
|
|
||||||
std::string query = "SELECT * FROM char_create_point_allocations ORDER BY id";
|
std::string query = "SELECT * FROM char_create_point_allocations ORDER BY id";
|
||||||
@ -514,7 +555,8 @@ bool WorldDatabase::LoadCharacterCreateAllocations() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldDatabase::LoadCharacterCreateCombos() {
|
bool WorldDatabase::LoadCharacterCreateCombos()
|
||||||
|
{
|
||||||
character_create_race_class_combos.clear();
|
character_create_race_class_combos.clear();
|
||||||
|
|
||||||
std::string query = "SELECT * FROM char_create_combinations ORDER BY race, class, deity, start_zone";
|
std::string query = "SELECT * FROM char_create_combinations ORDER BY race, class, deity, start_zone";
|
||||||
@ -536,4 +578,3 @@ bool WorldDatabase::LoadCharacterCreateCombos() {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "../common/shareddb.h"
|
#include "../common/shareddb.h"
|
||||||
#include "../common/zone_numbers.h"
|
#include "../common/zone_numbers.h"
|
||||||
|
#include "../common/eq_packet.h"
|
||||||
|
|
||||||
struct PlayerProfile_Struct;
|
struct PlayerProfile_Struct;
|
||||||
struct CharCreate_Struct;
|
struct CharCreate_Struct;
|
||||||
@ -29,7 +30,7 @@ struct CharacterSelect_Struct;
|
|||||||
class WorldDatabase : public SharedDatabase {
|
class WorldDatabase : public SharedDatabase {
|
||||||
public:
|
public:
|
||||||
bool GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc, bool isTitanium);
|
bool GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc, bool isTitanium);
|
||||||
void GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*, uint32 ClientVersion);
|
void GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit);
|
||||||
int MoveCharacterToBind(int CharID, uint8 bindnum = 0);
|
int MoveCharacterToBind(int CharID, uint8 bindnum = 0);
|
||||||
|
|
||||||
void GetLauncherList(std::vector<std::string> &result);
|
void GetLauncherList(std::vector<std::string> &result);
|
||||||
|
|||||||
@ -525,7 +525,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
|
|||||||
|
|
||||||
NPCType *made_npc = nullptr;
|
NPCType *made_npc = nullptr;
|
||||||
|
|
||||||
const NPCType *npc_type = database.GetNPCType(pet.npc_id);
|
const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id);
|
||||||
if(npc_type == nullptr) {
|
if(npc_type == nullptr) {
|
||||||
//log write
|
//log write
|
||||||
Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet spell id: %d", spell_id);
|
Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet spell id: %d", spell_id);
|
||||||
@ -622,7 +622,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
|
|||||||
|
|
||||||
NPCType *made_npc = nullptr;
|
NPCType *made_npc = nullptr;
|
||||||
|
|
||||||
const NPCType *npc_type = database.GetNPCType(typesid);
|
const NPCType *npc_type = database.LoadNPCTypesData(typesid);
|
||||||
if(npc_type == nullptr) {
|
if(npc_type == nullptr) {
|
||||||
//log write
|
//log write
|
||||||
Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet type id: %d", typesid);
|
Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet type id: %d", typesid);
|
||||||
@ -715,7 +715,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
//assuming we have pets in our table; we take the first pet as a base type.
|
//assuming we have pets in our table; we take the first pet as a base type.
|
||||||
const NPCType *base_type = database.GetNPCType(500);
|
const NPCType *base_type = database.LoadNPCTypesData(500);
|
||||||
NPCType *make_npc = new NPCType;
|
NPCType *make_npc = new NPCType;
|
||||||
memcpy(make_npc, base_type, sizeof(NPCType));
|
memcpy(make_npc, base_type, sizeof(NPCType));
|
||||||
|
|
||||||
|
|||||||
125
zone/attack.cpp
125
zone/attack.cpp
@ -363,13 +363,40 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
|
|
||||||
//garunteed hit
|
//garunteed hit
|
||||||
bool ghit = false;
|
bool ghit = false;
|
||||||
if((attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
||||||
ghit = true;
|
ghit = true;
|
||||||
|
|
||||||
|
bool InFront = false;
|
||||||
|
|
||||||
|
if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY()))
|
||||||
|
InFront = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This special ability adds a negative modifer to the defenders riposte/block/parry/chance
|
||||||
|
therefore reducing the defenders chance to successfully avoid the melee attack. At present
|
||||||
|
time this is the only way to fine tune counter these mods on players. This may
|
||||||
|
ultimately end up being more useful as fields in npc_types.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int counter_all = 0;
|
||||||
|
int counter_riposte = 0;
|
||||||
|
int counter_block = 0;
|
||||||
|
int counter_parry = 0;
|
||||||
|
int counter_dodge = 0;
|
||||||
|
|
||||||
|
if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)){
|
||||||
|
|
||||||
|
counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0);
|
||||||
|
counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE,1);
|
||||||
|
counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2);
|
||||||
|
counter_parry = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 3);
|
||||||
|
counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
// make enrage same as riposte
|
// make enrage same as riposte
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
if (IsEnraged() && other->InFrontMob(this, other->GetX(), other->GetY())) {
|
if (IsEnraged() && InFront) {
|
||||||
damage = -3;
|
damage = -3;
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
||||||
}
|
}
|
||||||
@ -378,9 +405,10 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
// riposte
|
// riposte
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
float riposte_chance = 0.0f;
|
float riposte_chance = 0.0f;
|
||||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront)
|
||||||
{
|
{
|
||||||
riposte_chance = (100.0f + (float)defender->aabonuses.RiposteChance + (float)defender->spellbonuses.RiposteChance + (float)defender->itembonuses.RiposteChance) / 100.0f;
|
riposte_chance = (100.0f + static_cast<float>(aabonuses.RiposteChance + spellbonuses.RiposteChance +
|
||||||
|
itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f;
|
||||||
skill = GetSkill(SkillRiposte);
|
skill = GetSkill(SkillRiposte);
|
||||||
if (IsClient()) {
|
if (IsClient()) {
|
||||||
CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
|
CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
|
||||||
@ -399,28 +427,19 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool bBlockFromRear = false;
|
bool bBlockFromRear = false;
|
||||||
bool bShieldBlockFromRear = false;
|
|
||||||
|
|
||||||
if (this->IsClient()) {
|
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
||||||
int aaChance = 0;
|
// from a direction other than the rear is granted.
|
||||||
|
|
||||||
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind;
|
||||||
// from a direction other than the rear is granted.
|
|
||||||
|
|
||||||
//Live AA - HightenedAwareness
|
if (BlockBehindChance && zone->random.Roll(BlockBehindChance))
|
||||||
int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind;
|
bBlockFromRear = true;
|
||||||
|
|
||||||
if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) {
|
|
||||||
bBlockFromRear = true;
|
|
||||||
|
|
||||||
if (spellbonuses.BlockBehind || itembonuses.BlockBehind)
|
|
||||||
bShieldBlockFromRear = true; //This bonus should allow a chance to Shield Block from behind.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float block_chance = 0.0f;
|
float block_chance = 0.0f;
|
||||||
if (damage > 0 && CanThisClassBlock() && (other->InFrontMob(this, other->GetX(), other->GetY()) || bBlockFromRear)) {
|
if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) {
|
||||||
block_chance = (100.0f + (float)spellbonuses.IncreaseBlockChance + (float)itembonuses.IncreaseBlockChance) / 100.0f;
|
block_chance = (100.0f + static_cast<float>(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance +
|
||||||
|
itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f;
|
||||||
skill = CastToClient()->GetSkill(SkillBlock);
|
skill = CastToClient()->GetSkill(SkillBlock);
|
||||||
if (IsClient()) {
|
if (IsClient()) {
|
||||||
CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10);
|
CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10);
|
||||||
@ -436,32 +455,20 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
RollTable[1] = RollTable[0];
|
RollTable[1] = RollTable[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock)
|
//Try Shield Block OR TwoHandBluntBlockCheck
|
||||||
&& (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear))
|
||||||
|
RollTable[1] += static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all);
|
||||||
float bonusShieldBlock = 0.0f;
|
|
||||||
bonusShieldBlock = static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock);
|
|
||||||
RollTable[1] += bonusShieldBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(IsClient() && damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock)
|
|
||||||
&& (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
|
||||||
if(CastToClient()->m_inv.GetItem(MainPrimary)) {
|
|
||||||
float bonusStaffBlock = 0.0f;
|
|
||||||
if (CastToClient()->m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HBlunt){
|
|
||||||
bonusStaffBlock = static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock);
|
|
||||||
RollTable[1] += bonusStaffBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear))
|
||||||
|
RollTable[1] += static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
// parry
|
// parry
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
float parry_chance = 0.0f;
|
float parry_chance = 0.0f;
|
||||||
if (damage > 0 && CanThisClassParry() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
if (damage > 0 && CanThisClassParry() && InFront){
|
||||||
{
|
parry_chance = (100.0f + static_cast<float>(aabonuses.ParryChance + itembonuses.ParryChance +
|
||||||
parry_chance = (100.0f + (float)defender->spellbonuses.ParryChance + (float)defender->itembonuses.ParryChance) / 100.0f;
|
itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f;
|
||||||
skill = CastToClient()->GetSkill(SkillParry);
|
skill = CastToClient()->GetSkill(SkillParry);
|
||||||
if (IsClient()) {
|
if (IsClient()) {
|
||||||
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
||||||
@ -482,9 +489,11 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
// dodge
|
// dodge
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
float dodge_chance = 0.0f;
|
float dodge_chance = 0.0f;
|
||||||
if (damage > 0 && CanThisClassDodge() && other->InFrontMob(this, other->GetX(), other->GetY()))
|
if (damage > 0 && CanThisClassDodge() && InFront){
|
||||||
{
|
|
||||||
dodge_chance = (100.0f + (float)defender->spellbonuses.DodgeChance + (float)defender->itembonuses.DodgeChance) / 100.0f;
|
dodge_chance = (100.0f + static_cast<float>(aabonuses.DodgeChance + spellbonuses.DodgeChance +
|
||||||
|
itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f;
|
||||||
|
|
||||||
skill = CastToClient()->GetSkill(SkillDodge);
|
skill = CastToClient()->GetSkill(SkillDodge);
|
||||||
if (IsClient()) {
|
if (IsClient()) {
|
||||||
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
||||||
@ -909,6 +918,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
|
|||||||
{
|
{
|
||||||
int dmg = 0;
|
int dmg = 0;
|
||||||
int banedmg = 0;
|
int banedmg = 0;
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
if(!against || against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)){
|
if(!against || against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)){
|
||||||
return 0;
|
return 0;
|
||||||
@ -937,10 +947,20 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate
|
|||||||
bool MagicWeapon = false;
|
bool MagicWeapon = false;
|
||||||
if(weapon_item->GetItem() && weapon_item->GetItem()->Magic)
|
if(weapon_item->GetItem() && weapon_item->GetItem()->Magic)
|
||||||
MagicWeapon = true;
|
MagicWeapon = true;
|
||||||
else {
|
else
|
||||||
if(spellbonuses.MagicWeapon || itembonuses.MagicWeapon)
|
if(spellbonuses.MagicWeapon || itembonuses.MagicWeapon)
|
||||||
MagicWeapon = true;
|
MagicWeapon = true;
|
||||||
}
|
else
|
||||||
|
// An augment on the weapon that is marked magic makes
|
||||||
|
// the item magical.
|
||||||
|
for(x = 0; MagicWeapon == false && x < EmuConstants::ITEM_COMMON_SIZE; x++)
|
||||||
|
{
|
||||||
|
if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem())
|
||||||
|
{
|
||||||
|
if (weapon_item->GetAugment(x)->GetItem()->Magic)
|
||||||
|
MagicWeapon = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(MagicWeapon) {
|
if(MagicWeapon) {
|
||||||
|
|
||||||
@ -2410,8 +2430,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
|||||||
|
|
||||||
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
|
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
|
||||||
{
|
{
|
||||||
|
if(!other)
|
||||||
assert(other != nullptr);
|
return;
|
||||||
|
|
||||||
if (other == this)
|
if (other == this)
|
||||||
return;
|
return;
|
||||||
@ -3536,6 +3556,10 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
|||||||
Log.Out(Logs::Detail, Logs::Combat, "Melee Damage reduced to %d", damage);
|
Log.Out(Logs::Detail, Logs::Combat, "Melee Damage reduced to %d", damage);
|
||||||
damage = ReduceAllDamage(damage);
|
damage = ReduceAllDamage(damage);
|
||||||
TryTriggerThreshHold(damage, SE_TriggerMeleeThreshold, attacker);
|
TryTriggerThreshHold(damage, SE_TriggerMeleeThreshold, attacker);
|
||||||
|
|
||||||
|
if (skill_used)
|
||||||
|
CheckNumHitsRemaining(NumHit::IncomingHitSuccess);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int32 origdmg = damage;
|
int32 origdmg = damage;
|
||||||
damage = AffectMagicalDamage(damage, spell_id, iBuffTic, attacker);
|
damage = AffectMagicalDamage(damage, spell_id, iBuffTic, attacker);
|
||||||
@ -3551,9 +3575,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
|||||||
TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker);
|
TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skill_used)
|
|
||||||
CheckNumHitsRemaining(NumHit::IncomingHitSuccess);
|
|
||||||
|
|
||||||
if(IsClient() && CastToClient()->sneaking){
|
if(IsClient() && CastToClient()->sneaking){
|
||||||
CastToClient()->sneaking = false;
|
CastToClient()->sneaking = false;
|
||||||
SendAppearancePacket(AT_Sneak, 0);
|
SendAppearancePacket(AT_Sneak, 0);
|
||||||
|
|||||||
201
zone/bonuses.cpp
201
zone/bonuses.cpp
@ -81,6 +81,8 @@ void Client::CalcBonuses()
|
|||||||
CalcAABonuses(&aabonuses); //we're not quite ready for this
|
CalcAABonuses(&aabonuses); //we're not quite ready for this
|
||||||
Log.Out(Logs::Detail, Logs::AA, "Finished calculating AA Bonuses for %s.", this->GetCleanName());
|
Log.Out(Logs::Detail, Logs::AA, "Finished calculating AA Bonuses for %s.", this->GetCleanName());
|
||||||
|
|
||||||
|
ProcessItemCaps(); // caps that depend on spell/aa bonuses
|
||||||
|
|
||||||
RecalcWeight();
|
RecalcWeight();
|
||||||
|
|
||||||
CalcAC();
|
CalcAC();
|
||||||
@ -139,7 +141,8 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
|||||||
|
|
||||||
// Clear item faction mods
|
// Clear item faction mods
|
||||||
ClearItemFactionBonuses();
|
ClearItemFactionBonuses();
|
||||||
ShieldEquiped(false);
|
SetShieldEquiped(false);
|
||||||
|
SetTwoHandBluntEquiped(false);
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
//should not include 21 (SLOT_AMMO)
|
//should not include 21 (SLOT_AMMO)
|
||||||
@ -149,9 +152,12 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
|||||||
continue;
|
continue;
|
||||||
AddItemBonuses(inst, newbon);
|
AddItemBonuses(inst, newbon);
|
||||||
|
|
||||||
//Check if item is secondary slot is a 'shield'. Required for multiple spelll effects.
|
//These are given special flags due to how often they are checked for various spell effects.
|
||||||
if (i == MainSecondary && (m_inv.GetItem(MainSecondary)->GetItem()->ItemType == ItemTypeShield))
|
const Item_Struct *item = inst->GetItem();
|
||||||
ShieldEquiped(true);
|
if (i == MainSecondary && (item && item->ItemType == ItemTypeShield))
|
||||||
|
SetShieldEquiped(true);
|
||||||
|
else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt))
|
||||||
|
SetTwoHandBluntEquiped(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Power Source Slot
|
//Power Source Slot
|
||||||
@ -169,15 +175,34 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
|||||||
continue;
|
continue;
|
||||||
AddItemBonuses(inst, newbon, false, true);
|
AddItemBonuses(inst, newbon, false, true);
|
||||||
}
|
}
|
||||||
// Caps
|
|
||||||
if(newbon->HPRegen > CalcHPRegenCap())
|
|
||||||
newbon->HPRegen = CalcHPRegenCap();
|
|
||||||
|
|
||||||
if(newbon->ManaRegen > CalcManaRegenCap())
|
//Optional ability to have worn effects calculate as an addititive bonus instead of highest value
|
||||||
newbon->ManaRegen = CalcManaRegenCap();
|
if (RuleI(Spells, AdditiveBonusWornType) && RuleI(Spells, AdditiveBonusWornType) != ET_WornEffect){
|
||||||
|
for (i = MainCharm; i < MainAmmo; i++) {
|
||||||
|
const ItemInst* inst = m_inv[i];
|
||||||
|
if(inst == 0)
|
||||||
|
continue;
|
||||||
|
AdditiveWornBonuses(inst, newbon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(newbon->EnduranceRegen > CalcEnduranceRegenCap())
|
// These item stat caps depend on spells/AAs so we process them after those are processed
|
||||||
newbon->EnduranceRegen = CalcEnduranceRegenCap();
|
void Client::ProcessItemCaps()
|
||||||
|
{
|
||||||
|
itembonuses.HPRegen = std::min(itembonuses.HPRegen, CalcHPRegenCap());
|
||||||
|
itembonuses.ManaRegen = std::min(itembonuses.ManaRegen, CalcManaRegenCap());
|
||||||
|
itembonuses.EnduranceRegen = std::min(itembonuses.EnduranceRegen, CalcEnduranceRegenCap());
|
||||||
|
|
||||||
|
// The Sleeper Tomb Avatar proc counts towards item ATK
|
||||||
|
// The client uses a 100 here, so using a 100 here the client and server will agree
|
||||||
|
// For example, if you set the effect to be 200 it will get 100 item ATK and 100 spell ATK
|
||||||
|
if (IsValidSpell(2434) && FindBuff(2434)) {
|
||||||
|
itembonuses.ATK += 100;
|
||||||
|
spellbonuses.ATK -= 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
itembonuses.ATK = std::min(itembonuses.ATK, CalcItemATKCap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug, bool isTribute) {
|
void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug, bool isTribute) {
|
||||||
@ -210,6 +235,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
|||||||
newbon->HP += item->HP;
|
newbon->HP += item->HP;
|
||||||
newbon->Mana += item->Mana;
|
newbon->Mana += item->Mana;
|
||||||
newbon->Endurance += item->Endur;
|
newbon->Endurance += item->Endur;
|
||||||
|
newbon->ATK += item->Attack;
|
||||||
newbon->STR += (item->AStr + item->HeroicStr);
|
newbon->STR += (item->AStr + item->HeroicStr);
|
||||||
newbon->STA += (item->ASta + item->HeroicSta);
|
newbon->STA += (item->ASta + item->HeroicSta);
|
||||||
newbon->DEX += (item->ADex + item->HeroicDex);
|
newbon->DEX += (item->ADex + item->HeroicDex);
|
||||||
@ -263,6 +289,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
|||||||
newbon->HP += CalcRecommendedLevelBonus( lvl, reclvl, item->HP );
|
newbon->HP += CalcRecommendedLevelBonus( lvl, reclvl, item->HP );
|
||||||
newbon->Mana += CalcRecommendedLevelBonus( lvl, reclvl, item->Mana );
|
newbon->Mana += CalcRecommendedLevelBonus( lvl, reclvl, item->Mana );
|
||||||
newbon->Endurance += CalcRecommendedLevelBonus( lvl, reclvl, item->Endur );
|
newbon->Endurance += CalcRecommendedLevelBonus( lvl, reclvl, item->Endur );
|
||||||
|
newbon->ATK += CalcRecommendedLevelBonus( lvl, reclvl, item->Attack );
|
||||||
newbon->STR += CalcRecommendedLevelBonus( lvl, reclvl, (item->AStr + item->HeroicStr) );
|
newbon->STR += CalcRecommendedLevelBonus( lvl, reclvl, (item->AStr + item->HeroicStr) );
|
||||||
newbon->STA += CalcRecommendedLevelBonus( lvl, reclvl, (item->ASta + item->HeroicSta) );
|
newbon->STA += CalcRecommendedLevelBonus( lvl, reclvl, (item->ASta + item->HeroicSta) );
|
||||||
newbon->DEX += CalcRecommendedLevelBonus( lvl, reclvl, (item->ADex + item->HeroicDex) );
|
newbon->DEX += CalcRecommendedLevelBonus( lvl, reclvl, (item->ADex + item->HeroicDex) );
|
||||||
@ -320,16 +347,6 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
|||||||
if(item->EnduranceRegen > 0)
|
if(item->EnduranceRegen > 0)
|
||||||
newbon->EnduranceRegen += item->EnduranceRegen;
|
newbon->EnduranceRegen += item->EnduranceRegen;
|
||||||
|
|
||||||
if(item->Attack > 0) {
|
|
||||||
|
|
||||||
int cap = RuleI(Character, ItemATKCap);
|
|
||||||
cap += itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
|
||||||
|
|
||||||
if((newbon->ATK + item->Attack) > cap)
|
|
||||||
newbon->ATK = RuleI(Character, ItemATKCap);
|
|
||||||
else
|
|
||||||
newbon->ATK += item->Attack;
|
|
||||||
}
|
|
||||||
if(item->DamageShield > 0) {
|
if(item->DamageShield > 0) {
|
||||||
if((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap))
|
if((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap))
|
||||||
newbon->DamageShield = RuleI(Character, ItemDamageShieldCap);
|
newbon->DamageShield = RuleI(Character, ItemDamageShieldCap);
|
||||||
@ -410,12 +427,12 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
|||||||
else
|
else
|
||||||
newbon->DSMitigation += item->DSMitigation;
|
newbon->DSMitigation += item->DSMitigation;
|
||||||
}
|
}
|
||||||
if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects
|
if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects
|
||||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true);
|
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true);
|
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(item->BardType)
|
switch(item->BardType)
|
||||||
@ -537,6 +554,45 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Powerful Non-live like option allows developers to add worn effects on items that
|
||||||
|
can stack with other worn effects of the same spell effect type, instead of only taking the highest value.
|
||||||
|
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||||
|
To enable use RuleI(Spells, AdditiveBonusWornType)
|
||||||
|
Setting value = 2 Will force all live items to automatically be calculated additivily
|
||||||
|
Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation
|
||||||
|
which will also stack with regular (worntype 2) effects. [Ie set rule = 3 and item worntype = 3]
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(!inst || !inst->IsType(ItemClassCommon))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(inst->GetAugmentType()==0 && isAug == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const Item_Struct *item = inst->GetItem();
|
||||||
|
|
||||||
|
if(!inst->IsEquipable(GetBaseRace(),GetClass()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(GetLevel() < item->ReqLevel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType))
|
||||||
|
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects
|
||||||
|
|
||||||
|
|
||||||
|
if (!isAug)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < EmuConstants::ITEM_COMMON_SIZE; i++) {
|
||||||
|
AdditiveWornBonuses(inst->GetAugment(i),newbon,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Client::CalcEdibleBonuses(StatBonuses* newbon) {
|
void Client::CalcEdibleBonuses(StatBonuses* newbon) {
|
||||||
uint32 i;
|
uint32 i;
|
||||||
|
|
||||||
@ -639,7 +695,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||||
if (focus)
|
if (focus)
|
||||||
{
|
{
|
||||||
newbon->FocusEffects[focus] = effect;
|
newbon->FocusEffects[focus] = static_cast<uint8>(effect);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,7 +703,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
{
|
{
|
||||||
//Note: AA effects that use accuracy are skill limited, while spell effect is not.
|
//Note: AA effects that use accuracy are skill limited, while spell effect is not.
|
||||||
case SE_Accuracy:
|
case SE_Accuracy:
|
||||||
if ((base2 == -1) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1))
|
if ((base2 == ALL_SKILLS) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1))
|
||||||
newbon->Accuracy[HIGHEST_SKILL+1] = base1;
|
newbon->Accuracy[HIGHEST_SKILL+1] = base1;
|
||||||
else if (newbon->Accuracy[base2] < base1)
|
else if (newbon->Accuracy[base2] < base1)
|
||||||
newbon->Accuracy[base2] += base1;
|
newbon->Accuracy[base2] += base1;
|
||||||
@ -989,7 +1045,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
|
|
||||||
case SE_HitChance:
|
case SE_HitChance:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
newbon->HitChanceEffect[HIGHEST_SKILL+1] += base1;
|
newbon->HitChanceEffect[HIGHEST_SKILL+1] += base1;
|
||||||
else
|
else
|
||||||
newbon->HitChanceEffect[base2] += base1;
|
newbon->HitChanceEffect[base2] += base1;
|
||||||
@ -1045,7 +1101,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
|
|
||||||
case SE_CriticalHitChance:
|
case SE_CriticalHitChance:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
newbon->CriticalHitChance[HIGHEST_SKILL+1] += base1;
|
newbon->CriticalHitChance[HIGHEST_SKILL+1] += base1;
|
||||||
else
|
else
|
||||||
newbon->CriticalHitChance[base2] += base1;
|
newbon->CriticalHitChance[base2] += base1;
|
||||||
@ -1055,7 +1111,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
case SE_CriticalDamageMob:
|
case SE_CriticalDamageMob:
|
||||||
{
|
{
|
||||||
// base1 = effect value, base2 = skill restrictions(-1 for all)
|
// base1 = effect value, base2 = skill restrictions(-1 for all)
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
newbon->CritDmgMob[HIGHEST_SKILL+1] += base1;
|
newbon->CritDmgMob[HIGHEST_SKILL+1] += base1;
|
||||||
else
|
else
|
||||||
newbon->CritDmgMob[base2] += base1;
|
newbon->CritDmgMob[base2] += base1;
|
||||||
@ -1083,7 +1139,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
|
|
||||||
case SE_SkillDamageAmount:
|
case SE_SkillDamageAmount:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
newbon->SkillDamageAmount[HIGHEST_SKILL+1] += base1;
|
newbon->SkillDamageAmount[HIGHEST_SKILL+1] += base1;
|
||||||
else
|
else
|
||||||
newbon->SkillDamageAmount[base2] += base1;
|
newbon->SkillDamageAmount[base2] += base1;
|
||||||
@ -1100,7 +1156,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
|
|
||||||
case SE_DamageModifier:
|
case SE_DamageModifier:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
newbon->DamageModifier[HIGHEST_SKILL+1] += base1;
|
newbon->DamageModifier[HIGHEST_SKILL+1] += base1;
|
||||||
else
|
else
|
||||||
newbon->DamageModifier[base2] += base1;
|
newbon->DamageModifier[base2] += base1;
|
||||||
@ -1109,7 +1165,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
|
|
||||||
case SE_DamageModifier2:
|
case SE_DamageModifier2:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
newbon->DamageModifier2[HIGHEST_SKILL+1] += base1;
|
newbon->DamageModifier2[HIGHEST_SKILL+1] += base1;
|
||||||
else
|
else
|
||||||
newbon->DamageModifier2[base2] += base1;
|
newbon->DamageModifier2[base2] += base1;
|
||||||
@ -1393,7 +1449,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
|||||||
int buff_count = GetMaxTotalSlots();
|
int buff_count = GetMaxTotalSlots();
|
||||||
for(i = 0; i < buff_count; i++) {
|
for(i = 0; i < buff_count; i++) {
|
||||||
if(buffs[i].spellid != SPELL_UNKNOWN){
|
if(buffs[i].spellid != SPELL_UNKNOWN){
|
||||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, buffs[i].ticsremaining,i);
|
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i);
|
||||||
|
|
||||||
if (buffs[i].numhits > 0)
|
if (buffs[i].numhits > 0)
|
||||||
Numhits(true);
|
Numhits(true);
|
||||||
@ -1416,10 +1472,11 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
|||||||
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, bool item_bonus, uint32 ticsremaining, int buffslot,
|
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot,
|
||||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||||
{
|
{
|
||||||
int i, effect_value, base2, max, effectid;
|
int i, effect_value, base2, max, effectid;
|
||||||
|
bool AdditiveWornBonus = false;
|
||||||
Mob *caster = nullptr;
|
Mob *caster = nullptr;
|
||||||
|
|
||||||
if(!IsAISpellEffect && !IsValidSpell(spell_id))
|
if(!IsAISpellEffect && !IsValidSpell(spell_id))
|
||||||
@ -1439,10 +1496,19 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
uint8 focus = IsFocusEffect(spell_id, i);
|
uint8 focus = IsFocusEffect(spell_id, i);
|
||||||
if (focus)
|
if (focus)
|
||||||
{
|
{
|
||||||
new_bonus->FocusEffects[focus] = spells[spell_id].effectid[i];
|
if (WornType){
|
||||||
|
if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||||
|
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
new_bonus->FocusEffects[focus] = static_cast<uint8>(spells[spell_id].effectid[i]);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType))
|
||||||
|
AdditiveWornBonus = true;
|
||||||
|
|
||||||
effectid = spells[spell_id].effectid[i];
|
effectid = spells[spell_id].effectid[i];
|
||||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining);
|
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining);
|
||||||
@ -1808,8 +1874,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_CriticalHitChance:
|
case SE_CriticalHitChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus) {
|
if (AdditiveWornBonus) {
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->CriticalHitChance[base2] += effect_value;
|
new_bonus->CriticalHitChance[base2] += effect_value;
|
||||||
@ -1817,16 +1883,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
else if(effect_value < 0) {
|
else if(effect_value < 0) {
|
||||||
|
|
||||||
if(base2 == -1 && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] > effect_value)
|
if(base2 == ALL_SKILLS && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] > effect_value)
|
||||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value;
|
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value;
|
||||||
else if(base2 != -1 && new_bonus->CriticalHitChance[base2] > effect_value)
|
else if(base2 != ALL_SKILLS && new_bonus->CriticalHitChance[base2] > effect_value)
|
||||||
new_bonus->CriticalHitChance[base2] = effect_value;
|
new_bonus->CriticalHitChance[base2] = effect_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
else if(base2 == -1 && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] < effect_value)
|
else if(base2 == ALL_SKILLS && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] < effect_value)
|
||||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value;
|
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value;
|
||||||
else if(base2 != -1 && new_bonus->CriticalHitChance[base2] < effect_value)
|
else if(base2 != ALL_SKILLS && new_bonus->CriticalHitChance[base2] < effect_value)
|
||||||
new_bonus->CriticalHitChance[base2] = effect_value;
|
new_bonus->CriticalHitChance[base2] = effect_value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1834,7 +1900,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_CrippBlowChance:
|
case SE_CrippBlowChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->CrippBlowChance += effect_value;
|
new_bonus->CrippBlowChance += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->CrippBlowChance > effect_value))
|
else if((effect_value < 0) && (new_bonus->CrippBlowChance > effect_value))
|
||||||
@ -1848,7 +1914,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_AvoidMeleeChance:
|
case SE_AvoidMeleeChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->AvoidMeleeChanceEffect += effect_value;
|
new_bonus->AvoidMeleeChanceEffect += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->AvoidMeleeChanceEffect > effect_value))
|
else if((effect_value < 0) && (new_bonus->AvoidMeleeChanceEffect > effect_value))
|
||||||
@ -1861,7 +1927,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_RiposteChance:
|
case SE_RiposteChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->RiposteChance += effect_value;
|
new_bonus->RiposteChance += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->RiposteChance > effect_value))
|
else if((effect_value < 0) && (new_bonus->RiposteChance > effect_value))
|
||||||
@ -1874,7 +1940,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_DodgeChance:
|
case SE_DodgeChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->DodgeChance += effect_value;
|
new_bonus->DodgeChance += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->DodgeChance > effect_value))
|
else if((effect_value < 0) && (new_bonus->DodgeChance > effect_value))
|
||||||
@ -1887,7 +1953,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_ParryChance:
|
case SE_ParryChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->ParryChance += effect_value;
|
new_bonus->ParryChance += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->ParryChance > effect_value))
|
else if((effect_value < 0) && (new_bonus->ParryChance > effect_value))
|
||||||
@ -1900,7 +1966,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_DualWieldChance:
|
case SE_DualWieldChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->DualWieldChance += effect_value;
|
new_bonus->DualWieldChance += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->DualWieldChance > effect_value))
|
else if((effect_value < 0) && (new_bonus->DualWieldChance > effect_value))
|
||||||
@ -1914,7 +1980,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
case SE_DoubleAttackChance:
|
case SE_DoubleAttackChance:
|
||||||
{
|
{
|
||||||
|
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->DoubleAttackChance += effect_value;
|
new_bonus->DoubleAttackChance += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->DoubleAttackChance > effect_value))
|
else if((effect_value < 0) && (new_bonus->DoubleAttackChance > effect_value))
|
||||||
@ -1928,7 +1994,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
case SE_TripleAttackChance:
|
case SE_TripleAttackChance:
|
||||||
{
|
{
|
||||||
|
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->TripleAttackChance += effect_value;
|
new_bonus->TripleAttackChance += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->TripleAttackChance > effect_value))
|
else if((effect_value < 0) && (new_bonus->TripleAttackChance > effect_value))
|
||||||
@ -1941,7 +2007,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_MeleeLifetap:
|
case SE_MeleeLifetap:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->MeleeLifetap += spells[spell_id].base[i];
|
new_bonus->MeleeLifetap += spells[spell_id].base[i];
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->MeleeLifetap > effect_value))
|
else if((effect_value < 0) && (new_bonus->MeleeLifetap > effect_value))
|
||||||
@ -1990,7 +2056,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_HundredHands:
|
case SE_HundredHands:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->HundredHands += effect_value;
|
new_bonus->HundredHands += effect_value;
|
||||||
|
|
||||||
if (effect_value > 0 && effect_value > new_bonus->HundredHands)
|
if (effect_value > 0 && effect_value > new_bonus->HundredHands)
|
||||||
@ -2004,7 +2070,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
{
|
{
|
||||||
if(new_bonus->MeleeSkillCheck < effect_value) {
|
if(new_bonus->MeleeSkillCheck < effect_value) {
|
||||||
new_bonus->MeleeSkillCheck = effect_value;
|
new_bonus->MeleeSkillCheck = effect_value;
|
||||||
new_bonus->MeleeSkillCheckSkill = base2==-1?255:base2;
|
new_bonus->MeleeSkillCheckSkill = base2==ALL_SKILLS?255:base2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2012,14 +2078,14 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
case SE_HitChance:
|
case SE_HitChance:
|
||||||
{
|
{
|
||||||
|
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus){
|
if (AdditiveWornBonus){
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->HitChanceEffect[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->HitChanceEffect[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->HitChanceEffect[base2] += effect_value;
|
new_bonus->HitChanceEffect[base2] += effect_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(base2 == -1){
|
else if(base2 == ALL_SKILLS){
|
||||||
|
|
||||||
if ((effect_value < 0) && (new_bonus->HitChanceEffect[HIGHEST_SKILL+1] > effect_value))
|
if ((effect_value < 0) && (new_bonus->HitChanceEffect[HIGHEST_SKILL+1] > effect_value))
|
||||||
new_bonus->HitChanceEffect[HIGHEST_SKILL+1] = effect_value;
|
new_bonus->HitChanceEffect[HIGHEST_SKILL+1] = effect_value;
|
||||||
@ -2045,7 +2111,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_DamageModifier:
|
case SE_DamageModifier:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->DamageModifier[base2] += effect_value;
|
new_bonus->DamageModifier[base2] += effect_value;
|
||||||
@ -2054,7 +2120,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_DamageModifier2:
|
case SE_DamageModifier2:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->DamageModifier2[base2] += effect_value;
|
new_bonus->DamageModifier2[base2] += effect_value;
|
||||||
@ -2063,7 +2129,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_MinDamageModifier:
|
case SE_MinDamageModifier:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->MinDamageModifier[base2] += effect_value;
|
new_bonus->MinDamageModifier[base2] += effect_value;
|
||||||
@ -2079,7 +2145,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_ProcChance:
|
case SE_ProcChance:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
if (AdditiveWornBonus)
|
||||||
new_bonus->ProcChanceSPA += effect_value;
|
new_bonus->ProcChanceSPA += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (new_bonus->ProcChanceSPA > effect_value))
|
else if((effect_value < 0) && (new_bonus->ProcChanceSPA > effect_value))
|
||||||
@ -2117,7 +2183,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_DivineSave:
|
case SE_DivineSave:
|
||||||
{
|
{
|
||||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus) {
|
if (AdditiveWornBonus) {
|
||||||
new_bonus->DivineSaveChance[0] += effect_value;
|
new_bonus->DivineSaveChance[0] += effect_value;
|
||||||
new_bonus->DivineSaveChance[1] = 0;
|
new_bonus->DivineSaveChance[1] = 0;
|
||||||
}
|
}
|
||||||
@ -2126,7 +2192,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
{
|
{
|
||||||
new_bonus->DivineSaveChance[0] = effect_value;
|
new_bonus->DivineSaveChance[0] = effect_value;
|
||||||
new_bonus->DivineSaveChance[1] = base2;
|
new_bonus->DivineSaveChance[1] = base2;
|
||||||
//SetDeathSaveChance(true);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2162,14 +2227,14 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
{
|
{
|
||||||
//When using npc_spells_effects if MAX value set, use stackable quest based modifier.
|
//When using npc_spells_effects if MAX value set, use stackable quest based modifier.
|
||||||
if (IsAISpellEffect && max){
|
if (IsAISpellEffect && max){
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
SkillDmgTaken_Mod[HIGHEST_SKILL+1] = effect_value;
|
SkillDmgTaken_Mod[HIGHEST_SKILL+1] = effect_value;
|
||||||
else
|
else
|
||||||
SkillDmgTaken_Mod[base2] = effect_value;
|
SkillDmgTaken_Mod[base2] = effect_value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->SkillDmgTaken[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->SkillDmgTaken[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->SkillDmgTaken[base2] += effect_value;
|
new_bonus->SkillDmgTaken[base2] += effect_value;
|
||||||
@ -2278,7 +2343,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_CriticalDamageMob:
|
case SE_CriticalDamageMob:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->CritDmgMob[base2] += effect_value;
|
new_bonus->CritDmgMob[base2] += effect_value;
|
||||||
@ -2294,7 +2359,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_SkillDamageAmount:
|
case SE_SkillDamageAmount:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->SkillDamageAmount[base2] += effect_value;
|
new_bonus->SkillDamageAmount[base2] += effect_value;
|
||||||
@ -2399,7 +2464,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
|
|
||||||
case SE_SkillDamageAmount2:
|
case SE_SkillDamageAmount2:
|
||||||
{
|
{
|
||||||
if(base2 == -1)
|
if(base2 == ALL_SKILLS)
|
||||||
new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value;
|
new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value;
|
||||||
else
|
else
|
||||||
new_bonus->SkillDamageAmount2[base2] += effect_value;
|
new_bonus->SkillDamageAmount2[base2] += effect_value;
|
||||||
@ -3046,12 +3111,12 @@ void NPC::CalcItemBonuses(StatBonuses *newbon)
|
|||||||
newbon->ProcChance += cur->CombatEffects;
|
newbon->ProcChance += cur->CombatEffects;
|
||||||
}
|
}
|
||||||
if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects
|
if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects
|
||||||
ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon);
|
ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, 0, cur->Worn.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RuleB(Spells, NPC_UseFocusFromItems)){
|
if (RuleB(Spells, NPC_UseFocusFromItems)){
|
||||||
if (cur->Focus.Effect>0 && (cur->Focus.Type == ET_Focus)){ // focus effects
|
if (cur->Focus.Effect>0 && (cur->Focus.Type == ET_Focus)){ // focus effects
|
||||||
ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon, 0, true);
|
ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
zone/bot.cpp
60
zone/bot.cpp
@ -97,7 +97,7 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
|
|||||||
|
|
||||||
strcpy(this->name, this->GetCleanName());
|
strcpy(this->name, this->GetCleanName());
|
||||||
|
|
||||||
active_light = spell_light = equip_light = innate_light = NOT_USED;
|
memset(&m_Light, 0, sizeof(LightProfile_Struct));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This constructor is used when the bot is loaded out of the database
|
// This constructor is used when the bot is loaded out of the database
|
||||||
@ -213,8 +213,6 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
|||||||
if(cur_mana > max_mana)
|
if(cur_mana > max_mana)
|
||||||
cur_mana = max_mana;
|
cur_mana = max_mana;
|
||||||
cur_end = max_end;
|
cur_end = max_end;
|
||||||
|
|
||||||
active_light = spell_light = equip_light = innate_light = NOT_USED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bot::~Bot() {
|
Bot::~Bot() {
|
||||||
@ -4121,8 +4119,8 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) {
|
|||||||
// Level the bot to the same level as the bot owner
|
// Level the bot to the same level as the bot owner
|
||||||
//this->SetLevel(botCharacterOwner->GetLevel());
|
//this->SetLevel(botCharacterOwner->GetLevel());
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
|
|
||||||
entity_list.AddBot(this, true, true);
|
entity_list.AddBot(this, true, true);
|
||||||
|
|
||||||
@ -4132,7 +4130,7 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) {
|
|||||||
this->SendPosition();
|
this->SendPosition();
|
||||||
|
|
||||||
// there is something askew with spawn struct appearance fields...
|
// there is something askew with spawn struct appearance fields...
|
||||||
// I re-enabled this until I can sort it out -U
|
// I re-enabled this until I can sort it out
|
||||||
uint32 itemID = 0;
|
uint32 itemID = 0;
|
||||||
uint8 materialFromSlot = 0xFF;
|
uint8 materialFromSlot = 0xFF;
|
||||||
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) {
|
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) {
|
||||||
@ -4187,7 +4185,7 @@ void Bot::RemoveBotItemBySlot(uint32 slotID, std::string *errorMessage) {
|
|||||||
*errorMessage = std::string(results.ErrorMessage());
|
*errorMessage = std::string(results.ErrorMessage());
|
||||||
|
|
||||||
m_inv.DeleteItem(slotID);
|
m_inv.DeleteItem(slotID);
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves all the inventory records from the database for this bot.
|
// Retrieves all the inventory records from the database for this bot.
|
||||||
@ -4249,7 +4247,7 @@ void Bot::GetBotItems(std::string* errorMessage, Inventory &inv) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the inventory record for this bot from the database for the specified equipment slot.
|
// Returns the inventory record for this bot from the database for the specified equipment slot.
|
||||||
@ -4375,8 +4373,8 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
|||||||
ns->spawn.size = 0;
|
ns->spawn.size = 0;
|
||||||
ns->spawn.NPC = 0; // 0=player,1=npc,2=pc corpse,3=npc corpse
|
ns->spawn.NPC = 0; // 0=player,1=npc,2=pc corpse,3=npc corpse
|
||||||
|
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
ns->spawn.light = active_light;
|
ns->spawn.light = m_Light.Type.Active;
|
||||||
|
|
||||||
ns->spawn.helm = helmtexture; //0xFF;
|
ns->spawn.helm = helmtexture; //0xFF;
|
||||||
ns->spawn.equip_chest2 = texture; //0xFF;
|
ns->spawn.equip_chest2 = texture; //0xFF;
|
||||||
@ -4395,24 +4393,24 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
|||||||
item = inst->GetItem();
|
item = inst->GetItem();
|
||||||
if (item != 0)
|
if (item != 0)
|
||||||
{
|
{
|
||||||
ns->spawn.equipment[i].material = item->Material;
|
ns->spawn.equipment[i].Material = item->Material;
|
||||||
ns->spawn.equipment[i].elitematerial = item->EliteMaterial;
|
ns->spawn.equipment[i].EliteMaterial = item->EliteMaterial;
|
||||||
ns->spawn.equipment[i].heroforgemodel = item->HerosForgeModel;
|
ns->spawn.equipment[i].HeroForgeModel = item->HerosForgeModel;
|
||||||
if (armor_tint[i])
|
if (armor_tint[i])
|
||||||
{
|
{
|
||||||
ns->spawn.colors[i].color = armor_tint[i];
|
ns->spawn.colors[i].Color = armor_tint[i];
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ns->spawn.colors[i].color = item->Color;
|
ns->spawn.colors[i].Color = item->Color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (armor_tint[i])
|
if (armor_tint[i])
|
||||||
{
|
{
|
||||||
ns->spawn.colors[i].color = armor_tint[i];
|
ns->spawn.colors[i].Color = armor_tint[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4426,9 +4424,9 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
|||||||
{
|
{
|
||||||
if(strlen(item->IDFile) > 2)
|
if(strlen(item->IDFile) > 2)
|
||||||
{
|
{
|
||||||
ns->spawn.equipment[MaterialPrimary].material = atoi(&item->IDFile[2]);
|
ns->spawn.equipment[MaterialPrimary].Material = atoi(&item->IDFile[2]);
|
||||||
}
|
}
|
||||||
ns->spawn.colors[MaterialPrimary].color = GetEquipmentColor(MaterialPrimary);
|
ns->spawn.colors[MaterialPrimary].Color = GetEquipmentColor(MaterialPrimary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4440,9 +4438,9 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
|||||||
{
|
{
|
||||||
if(strlen(item->IDFile) > 2)
|
if(strlen(item->IDFile) > 2)
|
||||||
{
|
{
|
||||||
ns->spawn.equipment[MaterialSecondary].material = atoi(&item->IDFile[2]);
|
ns->spawn.equipment[MaterialSecondary].Material = atoi(&item->IDFile[2]);
|
||||||
}
|
}
|
||||||
ns->spawn.colors[MaterialSecondary].color = GetEquipmentColor(MaterialSecondary);
|
ns->spawn.colors[MaterialSecondary].Color = GetEquipmentColor(MaterialSecondary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5061,7 +5059,7 @@ void Bot::SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32
|
|||||||
|
|
||||||
wc->spawn_id = GetID();
|
wc->spawn_id = GetID();
|
||||||
wc->material = material;
|
wc->material = material;
|
||||||
wc->color.color = color;
|
wc->color.Color = color;
|
||||||
wc->wear_slot_id = material_slot;
|
wc->wear_slot_id = material_slot;
|
||||||
|
|
||||||
entity_list.QueueClients(this, outapp);
|
entity_list.QueueClients(this, outapp);
|
||||||
@ -5088,9 +5086,9 @@ void Bot::BotAddEquipItem(int slot, uint32 id) {
|
|||||||
SendWearChange(materialFromSlot);
|
SendWearChange(materialFromSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue())
|
if (UpdateActiveLight())
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5106,9 +5104,9 @@ void Bot::BotRemoveEquipItem(int slot) {
|
|||||||
SendWearChange(MaterialArms);
|
SendWearChange(MaterialArms);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue())
|
if (UpdateActiveLight())
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8407,7 +8405,7 @@ void Bot::EquipBot(std::string* errorMessage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
//// This method is meant to be called by zone or client methods to clean up objects when a client camps, goes LD, zones out or something like that.
|
//// This method is meant to be called by zone or client methods to clean up objects when a client camps, goes LD, zones out or something like that.
|
||||||
@ -10823,7 +10821,7 @@ void Bot::ProcessBotInspectionRequest(Bot* inspectedBot, Client* client) {
|
|||||||
|
|
||||||
// Modded to display power source items (will only show up on SoF+ client inspect windows though.)
|
// Modded to display power source items (will only show up on SoF+ client inspect windows though.)
|
||||||
// I don't think bots are currently coded to use them..but, you'll have to use '#bot inventory list'
|
// I don't think bots are currently coded to use them..but, you'll have to use '#bot inventory list'
|
||||||
// to see them on a Titanium client when/if they are activated. -U
|
// to see them on a Titanium client when/if they are activated.
|
||||||
for(int16 L = EmuConstants::EQUIPMENT_BEGIN; L <= MainWaist; L++) {
|
for(int16 L = EmuConstants::EQUIPMENT_BEGIN; L <= MainWaist; L++) {
|
||||||
inst = inspectedBot->GetBotItem(L);
|
inst = inspectedBot->GetBotItem(L);
|
||||||
|
|
||||||
@ -10959,7 +10957,7 @@ void Bot::CalcItemBonuses()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
||||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses);
|
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11043,7 +11041,7 @@ void Bot::CalcItemBonuses()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects
|
||||||
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses);
|
ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -332,7 +332,7 @@ public:
|
|||||||
void EquipBot(std::string* errorMessage);
|
void EquipBot(std::string* errorMessage);
|
||||||
bool CheckLoreConflict(const Item_Struct* item);
|
bool CheckLoreConflict(const Item_Struct* item);
|
||||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||||
virtual void UpdateEquipLightValue() { equip_light = m_inv.FindHighestLightValue(); }
|
virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = m_inv.FindBrightestLightType(); m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); }
|
||||||
|
|
||||||
// Static Class Methods
|
// Static Class Methods
|
||||||
static void SaveBotGroup(Group* botGroup, std::string botGroupName, std::string* errorMessage);
|
static void SaveBotGroup(Group* botGroup, std::string botGroupName, std::string* errorMessage);
|
||||||
|
|||||||
172
zone/client.cpp
172
zone/client.cpp
@ -141,6 +141,10 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
merc_timer(RuleI(Mercs, UpkeepIntervalMS)),
|
merc_timer(RuleI(Mercs, UpkeepIntervalMS)),
|
||||||
ItemTickTimer(10000),
|
ItemTickTimer(10000),
|
||||||
ItemQuestTimer(500),
|
ItemQuestTimer(500),
|
||||||
|
anon_toggle_timer(250),
|
||||||
|
afk_toggle_timer(250),
|
||||||
|
helm_toggle_timer(250),
|
||||||
|
light_update_timer(600),
|
||||||
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
|
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
|
||||||
m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f),
|
m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f),
|
||||||
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
|
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
|
||||||
@ -161,6 +165,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
Trader=false;
|
Trader=false;
|
||||||
Buyer = false;
|
Buyer = false;
|
||||||
CustomerID = 0;
|
CustomerID = 0;
|
||||||
|
TraderID = 0;
|
||||||
TrackingID = 0;
|
TrackingID = 0;
|
||||||
WID = 0;
|
WID = 0;
|
||||||
account_id = 0;
|
account_id = 0;
|
||||||
@ -245,7 +250,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
AttemptedMessages = 0;
|
AttemptedMessages = 0;
|
||||||
TotalKarma = 0;
|
TotalKarma = 0;
|
||||||
m_ClientVersion = ClientVersion::Unknown;
|
m_ClientVersion = ClientVersion::Unknown;
|
||||||
ClientVersionBit = 0;
|
m_ClientVersionBit = 0;
|
||||||
AggroCount = 0;
|
AggroCount = 0;
|
||||||
RestRegenHP = 0;
|
RestRegenHP = 0;
|
||||||
RestRegenMana = 0;
|
RestRegenMana = 0;
|
||||||
@ -303,9 +308,6 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
|
|
||||||
interrogateinv_flag = false;
|
interrogateinv_flag = false;
|
||||||
|
|
||||||
active_light = innate_light;
|
|
||||||
spell_light = equip_light = NOT_USED;
|
|
||||||
|
|
||||||
AI_Init();
|
AI_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,6 +411,69 @@ Client::~Client() {
|
|||||||
UninitializeBuffSlots();
|
UninitializeBuffSlots();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::SendZoneInPackets()
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// Spawn Appearance Packet
|
||||||
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
||||||
|
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
||||||
|
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
||||||
|
sa->parameter = GetID(); // Four bytes for this parameter...
|
||||||
|
outapp->priority = 6;
|
||||||
|
QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
|
||||||
|
// Inform the world about the client
|
||||||
|
outapp = new EQApplicationPacket();
|
||||||
|
|
||||||
|
CreateSpawnPacket(outapp);
|
||||||
|
outapp->priority = 6;
|
||||||
|
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
||||||
|
safe_delete(outapp);
|
||||||
|
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
||||||
|
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
||||||
|
|
||||||
|
//Send AA Exp packet:
|
||||||
|
if (GetLevel() >= 51)
|
||||||
|
SendAAStats();
|
||||||
|
|
||||||
|
// Send exp packets
|
||||||
|
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||||
|
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
||||||
|
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
||||||
|
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
||||||
|
|
||||||
|
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
||||||
|
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
||||||
|
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
||||||
|
eu->exp = (uint32)(330.0f * tmpxp);
|
||||||
|
outapp->priority = 6;
|
||||||
|
QueuePacket(outapp);
|
||||||
|
}
|
||||||
|
safe_delete(outapp);
|
||||||
|
|
||||||
|
SendAATimers();
|
||||||
|
|
||||||
|
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||||
|
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||||
|
strcpy(zonesendname->name, m_pp.name);
|
||||||
|
strcpy(zonesendname->name2, m_pp.name);
|
||||||
|
zonesendname->unknown0 = 0x0A;
|
||||||
|
QueuePacket(outapp);
|
||||||
|
safe_delete(outapp);
|
||||||
|
|
||||||
|
if (IsInAGuild()) {
|
||||||
|
SendGuildMembers();
|
||||||
|
SendGuildURL();
|
||||||
|
SendGuildChannel();
|
||||||
|
SendGuildLFGuildStatus();
|
||||||
|
}
|
||||||
|
SendLFGuildStatus();
|
||||||
|
|
||||||
|
//No idea why live sends this if even were not in a guild
|
||||||
|
SendGuildMOTD();
|
||||||
|
}
|
||||||
|
|
||||||
void Client::SendLogoutPackets() {
|
void Client::SendLogoutPackets() {
|
||||||
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_CancelTrade, sizeof(CancelTrade_Struct));
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_CancelTrade, sizeof(CancelTrade_Struct));
|
||||||
@ -1801,9 +1866,9 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
ns->spawn.runspeed = (gmspeed == 0) ? runspeed : 3.125f;
|
ns->spawn.runspeed = (gmspeed == 0) ? runspeed : 3.125f;
|
||||||
ns->spawn.showhelm = m_pp.showhelm ? 1 : 0;
|
ns->spawn.showhelm = m_pp.showhelm ? 1 : 0;
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
ns->spawn.light = active_light;
|
ns->spawn.light = m_Light.Type.Active;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::GMHideMe(Client* client) {
|
bool Client::GMHideMe(Client* client) {
|
||||||
@ -2471,11 +2536,13 @@ void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32
|
|||||||
|
|
||||||
bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
||||||
EQApplicationPacket* outapp = 0;
|
EQApplicationPacket* outapp = 0;
|
||||||
if(!fail) {
|
if(!fail)
|
||||||
|
{
|
||||||
outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct));
|
outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct));
|
||||||
BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer;
|
BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer;
|
||||||
// Start bind
|
// Start bind
|
||||||
if(!bindwound_timer.Enabled()) {
|
if(!bindwound_timer.Enabled())
|
||||||
|
{
|
||||||
//make sure we actually have a bandage... and consume it.
|
//make sure we actually have a bandage... and consume it.
|
||||||
int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal);
|
int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal);
|
||||||
if (bslot == INVALID_INDEX) {
|
if (bslot == INVALID_INDEX) {
|
||||||
@ -2521,7 +2588,9 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){
|
|||||||
; // Binding self
|
; // Binding self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else if (bindwound_timer.Check()) // Did the timer finish?
|
||||||
|
{
|
||||||
// finish bind
|
// finish bind
|
||||||
// disable complete timer
|
// disable complete timer
|
||||||
bindwound_timer.Disable();
|
bindwound_timer.Disable();
|
||||||
@ -2967,7 +3036,7 @@ void Client::Tell_StringID(uint32 string_id, const char *who, const char *messag
|
|||||||
|
|
||||||
void Client::SetTint(int16 in_slot, uint32 color) {
|
void Client::SetTint(int16 in_slot, uint32 color) {
|
||||||
Color_Struct new_color;
|
Color_Struct new_color;
|
||||||
new_color.color = color;
|
new_color.Color = color;
|
||||||
SetTint(in_slot, new_color);
|
SetTint(in_slot, new_color);
|
||||||
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color);
|
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color);
|
||||||
}
|
}
|
||||||
@ -2978,8 +3047,8 @@ void Client::SetTint(int16 in_slot, Color_Struct& color) {
|
|||||||
uint8 matslot = Inventory::CalcMaterialFromSlot(in_slot);
|
uint8 matslot = Inventory::CalcMaterialFromSlot(in_slot);
|
||||||
if (matslot != _MaterialInvalid)
|
if (matslot != _MaterialInvalid)
|
||||||
{
|
{
|
||||||
m_pp.item_tint[matslot].color = color.color;
|
m_pp.item_tint[matslot].Color = color.Color;
|
||||||
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.color);
|
database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.Color);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -5290,35 +5359,35 @@ void Client::SendRewards()
|
|||||||
FastQueuePacket(&vetapp);
|
FastQueuePacket(&vetapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::TryReward(uint32 claim_id) {
|
bool Client::TryReward(uint32 claim_id)
|
||||||
//Make sure we have an open spot
|
{
|
||||||
//Make sure we have it in our acct and count > 0
|
// Make sure we have an open spot
|
||||||
//Make sure the entry was found
|
// Make sure we have it in our acct and count > 0
|
||||||
//If we meet all the criteria:
|
// Make sure the entry was found
|
||||||
//Decrement our count by 1 if it > 1 delete if it == 1
|
// If we meet all the criteria:
|
||||||
//Create our item in bag if necessary at the free inv slot
|
// Decrement our count by 1 if it > 1 delete if it == 1
|
||||||
//save
|
// Create our item in bag if necessary at the free inv slot
|
||||||
|
// save
|
||||||
uint32 free_slot = 0xFFFFFFFF;
|
uint32 free_slot = 0xFFFFFFFF;
|
||||||
|
|
||||||
for(int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; ++i) {
|
for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; ++i) {
|
||||||
ItemInst *item = GetInv().GetItem(i);
|
ItemInst *item = GetInv().GetItem(i);
|
||||||
if(!item) {
|
if (!item) {
|
||||||
free_slot = i;
|
free_slot = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(free_slot == 0xFFFFFFFF)
|
if (free_slot == 0xFFFFFFFF)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||||
std::string query = StringFormat("SELECT amount FROM account_rewards "
|
std::string query = StringFormat("SELECT amount FROM account_rewards "
|
||||||
"WHERE account_id = %i AND reward_id = %i",
|
"WHERE account_id = %i AND reward_id = %i",
|
||||||
AccountID(), claim_id);
|
AccountID(), claim_id);
|
||||||
auto results = database.QueryDatabase(query);
|
auto results = database.QueryDatabase(query);
|
||||||
if (!results.Success()) {
|
if (!results.Success())
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (results.RowCount() == 0)
|
if (results.RowCount() == 0)
|
||||||
return false;
|
return false;
|
||||||
@ -5326,58 +5395,57 @@ bool Client::TryReward(uint32 claim_id) {
|
|||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
uint32 amt = atoi(row[0]);
|
uint32 amt = atoi(row[0]);
|
||||||
if(amt == 0)
|
if (amt == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::list<InternalVeteranReward>::iterator iter = zone->VeteranRewards.begin();
|
auto iter = std::find_if(zone->VeteranRewards.begin(), zone->VeteranRewards.end(),
|
||||||
for (; iter != zone->VeteranRewards.end(); ++row)
|
[claim_id](const InternalVeteranReward &a) { return a.claim_id == claim_id; });
|
||||||
if((*iter).claim_id == claim_id)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(iter == zone->VeteranRewards.end())
|
if (iter == zone->VeteranRewards.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(amt == 1) {
|
if (amt == 1) {
|
||||||
query = StringFormat("DELETE FROM account_rewards "
|
query = StringFormat("DELETE FROM account_rewards "
|
||||||
"WHERE account_id = %i AND reward_id = %i",
|
"WHERE account_id = %i AND reward_id = %i",
|
||||||
AccountID(), claim_id);
|
AccountID(), claim_id);
|
||||||
auto results = database.QueryDatabase(query);
|
auto results = database.QueryDatabase(query);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
query = StringFormat("UPDATE account_rewards SET amount = (amount-1) "
|
query = StringFormat("UPDATE account_rewards SET amount = (amount-1) "
|
||||||
"WHERE account_id = %i AND reward_id = %i",
|
"WHERE account_id = %i AND reward_id = %i",
|
||||||
AccountID(), claim_id);
|
AccountID(), claim_id);
|
||||||
auto results = database.QueryDatabase(query);
|
auto results = database.QueryDatabase(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalVeteranReward ivr = (*iter);
|
auto &ivr = (*iter);
|
||||||
ItemInst *claim = database.CreateItem(ivr.items[0].item_id, ivr.items[0].charges);
|
ItemInst *claim = database.CreateItem(ivr.items[0].item_id, ivr.items[0].charges);
|
||||||
if(!claim) {
|
if (!claim) {
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lore_conflict = CheckLoreConflict(claim->GetItem());
|
bool lore_conflict = CheckLoreConflict(claim->GetItem());
|
||||||
|
|
||||||
for(int y = 1; y < 8; y++)
|
for (int y = 1; y < 8; y++)
|
||||||
if(ivr.items[y].item_id && claim->GetItem()->ItemClass == 1) {
|
if (ivr.items[y].item_id && claim->GetItem()->ItemClass == 1) {
|
||||||
ItemInst *item_temp = database.CreateItem(ivr.items[y].item_id, ivr.items[y].charges);
|
ItemInst *item_temp = database.CreateItem(ivr.items[y].item_id, ivr.items[y].charges);
|
||||||
if(item_temp) {
|
if (item_temp) {
|
||||||
if(CheckLoreConflict(item_temp->GetItem())) {
|
if (CheckLoreConflict(item_temp->GetItem())) {
|
||||||
lore_conflict = true;
|
lore_conflict = true;
|
||||||
DuplicateLoreMessage(ivr.items[y].item_id);
|
DuplicateLoreMessage(ivr.items[y].item_id);
|
||||||
}
|
}
|
||||||
claim->PutItem(y-1, *item_temp);
|
claim->PutItem(y - 1, *item_temp);
|
||||||
|
safe_delete(item_temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lore_conflict) {
|
if (lore_conflict) {
|
||||||
safe_delete(claim);
|
safe_delete(claim);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PutItemInInventory(free_slot, *claim);
|
PutItemInInventory(free_slot, *claim);
|
||||||
SendItemPacket(free_slot, claim, ItemPacketTrade);
|
SendItemPacket(free_slot, claim, ItemPacketTrade);
|
||||||
|
safe_delete(claim);
|
||||||
|
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
@ -6149,6 +6217,8 @@ void Client::DragCorpses()
|
|||||||
!corpse->CastToCorpse()->Summon(this, false, false)) {
|
!corpse->CastToCorpse()->Summon(this, false, false)) {
|
||||||
Message_StringID(MT_DefaultText, CORPSEDRAG_STOP);
|
Message_StringID(MT_DefaultText, CORPSEDRAG_STOP);
|
||||||
It = DraggedCorpses.erase(It);
|
It = DraggedCorpses.erase(It);
|
||||||
|
if (It == DraggedCorpses.end())
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6173,7 +6243,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
|
|||||||
|
|
||||||
NPCType *made_npc = nullptr;
|
NPCType *made_npc = nullptr;
|
||||||
|
|
||||||
const NPCType *npc_type = database.GetNPCType(pet.npc_id);
|
const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id);
|
||||||
if(npc_type == nullptr) {
|
if(npc_type == nullptr) {
|
||||||
Log.Out(Logs::General, Logs::Error, "Unknown npc type for doppelganger spell id: %d", spell_id);
|
Log.Out(Logs::General, Logs::Error, "Unknown npc type for doppelganger spell id: %d", spell_id);
|
||||||
Message(0,"Unable to find pet!");
|
Message(0,"Unable to find pet!");
|
||||||
@ -7396,7 +7466,7 @@ void Client::SendClearMercInfo()
|
|||||||
|
|
||||||
void Client::DuplicateLoreMessage(uint32 ItemID)
|
void Client::DuplicateLoreMessage(uint32 ItemID)
|
||||||
{
|
{
|
||||||
if(!(ClientVersionBit & BIT_RoFAndLater))
|
if (!(m_ClientVersionBit & BIT_RoFAndLater))
|
||||||
{
|
{
|
||||||
Message_StringID(0, PICK_LORE);
|
Message_StringID(0, PICK_LORE);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -266,10 +266,11 @@ public:
|
|||||||
void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice);
|
void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice);
|
||||||
void SendTraderItem(uint32 item_id,uint16 quantity);
|
void SendTraderItem(uint32 item_id,uint16 quantity);
|
||||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||||
|
uint32 FindTraderItemSerialNumber(int32 ItemID);
|
||||||
ItemInst* FindTraderItemBySerialNumber(int32 SerialNumber);
|
ItemInst* FindTraderItemBySerialNumber(int32 SerialNumber);
|
||||||
void FindAndNukeTraderItem(int32 item_id,uint16 quantity,Client* customer,uint16 traderslot);
|
void FindAndNukeTraderItem(int32 item_id,uint16 quantity,Client* customer,uint16 traderslot);
|
||||||
void NukeTraderItem(uint16 slot,int16 charges,uint16 quantity,Client* customer,uint16 traderslot, int uniqueid);
|
void NukeTraderItem(uint16 slot, int16 charges, uint16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0);
|
||||||
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges);
|
void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0);
|
||||||
void TradeRequestFailed(const EQApplicationPacket* app);
|
void TradeRequestFailed(const EQApplicationPacket* app);
|
||||||
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app);
|
||||||
void TraderUpdate(uint16 slot_id,uint32 trader_id);
|
void TraderUpdate(uint16 slot_id,uint32 trader_id);
|
||||||
@ -730,7 +731,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
uint32 GetEquipment(uint8 material_slot) const; // returns item id
|
uint32 GetEquipment(uint8 material_slot) const; // returns item id
|
||||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||||
virtual void UpdateEquipLightValue() { equip_light = m_inv.FindHighestLightValue(); }
|
virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = m_inv.FindBrightestLightType(); m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); }
|
||||||
|
|
||||||
inline bool AutoSplitEnabled() { return m_pp.autosplit != 0; }
|
inline bool AutoSplitEnabled() { return m_pp.autosplit != 0; }
|
||||||
|
|
||||||
@ -1021,7 +1022,7 @@ public:
|
|||||||
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
|
inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); }
|
||||||
|
|
||||||
inline const ClientVersion GetClientVersion() const { return m_ClientVersion; }
|
inline const ClientVersion GetClientVersion() const { return m_ClientVersion; }
|
||||||
inline const uint32 GetClientVersionBit() const { return ClientVersionBit; }
|
inline const uint32 GetClientVersionBit() const { return m_ClientVersionBit; }
|
||||||
inline void SetClientVersion(ClientVersion in) { m_ClientVersion = in; }
|
inline void SetClientVersion(ClientVersion in) { m_ClientVersion = in; }
|
||||||
|
|
||||||
/** Adventure Stuff **/
|
/** Adventure Stuff **/
|
||||||
@ -1139,7 +1140,7 @@ public:
|
|||||||
void HandleLFGuildResponse(ServerPacket *pack);
|
void HandleLFGuildResponse(ServerPacket *pack);
|
||||||
void SendLFGuildStatus();
|
void SendLFGuildStatus();
|
||||||
void SendGuildLFGuildStatus();
|
void SendGuildLFGuildStatus();
|
||||||
inline bool XTargettingAvailable() const { return ((ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); }
|
inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); }
|
||||||
inline uint8 GetMaxXTargets() const { return MaxXTargets; }
|
inline uint8 GetMaxXTargets() const { return MaxXTargets; }
|
||||||
void SetMaxXTargets(uint8 NewMax);
|
void SetMaxXTargets(uint8 NewMax);
|
||||||
bool IsXTarget(const Mob *m) const;
|
bool IsXTarget(const Mob *m) const;
|
||||||
@ -1257,10 +1258,12 @@ protected:
|
|||||||
friend class Mob;
|
friend class Mob;
|
||||||
void CalcItemBonuses(StatBonuses* newbon);
|
void CalcItemBonuses(StatBonuses* newbon);
|
||||||
void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false);
|
void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false);
|
||||||
|
void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false);
|
||||||
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
|
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
|
||||||
void CalcEdibleBonuses(StatBonuses* newbon);
|
void CalcEdibleBonuses(StatBonuses* newbon);
|
||||||
void CalcAABonuses(StatBonuses* newbon);
|
void CalcAABonuses(StatBonuses* newbon);
|
||||||
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
|
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
|
||||||
|
void ProcessItemCaps();
|
||||||
void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true);
|
void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true);
|
||||||
bool client_data_loaded;
|
bool client_data_loaded;
|
||||||
|
|
||||||
@ -1314,6 +1317,7 @@ private:
|
|||||||
int32 GetACMit();
|
int32 GetACMit();
|
||||||
int32 GetACAvoid();
|
int32 GetACAvoid();
|
||||||
int32 CalcATK();
|
int32 CalcATK();
|
||||||
|
int32 CalcItemATKCap();
|
||||||
int32 CalcHaste();
|
int32 CalcHaste();
|
||||||
|
|
||||||
int32 CalcAlcoholPhysicalEffect();
|
int32 CalcAlcoholPhysicalEffect();
|
||||||
@ -1387,6 +1391,7 @@ private:
|
|||||||
uint16 BoatID;
|
uint16 BoatID;
|
||||||
uint16 TrackingID;
|
uint16 TrackingID;
|
||||||
uint16 CustomerID;
|
uint16 CustomerID;
|
||||||
|
uint16 TraderID;
|
||||||
uint32 account_creation;
|
uint32 account_creation;
|
||||||
uint8 firstlogon;
|
uint8 firstlogon;
|
||||||
uint32 mercid; // current merc
|
uint32 mercid; // current merc
|
||||||
@ -1414,6 +1419,7 @@ private:
|
|||||||
|
|
||||||
bool CanBeInZone();
|
bool CanBeInZone();
|
||||||
void SendLogoutPackets();
|
void SendLogoutPackets();
|
||||||
|
void SendZoneInPackets();
|
||||||
bool AddPacket(const EQApplicationPacket *, bool);
|
bool AddPacket(const EQApplicationPacket *, bool);
|
||||||
bool AddPacket(EQApplicationPacket**, bool);
|
bool AddPacket(EQApplicationPacket**, bool);
|
||||||
bool SendAllPackets();
|
bool SendAllPackets();
|
||||||
@ -1464,6 +1470,10 @@ private:
|
|||||||
Timer TrackingTimer;
|
Timer TrackingTimer;
|
||||||
Timer RespawnFromHoverTimer;
|
Timer RespawnFromHoverTimer;
|
||||||
Timer merc_timer;
|
Timer merc_timer;
|
||||||
|
Timer anon_toggle_timer;
|
||||||
|
Timer afk_toggle_timer;
|
||||||
|
Timer helm_toggle_timer;
|
||||||
|
Timer light_update_timer;
|
||||||
|
|
||||||
glm::vec3 m_Proximity;
|
glm::vec3 m_Proximity;
|
||||||
|
|
||||||
@ -1509,7 +1519,7 @@ private:
|
|||||||
uint32 AttemptedMessages;
|
uint32 AttemptedMessages;
|
||||||
|
|
||||||
ClientVersion m_ClientVersion;
|
ClientVersion m_ClientVersion;
|
||||||
uint32 ClientVersionBit;
|
uint32 m_ClientVersionBit;
|
||||||
|
|
||||||
int XPRate;
|
int XPRate;
|
||||||
|
|
||||||
|
|||||||
@ -2148,6 +2148,12 @@ int32 Client::CalcEnduranceRegenCap()
|
|||||||
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 Client::CalcItemATKCap()
|
||||||
|
{
|
||||||
|
int cap = RuleI(Character, ItemATKCap) + itembonuses.ItemATKCap + spellbonuses.ItemATKCap + aabonuses.ItemATKCap;
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
|
|
||||||
int Client::GetRawACNoShield(int &shield_ac) const
|
int Client::GetRawACNoShield(int &shield_ac) const
|
||||||
{
|
{
|
||||||
int ac = itembonuses.AC + spellbonuses.AC + aabonuses.AC;
|
int ac = itembonuses.AC + spellbonuses.AC + aabonuses.AC;
|
||||||
|
|||||||
@ -335,7 +335,13 @@ void MapOpcodes()
|
|||||||
ConnectedOpcodes[OP_Save] = &Client::Handle_OP_Save;
|
ConnectedOpcodes[OP_Save] = &Client::Handle_OP_Save;
|
||||||
ConnectedOpcodes[OP_SaveOnZoneReq] = &Client::Handle_OP_SaveOnZoneReq;
|
ConnectedOpcodes[OP_SaveOnZoneReq] = &Client::Handle_OP_SaveOnZoneReq;
|
||||||
ConnectedOpcodes[OP_SelectTribute] = &Client::Handle_OP_SelectTribute;
|
ConnectedOpcodes[OP_SelectTribute] = &Client::Handle_OP_SelectTribute;
|
||||||
ConnectedOpcodes[OP_SenseHeading] = &Client::Handle_OP_Ignore;
|
|
||||||
|
// Use or Ignore sense heading based on rule.
|
||||||
|
bool train=RuleB(Skills, TrainSenseHeading);
|
||||||
|
|
||||||
|
ConnectedOpcodes[OP_SenseHeading] =
|
||||||
|
(train) ? &Client::Handle_OP_SenseHeading : &Client::Handle_OP_Ignore;
|
||||||
|
|
||||||
ConnectedOpcodes[OP_SenseTraps] = &Client::Handle_OP_SenseTraps;
|
ConnectedOpcodes[OP_SenseTraps] = &Client::Handle_OP_SenseTraps;
|
||||||
ConnectedOpcodes[OP_SetGuildMOTD] = &Client::Handle_OP_SetGuildMOTD;
|
ConnectedOpcodes[OP_SetGuildMOTD] = &Client::Handle_OP_SetGuildMOTD;
|
||||||
ConnectedOpcodes[OP_SetRunMode] = &Client::Handle_OP_SetRunMode;
|
ConnectedOpcodes[OP_SetRunMode] = &Client::Handle_OP_SetRunMode;
|
||||||
@ -728,8 +734,8 @@ void Client::CompleteConnect()
|
|||||||
SendWearChange(x);
|
SendWearChange(x);
|
||||||
}
|
}
|
||||||
// added due to wear change above
|
// added due to wear change above
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
|
|
||||||
Mob *pet = GetPet();
|
Mob *pet = GetPet();
|
||||||
if (pet != nullptr) {
|
if (pet != nullptr) {
|
||||||
@ -737,8 +743,8 @@ void Client::CompleteConnect()
|
|||||||
pet->SendWearChange(x);
|
pet->SendWearChange(x);
|
||||||
}
|
}
|
||||||
// added due to wear change above
|
// added due to wear change above
|
||||||
pet->UpdateActiveLightValue();
|
pet->UpdateActiveLight();
|
||||||
pet->SendAppearancePacket(AT_Light, pet->GetActiveLightValue());
|
pet->SendAppearancePacket(AT_Light, pet->GetActiveLightType());
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_list.SendTraders(this);
|
entity_list.SendTraders(this);
|
||||||
@ -1092,76 +1098,15 @@ void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app)
|
void Client::Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////////
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendExpZonein, 0);
|
||||||
// Spawn Appearance Packet
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
|
||||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
|
||||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
|
||||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
|
||||||
outapp->priority = 6;
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
// Inform the world about the client
|
// SoF+ Gets Zone-In packets after sending OP_WorldObjectsSent
|
||||||
outapp = new EQApplicationPacket();
|
if (GetClientVersion() < ClientVersion::SoF)
|
||||||
|
{
|
||||||
CreateSpawnPacket(outapp);
|
SendZoneInPackets();
|
||||||
outapp->priority = 6;
|
|
||||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
|
||||||
safe_delete(outapp);
|
|
||||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
|
||||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
|
||||||
|
|
||||||
//Send AA Exp packet:
|
|
||||||
if (GetLevel() >= 51)
|
|
||||||
SendAAStats();
|
|
||||||
|
|
||||||
// Send exp packets
|
|
||||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
|
||||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
|
||||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
|
||||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
|
||||||
|
|
||||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
|
||||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
|
||||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
|
||||||
eu->exp = (uint32)(330.0f * tmpxp);
|
|
||||||
outapp->priority = 6;
|
|
||||||
QueuePacket(outapp);
|
|
||||||
}
|
}
|
||||||
safe_delete(outapp);
|
|
||||||
|
|
||||||
SendAATimers();
|
|
||||||
|
|
||||||
outapp = new EQApplicationPacket(OP_SendExpZonein, 0);
|
|
||||||
QueuePacket(outapp);
|
|
||||||
safe_delete(outapp);
|
|
||||||
|
|
||||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
|
||||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
|
||||||
strcpy(zonesendname->name, m_pp.name);
|
|
||||||
strcpy(zonesendname->name2, m_pp.name);
|
|
||||||
zonesendname->unknown0 = 0x0A;
|
|
||||||
QueuePacket(outapp);
|
|
||||||
safe_delete(outapp);
|
|
||||||
|
|
||||||
/* this is actually the guild MOTD
|
|
||||||
outapp = new EQApplicationPacket(OP_ZoneInSendName2, sizeof(ZoneInSendName_Struct2));
|
|
||||||
ZoneInSendName_Struct2* zonesendname2=(ZoneInSendName_Struct2*)outapp->pBuffer;
|
|
||||||
strcpy(zonesendname2->name,m_pp.name);
|
|
||||||
QueuePacket(outapp);
|
|
||||||
safe_delete(outapp);*/
|
|
||||||
|
|
||||||
if (IsInAGuild()) {
|
|
||||||
SendGuildMembers();
|
|
||||||
SendGuildURL();
|
|
||||||
SendGuildChannel();
|
|
||||||
SendGuildLFGuildStatus();
|
|
||||||
}
|
|
||||||
SendLFGuildStatus();
|
|
||||||
|
|
||||||
//No idea why live sends this if even were not in a guild
|
|
||||||
SendGuildMOTD();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1219,72 +1164,13 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app)
|
void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
//This is a copy of SendExpZonein created for SoF+ due to packet order change
|
// New for SoF+
|
||||||
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0);
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
// Spawn Appearance Packet
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
|
|
||||||
SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer;
|
|
||||||
sa->type = AT_SpawnID; // Is 0x10 used to set the player id?
|
|
||||||
sa->parameter = GetID(); // Four bytes for this parameter...
|
|
||||||
outapp->priority = 6;
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
// Inform the world about the client
|
// Packet order changed for SoF+, so below is sent here instead of OP_SendExpLogin
|
||||||
outapp = new EQApplicationPacket();
|
SendZoneInPackets();
|
||||||
|
|
||||||
CreateSpawnPacket(outapp);
|
|
||||||
outapp->priority = 6;
|
|
||||||
if (!GetHideMe()) entity_list.QueueClients(this, outapp, true);
|
|
||||||
safe_delete(outapp);
|
|
||||||
if (GetPVP()) //force a PVP update until we fix the spawn struct
|
|
||||||
SendAppearancePacket(AT_PVP, GetPVP(), true, false);
|
|
||||||
|
|
||||||
//Send AA Exp packet:
|
|
||||||
if (GetLevel() >= 51)
|
|
||||||
SendAAStats();
|
|
||||||
|
|
||||||
// Send exp packets
|
|
||||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
|
||||||
ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer;
|
|
||||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1);
|
|
||||||
uint32 tmpxp2 = GetEXPForLevel(GetLevel());
|
|
||||||
|
|
||||||
// Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc)
|
|
||||||
if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) {
|
|
||||||
float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2);
|
|
||||||
eu->exp = (uint32)(330.0f * tmpxp);
|
|
||||||
outapp->priority = 6;
|
|
||||||
QueuePacket(outapp);
|
|
||||||
}
|
|
||||||
safe_delete(outapp);
|
|
||||||
|
|
||||||
SendAATimers();
|
|
||||||
|
|
||||||
// New for Secrets of Faydwer - Used in Place of OP_SendExpZonein
|
|
||||||
outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0);
|
|
||||||
QueuePacket(outapp);
|
|
||||||
safe_delete(outapp);
|
|
||||||
|
|
||||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
|
||||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
|
||||||
strcpy(zonesendname->name, m_pp.name);
|
|
||||||
strcpy(zonesendname->name2, m_pp.name);
|
|
||||||
zonesendname->unknown0 = 0x0A;
|
|
||||||
QueuePacket(outapp);
|
|
||||||
safe_delete(outapp);
|
|
||||||
|
|
||||||
if (IsInAGuild()) {
|
|
||||||
SendGuildMembers();
|
|
||||||
SendGuildURL();
|
|
||||||
SendGuildChannel();
|
|
||||||
SendGuildLFGuildStatus();
|
|
||||||
}
|
|
||||||
SendLFGuildStatus();
|
|
||||||
|
|
||||||
//No idea why live sends this if even were not in a guild
|
|
||||||
SendGuildMOTD();
|
|
||||||
|
|
||||||
if (RuleB(Mercs, AllowMercs))
|
if (RuleB(Mercs, AllowMercs))
|
||||||
{
|
{
|
||||||
@ -1314,8 +1200,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
conn_state = ReceivedZoneEntry;
|
conn_state = ReceivedZoneEntry;
|
||||||
|
|
||||||
SetClientVersion(Connection()->GetClientVersion());
|
SetClientVersion(Connection()->GetClientVersion());
|
||||||
if (m_ClientVersion != ClientVersion::Unknown)
|
m_ClientVersionBit = ClientBitFromVersion(Connection()->GetClientVersion());
|
||||||
ClientVersionBit = 1 << (static_cast<unsigned int>(m_ClientVersion) - 1);
|
|
||||||
|
|
||||||
bool siv = m_inv.SetInventoryVersion(m_ClientVersion);
|
bool siv = m_inv.SetInventoryVersion(m_ClientVersion);
|
||||||
Log.Out(Logs::General, Logs::None, "%s inventory version to %s(%i)", (siv ? "Succeeded in setting" : "Failed to set"), ClientVersionName(m_ClientVersion), m_ClientVersion);
|
Log.Out(Logs::General, Logs::None, "%s inventory version to %s(%i)", (siv ? "Succeeded in setting" : "Failed to set"), ClientVersionName(m_ClientVersion), m_ClientVersion);
|
||||||
@ -1430,9 +1315,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
/* Set item material tint */
|
/* Set item material tint */
|
||||||
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++)
|
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++)
|
||||||
{
|
{
|
||||||
if (m_pp.item_tint[i].rgb.use_tint == 1 || m_pp.item_tint[i].rgb.use_tint == 255)
|
if (m_pp.item_tint[i].RGB.UseTint == 1 || m_pp.item_tint[i].RGB.UseTint == 255)
|
||||||
{
|
{
|
||||||
m_pp.item_tint[i].rgb.use_tint = 0xFF;
|
m_pp.item_tint[i].RGB.UseTint = 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1555,10 +1440,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; }
|
if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; }
|
||||||
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; }
|
if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; }
|
||||||
|
|
||||||
/* Set Swimming Skill 100 by default if under 100 */
|
|
||||||
if (GetSkill(SkillSwimming) < 100)
|
|
||||||
SetSkill(SkillSwimming, 100);
|
|
||||||
|
|
||||||
/* Initialize AA's : Move to function eventually */
|
/* Initialize AA's : Move to function eventually */
|
||||||
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; }
|
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; }
|
||||||
query = StringFormat(
|
query = StringFormat(
|
||||||
@ -1841,9 +1722,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
if (loaditems) { /* Dont load if a length error occurs */
|
if (loaditems) { /* Dont load if a length error occurs */
|
||||||
BulkSendInventoryItems();
|
BulkSendInventoryItems();
|
||||||
/* Send stuff on the cursor which isnt sent in bulk */
|
/* Send stuff on the cursor which isnt sent in bulk */
|
||||||
for (auto iter = m_inv.cursor_begin(); iter != m_inv.cursor_end(); ++iter) {
|
for (auto iter = m_inv.cursor_cbegin(); iter != m_inv.cursor_cend(); ++iter) {
|
||||||
/* First item cursor is sent in bulk inventory packet */
|
/* First item cursor is sent in bulk inventory packet */
|
||||||
if (iter == m_inv.cursor_begin())
|
if (iter == m_inv.cursor_cbegin())
|
||||||
continue;
|
continue;
|
||||||
const ItemInst *inst = *iter;
|
const ItemInst *inst = *iter;
|
||||||
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
|
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
|
||||||
@ -1859,7 +1740,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ClientVersionBit & BIT_UFAndLater) {
|
if (m_ClientVersionBit & BIT_UFAndLater) {
|
||||||
outapp = new EQApplicationPacket(OP_XTargetResponse, 8);
|
outapp = new EQApplicationPacket(OP_XTargetResponse, 8);
|
||||||
outapp->WriteUInt32(GetMaxXTargets());
|
outapp->WriteUInt32(GetMaxXTargets());
|
||||||
outapp->WriteUInt32(0);
|
outapp->WriteUInt32(0);
|
||||||
@ -3309,7 +3190,6 @@ void Client::Handle_OP_AutoFire(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_OP_Bandolier(const EQApplicationPacket *app)
|
void Client::Handle_OP_Bandolier(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Although there are three different structs for OP_Bandolier, they are all the same size.
|
// Although there are three different structs for OP_Bandolier, they are all the same size.
|
||||||
//
|
//
|
||||||
if (app->size != sizeof(BandolierCreate_Struct)) {
|
if (app->size != sizeof(BandolierCreate_Struct)) {
|
||||||
@ -3321,19 +3201,20 @@ void Client::Handle_OP_Bandolier(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
|
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
|
||||||
|
|
||||||
switch (bs->action) {
|
switch (bs->Action)
|
||||||
case BandolierCreate:
|
{
|
||||||
|
case bandolierCreate:
|
||||||
CreateBandolier(app);
|
CreateBandolier(app);
|
||||||
break;
|
break;
|
||||||
case BandolierRemove:
|
case bandolierRemove:
|
||||||
RemoveBandolier(app);
|
RemoveBandolier(app);
|
||||||
break;
|
break;
|
||||||
case BandolierSet:
|
case bandolierSet:
|
||||||
SetBandolier(app);
|
SetBandolier(app);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.Out(Logs::General, Logs::None, "Uknown Bandolier action %i", bs->action);
|
Log.Out(Logs::General, Logs::None, "Unknown Bandolier action %i", bs->Action);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4038,7 +3919,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
else if (m_inv.SupportsClickCasting(castspell->inventoryslot) || (castspell->slot == POTION_BELT_SPELL_SLOT) || (castspell->slot == TARGET_RING_SPELL_SLOT)) // sanity check
|
else if (m_inv.SupportsClickCasting(castspell->inventoryslot) || (castspell->slot == POTION_BELT_SPELL_SLOT) || (castspell->slot == TARGET_RING_SPELL_SLOT)) // sanity check
|
||||||
{
|
{
|
||||||
// packet field types will be reviewed as packet transistions occur -U
|
// packet field types will be reviewed as packet transistions occur
|
||||||
const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field
|
const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field
|
||||||
//bool cancast = true;
|
//bool cancast = true;
|
||||||
if (inst && inst->IsType(ItemClassCommon))
|
if (inst && inst->IsType(ItemClassCommon))
|
||||||
@ -5230,6 +5111,7 @@ void Client::Handle_OP_DeleteSpell(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
if (m_pp.spell_book[dss->spell_slot] != SPELLBOOK_UNKNOWN) {
|
if (m_pp.spell_book[dss->spell_slot] != SPELLBOOK_UNKNOWN) {
|
||||||
m_pp.spell_book[dss->spell_slot] = SPELLBOOK_UNKNOWN;
|
m_pp.spell_book[dss->spell_slot] = SPELLBOOK_UNKNOWN;
|
||||||
|
database.DeleteCharacterSpell(this->CharacterID(), m_pp.spell_book[dss->spell_slot], dss->spell_slot);
|
||||||
dss->success = 1;
|
dss->success = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -5547,7 +5429,7 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
|||||||
if (damage < 0)
|
if (damage < 0)
|
||||||
damage = 31337;
|
damage = 31337;
|
||||||
|
|
||||||
if (admin >= minStatusToAvoidFalling && GetGM()){
|
if (admin >= minStatusToAvoidFalling && GetGM()) {
|
||||||
Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
|
Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype);
|
||||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||||
return;
|
return;
|
||||||
@ -5557,11 +5439,11 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
|
|||||||
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
SetHP(GetHP() - 1);//needed or else the client wont acknowledge
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184) {
|
||||||
else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184){
|
// Hard coded tutorial and load zones for no fall damage
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter)));
|
SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter)));
|
||||||
|
|
||||||
/* EVENT_ENVIRONMENTAL_DAMAGE */
|
/* EVENT_ENVIRONMENTAL_DAMAGE */
|
||||||
@ -7391,6 +7273,16 @@ void Client::Handle_OP_GuildInvite(const EQApplicationPacket *app)
|
|||||||
if (gc->guildeqid == 0)
|
if (gc->guildeqid == 0)
|
||||||
gc->guildeqid = GuildID();
|
gc->guildeqid = GuildID();
|
||||||
|
|
||||||
|
// Convert Membership Level between RoF and previous clients.
|
||||||
|
if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
gc->officer = 0;
|
||||||
|
}
|
||||||
|
if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
gc->officer = 8;
|
||||||
|
}
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Guilds, "Sending OP_GuildInvite for invite to %s, length %d", client->GetName(), app->size);
|
Log.Out(Logs::Detail, Logs::Guilds, "Sending OP_GuildInvite for invite to %s, length %d", client->GetName(), app->size);
|
||||||
client->SetPendingGuildInvitation(true);
|
client->SetPendingGuildInvitation(true);
|
||||||
client->QueuePacket(app);
|
client->QueuePacket(app);
|
||||||
@ -7425,6 +7317,8 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
GuildInviteAccept_Struct* gj = (GuildInviteAccept_Struct*)app->pBuffer;
|
GuildInviteAccept_Struct* gj = (GuildInviteAccept_Struct*)app->pBuffer;
|
||||||
|
|
||||||
|
uint32 guildrank = gj->response;
|
||||||
|
|
||||||
if (GetClientVersion() >= ClientVersion::RoF)
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
{
|
{
|
||||||
if (gj->response > 9)
|
if (gj->response > 9)
|
||||||
@ -7453,9 +7347,25 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
|||||||
Log.Out(Logs::Detail, Logs::Guilds, "Guild Invite Accept: guild %d, response %d, inviter %s, person %s",
|
Log.Out(Logs::Detail, Logs::Guilds, "Guild Invite Accept: guild %d, response %d, inviter %s, person %s",
|
||||||
gj->guildeqid, gj->response, gj->inviter, gj->newmember);
|
gj->guildeqid, gj->response, gj->inviter, gj->newmember);
|
||||||
|
|
||||||
|
//ok, the invite is also used for changing rank as well.
|
||||||
|
Mob* inviter = entity_list.GetMob(gj->inviter);
|
||||||
|
|
||||||
|
if (inviter && inviter->IsClient())
|
||||||
|
{
|
||||||
|
Client* client = inviter->CastToClient();
|
||||||
|
// Convert Membership Level between RoF and previous clients.
|
||||||
|
if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
guildrank = 0;
|
||||||
|
}
|
||||||
|
if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
guildrank = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
//we dont really care a lot about what this packet means, as long as
|
//we dont really care a lot about what this packet means, as long as
|
||||||
//it has been authorized with the guild manager
|
//it has been authorized with the guild manager
|
||||||
if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, gj->response)) {
|
if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, guildrank)) {
|
||||||
worldserver.SendEmoteMessage(gj->inviter, 0, 0, "%s has sent an invalid response to your invite!", GetName());
|
worldserver.SendEmoteMessage(gj->inviter, 0, 0, "%s has sent an invalid response to your invite!", GetName());
|
||||||
Message(13, "Invalid invite response packet!");
|
Message(13, "Invalid invite response packet!");
|
||||||
return;
|
return;
|
||||||
@ -7483,7 +7393,7 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
//change guild and rank
|
//change guild and rank
|
||||||
|
|
||||||
uint32 guildrank = gj->response;
|
guildrank = gj->response;
|
||||||
|
|
||||||
if (GetClientVersion() >= ClientVersion::RoF)
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
{
|
{
|
||||||
@ -9893,6 +9803,9 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST))
|
||||||
|
return;
|
||||||
|
|
||||||
if (mypet->GetPetType() == petAnimation && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST) && !GetAA(aaAnimationEmpathy))
|
if (mypet->GetPetType() == petAnimation && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST) && !GetAA(aaAnimationEmpathy))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -10562,16 +10475,16 @@ void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app)
|
|||||||
if (mptbs->Action == 0) {
|
if (mptbs->Action == 0) {
|
||||||
const Item_Struct *BaseItem = database.GetItem(mptbs->ItemID);
|
const Item_Struct *BaseItem = database.GetItem(mptbs->ItemID);
|
||||||
if (BaseItem) {
|
if (BaseItem) {
|
||||||
m_pp.potionbelt.items[mptbs->SlotNumber].item_id = BaseItem->ID;
|
m_pp.potionbelt.Items[mptbs->SlotNumber].ID = BaseItem->ID;
|
||||||
m_pp.potionbelt.items[mptbs->SlotNumber].icon = BaseItem->Icon;
|
m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = BaseItem->Icon;
|
||||||
strn0cpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, BaseItem->Name, sizeof(BaseItem->Name));
|
strn0cpy(m_pp.potionbelt.Items[mptbs->SlotNumber].Name, BaseItem->Name, sizeof(BaseItem->Name));
|
||||||
database.SaveCharacterPotionBelt(this->CharacterID(), mptbs->SlotNumber, m_pp.potionbelt.items[mptbs->SlotNumber].item_id, m_pp.potionbelt.items[mptbs->SlotNumber].icon);
|
database.SaveCharacterPotionBelt(this->CharacterID(), mptbs->SlotNumber, m_pp.potionbelt.Items[mptbs->SlotNumber].ID, m_pp.potionbelt.Items[mptbs->SlotNumber].Icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_pp.potionbelt.items[mptbs->SlotNumber].item_id = 0;
|
m_pp.potionbelt.Items[mptbs->SlotNumber].ID = 0;
|
||||||
m_pp.potionbelt.items[mptbs->SlotNumber].icon = 0;
|
m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = 0;
|
||||||
strncpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, "\0", 1);
|
m_pp.potionbelt.Items[mptbs->SlotNumber].Name[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11773,6 +11686,27 @@ void Client::Handle_OP_SelectTribute(const EQApplicationPacket *app)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::Handle_OP_SenseHeading(const EQApplicationPacket *app)
|
||||||
|
{
|
||||||
|
if (!HasSkill(SkillSenseHeading))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int chancemod=0;
|
||||||
|
|
||||||
|
// The client seems to limit sense heading packets based on skill
|
||||||
|
// level. So if we're really low, we don't hit this routine very often.
|
||||||
|
// I think it's the GUI deciding when to skill you up.
|
||||||
|
// So, I'm adding a mod here which is larger at lower levels so
|
||||||
|
// very low levels get a much better chance to skill up when the GUI
|
||||||
|
// eventually sends a message.
|
||||||
|
if (GetLevel() <= 8)
|
||||||
|
chancemod += (9-level) * 10;
|
||||||
|
|
||||||
|
CheckIncreaseSkill(SkillSenseHeading, nullptr, chancemod);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app)
|
void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
if (!HasSkill(SkillSenseTraps))
|
if (!HasSkill(SkillSenseTraps))
|
||||||
@ -12072,12 +12006,6 @@ void Client::Handle_OP_ShopEnd(const EQApplicationPacket *app)
|
|||||||
{
|
{
|
||||||
EQApplicationPacket empty(OP_ShopEndConfirm);
|
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||||
QueuePacket(&empty);
|
QueuePacket(&empty);
|
||||||
//EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopEndConfirm, 2);
|
|
||||||
//outapp->pBuffer[0] = 0x0a;
|
|
||||||
//outapp->pBuffer[1] = 0x66;
|
|
||||||
//QueuePacket(outapp);
|
|
||||||
//safe_delete(outapp);
|
|
||||||
//Save();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12173,6 +12101,10 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
|||||||
mp->quantity = prevcharges;
|
mp->quantity = prevcharges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Item's stackable, but the quantity they want to buy exceeds the max stackable quantity.
|
||||||
|
if (item->Stackable && mp->quantity > item->StackSize)
|
||||||
|
mp->quantity = item->StackSize;
|
||||||
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct));
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct));
|
||||||
Merchant_Sell_Struct* mpo = (Merchant_Sell_Struct*)outapp->pBuffer;
|
Merchant_Sell_Struct* mpo = (Merchant_Sell_Struct*)outapp->pBuffer;
|
||||||
mpo->quantity = mp->quantity;
|
mpo->quantity = mp->quantity;
|
||||||
@ -12199,6 +12131,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
|
|||||||
mpo->price = SinglePrice;
|
mpo->price = SinglePrice;
|
||||||
else
|
else
|
||||||
mpo->price = SinglePrice * mp->quantity;
|
mpo->price = SinglePrice * mp->quantity;
|
||||||
|
|
||||||
if (mpo->price < 0)
|
if (mpo->price < 0)
|
||||||
{
|
{
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@ -12668,6 +12601,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
else if (sa->type == AT_Anim) {
|
else if (sa->type == AT_Anim) {
|
||||||
if (IsAIControlled())
|
if (IsAIControlled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sa->parameter == ANIM_STAND) {
|
if (sa->parameter == ANIM_STAND) {
|
||||||
SetAppearance(eaStanding);
|
SetAppearance(eaStanding);
|
||||||
playeraction = 0;
|
playeraction = 0;
|
||||||
@ -12701,15 +12635,6 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
SetFeigned(false);
|
SetFeigned(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is from old code
|
|
||||||
// I have no clue what it's for
|
|
||||||
/*
|
|
||||||
else if (sa->parameter == 0x05) {
|
|
||||||
// Illusion
|
|
||||||
std::cout << "Illusion packet recv'd:" << std::endl;
|
|
||||||
DumpPacket(app);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
else {
|
else {
|
||||||
std::cerr << "Client " << name << " unknown apperance " << (int)sa->parameter << std::endl;
|
std::cerr << "Client " << name << " unknown apperance " << (int)sa->parameter << std::endl;
|
||||||
return;
|
return;
|
||||||
@ -12718,6 +12643,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
entity_list.QueueClients(this, app, true);
|
entity_list.QueueClients(this, app, true);
|
||||||
}
|
}
|
||||||
else if (sa->type == AT_Anon) {
|
else if (sa->type == AT_Anon) {
|
||||||
|
if(!anon_toggle_timer.Check()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// For Anon/Roleplay
|
// For Anon/Roleplay
|
||||||
if (sa->parameter == 1) { // Anon
|
if (sa->parameter == 1) { // Anon
|
||||||
m_pp.anon = 1;
|
m_pp.anon = 1;
|
||||||
@ -12739,13 +12668,18 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (sa->type == AT_AFK) {
|
else if (sa->type == AT_AFK) {
|
||||||
this->AFK = (sa->parameter == 1);
|
if(afk_toggle_timer.Check()) {
|
||||||
entity_list.QueueClients(this, app, true);
|
AFK = (sa->parameter == 1);
|
||||||
|
entity_list.QueueClients(this, app, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (sa->type == AT_Split) {
|
else if (sa->type == AT_Split) {
|
||||||
m_pp.autosplit = (sa->parameter == 1);
|
m_pp.autosplit = (sa->parameter == 1);
|
||||||
}
|
}
|
||||||
else if (sa->type == AT_Sneak) {
|
else if (sa->type == AT_Sneak) {
|
||||||
|
if(sneaking == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (sa->parameter != 0)
|
if (sa->parameter != 0)
|
||||||
{
|
{
|
||||||
if (!HasSkill(SkillSneak))
|
if (!HasSkill(SkillSneak))
|
||||||
@ -12757,7 +12691,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->sneaking = 0;
|
sneaking = 0;
|
||||||
entity_list.QueueClients(this, app, true);
|
entity_list.QueueClients(this, app, true);
|
||||||
}
|
}
|
||||||
else if (sa->type == AT_Size)
|
else if (sa->type == AT_Size)
|
||||||
@ -12769,7 +12703,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
else if (sa->type == AT_Light) // client emitting light (lightstone, shiny shield)
|
else if (sa->type == AT_Light) // client emitting light (lightstone, shiny shield)
|
||||||
{
|
{
|
||||||
entity_list.QueueClients(this, app, false);
|
//don't do anything with this
|
||||||
}
|
}
|
||||||
else if (sa->type == AT_Levitate)
|
else if (sa->type == AT_Levitate)
|
||||||
{
|
{
|
||||||
@ -12778,8 +12712,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
else if (sa->type == AT_ShowHelm)
|
else if (sa->type == AT_ShowHelm)
|
||||||
{
|
{
|
||||||
m_pp.showhelm = (sa->parameter == 1);
|
if(helm_toggle_timer.Check()) {
|
||||||
entity_list.QueueClients(this, app, true);
|
m_pp.showhelm = (sa->parameter == 1);
|
||||||
|
entity_list.QueueClients(this, app, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec
|
std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec
|
||||||
@ -13390,7 +13326,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
if (GetClientVersion() >= EQClientRoF)
|
if (GetClientVersion() >= EQClientRoF)
|
||||||
max_items = 200;
|
max_items = 200;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//Show Items
|
//Show Items
|
||||||
@ -13402,20 +13338,25 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
{
|
{
|
||||||
case BazaarTrader_EndTraderMode: {
|
case BazaarTrader_EndTraderMode: {
|
||||||
Trader_EndTrader();
|
Trader_EndTrader();
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BazaarTrader_EndTransaction: {
|
case BazaarTrader_EndTransaction: {
|
||||||
|
|
||||||
Client* c = entity_list.GetClientByID(sis->TraderID);
|
Client* c = entity_list.GetClientByID(sis->TraderID);
|
||||||
if (c)
|
if (c)
|
||||||
|
{
|
||||||
c->WithCustomer(0);
|
c->WithCustomer(0);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BazaarTrader_ShowItems: {
|
case BazaarTrader_ShowItems: {
|
||||||
Trader_ShowItems();
|
Trader_ShowItems();
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -13438,6 +13379,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
{
|
{
|
||||||
GetItems_Struct* gis = GetTraderItems();
|
GetItems_Struct* gis = GetTraderItems();
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Start Trader Mode");
|
||||||
// Verify there are no NODROP or items with a zero price
|
// Verify there are no NODROP or items with a zero price
|
||||||
bool TradeItemsValid = true;
|
bool TradeItemsValid = true;
|
||||||
|
|
||||||
@ -13484,7 +13426,8 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
safe_delete(gis);
|
safe_delete(gis);
|
||||||
|
|
||||||
this->Trader_StartTrader();
|
this->Trader_StartTrader();
|
||||||
|
|
||||||
|
// This refreshes the Trader window to display the End Trader button
|
||||||
if (GetClientVersion() >= ClientVersion::RoF)
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
{
|
{
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct));
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct));
|
||||||
@ -13494,15 +13437,6 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (app->size == sizeof(TraderStatus_Struct))
|
|
||||||
{
|
|
||||||
TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer;
|
|
||||||
|
|
||||||
if (tss->Code == BazaarTrader_ShowItems)
|
|
||||||
{
|
|
||||||
Trader_ShowItems();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unknown TraderStruct code of: %i\n",
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unknown TraderStruct code of: %i\n",
|
||||||
ints->Code);
|
ints->Code);
|
||||||
@ -13510,9 +13444,35 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app)
|
|||||||
Log.Out(Logs::General, Logs::Error, "Unknown TraderStruct code of: %i\n", ints->Code);
|
Log.Out(Logs::General, Logs::Error, "Unknown TraderStruct code of: %i\n", ints->Code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (app->size == sizeof(TraderStatus_Struct))
|
||||||
|
{
|
||||||
|
TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer;
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Status Code: %d", tss->Code);
|
||||||
|
|
||||||
|
switch (tss->Code)
|
||||||
|
{
|
||||||
|
case BazaarTrader_EndTraderMode: {
|
||||||
|
Trader_EndTrader();
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BazaarTrader_ShowItems: {
|
||||||
|
Trader_ShowItems();
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Unhandled action code in OP_Trader ShowItems_Struct");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
else if (app->size == sizeof(TraderPriceUpdate_Struct))
|
else if (app->size == sizeof(TraderPriceUpdate_Struct))
|
||||||
{
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Price Update");
|
||||||
HandleTraderPriceUpdate(app);
|
HandleTraderPriceUpdate(app);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -13531,23 +13491,22 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app)
|
|||||||
//
|
//
|
||||||
// Client has elected to buy an item from a Trader
|
// Client has elected to buy an item from a Trader
|
||||||
//
|
//
|
||||||
|
if (app->size != sizeof(TraderBuy_Struct)) {
|
||||||
|
Log.Out(Logs::General, Logs::Error, "Wrong size: OP_TraderBuy, size=%i, expected %i", app->size, sizeof(TraderBuy_Struct));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (app->size == sizeof(TraderBuy_Struct)){
|
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||||
|
|
||||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){
|
||||||
|
BuyTraderItem(tbs, Trader, app);
|
||||||
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Buy Trader Item ");
|
||||||
|
|
||||||
BuyTraderItem(tbs, Trader, app);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Struct size mismatch");
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13609,51 +13568,124 @@ void Client::Handle_OP_TradeRequestAck(const EQApplicationPacket *app)
|
|||||||
void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
void Client::Handle_OP_TraderShop(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
// Bazaar Trader:
|
// Bazaar Trader:
|
||||||
//
|
|
||||||
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
|
||||||
// browse their goods.
|
|
||||||
//
|
|
||||||
|
|
||||||
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
if (app->size == sizeof(TraderClick_Struct))
|
||||||
|
{
|
||||||
|
|
||||||
|
TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer;
|
||||||
|
|
||||||
if (app->size != sizeof(TraderClick_Struct)) {
|
Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: TraderClick_Struct TraderID %d, Code %d, Unknown008 %d, Approval %d",
|
||||||
|
tcs->TraderID, tcs->Code, tcs->Unknown008, tcs->Approval);
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Returning due to struct size mismatch");
|
if (tcs->Code == BazaarWelcome)
|
||||||
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
||||||
|
SendBazaarWelcome();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This is when a potential purchaser right clicks on this client who is in Trader mode to
|
||||||
|
// browse their goods.
|
||||||
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
||||||
|
|
||||||
|
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
|
Client* Trader = entity_list.GetClientByID(tcs->TraderID);
|
||||||
|
|
||||||
|
if (Trader)
|
||||||
|
{
|
||||||
|
outtcs->Approval = Trader->WithCustomer(GetID());
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
||||||
|
" returned a nullptr pointer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
outtcs->TraderID = tcs->TraderID;
|
||||||
|
|
||||||
|
outtcs->Unknown008 = 0x3f800000;
|
||||||
|
|
||||||
|
QueuePacket(outapp);
|
||||||
|
|
||||||
|
|
||||||
|
if (outtcs->Approval) {
|
||||||
|
this->BulkSendTraderInventory(Trader->CharacterID());
|
||||||
|
Trader->Trader_CustomerBrowsing(this);
|
||||||
|
TraderID = tcs->TraderID;
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message_StringID(clientMessageYellow, TRADER_BUSY);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy");
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_delete(outapp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (app->size == sizeof(BazaarWelcome_Struct))
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct));
|
{
|
||||||
|
// RoF+
|
||||||
TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer;
|
// Client requested Bazaar Welcome Info (Trader and Item Total Counts)
|
||||||
|
SendBazaarWelcome();
|
||||||
Client* Customer = entity_list.GetClientByID(tcs->TraderID);
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info");
|
||||||
|
|
||||||
if (Customer)
|
|
||||||
outtcs->Approval = Customer->WithCustomer(GetID());
|
|
||||||
else {
|
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)"
|
|
||||||
" returned a nullptr pointer");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (app->size == sizeof(TraderBuy_Struct))
|
||||||
|
{
|
||||||
|
// RoF+
|
||||||
|
// Customer has purchased an item from the Trader
|
||||||
|
|
||||||
outtcs->TraderID = tcs->TraderID;
|
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||||
|
|
||||||
outtcs->Unknown008 = 0x3f800000;
|
if (Client* Trader = entity_list.GetClientByID(tbs->TraderID))
|
||||||
|
{
|
||||||
|
BuyTraderItem(tbs, Trader, app);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s",
|
||||||
|
tbs->Action, tbs->Price, tbs->TraderID, tbs->ItemID, tbs->Quantity, tbs->ItemName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "OP_TraderShop: Null Client Pointer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (app->size == 4)
|
||||||
|
{
|
||||||
|
// RoF+
|
||||||
|
// Customer has closed the trade window
|
||||||
|
uint32 Command = *((uint32 *)app->pBuffer);
|
||||||
|
|
||||||
QueuePacket(outapp);
|
if (Command == 4)
|
||||||
|
{
|
||||||
|
Client* c = entity_list.GetClientByID(TraderID);
|
||||||
if (outtcs->Approval) {
|
TraderID = 0;
|
||||||
this->BulkSendTraderInventory(Customer->CharacterID());
|
if (c)
|
||||||
Customer->Trader_CustomerBrowsing(this);
|
{
|
||||||
|
c->WithCustomer(0);
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction - Code %d", Command);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer for Trader - Code %d", Command);
|
||||||
|
}
|
||||||
|
EQApplicationPacket empty(OP_ShopEndConfirm);
|
||||||
|
QueuePacket(&empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unhandled Code %d", Command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Message_StringID(clientMessageYellow, TRADER_BUSY);
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Unknown size for OP_TraderShop: %i\n", app->size);
|
||||||
safe_delete(outapp);
|
Log.Out(Logs::General, Logs::Error, "Unknown size for OP_TraderShop: %i\n", app->size);
|
||||||
|
DumpPacket(app);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app)
|
void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app)
|
||||||
@ -13816,41 +13848,32 @@ void Client::Handle_OP_TributeUpdate(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
void Client::Handle_OP_VetClaimRequest(const EQApplicationPacket *app)
|
void Client::Handle_OP_VetClaimRequest(const EQApplicationPacket *app)
|
||||||
{
|
{
|
||||||
if (app->size < sizeof(VeteranClaimRequest))
|
if (app->size < sizeof(VeteranClaim)) {
|
||||||
{
|
Log.Out(Logs::General, Logs::None,
|
||||||
Log.Out(Logs::General, Logs::None, "OP_VetClaimRequest size lower than expected: got %u expected at least %u", app->size, sizeof(VeteranClaimRequest));
|
"OP_VetClaimRequest size lower than expected: got %u expected at least %u", app->size,
|
||||||
|
sizeof(VeteranClaim));
|
||||||
DumpPacket(app);
|
DumpPacket(app);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VeteranClaimRequest *vcr = (VeteranClaimRequest*)app->pBuffer;
|
VeteranClaim *vcr = (VeteranClaim *)app->pBuffer;
|
||||||
|
|
||||||
if (vcr->claim_id == 0xFFFFFFFF) //request update packet
|
if (vcr->claim_id == 0xFFFFFFFF) { // request update packet
|
||||||
{
|
|
||||||
SendRewards();
|
SendRewards();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else //try to claim something!
|
// try to claim something!
|
||||||
{
|
EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaim));
|
||||||
if (!TryReward(vcr->claim_id))
|
VeteranClaim *cr = (VeteranClaim *)vetapp->pBuffer;
|
||||||
{
|
strcpy(cr->name, GetName());
|
||||||
Message(13, "Your claim has been rejected.");
|
cr->claim_id = vcr->claim_id;
|
||||||
EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaimReply));
|
|
||||||
VeteranClaimReply * cr = (VeteranClaimReply*)vetapp->pBuffer;
|
if (!TryReward(vcr->claim_id))
|
||||||
strcpy(cr->name, GetName());
|
cr->action = 1;
|
||||||
cr->claim_id = vcr->claim_id;
|
else
|
||||||
cr->reject_field = -1;
|
cr->action = 0;
|
||||||
FastQueuePacket(&vetapp);
|
|
||||||
}
|
FastQueuePacket(&vetapp);
|
||||||
else
|
|
||||||
{
|
|
||||||
EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaimReply));
|
|
||||||
VeteranClaimReply * cr = (VeteranClaimReply*)vetapp->pBuffer;
|
|
||||||
strcpy(cr->name, GetName());
|
|
||||||
cr->claim_id = vcr->claim_id;
|
|
||||||
cr->reject_field = 0;
|
|
||||||
FastQueuePacket(&vetapp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Handle_OP_VoiceMacroIn(const EQApplicationPacket *app)
|
void Client::Handle_OP_VoiceMacroIn(const EQApplicationPacket *app)
|
||||||
|
|||||||
@ -239,7 +239,8 @@ bool Client::Process() {
|
|||||||
if(IsAIControlled())
|
if(IsAIControlled())
|
||||||
AI_Process();
|
AI_Process();
|
||||||
|
|
||||||
if (bindwound_timer.Check() && bindwound_target != 0) {
|
// Don't reset the bindwound timer so we can check it in BindWound as well.
|
||||||
|
if (bindwound_timer.Check(false) && bindwound_target != 0) {
|
||||||
BindWound(bindwound_target, false);
|
BindWound(bindwound_target, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +261,14 @@ bool Client::Process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(light_update_timer.Check()) {
|
||||||
|
|
||||||
|
UpdateEquipmentLight();
|
||||||
|
if(UpdateActiveLight()) {
|
||||||
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool may_use_attacks = false;
|
bool may_use_attacks = false;
|
||||||
/*
|
/*
|
||||||
Things which prevent us from attacking:
|
Things which prevent us from attacking:
|
||||||
@ -808,14 +817,14 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
|||||||
|
|
||||||
// Sends the client complete inventory used in character login
|
// Sends the client complete inventory used in character login
|
||||||
|
|
||||||
// DO WE STILL NEED THE 'ITEMCOMBINED' CONDITIONAL CODE? -U
|
// DO WE STILL NEED THE 'ITEMCOMBINED' CONDITIONAL CODE?
|
||||||
|
|
||||||
//#ifdef ITEMCOMBINED
|
//#ifdef ITEMCOMBINED
|
||||||
void Client::BulkSendInventoryItems() {
|
void Client::BulkSendInventoryItems() {
|
||||||
int16 slot_id = 0;
|
int16 slot_id = 0;
|
||||||
|
|
||||||
// LINKDEAD TRADE ITEMS
|
// LINKDEAD TRADE ITEMS
|
||||||
// Move trade slot items back into normal inventory..need them there now for the proceeding validity checks -U
|
// Move trade slot items back into normal inventory..need them there now for the proceeding validity checks
|
||||||
for(slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) {
|
for(slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) {
|
||||||
ItemInst* inst = m_inv.PopItem(slot_id);
|
ItemInst* inst = m_inv.PopItem(slot_id);
|
||||||
if(inst) {
|
if(inst) {
|
||||||
@ -834,7 +843,7 @@ void Client::BulkSendInventoryItems() {
|
|||||||
RemoveDuplicateLore(false);
|
RemoveDuplicateLore(false);
|
||||||
MoveSlotNotAllowed(false);
|
MoveSlotNotAllowed(false);
|
||||||
|
|
||||||
// The previous three method calls took care of moving/removing expired/illegal item placements -U
|
// The previous three method calls took care of moving/removing expired/illegal item placements
|
||||||
|
|
||||||
//TODO: this function is just retarded... it re-allocates the buffer for every
|
//TODO: this function is just retarded... it re-allocates the buffer for every
|
||||||
//new item. It should be changed to loop through once, gather the
|
//new item. It should be changed to loop through once, gather the
|
||||||
@ -960,7 +969,7 @@ void Client::BulkSendInventoryItems()
|
|||||||
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||||
const Item_Struct* handyitem = nullptr;
|
const Item_Struct* handyitem = nullptr;
|
||||||
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
|
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
|
||||||
if (ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items
|
if (m_ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items
|
||||||
numItemSlots = 200;
|
numItemSlots = 200;
|
||||||
}
|
}
|
||||||
const Item_Struct *item;
|
const Item_Struct *item;
|
||||||
@ -1886,7 +1895,7 @@ void Client::DoHPRegen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::DoManaRegen() {
|
void Client::DoManaRegen() {
|
||||||
if (GetMana() >= max_mana)
|
if (GetMana() >= max_mana && spellbonuses.ManaRegen >= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SetMana(GetMana() + CalcManaRegen() + RestRegenMana);
|
SetMana(GetMana() + CalcManaRegen() + RestRegenMana);
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
set to nullptr and 0 respectively since they aren't used when adding
|
set to nullptr and 0 respectively since they aren't used when adding
|
||||||
an alias. The function pointers being equal is makes it an alias.
|
an alias. The function pointers being equal is makes it an alias.
|
||||||
The access level you set with command_add is only a default if
|
The access level you set with command_add is only a default if
|
||||||
the command isn't listed in the addon.ini file.
|
the command isn't listed in the commands db table.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -2461,7 +2461,7 @@ void command_npctypespawn(Client *c, const Seperator *sep)
|
|||||||
{
|
{
|
||||||
if (sep->IsNumber(1)) {
|
if (sep->IsNumber(1)) {
|
||||||
const NPCType* tmp = 0;
|
const NPCType* tmp = 0;
|
||||||
if ((tmp = database.GetNPCType(atoi(sep->arg[1])))) {
|
if ((tmp = database.LoadNPCTypesData(atoi(sep->arg[1])))) {
|
||||||
//tmp->fixedZ = 1;
|
//tmp->fixedZ = 1;
|
||||||
NPC* npc = new NPC(tmp, 0, c->GetPosition(), FlyMode3);
|
NPC* npc = new NPC(tmp, 0, c->GetPosition(), FlyMode3);
|
||||||
if (npc && sep->IsNumber(2))
|
if (npc && sep->IsNumber(2))
|
||||||
@ -2618,7 +2618,7 @@ void command_peekinv(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int cursorDepth = 0;
|
int cursorDepth = 0;
|
||||||
for (auto it = targetClient->GetInv().cursor_begin(); (it != targetClient->GetInv().cursor_end()); ++it, ++cursorDepth) {
|
for (auto it = targetClient->GetInv().cursor_cbegin(); (it != targetClient->GetInv().cursor_cend()); ++it, ++cursorDepth) {
|
||||||
inst_main = *it;
|
inst_main = *it;
|
||||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||||
linker.SetItemInst(inst_main);
|
linker.SetItemInst(inst_main);
|
||||||
@ -2923,7 +2923,7 @@ void command_viewnpctype(Client *c, const Seperator *sep)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32 npctypeid=atoi(sep->arg[1]);
|
uint32 npctypeid=atoi(sep->arg[1]);
|
||||||
const NPCType* npct = database.GetNPCType(npctypeid);
|
const NPCType* npct = database.LoadNPCTypesData(npctypeid);
|
||||||
if (npct) {
|
if (npct) {
|
||||||
c->Message(0, " NPCType Info, ");
|
c->Message(0, " NPCType Info, ");
|
||||||
c->Message(0, " NPCTypeID: %u", npct->npc_id);
|
c->Message(0, " NPCTypeID: %u", npct->npc_id);
|
||||||
@ -4284,31 +4284,49 @@ void command_goto(Client *c, const Seperator *sep)
|
|||||||
|
|
||||||
void command_iteminfo(Client *c, const Seperator *sep)
|
void command_iteminfo(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
const ItemInst* inst = c->GetInv()[MainCursor];
|
auto inst = c->GetInv()[MainCursor];
|
||||||
|
if (!inst) { c->Message(13, "Error: You need an item on your cursor for this command"); }
|
||||||
if (!inst)
|
auto item = inst->GetItem();
|
||||||
c->Message(13, "Error: You need an item on your cursor for this command");
|
if (!item) {
|
||||||
else {
|
Log.Out(Logs::General, Logs::Inventory, "(%s) Command #iteminfo processed an item with no data pointer");
|
||||||
const Item_Struct* item = inst->GetItem();
|
c->Message(13, "Error: This item has no data reference");
|
||||||
c->Message(0, "ID: %i Name: %s", item->ID, item->Name);
|
|
||||||
c->Message(0, " Lore: %s ND: %i NS: %i Type: %i", (item->LoreFlag) ? "true":"false", item->NoDrop, item->NoRent, item->ItemClass);
|
|
||||||
c->Message(0, " IDF: %s Size: %i Weight: %i icon_id: %i Price: %i", item->IDFile, item->Size, item->Weight, item->Icon, item->Price);
|
|
||||||
if (c->Admin() >= 200)
|
|
||||||
c->Message(0, "MinStatus: %i", item->MinStatus);
|
|
||||||
if (item->ItemClass==ItemClassBook)
|
|
||||||
c->Message(0, " This item is a Book: %s", item->Filename);
|
|
||||||
else if (item->ItemClass==ItemClassContainer)
|
|
||||||
c->Message(0, " This item is a container with %i slots", item->BagSlots);
|
|
||||||
else {
|
|
||||||
c->Message(0, " equipableSlots: %u equipable Classes: %u", item->Slots, item->Classes);
|
|
||||||
c->Message(0, " Magic: %i SpellID: %i Proc Level: %i DBCharges: %i CurCharges: %i", item->Magic, item->Click.Effect, item->Click.Level, item->MaxCharges, inst->GetCharges());
|
|
||||||
c->Message(0, " EffectType: 0x%02x CastTime: %.2f", (uint8) item->Click.Type, (double) item->CastTime/1000);
|
|
||||||
c->Message(0, " Material: 0x%02x Color: 0x%08x Skill: %i", item->Material, item->Color, item->ItemType);
|
|
||||||
c->Message(0, " Required level: %i Required skill: %i Recommended level:%i", item->ReqLevel, item->RecSkill, item->RecLevel);
|
|
||||||
c->Message(0, " Skill mod: %i percent: %i", item->SkillModType, item->SkillModValue);
|
|
||||||
c->Message(0, " BaneRace: %i BaneBody: %i BaneDMG: %i", item->BaneDmgRace, item->BaneDmgBody, item->BaneDmgAmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client::TextLink linker;
|
||||||
|
linker.SetLinkType(linker.linkItemInst);
|
||||||
|
linker.SetItemInst(inst);
|
||||||
|
|
||||||
|
auto item_link = linker.GenerateLink();
|
||||||
|
|
||||||
|
c->Message(0, "*** Item Info for [%s] ***", item_link.c_str());
|
||||||
|
c->Message(0, ">> ID: %u, ItemUseType: %u, ItemClassType: %u", item->ID, item->ItemType, item->ItemClass);
|
||||||
|
c->Message(0, ">> IDFile: '%s', IconID: %u", item->IDFile, item->Icon);
|
||||||
|
c->Message(0, ">> Size: %u, Weight: %u, Price: %u, LDoNPrice: %u", item->Size, item->Weight, item->Price, item->LDoNPrice);
|
||||||
|
c->Message(0, ">> Material: 0x%02X, Color: 0x%08X, Tint: 0x%08X, Light: 0x%02X", item->Material, item->Color, inst->GetColor(), item->Light);
|
||||||
|
c->Message(0, ">> IsLore: %s, LoreGroup: %u, Lore: '%s'", (item->LoreFlag ? "TRUE" : "FALSE"), item->LoreGroup, item->Lore);
|
||||||
|
c->Message(0, ">> NoDrop: %u, NoRent: %u, NoPet: %u, NoTransfer: %u, FVNoDrop: %u",
|
||||||
|
item->NoDrop, item->NoRent, (uint8)item->NoPet, (uint8)item->NoTransfer, item->FVNoDrop);
|
||||||
|
|
||||||
|
if (item->ItemClass == ItemClassBook) {
|
||||||
|
c->Message(0, "*** This item is a Book (filename:'%s') ***", item->Filename);
|
||||||
|
}
|
||||||
|
else if (item->ItemClass == ItemClassContainer) {
|
||||||
|
c->Message(0, "*** This item is a Container (%u slots) ***", item->BagSlots);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c->Message(0, "*** This item is Common ***");
|
||||||
|
c->Message(0, ">> Classes: %u, Races: %u, Slots: %u", item->Classes, item->Races, item->Slots);
|
||||||
|
c->Message(0, ">> ReqSkill: %u, ReqLevel: %u, RecLevel: %u", item->RecSkill, item->ReqLevel, item->RecLevel);
|
||||||
|
c->Message(0, ">> SkillModType: %u, SkillModValue: %i", item->SkillModType, item->SkillModValue);
|
||||||
|
c->Message(0, ">> BaneRaceType: %u, BaneRaceDamage: %u, BaneBodyType: %u, BaneBodyDamage: %i",
|
||||||
|
item->BaneDmgRace, item->BaneDmgRaceAmt, item->BaneDmgBody, item->BaneDmgAmt);
|
||||||
|
c->Message(0, ">> Magic: %s, SpellID: %i, ProcLevel: %u, Charges: %u, MaxCharges: %u",
|
||||||
|
(item->Magic ? "TRUE" : "FALSE"), item->Click.Effect, item->Click.Level, inst->GetCharges(), item->MaxCharges);
|
||||||
|
c->Message(0, ">> EffectType: 0x%02X, CastTime: %.2f", (uint8)item->Click.Type, ((double)item->CastTime / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->Admin() >= 200)
|
||||||
|
c->Message(0, ">> MinStatus: %u", item->MinStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_uptime(Client *c, const Seperator *sep)
|
void command_uptime(Client *c, const Seperator *sep)
|
||||||
@ -6669,7 +6687,7 @@ void command_qglobal(Client *c, const Seperator *sep) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!strcasecmp(sep->arg[1], "view")) {
|
if(!strcasecmp(sep->arg[1], "view")) {
|
||||||
const NPCType *type = database.GetNPCType(target->GetNPCTypeID());
|
const NPCType *type = database.LoadNPCTypesData(target->GetNPCTypeID());
|
||||||
if(!type)
|
if(!type)
|
||||||
c->Message(15, "Invalid NPC type.");
|
c->Message(15, "Invalid NPC type.");
|
||||||
else if(type->qglobal)
|
else if(type->qglobal)
|
||||||
@ -7002,7 +7020,7 @@ void Client::Undye() {
|
|||||||
database.SaveInventory(CharacterID(), inst, slot2);
|
database.SaveInventory(CharacterID(), inst, slot2);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pp.item_tint[cur_slot].color = 0;
|
m_pp.item_tint[cur_slot].Color = 0;
|
||||||
SendWearChange(cur_slot);
|
SendWearChange(cur_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -136,7 +136,8 @@ enum {
|
|||||||
ALLOW_TO_TANK = 41,
|
ALLOW_TO_TANK = 41,
|
||||||
IGNORE_ROOT_AGGRO_RULES = 42,
|
IGNORE_ROOT_AGGRO_RULES = 42,
|
||||||
CASTING_RESIST_DIFF = 43,
|
CASTING_RESIST_DIFF = 43,
|
||||||
MAX_SPECIAL_ATTACK = 44
|
COUNTER_AVOID_DAMAGE = 44,
|
||||||
|
MAX_SPECIAL_ATTACK = 45
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum { //fear states
|
typedef enum { //fear states
|
||||||
@ -350,7 +351,8 @@ struct StatBonuses {
|
|||||||
int32 CharmBreakChance; // chance to break charm
|
int32 CharmBreakChance; // chance to break charm
|
||||||
int32 SongRange; // increases range of beneficial bard songs
|
int32 SongRange; // increases range of beneficial bard songs
|
||||||
uint32 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
uint32 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
||||||
uint32 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
uint8 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||||
|
int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot
|
||||||
bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses)
|
bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses)
|
||||||
int32 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage
|
int32 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage
|
||||||
uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit
|
uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit
|
||||||
@ -505,7 +507,7 @@ typedef enum {
|
|||||||
petOther,
|
petOther,
|
||||||
petCharmed,
|
petCharmed,
|
||||||
petNPCFollow,
|
petNPCFollow,
|
||||||
petHatelist //remain active as long something is on the hatelist. Don't listen to any commands
|
petTargetLock //remain active as long something is on the hatelist. Don't listen to any commands
|
||||||
} PetType;
|
} PetType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
115
zone/corpse.cpp
115
zone/corpse.cpp
@ -114,15 +114,15 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std:
|
|||||||
pc->Lock();
|
pc->Lock();
|
||||||
|
|
||||||
/* Load Item Tints */
|
/* Load Item Tints */
|
||||||
pc->item_tint[0].color = pcs->item_tint[0].color;
|
pc->item_tint[0].Color = pcs->item_tint[0].Color;
|
||||||
pc->item_tint[1].color = pcs->item_tint[1].color;
|
pc->item_tint[1].Color = pcs->item_tint[1].Color;
|
||||||
pc->item_tint[2].color = pcs->item_tint[2].color;
|
pc->item_tint[2].Color = pcs->item_tint[2].Color;
|
||||||
pc->item_tint[3].color = pcs->item_tint[3].color;
|
pc->item_tint[3].Color = pcs->item_tint[3].Color;
|
||||||
pc->item_tint[4].color = pcs->item_tint[4].color;
|
pc->item_tint[4].Color = pcs->item_tint[4].Color;
|
||||||
pc->item_tint[5].color = pcs->item_tint[5].color;
|
pc->item_tint[5].Color = pcs->item_tint[5].Color;
|
||||||
pc->item_tint[6].color = pcs->item_tint[6].color;
|
pc->item_tint[6].Color = pcs->item_tint[6].Color;
|
||||||
pc->item_tint[7].color = pcs->item_tint[7].color;
|
pc->item_tint[7].Color = pcs->item_tint[7].Color;
|
||||||
pc->item_tint[8].color = pcs->item_tint[8].color;
|
pc->item_tint[8].Color = pcs->item_tint[8].Color;
|
||||||
|
|
||||||
/* Load Physical Appearance */
|
/* Load Physical Appearance */
|
||||||
pc->haircolor = pcs->haircolor;
|
pc->haircolor = pcs->haircolor;
|
||||||
@ -138,9 +138,9 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std:
|
|||||||
pc->IsRezzed(rezzed);
|
pc->IsRezzed(rezzed);
|
||||||
pc->become_npc = false;
|
pc->become_npc = false;
|
||||||
|
|
||||||
pc->spell_light = pc->innate_light = NOT_USED;
|
pc->m_Light.Level.Innate = pc->m_Light.Type.Innate = 0;
|
||||||
pc->UpdateEquipLightValue();
|
pc->UpdateEquipmentLight(); // itemlist populated above..need to determine actual values
|
||||||
//pc->UpdateActiveLightValue();
|
pc->m_Light.Level.Spell = pc->m_Light.Type.Spell = 0;
|
||||||
|
|
||||||
safe_delete_array(pcs);
|
safe_delete_array(pcs);
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
|||||||
// vesuvias - appearence fix
|
// vesuvias - appearence fix
|
||||||
: Mob("Unnamed_Corpse","",0,0,in_npc->GetGender(),in_npc->GetRace(),in_npc->GetClass(),BT_Humanoid,//bodytype added
|
: Mob("Unnamed_Corpse","",0,0,in_npc->GetGender(),in_npc->GetRace(),in_npc->GetClass(),BT_Humanoid,//bodytype added
|
||||||
in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0,
|
in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0,
|
||||||
in_npc->GetPosition(), in_npc->GetInnateLightValue(), in_npc->GetTexture(),in_npc->GetHelmTexture(),
|
in_npc->GetPosition(), in_npc->GetInnateLightType(), in_npc->GetTexture(),in_npc->GetHelmTexture(),
|
||||||
0,0,0,0,0,0,0,0,0,
|
0,0,0,0,0,0,0,0,0,
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0),
|
0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0),
|
||||||
corpse_decay_timer(in_decaytime),
|
corpse_decay_timer(in_decaytime),
|
||||||
@ -203,9 +203,8 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
|||||||
}
|
}
|
||||||
this->rez_experience = 0;
|
this->rez_experience = 0;
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
spell_light = NOT_USED;
|
UpdateActiveLight();
|
||||||
UpdateActiveLightValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||||
@ -223,7 +222,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
|||||||
client->GetSize(), // float in_size,
|
client->GetSize(), // float in_size,
|
||||||
0, // float in_runspeed,
|
0, // float in_runspeed,
|
||||||
client->GetPosition(),
|
client->GetPosition(),
|
||||||
0, // uint8 in_light, - verified for client innate_light value
|
client->GetInnateLightType(), // uint8 in_light, - verified for client innate_light value
|
||||||
client->GetTexture(), // uint8 in_texture,
|
client->GetTexture(), // uint8 in_texture,
|
||||||
client->GetHelmTexture(), // uint8 in_helmtexture,
|
client->GetHelmTexture(), // uint8 in_helmtexture,
|
||||||
0, // uint16 in_ac,
|
0, // uint16 in_ac,
|
||||||
@ -341,7 +340,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
|||||||
|
|
||||||
database.TransactionBegin();
|
database.TransactionBegin();
|
||||||
|
|
||||||
// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke -U
|
// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke
|
||||||
if (!removed_list.empty()) {
|
if (!removed_list.empty()) {
|
||||||
std::stringstream ss("");
|
std::stringstream ss("");
|
||||||
ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
|
ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
|
||||||
@ -362,8 +361,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
|||||||
database.QueryDatabase(ss.str().c_str());
|
database.QueryDatabase(ss.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto start = client->GetInv().cursor_begin();
|
auto start = client->GetInv().cursor_cbegin();
|
||||||
auto finish = client->GetInv().cursor_end();
|
auto finish = client->GetInv().cursor_cend();
|
||||||
database.SaveCursor(client->CharacterID(), start, finish);
|
database.SaveCursor(client->CharacterID(), start, finish);
|
||||||
|
|
||||||
client->CalcBonuses();
|
client->CalcBonuses();
|
||||||
@ -374,16 +373,14 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
|||||||
|
|
||||||
database.TransactionCommit();
|
database.TransactionCommit();
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
spell_light = NOT_USED;
|
UpdateActiveLight();
|
||||||
UpdateActiveLightValue();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} //end "not leaving naked corpses"
|
} //end "not leaving naked corpses"
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
spell_light = NOT_USED;
|
UpdateActiveLight();
|
||||||
UpdateActiveLightValue();
|
|
||||||
|
|
||||||
IsRezzed(false);
|
IsRezzed(false);
|
||||||
Save();
|
Save();
|
||||||
@ -522,9 +519,9 @@ in_helmtexture,
|
|||||||
}
|
}
|
||||||
SetPlayerKillItemID(0);
|
SetPlayerKillItemID(0);
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
spell_light = NOT_USED;
|
m_Light.Level.Spell = m_Light.Type.Spell = 0;
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
Corpse::~Corpse() {
|
Corpse::~Corpse() {
|
||||||
@ -675,7 +672,7 @@ void Corpse::AddItem(uint32 itemnum, uint16 charges, int16 slot, uint32 aug1, ui
|
|||||||
item->attuned=attuned;
|
item->attuned=attuned;
|
||||||
itemlist.push_back(item);
|
itemlist.push_back(item);
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct** bag_item_data) {
|
ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct** bag_item_data) {
|
||||||
@ -750,9 +747,9 @@ void Corpse::RemoveItem(ServerLootItem_Struct* item_data)
|
|||||||
if (material != _MaterialInvalid)
|
if (material != _MaterialInvalid)
|
||||||
SendWearChange(material);
|
SendWearChange(material);
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue())
|
if (UpdateActiveLight())
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
|
|
||||||
safe_delete(sitem);
|
safe_delete(sitem);
|
||||||
return;
|
return;
|
||||||
@ -1228,9 +1225,9 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
|
|||||||
linker.SetLinkType(linker.linkItemInst);
|
linker.SetLinkType(linker.linkItemInst);
|
||||||
linker.SetItemInst(inst);
|
linker.SetItemInst(inst);
|
||||||
|
|
||||||
auto item_link = linker.GenerateLink();
|
auto item_link = linker.GenerateLink();
|
||||||
|
|
||||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
||||||
|
|
||||||
if (!IsPlayerCorpse()) {
|
if (!IsPlayerCorpse()) {
|
||||||
Group *g = client->GetGroup();
|
Group *g = client->GetGroup();
|
||||||
@ -1279,14 +1276,10 @@ void Corpse::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
|||||||
Mob::FillSpawnStruct(ns, ForWho);
|
Mob::FillSpawnStruct(ns, ForWho);
|
||||||
|
|
||||||
ns->spawn.max_hp = 120;
|
ns->spawn.max_hp = 120;
|
||||||
|
ns->spawn.NPC = 2;
|
||||||
|
|
||||||
if (IsPlayerCorpse())
|
UpdateActiveLight();
|
||||||
ns->spawn.NPC = 3;
|
ns->spawn.light = m_Light.Type.Active;
|
||||||
else
|
|
||||||
ns->spawn.NPC = 2;
|
|
||||||
|
|
||||||
UpdateActiveLightValue();
|
|
||||||
ns->spawn.light = active_light;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Corpse::QueryLoot(Client* to) {
|
void Corpse::QueryLoot(Client* to) {
|
||||||
@ -1425,26 +1418,48 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const {
|
|||||||
|
|
||||||
item = database.GetItem(GetEquipment(material_slot));
|
item = database.GetItem(GetEquipment(material_slot));
|
||||||
if(item != NO_ITEM) {
|
if(item != NO_ITEM) {
|
||||||
return item_tint[material_slot].rgb.use_tint ?
|
return item_tint[material_slot].RGB.UseTint ?
|
||||||
item_tint[material_slot].color :
|
item_tint[material_slot].Color :
|
||||||
item->Color;
|
item->Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Corpse::UpdateEquipLightValue()
|
void Corpse::UpdateEquipmentLight()
|
||||||
{
|
{
|
||||||
equip_light = NOT_USED;
|
m_Light.Type.Equipment = 0;
|
||||||
|
m_Light.Level.Equipment = 0;
|
||||||
|
|
||||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||||
if (((*iter)->equip_slot < EmuConstants::EQUIPMENT_BEGIN || (*iter)->equip_slot > EmuConstants::GENERAL_END) && (*iter)->equip_slot != MainPowerSource) { continue; }
|
if (((*iter)->equip_slot < EmuConstants::EQUIPMENT_BEGIN || (*iter)->equip_slot > EmuConstants::EQUIPMENT_END) && (*iter)->equip_slot != MainPowerSource) { continue; }
|
||||||
|
if ((*iter)->equip_slot == MainAmmo) { continue; }
|
||||||
|
|
||||||
auto item = database.GetItem((*iter)->item_id);
|
auto item = database.GetItem((*iter)->item_id);
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
|
||||||
if (item->Light & 0xF0) { continue; }
|
if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment))
|
||||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
m_Light.Type.Equipment = item->Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8 general_light_type = 0;
|
||||||
|
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||||
|
if ((*iter)->equip_slot < EmuConstants::GENERAL_BEGIN || (*iter)->equip_slot > EmuConstants::GENERAL_END) { continue; }
|
||||||
|
|
||||||
|
auto item = database.GetItem((*iter)->item_id);
|
||||||
|
if (item == nullptr) { continue; }
|
||||||
|
|
||||||
|
if (item->ItemClass != ItemClassCommon) { continue; }
|
||||||
|
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||||
|
|
||||||
|
if (m_Light.TypeToLevel(item->Light))
|
||||||
|
general_light_type = item->Light;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment))
|
||||||
|
m_Light.Type.Equipment = general_light_type;
|
||||||
|
|
||||||
|
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Corpse::AddLooter(Mob* who) {
|
void Corpse::AddLooter(Mob* who) {
|
||||||
|
|||||||
@ -125,7 +125,7 @@ class Corpse : public Mob {
|
|||||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||||
inline int GetRezExp() { return rez_experience; }
|
inline int GetRezExp() { return rez_experience; }
|
||||||
|
|
||||||
virtual void UpdateEquipLightValue();
|
virtual void UpdateEquipmentLight();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void MoveItemToCorpse(Client *client, ItemInst *inst, int16 equipSlot, std::list<uint32> &removedList);
|
void MoveItemToCorpse(Client *client, ItemInst *inst, int16 equipSlot, std::list<uint32> &removedList);
|
||||||
|
|||||||
@ -41,14 +41,14 @@ extern EntityList entity_list;
|
|||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
|
|
||||||
Doors::Doors(const Door* door) :
|
Doors::Doors(const Door* door) :
|
||||||
close_timer(5000),
|
close_timer(5000),
|
||||||
m_Position(door->pos_x, door->pos_y, door->pos_z, door->heading),
|
m_Position(door->pos_x, door->pos_y, door->pos_z, door->heading),
|
||||||
m_Destination(door->dest_x, door->dest_y, door->dest_z, door->dest_heading)
|
m_Destination(door->dest_x, door->dest_y, door->dest_z, door->dest_heading)
|
||||||
{
|
{
|
||||||
db_id = door->db_id;
|
db_id = door->db_id;
|
||||||
door_id = door->door_id;
|
door_id = door->door_id;
|
||||||
strn0cpy(zone_name,door->zone_name,32);
|
strn0cpy(zone_name, door->zone_name, 32);
|
||||||
strn0cpy(door_name,door->door_name,32);
|
strn0cpy(door_name, door->door_name, 32);
|
||||||
incline = door->incline;
|
incline = door->incline;
|
||||||
opentype = door->opentype;
|
opentype = door->opentype;
|
||||||
guild_id = door->guild_id;
|
guild_id = door->guild_id;
|
||||||
@ -57,7 +57,7 @@ Doors::Doors(const Door* door) :
|
|||||||
nokeyring = door->nokeyring;
|
nokeyring = door->nokeyring;
|
||||||
trigger_door = door->trigger_door;
|
trigger_door = door->trigger_door;
|
||||||
trigger_type = door->trigger_type;
|
trigger_type = door->trigger_type;
|
||||||
triggered=false;
|
triggered = false;
|
||||||
door_param = door->door_param;
|
door_param = door->door_param;
|
||||||
size = door->size;
|
size = door->size;
|
||||||
invert_state = door->invert_state;
|
invert_state = door->invert_state;
|
||||||
@ -65,7 +65,7 @@ Doors::Doors(const Door* door) :
|
|||||||
|
|
||||||
close_timer.Disable();
|
close_timer.Disable();
|
||||||
|
|
||||||
strn0cpy(dest_zone,door->dest_zone,16);
|
strn0cpy(dest_zone, door->dest_zone, 16);
|
||||||
dest_instance_id = door->dest_instance_id;
|
dest_instance_id = door->dest_instance_id;
|
||||||
|
|
||||||
is_ldon_door = door->is_ldon_door;
|
is_ldon_door = door->is_ldon_door;
|
||||||
@ -73,14 +73,14 @@ Doors::Doors(const Door* door) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uint16 dsize) :
|
Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uint16 dsize) :
|
||||||
close_timer(5000),
|
close_timer(5000),
|
||||||
m_Position(position),
|
m_Position(position),
|
||||||
m_Destination(glm::vec4())
|
m_Destination(glm::vec4())
|
||||||
{
|
{
|
||||||
db_id = database.GetDoorsCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion());
|
db_id = database.GetDoorsCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion());
|
||||||
door_id = database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion());
|
door_id = database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion());
|
||||||
strn0cpy(zone_name,zone->GetShortName(),32);
|
strn0cpy(zone_name, zone->GetShortName(), 32);
|
||||||
strn0cpy(door_name,dmodel,32);
|
strn0cpy(door_name, dmodel, 32);
|
||||||
incline = 0;
|
incline = 0;
|
||||||
opentype = dopentype;
|
opentype = dopentype;
|
||||||
guild_id = 0;
|
guild_id = 0;
|
||||||
@ -89,7 +89,7 @@ Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uin
|
|||||||
nokeyring = 0;
|
nokeyring = 0;
|
||||||
trigger_door = 0;
|
trigger_door = 0;
|
||||||
trigger_type = 0;
|
trigger_type = 0;
|
||||||
triggered=false;
|
triggered = false;
|
||||||
door_param = 0;
|
door_param = 0;
|
||||||
size = dsize;
|
size = dsize;
|
||||||
invert_state = 0;
|
invert_state = 0;
|
||||||
@ -97,7 +97,7 @@ Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uin
|
|||||||
|
|
||||||
close_timer.Disable();
|
close_timer.Disable();
|
||||||
|
|
||||||
strn0cpy(dest_zone,"NONE",32);
|
strn0cpy(dest_zone, "NONE", 32);
|
||||||
dest_instance_id = 0;
|
dest_instance_id = 0;
|
||||||
|
|
||||||
is_ldon_door = 0;
|
is_ldon_door = 0;
|
||||||
@ -655,6 +655,8 @@ bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name
|
|||||||
into[rowIndex].db_id = atoi(row[0]);
|
into[rowIndex].db_id = atoi(row[0]);
|
||||||
into[rowIndex].door_id = atoi(row[1]);
|
into[rowIndex].door_id = atoi(row[1]);
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Doors, "Door Load: db id: %u, door_id %u", into[rowIndex].db_id, into[rowIndex].door_id);
|
||||||
|
|
||||||
strn0cpy(into[rowIndex].zone_name,row[2],32);
|
strn0cpy(into[rowIndex].zone_name,row[2],32);
|
||||||
strn0cpy(into[rowIndex].door_name,row[3],32);
|
strn0cpy(into[rowIndex].door_name,row[3],32);
|
||||||
|
|
||||||
|
|||||||
@ -756,7 +756,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
|||||||
} else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
|
} else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
|
||||||
// This does not check faction for beneficial AE buffs..only agro and attackable.
|
// This does not check faction for beneficial AE buffs..only agro and attackable.
|
||||||
// I've tested for spells that I can find without problem, but a faction-based
|
// I've tested for spells that I can find without problem, but a faction-based
|
||||||
// check may still be needed. Any changes here should also reflect in BardAEPulse() -U
|
// check may still be needed. Any changes here should also reflect in BardAEPulse()
|
||||||
if (caster->IsAttackAllowed(curmob, true))
|
if (caster->IsAttackAllowed(curmob, true))
|
||||||
continue;
|
continue;
|
||||||
if (caster->CheckAggro(curmob))
|
if (caster->CheckAggro(curmob))
|
||||||
|
|||||||
@ -863,7 +863,7 @@ void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlaye
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(isItemQuest) {
|
else if(isItemQuest) {
|
||||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
// need a valid ItemInst pointer check here..unsure how to cancel this process
|
||||||
const Item_Struct* item = iteminst->GetItem();
|
const Item_Struct* item = iteminst->GetItem();
|
||||||
package_name = "qst_item_";
|
package_name = "qst_item_";
|
||||||
package_name += itoa(item->ID);
|
package_name += itoa(item->ID);
|
||||||
@ -1308,7 +1308,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
|||||||
|
|
||||||
case EVENT_SCALE_CALC:
|
case EVENT_SCALE_CALC:
|
||||||
case EVENT_ITEM_ENTER_ZONE: {
|
case EVENT_ITEM_ENTER_ZONE: {
|
||||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
// need a valid ItemInst pointer check here..unsure how to cancel this process
|
||||||
ExportVar(package_name.c_str(), "itemid", objid);
|
ExportVar(package_name.c_str(), "itemid", objid);
|
||||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||||
break;
|
break;
|
||||||
@ -1316,7 +1316,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
|||||||
|
|
||||||
case EVENT_ITEM_CLICK_CAST:
|
case EVENT_ITEM_CLICK_CAST:
|
||||||
case EVENT_ITEM_CLICK: {
|
case EVENT_ITEM_CLICK: {
|
||||||
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
|
// need a valid ItemInst pointer check here..unsure how to cancel this process
|
||||||
ExportVar(package_name.c_str(), "itemid", objid);
|
ExportVar(package_name.c_str(), "itemid", objid);
|
||||||
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
|
||||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||||
|
|||||||
@ -2767,7 +2767,7 @@ void EntityList::WriteEntityIDs()
|
|||||||
|
|
||||||
BulkZoneSpawnPacket::BulkZoneSpawnPacket(Client *iSendTo, uint32 iMaxSpawnsPerPacket)
|
BulkZoneSpawnPacket::BulkZoneSpawnPacket(Client *iSendTo, uint32 iMaxSpawnsPerPacket)
|
||||||
{
|
{
|
||||||
data = 0;
|
data = nullptr;
|
||||||
pSendTo = iSendTo;
|
pSendTo = iSendTo;
|
||||||
pMaxSpawnsPerPacket = iMaxSpawnsPerPacket;
|
pMaxSpawnsPerPacket = iMaxSpawnsPerPacket;
|
||||||
}
|
}
|
||||||
@ -2775,7 +2775,7 @@ BulkZoneSpawnPacket::BulkZoneSpawnPacket(Client *iSendTo, uint32 iMaxSpawnsPerPa
|
|||||||
BulkZoneSpawnPacket::~BulkZoneSpawnPacket()
|
BulkZoneSpawnPacket::~BulkZoneSpawnPacket()
|
||||||
{
|
{
|
||||||
SendBuffer();
|
SendBuffer();
|
||||||
safe_delete_array(data)
|
safe_delete_array(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BulkZoneSpawnPacket::AddSpawn(NewSpawn_Struct *ns)
|
bool BulkZoneSpawnPacket::AddSpawn(NewSpawn_Struct *ns)
|
||||||
@ -2794,7 +2794,8 @@ bool BulkZoneSpawnPacket::AddSpawn(NewSpawn_Struct *ns)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BulkZoneSpawnPacket::SendBuffer() {
|
void BulkZoneSpawnPacket::SendBuffer()
|
||||||
|
{
|
||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@ -270,7 +270,7 @@ void Client::GoFish()
|
|||||||
//check for add NPC
|
//check for add NPC
|
||||||
if(npc_chance > 0 && npc_id) {
|
if(npc_chance > 0 && npc_id) {
|
||||||
if(npc_chance < zone->random.Int(0, 99)) {
|
if(npc_chance < zone->random.Int(0, 99)) {
|
||||||
const NPCType* tmp = database.GetNPCType(npc_id);
|
const NPCType* tmp = database.LoadNPCTypesData(npc_id);
|
||||||
if(tmp != nullptr) {
|
if(tmp != nullptr) {
|
||||||
auto positionNPC = GetPosition();
|
auto positionNPC = GetPosition();
|
||||||
positionNPC.x = positionNPC.x + 3;
|
positionNPC.x = positionNPC.x + 3;
|
||||||
|
|||||||
@ -72,8 +72,8 @@ public:
|
|||||||
uint32 GetTotalGroupDamage(Mob* other);
|
uint32 GetTotalGroupDamage(Mob* other);
|
||||||
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
|
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
|
||||||
inline void SetLeader(Mob* newleader){ leader=newleader; };
|
inline void SetLeader(Mob* newleader){ leader=newleader; };
|
||||||
inline Mob* GetLeader(){ return leader; };
|
inline Mob* GetLeader() { return leader; };
|
||||||
char* GetLeaderName() { return membername[0]; };
|
const char* GetLeaderName() { return membername[0]; };
|
||||||
void SendHPPacketsTo(Mob* newmember);
|
void SendHPPacketsTo(Mob* newmember);
|
||||||
void SendHPPacketsFrom(Mob* newmember);
|
void SendHPPacketsFrom(Mob* newmember);
|
||||||
bool UpdatePlayer(Mob* update);
|
bool UpdatePlayer(Mob* update);
|
||||||
|
|||||||
@ -219,17 +219,17 @@ bool HateList::RemoveEntFromHateList(Mob *in_entity)
|
|||||||
{
|
{
|
||||||
if ((*iterator)->entity_on_hatelist == in_entity)
|
if ((*iterator)->entity_on_hatelist == in_entity)
|
||||||
{
|
{
|
||||||
if (in_entity)
|
|
||||||
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0);
|
|
||||||
is_found = true;
|
is_found = true;
|
||||||
|
|
||||||
|
|
||||||
if (in_entity && in_entity->IsClient())
|
if (in_entity && in_entity->IsClient())
|
||||||
in_entity->CastToClient()->DecrementAggroCount();
|
in_entity->CastToClient()->DecrementAggroCount();
|
||||||
|
|
||||||
delete (*iterator);
|
delete (*iterator);
|
||||||
iterator = list.erase(iterator);
|
iterator = list.erase(iterator);
|
||||||
|
|
||||||
|
if (in_entity)
|
||||||
|
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
++iterator;
|
++iterator;
|
||||||
@ -282,14 +282,14 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Mob* top_hate = nullptr;
|
Mob* top_hate = nullptr;
|
||||||
int32 hate = -1;
|
int64 hate = -1;
|
||||||
|
|
||||||
if (center == nullptr)
|
if (center == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (RuleB(Aggro, SmartAggroList)){
|
if (RuleB(Aggro, SmartAggroList)){
|
||||||
Mob* top_client_type_in_range = nullptr;
|
Mob* top_client_type_in_range = nullptr;
|
||||||
int32 hate_client_type_in_range = -1;
|
int64 hate_client_type_in_range = -1;
|
||||||
int skipped_count = 0;
|
int skipped_count = 0;
|
||||||
|
|
||||||
auto iterator = list.begin();
|
auto iterator = list.begin();
|
||||||
@ -337,7 +337,7 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 current_hate = cur->stored_hate_amount;
|
int64 current_hate = cur->stored_hate_amount;
|
||||||
|
|
||||||
if (cur->entity_on_hatelist->IsClient()){
|
if (cur->entity_on_hatelist->IsClient()){
|
||||||
|
|
||||||
@ -459,13 +459,13 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center)
|
|||||||
|
|
||||||
Mob *HateList::GetEntWithMostHateOnList(){
|
Mob *HateList::GetEntWithMostHateOnList(){
|
||||||
Mob* top = nullptr;
|
Mob* top = nullptr;
|
||||||
int32 hate = -1;
|
int64 hate = -1;
|
||||||
|
|
||||||
auto iterator = list.begin();
|
auto iterator = list.begin();
|
||||||
while (iterator != list.end())
|
while (iterator != list.end())
|
||||||
{
|
{
|
||||||
struct_HateList *cur = (*iterator);
|
struct_HateList *cur = (*iterator);
|
||||||
if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
|
if (cur && cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
|
||||||
{
|
{
|
||||||
top = cur->entity_on_hatelist;
|
top = cur->entity_on_hatelist;
|
||||||
hate = cur->stored_hate_amount;
|
hate = cur->stored_hate_amount;
|
||||||
|
|||||||
@ -177,16 +177,16 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Client::CheckLoreConflict(const Item_Struct* item) {
|
bool Client::CheckLoreConflict(const Item_Struct* item)
|
||||||
if (!item)
|
{
|
||||||
return false;
|
if (!item) { return false; }
|
||||||
if (!(item->LoreFlag))
|
if (!item->LoreFlag) { return false; }
|
||||||
return false;
|
if (item->LoreGroup == 0) { return false; }
|
||||||
|
|
||||||
if (item->LoreGroup == -1) // Standard lore items; look everywhere except the shared bank, return the result
|
if (item->LoreGroup == 0xFFFFFFFF) // Standard lore items; look everywhere except the shared bank, return the result
|
||||||
return (m_inv.HasItem(item->ID, 0, ~invWhereSharedBank) != INVALID_INDEX);
|
return (m_inv.HasItem(item->ID, 0, ~invWhereSharedBank) != INVALID_INDEX);
|
||||||
|
|
||||||
//If the item has a lore group, we check for other items with the same group and return the result
|
// If the item has a lore group, we check for other items with the same group and return the result
|
||||||
return (m_inv.HasItemByLoreGroup(item->LoreGroup, ~invWhereSharedBank) != INVALID_INDEX);
|
return (m_inv.HasItemByLoreGroup(item->LoreGroup, ~invWhereSharedBank) != INVALID_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,7 +619,7 @@ void Client::DropItem(int16 slot_id)
|
|||||||
// Save client inventory change to database
|
// Save client inventory change to database
|
||||||
if (slot_id == MainCursor) {
|
if (slot_id == MainCursor) {
|
||||||
SendCursorBuffer();
|
SendCursorBuffer();
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(CharacterID(), s, e);
|
database.SaveCursor(CharacterID(), s, e);
|
||||||
} else {
|
} else {
|
||||||
database.SaveInventory(CharacterID(), nullptr, slot_id);
|
database.SaveInventory(CharacterID(), nullptr, slot_id);
|
||||||
@ -680,20 +680,37 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
|
|||||||
return INVALID_ID;
|
return INVALID_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendCursorBuffer() {
|
void Client::SendCursorBuffer()
|
||||||
|
{
|
||||||
// Temporary work-around for the RoF+ Client Buffer
|
// Temporary work-around for the RoF+ Client Buffer
|
||||||
// Instead of dealing with client moving items in cursor buffer,
|
// Instead of dealing with client moving items in cursor buffer,
|
||||||
// we can just send the next item in the cursor buffer to the cursor.
|
// we can just send the next item in the cursor buffer to the cursor.
|
||||||
if (GetClientVersion() >= ClientVersion::RoF)
|
if (GetClientVersion() < ClientVersion::RoF) { return; }
|
||||||
{
|
if (GetInv().CursorEmpty()) { return; }
|
||||||
if (!GetInv().CursorEmpty())
|
|
||||||
{
|
auto test_inst = GetInv().GetCursorItem();
|
||||||
const ItemInst* inst = GetInv().GetCursorItem();
|
if (test_inst == nullptr) { return; }
|
||||||
if (inst)
|
auto test_item = test_inst->GetItem();
|
||||||
{
|
if (test_item == nullptr) { return; }
|
||||||
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
|
|
||||||
}
|
bool lore_pass = true;
|
||||||
}
|
if (test_item->LoreGroup == 0xFFFFFFFF) {
|
||||||
|
lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||||
|
}
|
||||||
|
else if (test_item->LoreGroup != 0) {
|
||||||
|
lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lore_pass) {
|
||||||
|
Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor",
|
||||||
|
GetName(), test_item->Name, test_item->ID);
|
||||||
|
Message_StringID(MT_LootMessages, 290);
|
||||||
|
parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0);
|
||||||
|
DeleteItemInInventory(MainCursor);
|
||||||
|
SendCursorBuffer();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SendItemPacket(MainCursor, test_inst, ItemPacketSummonItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,7 +789,7 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
|
|||||||
|
|
||||||
const ItemInst* inst = nullptr;
|
const ItemInst* inst = nullptr;
|
||||||
if (slot_id == MainCursor) {
|
if (slot_id == MainCursor) {
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
if(update_db)
|
if(update_db)
|
||||||
database.SaveCursor(character_id, s, e);
|
database.SaveCursor(character_id, s, e);
|
||||||
}
|
}
|
||||||
@ -826,7 +843,7 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
|
|||||||
SendItemPacket(MainCursor, &inst, ItemPacketSummonItem);
|
SendItemPacket(MainCursor, &inst, ItemPacketSummonItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
return database.SaveCursor(CharacterID(), s, e);
|
return database.SaveCursor(CharacterID(), s, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -851,7 +868,7 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (slot_id == MainCursor) {
|
if (slot_id == MainCursor) {
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
return database.SaveCursor(this->CharacterID(), s, e);
|
return database.SaveCursor(this->CharacterID(), s, e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -865,28 +882,64 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
|
|||||||
void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data)
|
void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data)
|
||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Putting loot item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
Log.Out(Logs::Detail, Logs::Inventory, "Putting loot item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
|
||||||
m_inv.PutItem(slot_id, inst);
|
|
||||||
|
|
||||||
SendLootItemInPacket(&inst, slot_id);
|
bool cursor_empty = m_inv.CursorEmpty();
|
||||||
|
|
||||||
if (slot_id == MainCursor) {
|
if (slot_id == MainCursor) {
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
m_inv.PushCursor(inst);
|
||||||
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(this->CharacterID(), s, e);
|
database.SaveCursor(this->CharacterID(), s, e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
m_inv.PutItem(slot_id, inst);
|
||||||
database.SaveInventory(this->CharacterID(), &inst, slot_id);
|
database.SaveInventory(this->CharacterID(), &inst, slot_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bag_item_data) { // bag contents
|
// Subordinate items in cursor buffer must be sent via ItemPacketSummonItem or we just overwrite the visible cursor and desync the client
|
||||||
int16 interior_slot;
|
if (slot_id == MainCursor && !cursor_empty) {
|
||||||
// our bag went into slot_id, now let's pack the contents in
|
// RoF+ currently has a specialized cursor handler
|
||||||
for(int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) {
|
if (GetClientVersion() < ClientVersion::RoF)
|
||||||
if(bag_item_data[i] == nullptr)
|
SendItemPacket(slot_id, &inst, ItemPacketSummonItem);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SendLootItemInPacket(&inst, slot_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bag_item_data) {
|
||||||
|
for (int index = 0; index < EmuConstants::ITEM_CONTAINER_SIZE; ++index) {
|
||||||
|
if (bag_item_data[index] == nullptr)
|
||||||
continue;
|
continue;
|
||||||
const ItemInst *bagitem = database.CreateItem(bag_item_data[i]->item_id, bag_item_data[i]->charges, bag_item_data[i]->aug_1, bag_item_data[i]->aug_2, bag_item_data[i]->aug_3, bag_item_data[i]->aug_4, bag_item_data[i]->aug_5, bag_item_data[i]->aug_6, bag_item_data[i]->attuned);
|
|
||||||
interior_slot = Inventory::CalcSlotId(slot_id, i);
|
const ItemInst *bagitem = database.CreateItem(
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Putting bag loot item %s (%d) into slot %d (bag slot %d)", inst.GetItem()->Name, inst.GetItem()->ID, interior_slot, i);
|
bag_item_data[index]->item_id,
|
||||||
PutLootInInventory(interior_slot, *bagitem);
|
bag_item_data[index]->charges,
|
||||||
|
bag_item_data[index]->aug_1,
|
||||||
|
bag_item_data[index]->aug_2,
|
||||||
|
bag_item_data[index]->aug_3,
|
||||||
|
bag_item_data[index]->aug_4,
|
||||||
|
bag_item_data[index]->aug_5,
|
||||||
|
bag_item_data[index]->aug_6,
|
||||||
|
bag_item_data[index]->attuned
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dump bag contents to cursor in the event that owning bag is not the first cursor item
|
||||||
|
// (This assumes that the data passed is correctly associated..no safety checks are implemented)
|
||||||
|
if (slot_id == MainCursor && !cursor_empty) {
|
||||||
|
Log.Out(Logs::Detail, Logs::Inventory,
|
||||||
|
"Putting bag loot item %s (%d) into slot %d (non-empty cursor override)",
|
||||||
|
inst.GetItem()->Name, inst.GetItem()->ID, MainCursor);
|
||||||
|
|
||||||
|
PutLootInInventory(MainCursor, *bagitem);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto bag_slot = Inventory::CalcSlotId(slot_id, index);
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Inventory,
|
||||||
|
"Putting bag loot item %s (%d) into slot %d (bag slot %d)",
|
||||||
|
inst.GetItem()->Name, inst.GetItem()->ID, bag_slot, index);
|
||||||
|
|
||||||
|
PutLootInInventory(bag_slot, *bagitem);
|
||||||
|
}
|
||||||
safe_delete(bagitem);
|
safe_delete(bagitem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1009,7 +1062,7 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
|
|||||||
from.SetCharges(from.GetCharges() - charges_to_move);
|
from.SetCharges(from.GetCharges() - charges_to_move);
|
||||||
SendLootItemInPacket(tmp_inst, to_slot);
|
SendLootItemInPacket(tmp_inst, to_slot);
|
||||||
if (to_slot == MainCursor) {
|
if (to_slot == MainCursor) {
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(this->CharacterID(), s, e);
|
database.SaveCursor(this->CharacterID(), s, e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1050,12 +1103,12 @@ bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32
|
|||||||
// Currently, enabling them causes misalignments in what the client expects. I haven't looked
|
// Currently, enabling them causes misalignments in what the client expects. I haven't looked
|
||||||
// into it further to determine the cause..but, the function is setup to accept the parameters.
|
// into it further to determine the cause..but, the function is setup to accept the parameters.
|
||||||
// Note: some links appear with '00000' in front of the name..so, it's likely we need to send
|
// Note: some links appear with '00000' in front of the name..so, it's likely we need to send
|
||||||
// some additional information when certain parameters are true -U
|
// some additional information when certain parameters are true
|
||||||
//switch (GetClientVersion()) {
|
//switch (GetClientVersion()) {
|
||||||
switch (0) {
|
switch (0) {
|
||||||
case EQClientRoF2:
|
case EQClientRoF2:
|
||||||
// This operator contains 14 parameter masks..but, only 13 parameter values.
|
// This operator contains 14 parameter masks..but, only 13 parameter values.
|
||||||
// Even so, the client link appears ok... Need to figure out the discrepancy -U
|
// Even so, the client link appears ok... Need to figure out the discrepancy
|
||||||
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X",
|
||||||
0,
|
0,
|
||||||
item->ID,
|
item->ID,
|
||||||
@ -1320,10 +1373,33 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This could be expounded upon at some point to let the server know that
|
|
||||||
// the client has moved a buffered cursor item onto the active cursor -U
|
|
||||||
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed
|
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed
|
||||||
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
|
||||||
|
if (GetClientVersion() >= ClientVersion::RoF) { return true; } // Can't do RoF+
|
||||||
|
|
||||||
|
if (move_in->to_slot == MainCursor) {
|
||||||
|
auto test_inst = m_inv.GetItem(MainCursor);
|
||||||
|
if (test_inst == nullptr) { return true; }
|
||||||
|
auto test_item = test_inst->GetItem();
|
||||||
|
if (test_item == nullptr) { return true; }
|
||||||
|
if (!test_item->LoreFlag) { return true; }
|
||||||
|
|
||||||
|
bool lore_pass = true;
|
||||||
|
if (test_item->LoreGroup == 0xFFFFFFFF) {
|
||||||
|
lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||||
|
}
|
||||||
|
else if (test_item->LoreGroup != 0) {
|
||||||
|
lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lore_pass) {
|
||||||
|
Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor",
|
||||||
|
GetName(), test_item->Name, test_item->ID);
|
||||||
|
Message_StringID(MT_LootMessages, 290);
|
||||||
|
parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0);
|
||||||
|
DeleteItemInInventory(MainCursor, 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1567,7 +1643,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
|||||||
{
|
{
|
||||||
SendCursorBuffer();
|
SendCursorBuffer();
|
||||||
}
|
}
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(character_id, s, e);
|
database.SaveCursor(character_id, s, e);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1726,7 +1802,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
|||||||
{
|
{
|
||||||
SendCursorBuffer();
|
SendCursorBuffer();
|
||||||
}
|
}
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(character_id, s, e);
|
database.SaveCursor(character_id, s, e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1734,7 +1810,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dst_slot_id == MainCursor) {
|
if (dst_slot_id == MainCursor) {
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(character_id, s, e);
|
database.SaveCursor(character_id, s, e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1753,14 +1829,14 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) {
|
|||||||
// with any luck..this won't be needed in the future
|
// with any luck..this won't be needed in the future
|
||||||
|
|
||||||
// resync the 'from' and 'to' slots on an as-needed basis
|
// resync the 'from' and 'to' slots on an as-needed basis
|
||||||
// Not as effective as the full process, but less intrusive to gameplay -U
|
// Not as effective as the full process, but less intrusive to gameplay
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Inventory desyncronization. (charname: %s, source: %i, destination: %i)", GetName(), move_slots->from_slot, move_slots->to_slot);
|
Log.Out(Logs::Detail, Logs::Inventory, "Inventory desyncronization. (charname: %s, source: %i, destination: %i)", GetName(), move_slots->from_slot, move_slots->to_slot);
|
||||||
Message(15, "Inventory Desyncronization detected: Resending slot data...");
|
Message(15, "Inventory Desyncronization detected: Resending slot data...");
|
||||||
|
|
||||||
if((move_slots->from_slot >= EmuConstants::EQUIPMENT_BEGIN && move_slots->from_slot <= EmuConstants::CURSOR_BAG_END) || move_slots->from_slot == MainPowerSource) {
|
if((move_slots->from_slot >= EmuConstants::EQUIPMENT_BEGIN && move_slots->from_slot <= EmuConstants::CURSOR_BAG_END) || move_slots->from_slot == MainPowerSource) {
|
||||||
int16 resync_slot = (Inventory::CalcSlotId(move_slots->from_slot) == INVALID_INDEX) ? move_slots->from_slot : Inventory::CalcSlotId(move_slots->from_slot);
|
int16 resync_slot = (Inventory::CalcSlotId(move_slots->from_slot) == INVALID_INDEX) ? move_slots->from_slot : Inventory::CalcSlotId(move_slots->from_slot);
|
||||||
if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) {
|
if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) {
|
||||||
// This prevents the client from crashing when closing any 'phantom' bags -U
|
// This prevents the client from crashing when closing any 'phantom' bags
|
||||||
const Item_Struct* token_struct = database.GetItem(22292); // 'Copper Coin'
|
const Item_Struct* token_struct = database.GetItem(22292); // 'Copper Coin'
|
||||||
ItemInst* token_inst = database.CreateItem(token_struct, 1);
|
ItemInst* token_inst = database.CreateItem(token_struct, 1);
|
||||||
|
|
||||||
@ -1944,9 +2020,9 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) {
|
|||||||
void Client::DyeArmor(DyeStruct* dye){
|
void Client::DyeArmor(DyeStruct* dye){
|
||||||
int16 slot=0;
|
int16 slot=0;
|
||||||
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) {
|
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) {
|
||||||
if (m_pp.item_tint[i].rgb.blue != dye->dye[i].rgb.blue ||
|
if (m_pp.item_tint[i].RGB.Blue != dye->dye[i].RGB.Blue ||
|
||||||
m_pp.item_tint[i].rgb.red != dye->dye[i].rgb.red ||
|
m_pp.item_tint[i].RGB.Red != dye->dye[i].RGB.Red ||
|
||||||
m_pp.item_tint[i].rgb.green != dye->dye[i].rgb.green
|
m_pp.item_tint[i].RGB.Green != dye->dye[i].RGB.Green
|
||||||
) {
|
) {
|
||||||
slot = m_inv.HasItem(32557, 1, invWherePersonal);
|
slot = m_inv.HasItem(32557, 1, invWherePersonal);
|
||||||
if (slot != INVALID_INDEX){
|
if (slot != INVALID_INDEX){
|
||||||
@ -1954,18 +2030,18 @@ void Client::DyeArmor(DyeStruct* dye){
|
|||||||
uint8 slot2=SlotConvert(i);
|
uint8 slot2=SlotConvert(i);
|
||||||
ItemInst* inst = this->m_inv.GetItem(slot2);
|
ItemInst* inst = this->m_inv.GetItem(slot2);
|
||||||
if(inst){
|
if(inst){
|
||||||
uint32 armor_color = ((uint32)dye->dye[i].rgb.red << 16) | ((uint32)dye->dye[i].rgb.green << 8) | ((uint32)dye->dye[i].rgb.blue);
|
uint32 armor_color = ((uint32)dye->dye[i].RGB.Red << 16) | ((uint32)dye->dye[i].RGB.Green << 8) | ((uint32)dye->dye[i].RGB.Blue);
|
||||||
inst->SetColor(armor_color);
|
inst->SetColor(armor_color);
|
||||||
database.SaveCharacterMaterialColor(this->CharacterID(), i, armor_color);
|
database.SaveCharacterMaterialColor(this->CharacterID(), i, armor_color);
|
||||||
database.SaveInventory(CharacterID(),inst,slot2);
|
database.SaveInventory(CharacterID(),inst,slot2);
|
||||||
if(dye->dye[i].rgb.use_tint)
|
if(dye->dye[i].RGB.UseTint)
|
||||||
m_pp.item_tint[i].rgb.use_tint = 0xFF;
|
m_pp.item_tint[i].RGB.UseTint = 0xFF;
|
||||||
else
|
else
|
||||||
m_pp.item_tint[i].rgb.use_tint=0x00;
|
m_pp.item_tint[i].RGB.UseTint=0x00;
|
||||||
}
|
}
|
||||||
m_pp.item_tint[i].rgb.blue=dye->dye[i].rgb.blue;
|
m_pp.item_tint[i].RGB.Blue=dye->dye[i].RGB.Blue;
|
||||||
m_pp.item_tint[i].rgb.red=dye->dye[i].rgb.red;
|
m_pp.item_tint[i].RGB.Red=dye->dye[i].RGB.Red;
|
||||||
m_pp.item_tint[i].rgb.green=dye->dye[i].rgb.green;
|
m_pp.item_tint[i].RGB.Green=dye->dye[i].RGB.Green;
|
||||||
SendWearChange(i);
|
SendWearChange(i);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@ -2170,7 +2246,7 @@ void Client::RemoveNoRent(bool client_update)
|
|||||||
}
|
}
|
||||||
local.clear();
|
local.clear();
|
||||||
|
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(this->CharacterID(), s, e);
|
database.SaveCursor(this->CharacterID(), s, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2257,7 +2333,7 @@ void Client::RemoveDuplicateLore(bool client_update)
|
|||||||
safe_delete(inst);
|
safe_delete(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shared Bank and Shared Bank Containers are not checked due to their allowing duplicate lore items -U
|
// Shared Bank and Shared Bank Containers are not checked due to their allowing duplicate lore items
|
||||||
|
|
||||||
if (!m_inv.CursorEmpty()) {
|
if (!m_inv.CursorEmpty()) {
|
||||||
std::list<ItemInst*> local_1;
|
std::list<ItemInst*> local_1;
|
||||||
@ -2298,7 +2374,7 @@ void Client::RemoveDuplicateLore(bool client_update)
|
|||||||
}
|
}
|
||||||
local_2.clear();
|
local_2.clear();
|
||||||
|
|
||||||
auto s = m_inv.cursor_begin(), e = m_inv.cursor_end();
|
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
|
||||||
database.SaveCursor(this->CharacterID(), s, e);
|
database.SaveCursor(this->CharacterID(), s, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2327,7 +2403,7 @@ void Client::MoveSlotNotAllowed(bool client_update)
|
|||||||
safe_delete(inst);
|
safe_delete(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to check inventory, cursor, bank or shared bank since they allow max item size and containers -U
|
// No need to check inventory, cursor, bank or shared bank since they allow max item size and containers
|
||||||
// Code can be added to check item size vs. container size, but it is left to attrition for now.
|
// Code can be added to check item size vs. container size, but it is left to attrition for now.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2380,7 +2456,7 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const
|
|||||||
|
|
||||||
const Item_Struct *item = database.GetItem(GetEquipment(material_slot));
|
const Item_Struct *item = database.GetItem(GetEquipment(material_slot));
|
||||||
if(item != nullptr)
|
if(item != nullptr)
|
||||||
return ((m_pp.item_tint[material_slot].rgb.use_tint) ? m_pp.item_tint[material_slot].color : item->Color);
|
return ((m_pp.item_tint[material_slot].RGB.UseTint) ? m_pp.item_tint[material_slot].Color : item->Color);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2436,97 +2512,99 @@ EQApplicationPacket* Client::ReturnItemPacket(int16 slot_id, const ItemInst* ins
|
|||||||
return outapp;
|
return outapp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16 BandolierSlotToWeaponSlot(int BandolierSlot) {
|
static int16 BandolierSlotToWeaponSlot(int BandolierSlot)
|
||||||
|
{
|
||||||
switch(BandolierSlot) {
|
switch (BandolierSlot)
|
||||||
case bandolierMainHand:
|
{
|
||||||
return MainPrimary;
|
case bandolierPrimary:
|
||||||
case bandolierOffHand:
|
return MainPrimary;
|
||||||
return MainSecondary;
|
case bandolierSecondary:
|
||||||
case bandolierRange:
|
return MainSecondary;
|
||||||
return MainRange;
|
case bandolierRange:
|
||||||
default:
|
return MainRange;
|
||||||
return MainAmmo;
|
default:
|
||||||
|
return MainAmmo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::CreateBandolier(const EQApplicationPacket *app) {
|
void Client::CreateBandolier(const EQApplicationPacket *app)
|
||||||
|
{
|
||||||
// Store bandolier set with the number and name passed by the client, along with the items that are currently
|
// Store bandolier set with the number and name passed by the client, along with the items that are currently
|
||||||
// in the players weapon slots.
|
// in the players weapon slots.
|
||||||
|
|
||||||
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
|
BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer;
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name);
|
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->Number, bs->Name);
|
||||||
strcpy(m_pp.bandoliers[bs->number].name, bs->name);
|
strcpy(m_pp.bandoliers[bs->Number].Name, bs->Name);
|
||||||
|
|
||||||
const ItemInst* InvItem = nullptr;
|
const ItemInst* InvItem = nullptr;
|
||||||
const Item_Struct *BaseItem = nullptr;
|
const Item_Struct *BaseItem = nullptr;
|
||||||
int16 WeaponSlot;
|
int16 WeaponSlot = 0;
|
||||||
|
|
||||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||||
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
||||||
InvItem = GetInv()[WeaponSlot];
|
InvItem = GetInv()[WeaponSlot];
|
||||||
if(InvItem) {
|
if(InvItem) {
|
||||||
BaseItem = InvItem->GetItem();
|
BaseItem = InvItem->GetItem();
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s adding item %s to slot %i", GetName(),BaseItem->Name, WeaponSlot);
|
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s adding item %s to slot %i", GetName(),BaseItem->Name, WeaponSlot);
|
||||||
m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = BaseItem->ID;
|
m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID = BaseItem->ID;
|
||||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = BaseItem->Icon;
|
m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon = BaseItem->Icon;
|
||||||
database.SaveCharacterBandolier(this->CharacterID(), bs->number, BandolierSlot, m_pp.bandoliers[bs->number].items[BandolierSlot].item_id, m_pp.bandoliers[bs->number].items[BandolierSlot].icon, bs->name);
|
database.SaveCharacterBandolier(this->CharacterID(), bs->Number, BandolierSlot, m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID, m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon, bs->Name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s no item in slot %i", GetName(), WeaponSlot);
|
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s no item in slot %i", GetName(), WeaponSlot);
|
||||||
m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = 0;
|
m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID = 0;
|
||||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = 0;
|
m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::RemoveBandolier(const EQApplicationPacket *app) {
|
void Client::RemoveBandolier(const EQApplicationPacket *app)
|
||||||
|
{
|
||||||
BandolierDelete_Struct *bds = (BandolierDelete_Struct*)app->pBuffer;
|
BandolierDelete_Struct *bds = (BandolierDelete_Struct*)app->pBuffer;
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s removing set", GetName(), bds->number);
|
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s removing set", GetName(), bds->Number);
|
||||||
memset(m_pp.bandoliers[bds->number].name, 0, 32);
|
memset(m_pp.bandoliers[bds->Number].Name, 0, 32);
|
||||||
for(int i = bandolierMainHand; i <= bandolierAmmo; i++) {
|
for(int i = bandolierPrimary; i <= bandolierAmmo; i++) {
|
||||||
m_pp.bandoliers[bds->number].items[i].item_id = 0;
|
m_pp.bandoliers[bds->Number].Items[i].ID = 0;
|
||||||
m_pp.bandoliers[bds->number].items[i].icon = 0;
|
m_pp.bandoliers[bds->Number].Items[i].Icon = 0;
|
||||||
}
|
}
|
||||||
database.DeleteCharacterBandolier(this->CharacterID(), bds->number);
|
database.DeleteCharacterBandolier(this->CharacterID(), bds->Number);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SetBandolier(const EQApplicationPacket *app) {
|
void Client::SetBandolier(const EQApplicationPacket *app)
|
||||||
|
{
|
||||||
// Swap the weapons in the given bandolier set into the character's weapon slots and return
|
// Swap the weapons in the given bandolier set into the character's weapon slots and return
|
||||||
// any items currently in the weapon slots to inventory.
|
// any items currently in the weapon slots to inventory.
|
||||||
|
|
||||||
BandolierSet_Struct *bss = (BandolierSet_Struct*)app->pBuffer;
|
BandolierSet_Struct *bss = (BandolierSet_Struct*)app->pBuffer;
|
||||||
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s activating set %i", GetName(), bss->number);
|
Log.Out(Logs::Detail, Logs::Inventory, "Char: %s activating set %i", GetName(), bss->Number);
|
||||||
int16 slot;
|
int16 slot = 0;
|
||||||
int16 WeaponSlot;
|
int16 WeaponSlot = 0;
|
||||||
ItemInst *BandolierItems[4]; // Temporary holding area for the weapons we pull out of their inventory
|
ItemInst *BandolierItems[4]; // Temporary holding area for the weapons we pull out of their inventory
|
||||||
|
|
||||||
// First we pull the items for this bandolier set out of their inventory, this makes space to put the
|
// First we pull the items for this bandolier set out of their inventory, this makes space to put the
|
||||||
// currently equipped items back.
|
// currently equipped items back.
|
||||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||||
// If this bandolier set has an item in this position
|
// If this bandolier set has an item in this position
|
||||||
if(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id) {
|
if(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID) {
|
||||||
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
||||||
|
|
||||||
// Check if the player has the item specified in the bandolier set on them.
|
// Check if the player has the item specified in the bandolier set on them.
|
||||||
//
|
//
|
||||||
slot = m_inv.HasItem(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id, 1,
|
slot = m_inv.HasItem(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID, 1,
|
||||||
invWhereWorn|invWherePersonal);
|
invWhereWorn|invWherePersonal);
|
||||||
|
|
||||||
// removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here
|
// removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here
|
||||||
if (slot == INVALID_INDEX) {
|
if (slot == INVALID_INDEX) {
|
||||||
if (m_inv.GetItem(MainCursor)) {
|
if (m_inv.GetItem(MainCursor)) {
|
||||||
if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
|
if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID &&
|
||||||
m_inv.GetItem(MainCursor)->GetCharges() >= 1) { // '> 0' the same, but this matches Inventory::_HasItem conditional check
|
m_inv.GetItem(MainCursor)->GetCharges() >= 1) { // '> 0' the same, but this matches Inventory::_HasItem conditional check
|
||||||
slot = MainCursor;
|
slot = MainCursor;
|
||||||
}
|
}
|
||||||
else if (m_inv.GetItem(MainCursor)->GetItem()->ItemClass == 1) {
|
else if (m_inv.GetItem(MainCursor)->GetItem()->ItemClass == 1) {
|
||||||
for(int16 CursorBagSlot = EmuConstants::CURSOR_BAG_BEGIN; CursorBagSlot <= EmuConstants::CURSOR_BAG_END; CursorBagSlot++) {
|
for(int16 CursorBagSlot = EmuConstants::CURSOR_BAG_BEGIN; CursorBagSlot <= EmuConstants::CURSOR_BAG_END; CursorBagSlot++) {
|
||||||
if (m_inv.GetItem(CursorBagSlot)) {
|
if (m_inv.GetItem(CursorBagSlot)) {
|
||||||
if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
|
if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID &&
|
||||||
m_inv.GetItem(CursorBagSlot)->GetCharges() >= 1) { // ditto
|
m_inv.GetItem(CursorBagSlot)->GetCharges() >= 1) { // ditto
|
||||||
slot = CursorBagSlot;
|
slot = CursorBagSlot;
|
||||||
break;
|
break;
|
||||||
@ -2590,14 +2668,14 @@ void Client::SetBandolier(const EQApplicationPacket *app) {
|
|||||||
// Now we move the required weapons into the character weapon slots, and return any items we are replacing
|
// Now we move the required weapons into the character weapon slots, and return any items we are replacing
|
||||||
// back to inventory.
|
// back to inventory.
|
||||||
//
|
//
|
||||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||||
|
|
||||||
// Find the inventory slot corresponding to this bandolier slot
|
// Find the inventory slot corresponding to this bandolier slot
|
||||||
|
|
||||||
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot);
|
||||||
|
|
||||||
// if there is an item in this Bandolier slot ?
|
// if there is an item in this Bandolier slot ?
|
||||||
if(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id) {
|
if(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID) {
|
||||||
// if the player has this item in their inventory, and it is not already where it needs to be
|
// if the player has this item in their inventory, and it is not already where it needs to be
|
||||||
if(BandolierItems[BandolierSlot]) {
|
if(BandolierItems[BandolierSlot]) {
|
||||||
// Pull the item that we are going to replace
|
// Pull the item that we are going to replace
|
||||||
@ -2826,9 +2904,9 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
int limbo = 0;
|
int limbo = 0;
|
||||||
for (auto cursor_itr = m_inv.cursor_begin(); cursor_itr != m_inv.cursor_end(); ++cursor_itr, ++limbo) {
|
for (auto cursor_itr = m_inv.cursor_cbegin(); cursor_itr != m_inv.cursor_cend(); ++cursor_itr, ++limbo) {
|
||||||
// m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above
|
// m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above
|
||||||
if (cursor_itr == m_inv.cursor_begin())
|
if (cursor_itr == m_inv.cursor_cbegin())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
instmap[8000 + limbo] = *cursor_itr;
|
instmap[8000 + limbo] = *cursor_itr;
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
#include "../common/global_define.h"
|
#include "../common/global_define.h"
|
||||||
#include "../common/loottable.h"
|
#include "../common/loottable.h"
|
||||||
#include "../common/misc_functions.h"
|
#include "../common/misc_functions.h"
|
||||||
|
#include "../common/data_verification.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "entity.h"
|
#include "entity.h"
|
||||||
@ -35,7 +36,7 @@
|
|||||||
|
|
||||||
// Queries the loottable: adds item & coin to the npc
|
// Queries the loottable: adds item & coin to the npc
|
||||||
void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
|
void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
|
||||||
const LootTable_Struct* lts = 0;
|
const LootTable_Struct* lts = nullptr;
|
||||||
*copper = 0;
|
*copper = 0;
|
||||||
*silver = 0;
|
*silver = 0;
|
||||||
*gold = 0;
|
*gold = 0;
|
||||||
@ -45,44 +46,39 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
|||||||
if (!lts)
|
if (!lts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// do coin
|
uint32 min_cash = lts->mincash;
|
||||||
if (lts->mincash > lts->maxcash) {
|
uint32 max_cash = lts->maxcash;
|
||||||
std::cerr << "Error in loottable #" << loottable_id << ": mincash > maxcash" << std::endl;
|
if(min_cash > max_cash) {
|
||||||
|
uint32 t = min_cash;
|
||||||
|
min_cash = max_cash;
|
||||||
|
max_cash = t;
|
||||||
}
|
}
|
||||||
else if (lts->maxcash != 0) {
|
|
||||||
uint32 cash = 0;
|
uint32 cash = 0;
|
||||||
if (lts->mincash == lts->maxcash)
|
if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) {
|
||||||
cash = lts->mincash;
|
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash);
|
||||||
else
|
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0);
|
||||||
cash = zone->random.Int(lts->mincash, lts->maxcash);
|
|
||||||
if (cash != 0) {
|
if(avg_cash_roll < upper_chance) {
|
||||||
if (lts->avgcoin != 0) {
|
cash = zone->random.Int(lts->avgcoin, max_cash);
|
||||||
//this is some crazy ass stuff... and makes very little sense... dont use it, k?
|
} else {
|
||||||
uint32 mincoin = (uint32) (lts->avgcoin * 0.75 + 1);
|
cash = zone->random.Int(min_cash, lts->avgcoin);
|
||||||
uint32 maxcoin = (uint32) (lts->avgcoin * 1.25 + 1);
|
|
||||||
*copper = zone->random.Int(mincoin, maxcoin);
|
|
||||||
*silver = zone->random.Int(mincoin, maxcoin);
|
|
||||||
*gold = zone->random.Int(mincoin, maxcoin);
|
|
||||||
if(*copper > cash) { *copper = cash; }
|
|
||||||
cash -= *copper;
|
|
||||||
if(*silver>(cash/10)) { *silver = (cash/10); }
|
|
||||||
cash -= *silver*10;
|
|
||||||
if(*gold > (cash/100)) { *gold = (cash/100); }
|
|
||||||
cash -= *gold*100;
|
|
||||||
}
|
|
||||||
if (cash < 0) {
|
|
||||||
cash = 0;
|
|
||||||
}
|
|
||||||
*plat = cash / 1000;
|
|
||||||
cash -= *plat * 1000;
|
|
||||||
uint32 gold2 = cash / 100;
|
|
||||||
cash -= gold2 * 100;
|
|
||||||
uint32 silver2 = cash / 10;
|
|
||||||
cash -= silver2 * 10;
|
|
||||||
*gold += gold2;
|
|
||||||
*silver += silver2;
|
|
||||||
*copper += cash;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cash = zone->random.Int(min_cash, max_cash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cash != 0) {
|
||||||
|
*plat = cash / 1000;
|
||||||
|
cash -= *plat * 1000;
|
||||||
|
|
||||||
|
*gold = cash / 100;
|
||||||
|
cash -= *gold * 100;
|
||||||
|
|
||||||
|
*silver = cash / 10;
|
||||||
|
cash -= *silver * 10;
|
||||||
|
|
||||||
|
*copper = cash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do items
|
// Do items
|
||||||
@ -97,11 +93,11 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite
|
|||||||
|
|
||||||
float drop_chance = 0.0f;
|
float drop_chance = 0.0f;
|
||||||
if(ltchance > 0.0 && ltchance < 100.0) {
|
if(ltchance > 0.0 && ltchance < 100.0) {
|
||||||
drop_chance = zone->random.Real(0.0, 100.0);
|
drop_chance = (float)zone->random.Real(0.0, 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance < ltchance)) {
|
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance <= ltchance)) {
|
||||||
AddLootDropToNPC(npc,lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop);
|
AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,68 +110,81 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml
|
|||||||
if (!lds) {
|
if (!lds) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(lds->NumEntries == 0) //nothing possible to add
|
|
||||||
|
if(lds->NumEntries == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Too long a list needs to be limited.
|
if(droplimit == 0 && mindrop == 0) {
|
||||||
if(lds->NumEntries > 99 && droplimit < 1)
|
for(uint32 i = 0; i < lds->NumEntries; ++i) {
|
||||||
droplimit = lds->NumEntries/100;
|
int charges = lds->Entries[i].multiplier;
|
||||||
|
for(int j = 0; j < charges; ++j) {
|
||||||
uint8 limit = 0;
|
if(zone->random.Real(0.0, 100.0) <= lds->Entries[i].chance) {
|
||||||
// Start at a random point in itemlist.
|
const Item_Struct* dbitem = GetItem(lds->Entries[i].item_id);
|
||||||
uint32 item = zone->random.Int(0, lds->NumEntries-1);
|
npc->AddLootDrop(dbitem, itemlist, lds->Entries[i].item_charges, lds->Entries[i].minlevel,
|
||||||
// Main loop.
|
lds->Entries[i].maxlevel, lds->Entries[i].equip_item > 0 ? true : false, false);
|
||||||
for (uint32 i=0; i<lds->NumEntries;)
|
}
|
||||||
{
|
|
||||||
//Force the itemlist back to beginning.
|
|
||||||
if (item > (lds->NumEntries-1))
|
|
||||||
item = 0;
|
|
||||||
|
|
||||||
uint8 charges = lds->Entries[item].multiplier;
|
|
||||||
uint8 pickedcharges = 0;
|
|
||||||
// Loop to check multipliers.
|
|
||||||
for (uint32 x=1; x<=charges; x++)
|
|
||||||
{
|
|
||||||
// Actual roll.
|
|
||||||
float thischance = 0.0;
|
|
||||||
thischance = lds->Entries[item].chance;
|
|
||||||
|
|
||||||
float drop_chance = 0.0;
|
|
||||||
if(thischance != 100.0)
|
|
||||||
drop_chance = zone->random.Real(0.0, 100.0);
|
|
||||||
|
|
||||||
#if EQDEBUG>=11
|
|
||||||
Log.Out(Logs::General, Logs::None, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance);
|
|
||||||
#endif
|
|
||||||
if (thischance == 100.0 || drop_chance < thischance)
|
|
||||||
{
|
|
||||||
uint32 itemid = lds->Entries[item].item_id;
|
|
||||||
|
|
||||||
const Item_Struct* dbitem = GetItem(itemid);
|
|
||||||
npc->AddLootDrop(dbitem, itemlist, lds->Entries[item].item_charges, lds->Entries[item].minlevel, lds->Entries[item].maxlevel, lds->Entries[item].equip_item, false);
|
|
||||||
pickedcharges++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Items with multipliers only count as 1 towards the limit.
|
return;
|
||||||
if(pickedcharges > 0)
|
}
|
||||||
limit++;
|
|
||||||
|
|
||||||
// If true, limit reached.
|
if(lds->NumEntries > 100 && droplimit == 0) {
|
||||||
if(limit >= droplimit && droplimit > 0)
|
droplimit = 10;
|
||||||
break;
|
}
|
||||||
|
|
||||||
item++;
|
if(droplimit < mindrop) {
|
||||||
i++;
|
droplimit = mindrop;
|
||||||
|
}
|
||||||
|
|
||||||
// We didn't reach our minimium, run loop again.
|
float roll_t = 0.0f;
|
||||||
if(i == lds->NumEntries){
|
bool active_item_list = false;
|
||||||
if(limit < mindrop){
|
for(uint32 i = 0; i < lds->NumEntries; ++i) {
|
||||||
i = 0;
|
const Item_Struct* db_item = GetItem(lds->Entries[i].item_id);
|
||||||
|
if(db_item) {
|
||||||
|
roll_t += lds->Entries[i].chance;
|
||||||
|
active_item_list = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roll_t = EQEmu::ClampLower(roll_t, 100.0f);
|
||||||
|
|
||||||
|
if(!active_item_list) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mindrop = EQEmu::ClampLower(mindrop, (uint8)1);
|
||||||
|
int item_count = zone->random.Int(mindrop, droplimit);
|
||||||
|
for(int i = 0; i < item_count; ++i) {
|
||||||
|
float roll = (float)zone->random.Real(0.0, roll_t);
|
||||||
|
for(uint32 j = 0; j < lds->NumEntries; ++j) {
|
||||||
|
const Item_Struct* db_item = GetItem(lds->Entries[j].item_id);
|
||||||
|
if(db_item) {
|
||||||
|
if(roll < lds->Entries[j].chance) {
|
||||||
|
npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel,
|
||||||
|
lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false);
|
||||||
|
|
||||||
|
int charges = (int)lds->Entries[i].multiplier;
|
||||||
|
charges = EQEmu::ClampLower(charges, 1);
|
||||||
|
|
||||||
|
for(int k = 1; k < charges; ++k) {
|
||||||
|
float c_roll = (float)zone->random.Real(0.0, 100.0);
|
||||||
|
if(c_roll <= lds->Entries[i].chance) {
|
||||||
|
npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel,
|
||||||
|
lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j = lds->NumEntries;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
roll -= lds->Entries[j].chance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // We either ran out of items or reached our limit.
|
} // We either ran out of items or reached our limit.
|
||||||
|
|
||||||
npc->UpdateEquipLightValue();
|
npc->UpdateEquipmentLight();
|
||||||
// no wearchange associated with this function..so, this should not be needed
|
// no wearchange associated with this function..so, this should not be needed
|
||||||
//if (npc->UpdateActiveLightValue())
|
//if (npc->UpdateActiveLightValue())
|
||||||
// npc->SendAppearancePacket(AT_Light, npc->GetActiveLightValue());
|
// npc->SendAppearancePacket(AT_Light, npc->GetActiveLightValue());
|
||||||
@ -215,6 +224,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
|
|||||||
item->attuned = 0;
|
item->attuned = 0;
|
||||||
item->min_level = minlevel;
|
item->min_level = minlevel;
|
||||||
item->max_level = maxlevel;
|
item->max_level = maxlevel;
|
||||||
|
|
||||||
if (equipit) {
|
if (equipit) {
|
||||||
uint8 eslot = 0xFF;
|
uint8 eslot = 0xFF;
|
||||||
char newid[20];
|
char newid[20];
|
||||||
@ -365,9 +375,9 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue())
|
if (UpdateActiveLight())
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::AddItem(const Item_Struct* item, uint16 charges, bool equipitem) {
|
void NPC::AddItem(const Item_Struct* item, uint16 charges, bool equipitem) {
|
||||||
|
|||||||
@ -449,11 +449,11 @@ void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) {
|
|||||||
newbon->DSMitigation += item->DSMitigation;
|
newbon->DSMitigation += item->DSMitigation;
|
||||||
}
|
}
|
||||||
if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects
|
if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects
|
||||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true);
|
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||||
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true);
|
ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(item->BardType)
|
switch(item->BardType)
|
||||||
@ -1201,8 +1201,8 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
|
|||||||
ns->spawn.NPC = 1; // 0=player,1=npc,2=pc corpse,3=npc corpse
|
ns->spawn.NPC = 1; // 0=player,1=npc,2=pc corpse,3=npc corpse
|
||||||
ns->spawn.IsMercenary = 1;
|
ns->spawn.IsMercenary = 1;
|
||||||
|
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
ns->spawn.light = active_light;
|
ns->spawn.light = m_Light.Type.Active;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Wear Slots are not setup for Mercs yet
|
// Wear Slots are not setup for Mercs yet
|
||||||
@ -5028,34 +5028,48 @@ void Merc::UpdateMercAppearance() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UpdateActiveLightValue())
|
if (UpdateActiveLight())
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Merc::UpdateEquipLightValue()
|
void Merc::UpdateEquipmentLight()
|
||||||
{
|
{
|
||||||
equip_light = NOT_USED;
|
m_Light.Type.Equipment = 0;
|
||||||
|
m_Light.Level.Equipment = 0;
|
||||||
|
|
||||||
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
|
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
|
||||||
if (equipment[index] == NOT_USED) { continue; }
|
if (index == MainAmmo) { continue; }
|
||||||
|
|
||||||
auto item = database.GetItem(equipment[index]);
|
auto item = database.GetItem(equipment[index]);
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
if (item->Light & 0xF0) { continue; }
|
|
||||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment)) {
|
||||||
|
m_Light.Type.Equipment = item->Light;
|
||||||
|
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8 general_light_type = 0;
|
||||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||||
auto item = database.GetItem((*iter)->item_id);
|
auto item = database.GetItem((*iter)->item_id);
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
|
||||||
if (item->Light & 0xF0) { continue; }
|
if (item->ItemClass != ItemClassCommon) { continue; }
|
||||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||||
|
|
||||||
|
if (m_Light.TypeToLevel(item->Light))
|
||||||
|
general_light_type = item->Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment))
|
||||||
|
m_Light.Type.Equipment = general_light_type;
|
||||||
|
|
||||||
|
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Merc::AddItem(uint8 slot, uint32 item_id) {
|
void Merc::AddItem(uint8 slot, uint32 item_id) {
|
||||||
equipment[slot] = item_id;
|
equipment[slot] = item_id;
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Merc::Spawn(Client *owner) {
|
bool Merc::Spawn(Client *owner) {
|
||||||
|
|||||||
@ -139,7 +139,7 @@ public:
|
|||||||
void UpdateMercInfo(Client *c);
|
void UpdateMercInfo(Client *c);
|
||||||
void UpdateMercStats(Client *c, bool setmax = false);
|
void UpdateMercStats(Client *c, bool setmax = false);
|
||||||
void UpdateMercAppearance();
|
void UpdateMercAppearance();
|
||||||
virtual void UpdateEquipLightValue();
|
virtual void UpdateEquipmentLight();
|
||||||
void AddItem(uint8 slot, uint32 item_id);
|
void AddItem(uint8 slot, uint32 item_id);
|
||||||
static const char *GetRandomName();
|
static const char *GetRandomName();
|
||||||
bool Spawn(Client *owner);
|
bool Spawn(Client *owner);
|
||||||
|
|||||||
124
zone/mob.cpp
124
zone/mob.cpp
@ -149,9 +149,13 @@ Mob::Mob(const char* in_name,
|
|||||||
if (runspeed < 0 || runspeed > 20)
|
if (runspeed < 0 || runspeed > 20)
|
||||||
runspeed = 1.25f;
|
runspeed = 1.25f;
|
||||||
|
|
||||||
active_light = innate_light = in_light;
|
m_Light.Type.Innate = in_light;
|
||||||
spell_light = equip_light = NOT_USED;
|
m_Light.Level.Innate = m_Light.TypeToLevel(m_Light.Type.Innate);
|
||||||
|
m_Light.Level.Equipment = m_Light.Type.Equipment = 0;
|
||||||
|
m_Light.Level.Spell = m_Light.Type.Spell = 0;
|
||||||
|
m_Light.Type.Active = m_Light.Type.Innate;
|
||||||
|
m_Light.Level.Active = m_Light.Level.Innate;
|
||||||
|
|
||||||
texture = in_texture;
|
texture = in_texture;
|
||||||
helmtexture = in_helmtexture;
|
helmtexture = in_helmtexture;
|
||||||
haircolor = in_haircolor;
|
haircolor = in_haircolor;
|
||||||
@ -170,6 +174,7 @@ Mob::Mob(const char* in_name,
|
|||||||
findable = false;
|
findable = false;
|
||||||
trackable = true;
|
trackable = true;
|
||||||
has_shieldequiped = false;
|
has_shieldequiped = false;
|
||||||
|
has_twohandbluntequiped = false;
|
||||||
has_numhits = false;
|
has_numhits = false;
|
||||||
has_MGB = false;
|
has_MGB = false;
|
||||||
has_ProjectIllusion = false;
|
has_ProjectIllusion = false;
|
||||||
@ -300,6 +305,7 @@ Mob::Mob(const char* in_name,
|
|||||||
focused = false;
|
focused = false;
|
||||||
_IsTempPet = false;
|
_IsTempPet = false;
|
||||||
pet_owner_client = false;
|
pet_owner_client = false;
|
||||||
|
pet_targetlock_id = 0;
|
||||||
|
|
||||||
attacked_count = 0;
|
attacked_count = 0;
|
||||||
mezzed = false;
|
mezzed = false;
|
||||||
@ -901,8 +907,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
ns->spawn.animation = 0;
|
ns->spawn.animation = 0;
|
||||||
ns->spawn.findable = findable?1:0;
|
ns->spawn.findable = findable?1:0;
|
||||||
|
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
ns->spawn.light = active_light;
|
ns->spawn.light = m_Light.Type.Active;
|
||||||
|
|
||||||
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
|
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
|
||||||
|
|
||||||
@ -959,10 +965,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
// Only Player Races Wear Armor
|
// Only Player Races Wear Armor
|
||||||
if (Mob::IsPlayerRace(race) || i > 6)
|
if (Mob::IsPlayerRace(race) || i > 6)
|
||||||
{
|
{
|
||||||
ns->spawn.equipment[i].material = GetEquipmentMaterial(i);
|
ns->spawn.equipment[i].Material = GetEquipmentMaterial(i);
|
||||||
ns->spawn.equipment[i].elitematerial = IsEliteMaterialItem(i);
|
ns->spawn.equipment[i].EliteMaterial = IsEliteMaterialItem(i);
|
||||||
ns->spawn.equipment[i].heroforgemodel = GetHerosForgeModel(i);
|
ns->spawn.equipment[i].HeroForgeModel = GetHerosForgeModel(i);
|
||||||
ns->spawn.colors[i].color = GetEquipmentColor(i);
|
ns->spawn.colors[i].Color = GetEquipmentColor(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1999,9 +2005,10 @@ void Mob::TempName(const char *newname)
|
|||||||
strn0cpy(temp_name, GetCleanName(), 64);
|
strn0cpy(temp_name, GetCleanName(), 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove Numbers before making name unique
|
||||||
|
EntityList::RemoveNumbers(temp_name);
|
||||||
// Make the new name unique and set it
|
// Make the new name unique and set it
|
||||||
strn0cpy(temp_name, entity_list.MakeNameUnique(temp_name), 64);
|
entity_list.MakeNameUnique(temp_name);
|
||||||
|
|
||||||
|
|
||||||
// Send the new name to all clients
|
// Send the new name to all clients
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MobRename, sizeof(MobRename_Struct));
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MobRename, sizeof(MobRename_Struct));
|
||||||
@ -2047,37 +2054,20 @@ void Mob::SetAppearance(EmuAppearance app, bool iIgnoreSelf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::UpdateActiveLightValue()
|
bool Mob::UpdateActiveLight()
|
||||||
{
|
{
|
||||||
/* This is old information...
|
uint8 old_light_level = m_Light.Level.Active;
|
||||||
0 - "None"
|
|
||||||
1 - "Candle"
|
|
||||||
2 - "Torch"
|
|
||||||
3 - "Tiny Glowing Skull"
|
|
||||||
4 - "Small Lantern"
|
|
||||||
5 - "Stein of Moggok"
|
|
||||||
6 - "Large Lantern"
|
|
||||||
7 - "Flameless Lantern"
|
|
||||||
8 - "Globe of Stars"
|
|
||||||
9 - "Light Globe"
|
|
||||||
10 - "Lightstone"
|
|
||||||
11 - "Greater Lightstone"
|
|
||||||
12 - "Fire Beatle Eye"
|
|
||||||
13 - "Coldlight"
|
|
||||||
14 - "Unknown"
|
|
||||||
15 - "Unknown"
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint8 old_light = (active_light & 0x0F);
|
|
||||||
active_light = (innate_light & 0x0F);
|
|
||||||
|
|
||||||
if (equip_light > active_light) { active_light = equip_light; } // limiter in property handler
|
m_Light.Type.Active = 0;
|
||||||
if (spell_light > active_light) { active_light = spell_light; } // limiter in property handler
|
m_Light.Level.Active = 0;
|
||||||
|
|
||||||
if (active_light != old_light)
|
if (m_Light.IsLevelGreater((m_Light.Type.Innate & 0x0F), m_Light.Type.Active)) { m_Light.Type.Active = m_Light.Type.Innate; }
|
||||||
return true;
|
if (m_Light.Level.Equipment > m_Light.Level.Active) { m_Light.Type.Active = m_Light.Type.Equipment; } // limiter in property handler
|
||||||
|
if (m_Light.Level.Spell > m_Light.Level.Active) { m_Light.Type.Active = m_Light.Type.Spell; } // limiter in property handler
|
||||||
|
|
||||||
return false;
|
m_Light.Level.Active = m_Light.TypeToLevel(m_Light.Type.Active);
|
||||||
|
|
||||||
|
return (m_Light.Level.Active != old_light_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::ChangeSize(float in_size = 0, bool bNoRestriction) {
|
void Mob::ChangeSize(float in_size = 0, bool bNoRestriction) {
|
||||||
@ -2577,7 +2567,7 @@ void Mob::SendWearChange(uint8 material_slot)
|
|||||||
wc->material = GetEquipmentMaterial(material_slot);
|
wc->material = GetEquipmentMaterial(material_slot);
|
||||||
wc->elite_material = IsEliteMaterialItem(material_slot);
|
wc->elite_material = IsEliteMaterialItem(material_slot);
|
||||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||||
wc->color.color = GetEquipmentColor(material_slot);
|
wc->color.Color = GetEquipmentColor(material_slot);
|
||||||
wc->wear_slot_id = material_slot;
|
wc->wear_slot_id = material_slot;
|
||||||
|
|
||||||
entity_list.QueueClients(this, outapp);
|
entity_list.QueueClients(this, outapp);
|
||||||
@ -2592,9 +2582,9 @@ void Mob::SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model, uin
|
|||||||
wc->spawn_id = this->GetID();
|
wc->spawn_id = this->GetID();
|
||||||
wc->material = texture;
|
wc->material = texture;
|
||||||
if (this->IsClient())
|
if (this->IsClient())
|
||||||
wc->color.color = GetEquipmentColor(slot);
|
wc->color.Color = GetEquipmentColor(slot);
|
||||||
else
|
else
|
||||||
wc->color.color = this->GetArmorTint(slot);
|
wc->color.Color = this->GetArmorTint(slot);
|
||||||
wc->wear_slot_id = slot;
|
wc->wear_slot_id = slot;
|
||||||
|
|
||||||
wc->unknown06 = unknown06;
|
wc->unknown06 = unknown06;
|
||||||
@ -2622,7 +2612,7 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin
|
|||||||
wc->spawn_id = this->GetID();
|
wc->spawn_id = this->GetID();
|
||||||
wc->material = GetEquipmentMaterial(material_slot);
|
wc->material = GetEquipmentMaterial(material_slot);
|
||||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||||
wc->color.color = color;
|
wc->color.Color = color;
|
||||||
wc->wear_slot_id = material_slot;
|
wc->wear_slot_id = material_slot;
|
||||||
|
|
||||||
entity_list.QueueClients(this, outapp);
|
entity_list.QueueClients(this, outapp);
|
||||||
@ -2639,7 +2629,7 @@ void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 h
|
|||||||
wc->spawn_id = this->GetID();
|
wc->spawn_id = this->GetID();
|
||||||
wc->material = texture;
|
wc->material = texture;
|
||||||
wc->hero_forge_model = hero_forge_model;
|
wc->hero_forge_model = hero_forge_model;
|
||||||
wc->color.color = color;
|
wc->color.Color = color;
|
||||||
wc->wear_slot_id = material_slot;
|
wc->wear_slot_id = material_slot;
|
||||||
|
|
||||||
entity_list.QueueClients(this, outapp);
|
entity_list.QueueClients(this, outapp);
|
||||||
@ -3578,17 +3568,14 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
|
|||||||
{
|
{
|
||||||
int skilldmg_mod = 0;
|
int skilldmg_mod = 0;
|
||||||
|
|
||||||
int16 MeleeVuln = spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability;
|
|
||||||
|
|
||||||
// All skill dmg mod + Skill specific
|
// All skill dmg mod + Skill specific
|
||||||
skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] +
|
skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] +
|
||||||
itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used];
|
itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used];
|
||||||
|
|
||||||
|
|
||||||
//Innate SetSkillDamgeTaken(skill,value)
|
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
||||||
if ((SkillDmgTaken_Mod[skill_used]) || (SkillDmgTaken_Mod[HIGHEST_SKILL+1]))
|
|
||||||
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
|
||||||
|
|
||||||
skilldmg_mod += MeleeVuln;
|
skilldmg_mod += spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability;
|
||||||
|
|
||||||
if(skilldmg_mod < -100)
|
if(skilldmg_mod < -100)
|
||||||
skilldmg_mod = -100;
|
skilldmg_mod = -100;
|
||||||
@ -4671,22 +4658,21 @@ void Mob::SetBodyType(bodyType new_body, bool overwrite_orig) {
|
|||||||
|
|
||||||
void Mob::ModSkillDmgTaken(SkillUseTypes skill_num, int value)
|
void Mob::ModSkillDmgTaken(SkillUseTypes skill_num, int value)
|
||||||
{
|
{
|
||||||
if (skill_num <= HIGHEST_SKILL)
|
if (skill_num == ALL_SKILLS)
|
||||||
SkillDmgTaken_Mod[skill_num] = value;
|
|
||||||
|
|
||||||
|
|
||||||
else if (skill_num == 255 || skill_num == -1)
|
|
||||||
SkillDmgTaken_Mod[HIGHEST_SKILL+1] = value;
|
SkillDmgTaken_Mod[HIGHEST_SKILL+1] = value;
|
||||||
|
|
||||||
|
else if (skill_num >= 0 && skill_num <= HIGHEST_SKILL)
|
||||||
|
SkillDmgTaken_Mod[skill_num] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 Mob::GetModSkillDmgTaken(const SkillUseTypes skill_num)
|
int16 Mob::GetModSkillDmgTaken(const SkillUseTypes skill_num)
|
||||||
{
|
{
|
||||||
if (skill_num <= HIGHEST_SKILL)
|
if (skill_num == ALL_SKILLS)
|
||||||
return SkillDmgTaken_Mod[skill_num];
|
|
||||||
|
|
||||||
else if (skill_num == 255 || skill_num == -1)
|
|
||||||
return SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
return SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
||||||
|
|
||||||
|
else if (skill_num >= 0 && skill_num <= HIGHEST_SKILL)
|
||||||
|
return SkillDmgTaken_Mod[skill_num];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5380,3 +5366,25 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
|
|||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mob::CanClassEquipItem(uint32 item_id)
|
||||||
|
{
|
||||||
|
const Item_Struct* itm = nullptr;
|
||||||
|
itm = database.GetItem(item_id);
|
||||||
|
|
||||||
|
if (!itm)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(itm->Classes == 65535 )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (GetClass() > 16)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int bitmask = 1;
|
||||||
|
bitmask = bitmask << (GetClass() - 1);
|
||||||
|
|
||||||
|
if(!(itm->Classes & bitmask))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
36
zone/mob.h
36
zone/mob.h
@ -194,7 +194,7 @@ public:
|
|||||||
bool IsBeneficialAllowed(Mob *target);
|
bool IsBeneficialAllowed(Mob *target);
|
||||||
virtual int GetCasterLevel(uint16 spell_id);
|
virtual int GetCasterLevel(uint16 spell_id);
|
||||||
void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0,
|
void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0,
|
||||||
bool item_bonus = false, uint32 ticsremaining = 0, int buffslot = -1,
|
uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1,
|
||||||
bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0);
|
bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0);
|
||||||
void NegateSpellsBonuses(uint16 spell_id);
|
void NegateSpellsBonuses(uint16 spell_id);
|
||||||
virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false);
|
virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false);
|
||||||
@ -308,13 +308,16 @@ public:
|
|||||||
void SetTargetable(bool on);
|
void SetTargetable(bool on);
|
||||||
bool IsTargetable() const { return m_targetable; }
|
bool IsTargetable() const { return m_targetable; }
|
||||||
bool HasShieldEquiped() const { return has_shieldequiped; }
|
bool HasShieldEquiped() const { return has_shieldequiped; }
|
||||||
inline void ShieldEquiped(bool val) { has_shieldequiped = val; }
|
inline void SetShieldEquiped(bool val) { has_shieldequiped = val; }
|
||||||
|
bool HasTwoHandBluntEquiped() const { return has_twohandbluntequiped; }
|
||||||
|
inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; }
|
||||||
virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; }
|
virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; }
|
||||||
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
||||||
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||||
virtual int32 GetHerosForgeModel(uint8 material_slot) const;
|
virtual int32 GetHerosForgeModel(uint8 material_slot) const;
|
||||||
virtual uint32 GetEquipmentColor(uint8 material_slot) const;
|
virtual uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||||
virtual uint32 IsEliteMaterialItem(uint8 material_slot) const;
|
virtual uint32 IsEliteMaterialItem(uint8 material_slot) const;
|
||||||
|
bool CanClassEquipItem(uint32 item_id);
|
||||||
bool AffectedBySpellExcludingSlot(int slot, int effect);
|
bool AffectedBySpellExcludingSlot(int slot, int effect);
|
||||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) = 0;
|
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) = 0;
|
||||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill,
|
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill,
|
||||||
@ -621,7 +624,7 @@ public:
|
|||||||
bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true);
|
bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true);
|
||||||
bool ImprovedTaunt();
|
bool ImprovedTaunt();
|
||||||
bool TryRootFadeByDamage(int buffslot, Mob* attacker);
|
bool TryRootFadeByDamage(int buffslot, Mob* attacker);
|
||||||
int16 GetSlowMitigation() const {return slow_mitigation;}
|
float GetSlowMitigation() const { return slow_mitigation; }
|
||||||
void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr);
|
void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr);
|
||||||
inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; };
|
inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; };
|
||||||
inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; };
|
inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; };
|
||||||
@ -652,14 +655,17 @@ public:
|
|||||||
bool IsDestructibleObject() { return destructibleobject; }
|
bool IsDestructibleObject() { return destructibleobject; }
|
||||||
void SetDestructibleObject(bool in) { destructibleobject = in; }
|
void SetDestructibleObject(bool in) { destructibleobject = in; }
|
||||||
|
|
||||||
inline uint8 GetInnateLightValue() { return innate_light; }
|
inline uint8 GetInnateLightType() { return m_Light.Type.Innate; }
|
||||||
inline uint8 GetEquipLightValue() { return equip_light; }
|
inline uint8 GetEquipmentLightType() { return m_Light.Type.Equipment; }
|
||||||
inline uint8 GetSpellLightValue() { return spell_light; }
|
inline uint8 GetSpellLightType() { return m_Light.Type.Spell; }
|
||||||
virtual void UpdateEquipLightValue() { equip_light = NOT_USED; }
|
|
||||||
inline void SetSpellLightValue(uint8 light_value) { spell_light = (light_value & 0x0F); }
|
|
||||||
|
|
||||||
inline uint8 GetActiveLightValue() { return active_light; }
|
virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = 0; m_Light.Level.Equipment = 0; }
|
||||||
bool UpdateActiveLightValue(); // returns true if change, false if no change
|
inline void SetSpellLightType(uint8 lightType) { m_Light.Type.Spell = (lightType & 0x0F); m_Light.Level.Spell = m_Light.TypeToLevel(m_Light.Type.Spell); }
|
||||||
|
|
||||||
|
inline uint8 GetActiveLightType() { return m_Light.Type.Active; }
|
||||||
|
bool UpdateActiveLight(); // returns true if change, false if no change
|
||||||
|
|
||||||
|
LightProfile_Struct* GetLightProfile() { return &m_Light; }
|
||||||
|
|
||||||
Mob* GetPet();
|
Mob* GetPet();
|
||||||
void SetPet(Mob* newpet);
|
void SetPet(Mob* newpet);
|
||||||
@ -675,6 +681,9 @@ public:
|
|||||||
bool IsFamiliar() const { return(typeofpet == petFamiliar); }
|
bool IsFamiliar() const { return(typeofpet == petFamiliar); }
|
||||||
bool IsAnimation() const { return(typeofpet == petAnimation); }
|
bool IsAnimation() const { return(typeofpet == petAnimation); }
|
||||||
bool IsCharmed() const { return(typeofpet == petCharmed); }
|
bool IsCharmed() const { return(typeofpet == petCharmed); }
|
||||||
|
bool IsTargetLockPet() const { return(typeofpet == petTargetLock); }
|
||||||
|
inline uint32 GetPetTargetLockID() { return pet_targetlock_id; };
|
||||||
|
inline void SetPetTargetLockID(uint32 value) { pet_targetlock_id = value; };
|
||||||
void SetOwnerID(uint16 NewOwnerID);
|
void SetOwnerID(uint16 NewOwnerID);
|
||||||
inline uint16 GetOwnerID() const { return ownerid; }
|
inline uint16 GetOwnerID() const { return ownerid; }
|
||||||
inline virtual bool HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); }
|
inline virtual bool HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); }
|
||||||
@ -1068,10 +1077,7 @@ protected:
|
|||||||
|
|
||||||
glm::vec4 m_Delta;
|
glm::vec4 m_Delta;
|
||||||
|
|
||||||
uint8 innate_light; // defined by db field `npc_types`.`light` - where appropriate
|
LightProfile_Struct m_Light;
|
||||||
uint8 equip_light; // highest value of equipped/carried light-producing items
|
|
||||||
uint8 spell_light; // set value of any light-producing spell (can be modded to mimic equip_light behavior)
|
|
||||||
uint8 active_light; // highest value of all light sources
|
|
||||||
|
|
||||||
float fixedZ;
|
float fixedZ;
|
||||||
EmuAppearance _appearance;
|
EmuAppearance _appearance;
|
||||||
@ -1146,6 +1152,7 @@ protected:
|
|||||||
uint16 viral_spells[MAX_SPELL_TRIGGER*2]; // Stores the spell ids of the viruses on target and caster ids
|
uint16 viral_spells[MAX_SPELL_TRIGGER*2]; // Stores the spell ids of the viruses on target and caster ids
|
||||||
bool offhand;
|
bool offhand;
|
||||||
bool has_shieldequiped;
|
bool has_shieldequiped;
|
||||||
|
bool has_twohandbluntequiped;
|
||||||
bool has_numhits;
|
bool has_numhits;
|
||||||
bool has_MGB;
|
bool has_MGB;
|
||||||
bool has_ProjectIllusion;
|
bool has_ProjectIllusion;
|
||||||
@ -1244,6 +1251,7 @@ protected:
|
|||||||
bool _IsTempPet;
|
bool _IsTempPet;
|
||||||
int16 count_TempPet;
|
int16 count_TempPet;
|
||||||
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
||||||
|
uint32 pet_targetlock_id;
|
||||||
|
|
||||||
EGNode *_egnode; //the EG node we are in
|
EGNode *_egnode; //the EG node we are in
|
||||||
glm::vec3 m_TargetLocation;
|
glm::vec3 m_TargetLocation;
|
||||||
|
|||||||
@ -2579,7 +2579,7 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
|||||||
|
|
||||||
for(int i=0; i < AIspellsEffects.size(); i++)
|
for(int i=0; i < AIspellsEffects.size(); i++)
|
||||||
{
|
{
|
||||||
ApplySpellsBonuses(0, 0, newbon, 0, false, 0,-1,
|
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1,
|
||||||
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
90
zone/npc.cpp
90
zone/npc.cpp
@ -352,9 +352,6 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
|||||||
InitializeBuffSlots();
|
InitializeBuffSlots();
|
||||||
CalcBonuses();
|
CalcBonuses();
|
||||||
raid_target = d->raid_target;
|
raid_target = d->raid_target;
|
||||||
|
|
||||||
active_light = d->light;
|
|
||||||
spell_light = equip_light = NOT_USED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NPC::~NPC()
|
NPC::~NPC()
|
||||||
@ -439,15 +436,15 @@ void NPC::RemoveItem(uint32 item_id, uint16 quantity, uint16 slot) {
|
|||||||
ServerLootItem_Struct* item = *cur;
|
ServerLootItem_Struct* item = *cur;
|
||||||
if (item->item_id == item_id && slot <= 0 && quantity <= 0) {
|
if (item->item_id == item_id && slot <= 0 && quantity <= 0) {
|
||||||
itemlist.erase(cur);
|
itemlist.erase(cur);
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue()) { SendAppearancePacket(AT_Light, GetActiveLightValue()); }
|
if (UpdateActiveLight()) { SendAppearancePacket(AT_Light, GetActiveLightType()); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (item->item_id == item_id && item->equip_slot == slot && quantity >= 1) {
|
else if (item->item_id == item_id && item->equip_slot == slot && quantity >= 1) {
|
||||||
if (item->charges <= quantity) {
|
if (item->charges <= quantity) {
|
||||||
itemlist.erase(cur);
|
itemlist.erase(cur);
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue()) { SendAppearancePacket(AT_Light, GetActiveLightValue()); }
|
if (UpdateActiveLight()) { SendAppearancePacket(AT_Light, GetActiveLightType()); }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
item->charges -= quantity;
|
item->charges -= quantity;
|
||||||
@ -483,9 +480,9 @@ void NPC::CheckMinMaxLevel(Mob *them)
|
|||||||
++cur;
|
++cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue())
|
if (UpdateActiveLight())
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::ClearItemList() {
|
void NPC::ClearItemList() {
|
||||||
@ -498,9 +495,9 @@ void NPC::ClearItemList() {
|
|||||||
}
|
}
|
||||||
itemlist.clear();
|
itemlist.clear();
|
||||||
|
|
||||||
UpdateEquipLightValue();
|
UpdateEquipmentLight();
|
||||||
if (UpdateActiveLightValue())
|
if (UpdateActiveLight())
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightValue());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::QueryLoot(Client* to)
|
void NPC::QueryLoot(Client* to)
|
||||||
@ -718,25 +715,39 @@ uint32 NPC::CountLoot() {
|
|||||||
return(itemlist.size());
|
return(itemlist.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::UpdateEquipLightValue()
|
void NPC::UpdateEquipmentLight()
|
||||||
{
|
{
|
||||||
equip_light = NOT_USED;
|
m_Light.Type.Equipment = 0;
|
||||||
|
m_Light.Level.Equipment = 0;
|
||||||
|
|
||||||
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
|
for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) {
|
||||||
if (equipment[index] == NOT_USED) { continue; }
|
if (index == MainAmmo) { continue; }
|
||||||
|
|
||||||
auto item = database.GetItem(equipment[index]);
|
auto item = database.GetItem(equipment[index]);
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
if (item->Light & 0xF0) { continue; }
|
|
||||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment)) {
|
||||||
|
m_Light.Type.Equipment = item->Light;
|
||||||
|
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8 general_light_type = 0;
|
||||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||||
auto item = database.GetItem((*iter)->item_id);
|
auto item = database.GetItem((*iter)->item_id);
|
||||||
if (item == nullptr) { continue; }
|
if (item == nullptr) { continue; }
|
||||||
if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; }
|
|
||||||
if (item->Light & 0xF0) { continue; }
|
if (item->ItemClass != ItemClassCommon) { continue; }
|
||||||
if (item->Light > equip_light) { equip_light = item->Light; }
|
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||||
|
|
||||||
|
if (m_Light.TypeToLevel(item->Light))
|
||||||
|
general_light_type = item->Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment))
|
||||||
|
m_Light.Type.Equipment = general_light_type;
|
||||||
|
|
||||||
|
m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::Depop(bool StartSpawnTimer) {
|
void NPC::Depop(bool StartSpawnTimer) {
|
||||||
@ -1810,8 +1821,8 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
Mob::FillSpawnStruct(ns, ForWho);
|
Mob::FillSpawnStruct(ns, ForWho);
|
||||||
PetOnSpawn(ns);
|
PetOnSpawn(ns);
|
||||||
ns->spawn.is_npc = 1;
|
ns->spawn.is_npc = 1;
|
||||||
UpdateActiveLightValue();
|
UpdateActiveLight();
|
||||||
ns->spawn.light = GetActiveLightValue();
|
ns->spawn.light = GetActiveLightType();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::PetOnSpawn(NewSpawn_Struct* ns)
|
void NPC::PetOnSpawn(NewSpawn_Struct* ns)
|
||||||
@ -2394,6 +2405,29 @@ void NPC::DoQuestPause(Mob *other) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NPC::ChangeLastName(const char* in_lastname)
|
||||||
|
{
|
||||||
|
|
||||||
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct));
|
||||||
|
GMLastName_Struct* gmn = (GMLastName_Struct*)outapp->pBuffer;
|
||||||
|
strcpy(gmn->name, GetName());
|
||||||
|
strcpy(gmn->gmname, GetName());
|
||||||
|
strcpy(gmn->lastname, in_lastname);
|
||||||
|
gmn->unknown[0]=1;
|
||||||
|
gmn->unknown[1]=1;
|
||||||
|
gmn->unknown[2]=1;
|
||||||
|
gmn->unknown[3]=1;
|
||||||
|
entity_list.QueueClients(this, outapp, false);
|
||||||
|
safe_delete(outapp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NPC::ClearLastName()
|
||||||
|
{
|
||||||
|
std::string WT;
|
||||||
|
WT = '\0'; //Clear Last Name
|
||||||
|
ChangeLastName( WT.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void NPC::DepopSwarmPets()
|
void NPC::DepopSwarmPets()
|
||||||
{
|
{
|
||||||
if (GetSwarmInfo()) {
|
if (GetSwarmInfo()) {
|
||||||
@ -2419,4 +2453,14 @@ void NPC::DepopSwarmPets()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){
|
||||||
|
|
||||||
|
Mob *targMob = entity_list.GetMob(GetPetTargetLockID());
|
||||||
|
|
||||||
|
if(!targMob || (targMob && targMob->IsCorpse())){
|
||||||
|
Kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -187,7 +187,7 @@ public:
|
|||||||
void QueryLoot(Client* to);
|
void QueryLoot(Client* to);
|
||||||
uint32 CountLoot();
|
uint32 CountLoot();
|
||||||
inline uint32 GetLoottableID() const { return loottable_id; }
|
inline uint32 GetLoottableID() const { return loottable_id; }
|
||||||
virtual void UpdateEquipLightValue();
|
virtual void UpdateEquipmentLight();
|
||||||
|
|
||||||
inline uint32 GetCopper() const { return copper; }
|
inline uint32 GetCopper() const { return copper; }
|
||||||
inline uint32 GetSilver() const { return silver; }
|
inline uint32 GetSilver() const { return silver; }
|
||||||
@ -253,7 +253,7 @@ public:
|
|||||||
|
|
||||||
uint32 GetMaxDMG() const {return max_dmg;}
|
uint32 GetMaxDMG() const {return max_dmg;}
|
||||||
uint32 GetMinDMG() const {return min_dmg;}
|
uint32 GetMinDMG() const {return min_dmg;}
|
||||||
int16 GetSlowMitigation() const {return slow_mitigation;}
|
float GetSlowMitigation() const { return slow_mitigation; }
|
||||||
float GetAttackSpeed() const {return attack_speed;}
|
float GetAttackSpeed() const {return attack_speed;}
|
||||||
uint8 GetAttackDelay() const {return attack_delay;}
|
uint8 GetAttackDelay() const {return attack_delay;}
|
||||||
bool IsAnimal() const { return(bodytype == BT_Animal); }
|
bool IsAnimal() const { return(bodytype == BT_Animal); }
|
||||||
@ -361,6 +361,9 @@ public:
|
|||||||
const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; }
|
const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; }
|
||||||
const char* GetRawNPCTypeName() const { return NPCTypedata->name; }
|
const char* GetRawNPCTypeName() const { return NPCTypedata->name; }
|
||||||
|
|
||||||
|
void ChangeLastName(const char* in_lastname);
|
||||||
|
void ClearLastName();
|
||||||
|
|
||||||
bool GetDepop() { return p_depop; }
|
bool GetDepop() { return p_depop; }
|
||||||
|
|
||||||
void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots
|
void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots
|
||||||
|
|||||||
@ -342,8 +342,8 @@ XS(XS_Group_GetLeaderName)
|
|||||||
if (items != 1)
|
if (items != 1)
|
||||||
Perl_croak(aTHX_ "Usage: Group::GetLeaderName(THIS)");
|
Perl_croak(aTHX_ "Usage: Group::GetLeaderName(THIS)");
|
||||||
{
|
{
|
||||||
Group * THIS;
|
Group * THIS;
|
||||||
char * RETVAL;
|
const char * RETVAL;
|
||||||
dXSTARG;
|
dXSTARG;
|
||||||
|
|
||||||
if (sv_derived_from(ST(0), "Group")) {
|
if (sv_derived_from(ST(0), "Group")) {
|
||||||
|
|||||||
@ -7783,7 +7783,7 @@ XS(XS_Mob_GetModSkillDmgTaken)
|
|||||||
Perl_croak(aTHX_ "Usage: Mob::GetModSkillDmgTaken(THIS, skill_num)");
|
Perl_croak(aTHX_ "Usage: Mob::GetModSkillDmgTaken(THIS, skill_num)");
|
||||||
{
|
{
|
||||||
Mob * THIS;
|
Mob * THIS;
|
||||||
uint32 RETVAL;
|
int16 RETVAL;
|
||||||
dXSTARG;
|
dXSTARG;
|
||||||
SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1));
|
SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1));
|
||||||
|
|
||||||
@ -7797,7 +7797,7 @@ XS(XS_Mob_GetModSkillDmgTaken)
|
|||||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
RETVAL = THIS->GetModSkillDmgTaken(skill_num);
|
RETVAL = THIS->GetModSkillDmgTaken(skill_num);
|
||||||
XSprePUSH; PUSHu((UV)RETVAL);
|
XSprePUSH; PUSHi((IV)RETVAL);
|
||||||
}
|
}
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
}
|
}
|
||||||
@ -8367,6 +8367,33 @@ XS(XS_Mob_ProcessSpecialAbilities)
|
|||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS_Mob_CanClassEquipItem); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_Mob_CanClassEquipItem)
|
||||||
|
{
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: Mob::CanClassEquipItem(THIS, item_id)");
|
||||||
|
{
|
||||||
|
Mob * THIS;
|
||||||
|
bool RETVAL;
|
||||||
|
uint32 item_id = (uint32)SvUV(ST(1));
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "Mob")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(Mob *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||||
|
if(THIS == nullptr)
|
||||||
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
RETVAL = THIS->CanClassEquipItem(item_id);
|
||||||
|
ST(0) = boolSV(RETVAL);
|
||||||
|
sv_2mortal(ST(0));
|
||||||
|
}
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
#endif
|
#endif
|
||||||
@ -8675,6 +8702,7 @@ XS(boot_Mob)
|
|||||||
newXSproto(strcpy(buf, "SetSpecialAbilityParam"), XS_Mob_SetSpecialAbilityParam, file, "$$$$");
|
newXSproto(strcpy(buf, "SetSpecialAbilityParam"), XS_Mob_SetSpecialAbilityParam, file, "$$$$");
|
||||||
newXSproto(strcpy(buf, "ClearSpecialAbilities"), XS_Mob_ClearSpecialAbilities, file, "$");
|
newXSproto(strcpy(buf, "ClearSpecialAbilities"), XS_Mob_ClearSpecialAbilities, file, "$");
|
||||||
newXSproto(strcpy(buf, "ProcessSpecialAbilities"), XS_Mob_ProcessSpecialAbilities, file, "$$");
|
newXSproto(strcpy(buf, "ProcessSpecialAbilities"), XS_Mob_ProcessSpecialAbilities, file, "$$");
|
||||||
|
newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$");
|
||||||
XSRETURN_YES;
|
XSRETURN_YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -795,6 +795,42 @@ XS(XS_NPC_IsOnHatelist)
|
|||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_RemoveFromHateList); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_NPC_RemoveFromHateList)
|
||||||
|
{
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: NPC::RemoveFromHateList(THIS, ent)");
|
||||||
|
{
|
||||||
|
NPC * THIS;
|
||||||
|
Mob* ent;
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(NPC *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||||
|
if(THIS == nullptr)
|
||||||
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(1), "Mob")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||||
|
ent = INT2PTR(Mob *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "ent is not of type Mob");
|
||||||
|
if(ent == nullptr)
|
||||||
|
Perl_croak(aTHX_ "ent is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
THIS->RemoveFromHateList(ent);
|
||||||
|
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
XS(XS_NPC_SetNPCFactionID); /* prototype to pass -Wmissing-prototypes */
|
XS(XS_NPC_SetNPCFactionID); /* prototype to pass -Wmissing-prototypes */
|
||||||
XS(XS_NPC_SetNPCFactionID)
|
XS(XS_NPC_SetNPCFactionID)
|
||||||
{
|
{
|
||||||
@ -2076,7 +2112,7 @@ XS(XS_NPC_GetSlowMitigation)
|
|||||||
Perl_croak(aTHX_ "Usage: NPC::GetSlowMitigation(THIS)");
|
Perl_croak(aTHX_ "Usage: NPC::GetSlowMitigation(THIS)");
|
||||||
{
|
{
|
||||||
NPC * THIS;
|
NPC * THIS;
|
||||||
int16 RETVAL;
|
float RETVAL;
|
||||||
dXSTARG;
|
dXSTARG;
|
||||||
|
|
||||||
if (sv_derived_from(ST(0), "NPC")) {
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
@ -2089,7 +2125,7 @@ XS(XS_NPC_GetSlowMitigation)
|
|||||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
RETVAL = THIS->GetSlowMitigation();
|
RETVAL = THIS->GetSlowMitigation();
|
||||||
XSprePUSH; PUSHn((UV)RETVAL);
|
XSprePUSH; PUSHn((double)RETVAL);
|
||||||
}
|
}
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
}
|
}
|
||||||
@ -2343,7 +2379,7 @@ XS(XS_NPC_AddRangedProc) {
|
|||||||
if(THIS == NULL)
|
if(THIS == NULL)
|
||||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||||
|
|
||||||
THIS->AddDefensiveProc(spell_id,chance);
|
THIS->AddRangedProc(spell_id,chance);
|
||||||
}
|
}
|
||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
@ -2368,7 +2404,128 @@ XS(XS_NPC_AddDefensiveProc) {
|
|||||||
if(THIS == NULL)
|
if(THIS == NULL)
|
||||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||||
|
|
||||||
THIS->AddProcToWeapon(spell_id, true, chance);
|
THIS->AddDefensiveProc(spell_id,chance);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_RemoveMeleeProc);
|
||||||
|
XS(XS_NPC_RemoveMeleeProc) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: NPC::RemoveMeleeProc(THIS,spellid)");
|
||||||
|
{
|
||||||
|
NPC * THIS;
|
||||||
|
int spell_id = (int)SvIV(ST(1));
|
||||||
|
dXSTARG;
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(NPC *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||||
|
if(THIS == NULL)
|
||||||
|
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||||
|
|
||||||
|
THIS->RemoveProcFromWeapon(spell_id, false);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_RemoveRangedProc);
|
||||||
|
XS(XS_NPC_RemoveRangedProc) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: NPC::RemoveRangedProc(THIS,spellid)");
|
||||||
|
{
|
||||||
|
NPC * THIS;
|
||||||
|
int spell_id = (int)SvIV(ST(1));
|
||||||
|
dXSTARG;
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(NPC *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||||
|
if(THIS == NULL)
|
||||||
|
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||||
|
|
||||||
|
THIS->RemoveRangedProc(spell_id, false);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_RemoveDefensiveProc);
|
||||||
|
XS(XS_NPC_RemoveDefensiveProc) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: NPC::RemoveDefensiveProc(THIS,spellid)");
|
||||||
|
{
|
||||||
|
NPC * THIS;
|
||||||
|
int spell_id = (int)SvIV(ST(1));
|
||||||
|
dXSTARG;
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(NPC *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||||
|
if(THIS == NULL)
|
||||||
|
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||||
|
|
||||||
|
THIS->RemoveDefensiveProc(spell_id, false);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_ChangeLastName); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_NPC_ChangeLastName)
|
||||||
|
{
|
||||||
|
dXSARGS;
|
||||||
|
if (items < 1 || items > 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: Mob::ChangeLastName(THIS, name)");
|
||||||
|
{
|
||||||
|
NPC * THIS;
|
||||||
|
char * name = nullptr;
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(NPC *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||||
|
if(THIS == nullptr)
|
||||||
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
if (items > 1) { name = (char *)SvPV_nolen(ST(1)); }
|
||||||
|
|
||||||
|
THIS->ChangeLastName(name);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_ClearLastName); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_NPC_ClearLastName)
|
||||||
|
{
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 1)
|
||||||
|
Perl_croak(aTHX_ "Usage: Mob::ClearLastName(THIS)");
|
||||||
|
{
|
||||||
|
NPC * THIS;
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(NPC *,tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||||
|
if(THIS == nullptr)
|
||||||
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
THIS->ClearLastName();
|
||||||
}
|
}
|
||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
@ -2420,6 +2577,7 @@ XS(boot_NPC)
|
|||||||
newXSproto(strcpy(buf, "GetPrimaryFaction"), XS_NPC_GetPrimaryFaction, file, "$");
|
newXSproto(strcpy(buf, "GetPrimaryFaction"), XS_NPC_GetPrimaryFaction, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetNPCHate"), XS_NPC_GetNPCHate, file, "$$");
|
newXSproto(strcpy(buf, "GetNPCHate"), XS_NPC_GetNPCHate, file, "$$");
|
||||||
newXSproto(strcpy(buf, "IsOnHatelist"), XS_NPC_IsOnHatelist, file, "$$");
|
newXSproto(strcpy(buf, "IsOnHatelist"), XS_NPC_IsOnHatelist, file, "$$");
|
||||||
|
newXSproto(strcpy(buf, "RemoveFromHateList"), XS_NPC_RemoveFromHateList, file, "$$");
|
||||||
newXSproto(strcpy(buf, "SetNPCFactionID"), XS_NPC_SetNPCFactionID, file, "$$");
|
newXSproto(strcpy(buf, "SetNPCFactionID"), XS_NPC_SetNPCFactionID, file, "$$");
|
||||||
newXSproto(strcpy(buf, "GetMaxDMG"), XS_NPC_GetMaxDMG, file, "$");
|
newXSproto(strcpy(buf, "GetMaxDMG"), XS_NPC_GetMaxDMG, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetMinDMG"), XS_NPC_GetMinDMG, file, "$");
|
newXSproto(strcpy(buf, "GetMinDMG"), XS_NPC_GetMinDMG, file, "$");
|
||||||
@ -2480,6 +2638,11 @@ XS(boot_NPC)
|
|||||||
newXSproto(strcpy(buf, "AddMeleeProc"), XS_NPC_AddMeleeProc, file, "$$$");
|
newXSproto(strcpy(buf, "AddMeleeProc"), XS_NPC_AddMeleeProc, file, "$$$");
|
||||||
newXSproto(strcpy(buf, "AddRangedProc"), XS_NPC_AddRangedProc, file, "$$$");
|
newXSproto(strcpy(buf, "AddRangedProc"), XS_NPC_AddRangedProc, file, "$$$");
|
||||||
newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$");
|
newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$");
|
||||||
|
newXSproto(strcpy(buf, "RemoveMeleeProc"), XS_NPC_RemoveMeleeProc, file, "$$");
|
||||||
|
newXSproto(strcpy(buf, "RemoveRangedProc"), XS_NPC_RemoveRangedProc, file, "$$");
|
||||||
|
newXSproto(strcpy(buf, "RemoveDefensiveProc"), XS_NPC_RemoveDefensiveProc, file, "$$");
|
||||||
|
newXSproto(strcpy(buf, "ChangeLastName"), XS_NPC_ChangeLastName, file, "$:$");
|
||||||
|
newXSproto(strcpy(buf, "ClearLastName"), XS_NPC_ClearLastName, file, "$");
|
||||||
XSRETURN_YES;
|
XSRETURN_YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -248,7 +248,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//find the NPC data for the specified NPC type
|
//find the NPC data for the specified NPC type
|
||||||
const NPCType *base = database.GetNPCType(record.npc_type);
|
const NPCType *base = database.LoadNPCTypesData(record.npc_type);
|
||||||
if(base == nullptr) {
|
if(base == nullptr) {
|
||||||
Message(13, "Unable to load NPC data for pet %s", pettype);
|
Message(13, "Unable to load NPC data for pet %s", pettype);
|
||||||
Log.Out(Logs::General, Logs::Error, "Unable to load NPC data for pet %s (NPC ID %d), check pets and npc_types tables.", pettype, record.npc_type);
|
Log.Out(Logs::General, Logs::Error, "Unable to load NPC data for pet %s (NPC ID %d), check pets and npc_types tables.", pettype, record.npc_type);
|
||||||
@ -384,7 +384,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
|||||||
monsterid = 567;
|
monsterid = 567;
|
||||||
|
|
||||||
// give the summoned pet the attributes of the monster we found
|
// give the summoned pet the attributes of the monster we found
|
||||||
const NPCType* monster = database.GetNPCType(monsterid);
|
const NPCType* monster = database.LoadNPCTypesData(monsterid);
|
||||||
if(monster) {
|
if(monster) {
|
||||||
npc_type->race = monster->race;
|
npc_type->race = monster->race;
|
||||||
npc_type->size = monster->size;
|
npc_type->size = monster->size;
|
||||||
@ -417,7 +417,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
npc->UpdateEquipLightValue();
|
npc->UpdateEquipmentLight();
|
||||||
|
|
||||||
// finally, override size if one was provided
|
// finally, override size if one was provided
|
||||||
if (in_size > 0.0f)
|
if (in_size > 0.0f)
|
||||||
@ -426,6 +426,20 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
|||||||
entity_list.AddNPC(npc, true, true);
|
entity_list.AddNPC(npc, true, true);
|
||||||
SetPetID(npc->GetID());
|
SetPetID(npc->GetID());
|
||||||
// We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet
|
// We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet
|
||||||
|
|
||||||
|
|
||||||
|
if (record.petcontrol == petTargetLock)
|
||||||
|
{
|
||||||
|
Mob* target = GetTarget();
|
||||||
|
|
||||||
|
if (target){
|
||||||
|
npc->AddToHateList(target, 1);
|
||||||
|
npc->SetPetTargetLockID(target->GetID());
|
||||||
|
npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
npc->Kill(); //On live casts spell 892 Unsummon (Kayen - Too limiting to use that for emu since pet can have more than 20k HP)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* This is why the pets ghost - pets were being spawned too far away from its npc owner and some
|
/* This is why the pets ghost - pets were being spawned too far away from its npc owner and some
|
||||||
into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I
|
into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I
|
||||||
|
|||||||
@ -483,7 +483,7 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
//second look for /quests/zone/npcname.ext (precedence)
|
//second look for /quests/zone/npcname.ext (precedence)
|
||||||
const NPCType *npc_type = database.GetNPCType(npcid);
|
const NPCType *npc_type = database.LoadNPCTypesData(npcid);
|
||||||
if(!npc_type) {
|
if(!npc_type) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -203,7 +203,7 @@ void QuestManager::write(const char *file, const char *str) {
|
|||||||
|
|
||||||
Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& position) {
|
Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& position) {
|
||||||
const NPCType* tmp = 0;
|
const NPCType* tmp = 0;
|
||||||
if (tmp = database.GetNPCType(npc_type))
|
if (tmp = database.LoadNPCTypesData(npc_type))
|
||||||
{
|
{
|
||||||
NPC* npc = new NPC(tmp, nullptr, position, FlyMode3);
|
NPC* npc = new NPC(tmp, nullptr, position, FlyMode3);
|
||||||
npc->AddLootTable();
|
npc->AddLootTable();
|
||||||
@ -225,7 +225,7 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v
|
|||||||
}
|
}
|
||||||
|
|
||||||
const NPCType* tmp = 0;
|
const NPCType* tmp = 0;
|
||||||
if (tmp = database.GetNPCType(npc_type))
|
if (tmp = database.LoadNPCTypesData(npc_type))
|
||||||
{
|
{
|
||||||
NPC* npc = new NPC(tmp, nullptr, position, FlyMode3);
|
NPC* npc = new NPC(tmp, nullptr, position, FlyMode3);
|
||||||
npc->AddLootTable();
|
npc->AddLootTable();
|
||||||
@ -275,7 +275,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NPCType* tmp = database.GetNPCType(npcid);
|
const NPCType* tmp = database.LoadNPCTypesData(npcid);
|
||||||
if(!tmp)
|
if(!tmp)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -297,7 +297,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0);
|
database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), 0);
|
||||||
found_spawn->SetCurrentNPCID(npcid);
|
found_spawn->SetCurrentNPCID(npcid);
|
||||||
|
|
||||||
auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading());
|
auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading());
|
||||||
@ -1574,7 +1574,7 @@ void QuestManager::respawn(int npcTypeID, int grid) {
|
|||||||
quests_running_.push(e);
|
quests_running_.push(e);
|
||||||
|
|
||||||
const NPCType* npcType = nullptr;
|
const NPCType* npcType = nullptr;
|
||||||
if ((npcType = database.GetNPCType(npcTypeID)))
|
if ((npcType = database.LoadNPCTypesData(npcTypeID)))
|
||||||
{
|
{
|
||||||
owner = new NPC(npcType, nullptr, owner->GetPosition(), FlyMode3);
|
owner = new NPC(npcType, nullptr, owner->GetPosition(), FlyMode3);
|
||||||
owner->CastToNPC()->AddLootTable();
|
owner->CastToNPC()->AddLootTable();
|
||||||
@ -2388,7 +2388,7 @@ void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime)
|
|||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
database.UpdateSpawn2Timeleft(id, 0, (newTime/1000));
|
database.UpdateRespawnTime(id, 0, (newTime/1000));
|
||||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||||
iterator.Reset();
|
iterator.Reset();
|
||||||
while (iterator.MoreElements())
|
while (iterator.MoreElements())
|
||||||
|
|||||||
110
zone/spawn2.cpp
110
zone/spawn2.cpp
@ -183,7 +183,7 @@ bool Spawn2::Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//try to find our NPC type.
|
//try to find our NPC type.
|
||||||
const NPCType* tmp = database.GetNPCType(npcid);
|
const NPCType* tmp = database.LoadNPCTypesData(npcid);
|
||||||
if (tmp == nullptr) {
|
if (tmp == nullptr) {
|
||||||
Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d", spawn2_id, spawngroup_id_, npcid);
|
Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d", spawn2_id, spawngroup_id_, npcid);
|
||||||
Reset(); //try again later
|
Reset(); //try again later
|
||||||
@ -214,9 +214,6 @@ bool Spawn2::Process() {
|
|||||||
if(IsDespawned)
|
if(IsDespawned)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(spawn2_id)
|
|
||||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0);
|
|
||||||
|
|
||||||
currentnpcid = npcid;
|
currentnpcid = npcid;
|
||||||
NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3);
|
NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3);
|
||||||
|
|
||||||
@ -348,7 +345,7 @@ void Spawn2::DeathReset(bool realdeath)
|
|||||||
//if we have a valid spawn id
|
//if we have a valid spawn id
|
||||||
if(spawn2_id)
|
if(spawn2_id)
|
||||||
{
|
{
|
||||||
database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), (cur/1000));
|
database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), (cur/1000));
|
||||||
Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn reset by death, repop in %d ms", spawn2_id, timer.GetRemainingTime());
|
Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn reset by death, repop in %d ms", spawn2_id, timer.GetRemainingTime());
|
||||||
//store it to database too
|
//store it to database too
|
||||||
}
|
}
|
||||||
@ -356,28 +353,95 @@ void Spawn2::DeathReset(bool realdeath)
|
|||||||
|
|
||||||
bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {
|
bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay) {
|
||||||
|
|
||||||
|
std::unordered_map<uint32, uint32> spawn_times;
|
||||||
|
|
||||||
|
timeval tv;
|
||||||
|
gettimeofday(&tv, nullptr);
|
||||||
|
|
||||||
|
/* Bulk Load NPC Types Data into the cache */
|
||||||
|
database.LoadNPCTypesData(0, true);
|
||||||
|
|
||||||
|
std::string spawn_query = StringFormat(
|
||||||
|
"SELECT "
|
||||||
|
"respawn_times.id, "
|
||||||
|
"respawn_times.`start`, "
|
||||||
|
"respawn_times.duration "
|
||||||
|
"FROM "
|
||||||
|
"respawn_times "
|
||||||
|
"WHERE instance_id = %u",
|
||||||
|
zone->GetInstanceID()
|
||||||
|
);
|
||||||
|
auto results = QueryDatabase(spawn_query);
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0;
|
||||||
|
uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0;
|
||||||
|
|
||||||
|
/* Our current time was expired */
|
||||||
|
if ((start_duration + end_duration) <= tv.tv_sec) {
|
||||||
|
spawn_times[atoi(row[0])] = 0;
|
||||||
|
}
|
||||||
|
/* We still have time left on this timer */
|
||||||
|
else {
|
||||||
|
spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *zone_name = database.GetZoneName(zoneid);
|
const char *zone_name = database.GetZoneName(zoneid);
|
||||||
std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, "
|
std::string query = StringFormat(
|
||||||
"respawntime, variance, pathgrid, _condition, "
|
"SELECT "
|
||||||
"cond_value, enabled, animation FROM spawn2 "
|
"id, "
|
||||||
"WHERE zone = '%s' AND version = %u",
|
"spawngroupID, "
|
||||||
zone_name, version);
|
"x, "
|
||||||
auto results = QueryDatabase(query);
|
"y, "
|
||||||
if (!results.Success()) {
|
"z, "
|
||||||
|
"heading, "
|
||||||
|
"respawntime, "
|
||||||
|
"variance, "
|
||||||
|
"pathgrid, "
|
||||||
|
"_condition, "
|
||||||
|
"cond_value, "
|
||||||
|
"enabled, "
|
||||||
|
"animation "
|
||||||
|
"FROM "
|
||||||
|
"spawn2 "
|
||||||
|
"WHERE zone = '%s' AND version = %u",
|
||||||
|
zone_name,
|
||||||
|
version
|
||||||
|
);
|
||||||
|
results = QueryDatabase(query);
|
||||||
|
|
||||||
|
if (!results.Success()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
Spawn2* newSpawn = 0;
|
|
||||||
|
|
||||||
bool perl_enabled = atoi(row[11]) == 1? true: false;
|
uint32 spawn_time_left = 0;
|
||||||
uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000);
|
Spawn2* new_spawn = 0;
|
||||||
newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]),
|
bool perl_enabled = atoi(row[11]) == 1 ? true : false;
|
||||||
atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]),
|
|
||||||
atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12]));
|
|
||||||
|
|
||||||
spawn2_list.Insert(newSpawn);
|
if (spawn_times.count(atoi(row[0])) != 0)
|
||||||
}
|
spawn_time_left = spawn_times[atoi(row[0])];
|
||||||
|
|
||||||
|
new_spawn = new Spawn2( //
|
||||||
|
atoi(row[0]), // uint32 in_spawn2_id
|
||||||
|
atoi(row[1]), // uint32 spawngroup_id
|
||||||
|
atof(row[2]), // float in_x
|
||||||
|
atof(row[3]), // float in_y
|
||||||
|
atof(row[4]), // float in_z
|
||||||
|
atof(row[5]), // float in_heading
|
||||||
|
atoi(row[6]), // uint32 respawn
|
||||||
|
atoi(row[7]), // uint32 variance
|
||||||
|
spawn_time_left, // uint32 timeleft
|
||||||
|
atoi(row[8]), // uint32 grid
|
||||||
|
atoi(row[9]), // uint16 in_cond_id
|
||||||
|
atoi(row[10]), // int16 in_min_value
|
||||||
|
perl_enabled, // bool in_enabled
|
||||||
|
(EmuAppearance)atoi(row[12]) // EmuAppearance anim
|
||||||
|
);
|
||||||
|
|
||||||
|
spawn2_list.Insert(new_spawn);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -427,8 +491,6 @@ bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* z
|
|||||||
if (results.RowsAffected() != 1)
|
if (results.RowsAffected() != 1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(client)
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1186,7 +1186,6 @@ float Mob::GetRangeDistTargetSizeMod(Mob* other)
|
|||||||
|
|
||||||
void NPC::RangedAttack(Mob* other)
|
void NPC::RangedAttack(Mob* other)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!other)
|
if (!other)
|
||||||
return;
|
return;
|
||||||
//make sure the attack and ranged timers are up
|
//make sure the attack and ranged timers are up
|
||||||
@ -1306,7 +1305,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
|||||||
|
|
||||||
if (TotalDmg > 0)
|
if (TotalDmg > 0)
|
||||||
CommonOutgoingHitSuccess(other, TotalDmg, skillInUse);
|
CommonOutgoingHitSuccess(other, TotalDmg, skillInUse);
|
||||||
else
|
else if (TotalDmg < -4)
|
||||||
TotalDmg = -5;
|
TotalDmg = -5;
|
||||||
|
|
||||||
if (TotalDmg > 0)
|
if (TotalDmg > 0)
|
||||||
|
|||||||
@ -5527,7 +5527,12 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) {
|
|||||||
//Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected
|
//Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected
|
||||||
//by reagent conservation for obvious reasons.
|
//by reagent conservation for obvious reasons.
|
||||||
|
|
||||||
return realTotal + realTotal2 + realTotal3;
|
//Non-Live like feature to allow for an additive focus bonus to be applied from foci that are placed in worn slot. (No limit checks)
|
||||||
|
int16 worneffect_bonus = 0;
|
||||||
|
if (RuleB(Spells, UseAdditiveFocusFromWornSlot))
|
||||||
|
worneffect_bonus = itembonuses.FocusEffectsWorn[type];
|
||||||
|
|
||||||
|
return realTotal + realTotal2 + realTotal3 + worneffect_bonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) {
|
int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||||
|
|||||||
@ -3742,7 +3742,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValidSpell(spells[spell_id].RecourseLink))
|
if (IsValidSpell(spells[spell_id].RecourseLink) && spells[spell_id].RecourseLink != spell_id)
|
||||||
SpellFinished(spells[spell_id].RecourseLink, this, 10, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff);
|
SpellFinished(spells[spell_id].RecourseLink, this, 10, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff);
|
||||||
|
|
||||||
if (IsDetrimentalSpell(spell_id)) {
|
if (IsDetrimentalSpell(spell_id)) {
|
||||||
|
|||||||
@ -2872,7 +2872,16 @@ int ClientTaskState::GetTaskActivityDoneCountFromTaskID(int TaskID, int Activity
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount;
|
|
||||||
|
if (ActiveTaskIndex == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount){
|
||||||
|
return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClientTaskState::GetTaskStartTime(int index) {
|
int ClientTaskState::GetTaskStartTime(int index) {
|
||||||
|
|||||||
259
zone/trading.cpp
259
zone/trading.cpp
@ -108,7 +108,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
|
|||||||
ItemInst* inst2 = client->GetInv().GetItem(trade_slot_id);
|
ItemInst* inst2 = client->GetInv().GetItem(trade_slot_id);
|
||||||
|
|
||||||
// it looks like the original code attempted to allow stacking...
|
// it looks like the original code attempted to allow stacking...
|
||||||
// (it just didn't handle partial stack move actions -U)
|
// (it just didn't handle partial stack move actions)
|
||||||
if (stack_size > 0) {
|
if (stack_size > 0) {
|
||||||
if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) {
|
if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) {
|
||||||
client->Kick();
|
client->Kick();
|
||||||
@ -800,7 +800,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
// QS code
|
// QS code
|
||||||
if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
if(RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||||
// Currently provides only basic functionality. Calling method will also
|
// Currently provides only basic functionality. Calling method will also
|
||||||
// need to be modified before item returns and rewards can be logged. -U
|
// need to be modified before item returns and rewards can be logged.
|
||||||
qs_audit = (QSPlayerLogHandin_Struct*)event_entry;
|
qs_audit = (QSPlayerLogHandin_Struct*)event_entry;
|
||||||
qs_log = true;
|
qs_log = true;
|
||||||
|
|
||||||
@ -819,7 +819,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
qs_audit->npc_count = 0;
|
qs_audit->npc_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(qs_log) { // This can be incorporated below when revisions are made -U
|
if(qs_log) { // This can be incorporated below when revisions are made
|
||||||
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) {
|
for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) {
|
||||||
const ItemInst* trade_inst = m_inv[trade_slot];
|
const ItemInst* trade_inst = m_inv[trade_slot];
|
||||||
|
|
||||||
@ -1098,7 +1098,15 @@ void Client::Trader_EndTrader() {
|
|||||||
for(int i = 0; i < 80; i++) {
|
for(int i = 0; i < 80; i++) {
|
||||||
if(gis->Items[i] != 0) {
|
if(gis->Items[i] != 0) {
|
||||||
|
|
||||||
tdis->ItemID = gis->SerialNumber[i];
|
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
// RoF+ use Item IDs for now
|
||||||
|
tdis->ItemID = gis->Items[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tdis->ItemID = gis->SerialNumber[i];
|
||||||
|
}
|
||||||
|
|
||||||
Customer->QueuePacket(outapp);
|
Customer->QueuePacket(outapp);
|
||||||
}
|
}
|
||||||
@ -1138,7 +1146,6 @@ void Client::Trader_EndTrader() {
|
|||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
|
|
||||||
|
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
WithCustomer(0);
|
WithCustomer(0);
|
||||||
@ -1221,6 +1228,29 @@ void Client::BulkSendTraderInventory(uint32 char_id) {
|
|||||||
safe_delete(TraderItems);
|
safe_delete(TraderItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 Client::FindTraderItemSerialNumber(int32 ItemID) {
|
||||||
|
|
||||||
|
ItemInst* item = nullptr;
|
||||||
|
uint16 SlotID = 0;
|
||||||
|
for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++){
|
||||||
|
item = this->GetInv().GetItem(i);
|
||||||
|
if (item && item->GetItem()->ID == 17899){ //Traders Satchel
|
||||||
|
for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++) {
|
||||||
|
// we already have the parent bag and a contents iterator..why not just iterate the bag!??
|
||||||
|
SlotID = Inventory::CalcSlotId(i, x);
|
||||||
|
item = this->GetInv().GetItem(SlotID);
|
||||||
|
if (item) {
|
||||||
|
if (item->GetID() == ItemID)
|
||||||
|
return item->GetSerialNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Client::FindTraderItemSerialNumber Couldn't find item! Item ID %i", ItemID);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ItemInst* Client::FindTraderItemBySerialNumber(int32 SerialNumber){
|
ItemInst* Client::FindTraderItemBySerialNumber(int32 SerialNumber){
|
||||||
|
|
||||||
ItemInst* item = nullptr;
|
ItemInst* item = nullptr;
|
||||||
@ -1288,9 +1318,9 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
|
|||||||
|
|
||||||
item = this->GetInv().GetItem(SlotID);
|
item = this->GetInv().GetItem(SlotID);
|
||||||
|
|
||||||
if(item && item->GetSerialNumber() == SerialNumber &&
|
if (item && item->GetSerialNumber() == SerialNumber &&
|
||||||
(item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1))){
|
(item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1)))
|
||||||
|
{
|
||||||
return SlotID;
|
return SlotID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1302,21 +1332,34 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int SerialNumber) {
|
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int32 SerialNumber, int32 itemid) {
|
||||||
|
|
||||||
|
if(!Customer)
|
||||||
|
return;
|
||||||
|
|
||||||
if(!Customer) return;
|
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
|
Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
|
||||||
if(Quantity < Charges) {
|
|
||||||
|
if(Quantity < Charges)
|
||||||
|
{
|
||||||
Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
|
Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
|
||||||
m_inv.DeleteItem(Slot, Quantity);
|
m_inv.DeleteItem(Slot, Quantity);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
|
||||||
TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
|
TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
tdis->Unknown000 = 0;
|
tdis->Unknown000 = 0;
|
||||||
tdis->TraderID = Customer->GetID();
|
tdis->TraderID = Customer->GetID();
|
||||||
tdis->ItemID = SerialNumber;
|
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
// RoF+ use Item IDs for now
|
||||||
|
tdis->ItemID = itemid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tdis->ItemID = SerialNumber;
|
||||||
|
}
|
||||||
tdis->Unknown012 = 0;
|
tdis->Unknown012 = 0;
|
||||||
|
|
||||||
|
|
||||||
@ -1324,7 +1367,6 @@ void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Cu
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
|
|
||||||
m_inv.DeleteItem(Slot);
|
m_inv.DeleteItem(Slot);
|
||||||
|
|
||||||
}
|
}
|
||||||
// This updates the trader. Removes it from his trading bags.
|
// This updates the trader. Removes it from his trading bags.
|
||||||
//
|
//
|
||||||
@ -1375,49 +1417,61 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client*
|
|||||||
int16 Charges=0;
|
int16 Charges=0;
|
||||||
|
|
||||||
uint16 SlotID = FindTraderItem(SerialNumber, Quantity);
|
uint16 SlotID = FindTraderItem(SerialNumber, Quantity);
|
||||||
if(SlotID > 0){
|
|
||||||
|
if(SlotID > 0) {
|
||||||
|
|
||||||
item = this->GetInv().GetItem(SlotID);
|
item = this->GetInv().GetItem(SlotID);
|
||||||
|
|
||||||
if(item) {
|
if (!item)
|
||||||
Charges = this->GetInv().GetItem(SlotID)->GetCharges();
|
{
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "Could not find Item: %i on Trader: %s", SerialNumber, Quantity, this->GetName());
|
||||||
Stackable = item->IsStackable();
|
return;
|
||||||
|
|
||||||
if(!Stackable)
|
|
||||||
Quantity = (Charges > 0) ? Charges : 1;
|
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity);
|
|
||||||
}
|
}
|
||||||
if(item && (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable)){
|
|
||||||
|
Charges = this->GetInv().GetItem(SlotID)->GetCharges();
|
||||||
|
|
||||||
|
Stackable = item->IsStackable();
|
||||||
|
|
||||||
|
if (!Stackable)
|
||||||
|
Quantity = (Charges > 0) ? Charges : 1;
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity);
|
||||||
|
|
||||||
|
if (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable)
|
||||||
|
{
|
||||||
this->DeleteItemInInventory(SlotID, Quantity);
|
this->DeleteItemInInventory(SlotID, Quantity);
|
||||||
|
|
||||||
TraderCharges_Struct* GetSlot = database.LoadTraderItemWithCharges(this->CharacterID());
|
TraderCharges_Struct* TraderItems = database.LoadTraderItemWithCharges(this->CharacterID());
|
||||||
|
|
||||||
uint8 Count = 0;
|
uint8 Count = 0;
|
||||||
|
|
||||||
bool TestSlot = true;
|
bool TestSlot = true;
|
||||||
|
|
||||||
for(int y = 0;y < 80;y++){
|
for(int i = 0;i < 80;i++){
|
||||||
|
|
||||||
if(TestSlot && GetSlot->SerialNumber[y] == SerialNumber){
|
if(TestSlot && TraderItems->SerialNumber[i] == SerialNumber)
|
||||||
|
{
|
||||||
database.DeleteTraderItem(this->CharacterID(),y);
|
database.DeleteTraderItem(this->CharacterID(),i);
|
||||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, GetSlot->SerialNumber[y]);
|
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, TraderItems->SerialNumber[i], TraderItems->ItemID[i]);
|
||||||
TestSlot=false;
|
TestSlot=false;
|
||||||
}
|
}
|
||||||
else if(GetSlot->ItemID[y] > 0)
|
else if (TraderItems->ItemID[i] > 0)
|
||||||
|
{
|
||||||
Count++;
|
Count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(Count == 0)
|
if (Count == 0)
|
||||||
|
{
|
||||||
Trader_EndTrader();
|
Trader_EndTrader();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(item) {
|
else
|
||||||
|
{
|
||||||
database.UpdateTraderItemCharges(this->CharacterID(), item->GetSerialNumber(), Charges-Quantity);
|
database.UpdateTraderItemCharges(this->CharacterID(), item->GetSerialNumber(), Charges-Quantity);
|
||||||
|
|
||||||
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber());
|
NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber(), item->GetID());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1427,22 +1481,38 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client*
|
|||||||
Quantity,this->GetName());
|
Quantity,this->GetName());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges){
|
void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges, uint32 itemid){
|
||||||
|
|
||||||
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer;
|
||||||
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct));
|
EQApplicationPacket* outapp = nullptr;
|
||||||
|
|
||||||
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct));
|
||||||
|
}
|
||||||
|
|
||||||
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
memcpy(outtbs, tbs, app->size);
|
memcpy(outtbs, tbs, app->size);
|
||||||
|
|
||||||
outtbs->Price = (tbs->Price * static_cast<uint32>(TraderItemCharges));
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
// Convert Serial Number back to Item ID for RoF+
|
||||||
|
outtbs->ItemID = itemid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// RoF+ requires individual price, but older clients require total price
|
||||||
|
outtbs->Price = (tbs->Price * static_cast<uint32>(TraderItemCharges));
|
||||||
|
}
|
||||||
|
|
||||||
outtbs->Quantity = TraderItemCharges;
|
outtbs->Quantity = TraderItemCharges;
|
||||||
|
// This should probably be trader ID, not customer ID as it is below.
|
||||||
outtbs->TraderID = this->GetID();
|
outtbs->TraderID = this->GetID();
|
||||||
|
|
||||||
outtbs->AlreadySold = 0;
|
outtbs->AlreadySold = 0;
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
@ -1479,9 +1549,7 @@ static void BazaarAuditTrail(const char *seller, const char *buyer, const char *
|
|||||||
database.QueryDatabase(query);
|
database.QueryDatabase(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplicationPacket* app){
|
||||||
|
|
||||||
void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicationPacket* app){
|
|
||||||
|
|
||||||
if(!Trader) return;
|
if(!Trader) return;
|
||||||
|
|
||||||
@ -1490,13 +1558,23 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader,sizeof(TraderBuy_Struct));
|
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct));
|
||||||
|
|
||||||
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer;
|
||||||
|
|
||||||
outtbs->ItemID = tbs->ItemID;
|
outtbs->ItemID = tbs->ItemID;
|
||||||
|
|
||||||
const ItemInst* BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID);
|
const ItemInst* BuyItem = nullptr;
|
||||||
|
uint32 ItemID = 0;
|
||||||
|
|
||||||
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
// Convert Item ID to Serial Number for RoF+
|
||||||
|
ItemID = tbs->ItemID;
|
||||||
|
tbs->ItemID = Trader->FindTraderItemSerialNumber(tbs->ItemID);
|
||||||
|
}
|
||||||
|
|
||||||
|
BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID);
|
||||||
|
|
||||||
if(!BuyItem) {
|
if(!BuyItem) {
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Unable to find item on trader.");
|
Log.Out(Logs::Detail, Logs::Trading, "Unable to find item on trader.");
|
||||||
@ -1509,15 +1587,15 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
|||||||
BuyItem->GetItem()->Name, BuyItem->IsStackable(), tbs->Quantity, BuyItem->GetCharges());
|
BuyItem->GetItem()->Name, BuyItem->IsStackable(), tbs->Quantity, BuyItem->GetCharges());
|
||||||
// If the item is not stackable, then we can only be buying one of them.
|
// If the item is not stackable, then we can only be buying one of them.
|
||||||
if(!BuyItem->IsStackable())
|
if(!BuyItem->IsStackable())
|
||||||
outtbs->Quantity = tbs->Quantity;
|
outtbs->Quantity = 1; // normally you can't send more than 1 here
|
||||||
else {
|
else {
|
||||||
// Stackable items, arrows, diamonds, etc
|
// Stackable items, arrows, diamonds, etc
|
||||||
int ItemCharges = BuyItem->GetCharges();
|
int32 ItemCharges = BuyItem->GetCharges();
|
||||||
// ItemCharges for stackables should not be <= 0
|
// ItemCharges for stackables should not be <= 0
|
||||||
if(ItemCharges <= 0)
|
if(ItemCharges <= 0)
|
||||||
outtbs->Quantity = 1;
|
outtbs->Quantity = 1;
|
||||||
// If the purchaser requested more than is in the stack, just sell them how many are actually in the stack.
|
// If the purchaser requested more than is in the stack, just sell them how many are actually in the stack.
|
||||||
else if(ItemCharges < (int16)tbs->Quantity)
|
else if(static_cast<uint32>(ItemCharges) < tbs->Quantity)
|
||||||
outtbs->Quantity = ItemCharges;
|
outtbs->Quantity = ItemCharges;
|
||||||
else
|
else
|
||||||
outtbs->Quantity = tbs->Quantity;
|
outtbs->Quantity = tbs->Quantity;
|
||||||
@ -1546,12 +1624,10 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnTraderReq(app, outtbs->Quantity);
|
ReturnTraderReq(app, outtbs->Quantity, ItemID);
|
||||||
|
|
||||||
outtbs->TraderID = this->GetID();
|
outtbs->TraderID = this->GetID();
|
||||||
|
|
||||||
outtbs->Action = BazaarBuyItem;
|
outtbs->Action = BazaarBuyItem;
|
||||||
|
|
||||||
strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64);
|
strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64);
|
||||||
|
|
||||||
int TraderSlot = 0;
|
int TraderSlot = 0;
|
||||||
@ -1561,55 +1637,50 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
|||||||
else
|
else
|
||||||
SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges());
|
SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges());
|
||||||
|
|
||||||
|
|
||||||
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoneyUpdate,sizeof(MoneyUpdate_Struct));
|
|
||||||
|
|
||||||
MoneyUpdate_Struct* mus= (MoneyUpdate_Struct*)outapp2->pBuffer;
|
|
||||||
|
|
||||||
// This cannot overflow assuming MAX_TRANSACTION_VALUE, checked above, is the default of 2000000000
|
// This cannot overflow assuming MAX_TRANSACTION_VALUE, checked above, is the default of 2000000000
|
||||||
uint32 TotalCost = tbs->Price * outtbs->Quantity;
|
uint32 TotalCost = tbs->Price * outtbs->Quantity;
|
||||||
|
|
||||||
outtbs->Price = TotalCost;
|
if (Trader->GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
// RoF+ uses individual item price where older clients use total price
|
||||||
|
outtbs->Price = tbs->Price;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outtbs->Price = TotalCost;
|
||||||
|
}
|
||||||
|
|
||||||
this->TakeMoneyFromPP(TotalCost);
|
this->TakeMoneyFromPP(TotalCost);
|
||||||
|
|
||||||
mus->platinum = TotalCost / 1000;
|
Log.Out(Logs::Detail, Logs::Trading, "Customer Paid: %d in Copper", TotalCost);
|
||||||
|
|
||||||
TotalCost -= (mus->platinum * 1000);
|
uint32 platinum = TotalCost / 1000;
|
||||||
|
TotalCost -= (platinum * 1000);
|
||||||
|
uint32 gold = TotalCost / 100;
|
||||||
|
TotalCost -= (gold * 100);
|
||||||
|
uint32 silver = TotalCost / 10;
|
||||||
|
TotalCost -= (silver * 10);
|
||||||
|
uint32 copper = TotalCost;
|
||||||
|
|
||||||
mus->gold = TotalCost / 100;
|
Trader->AddMoneyToPP(copper, silver, gold, platinum, true);
|
||||||
|
|
||||||
TotalCost -= (mus->gold * 100);
|
Log.Out(Logs::Detail, Logs::Trading, "Trader Received: %d Platinum, %d Gold, %d Silver, %d Copper", platinum, gold, silver, copper);
|
||||||
|
|
||||||
mus->silver = TotalCost / 10;
|
|
||||||
|
|
||||||
TotalCost -= (mus->silver * 10);
|
|
||||||
|
|
||||||
mus->copper = TotalCost;
|
|
||||||
|
|
||||||
Trader->AddMoneyToPP(mus->copper,mus->silver,mus->gold,mus->platinum,false);
|
|
||||||
|
|
||||||
mus->platinum = Trader->GetPlatinum();
|
|
||||||
mus->gold = Trader->GetGold();
|
|
||||||
mus->silver = Trader->GetSilver();
|
|
||||||
mus->copper = Trader->GetCopper();
|
|
||||||
|
|
||||||
TraderSlot = Trader->FindTraderItem(tbs->ItemID, outtbs->Quantity);
|
TraderSlot = Trader->FindTraderItem(tbs->ItemID, outtbs->Quantity);
|
||||||
|
|
||||||
Trader->QueuePacket(outapp2);
|
|
||||||
|
|
||||||
|
|
||||||
if(RuleB(Bazaar, AuditTrail))
|
if(RuleB(Bazaar, AuditTrail))
|
||||||
BazaarAuditTrail(Trader->GetName(), GetName(), BuyItem->GetItem()->Name, outtbs->Quantity, outtbs->Price, 0);
|
BazaarAuditTrail(Trader->GetName(), GetName(), BuyItem->GetItem()->Name, outtbs->Quantity, outtbs->Price, 0);
|
||||||
|
|
||||||
Trader->FindAndNukeTraderItem(tbs->ItemID, outtbs->Quantity, this, 0);
|
Trader->FindAndNukeTraderItem(tbs->ItemID, outtbs->Quantity, this, 0);
|
||||||
|
|
||||||
|
if (ItemID > 0 && Trader->GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
// Convert Serial Number back to ItemID for RoF+
|
||||||
|
outtbs->ItemID = ItemID;
|
||||||
|
}
|
||||||
|
|
||||||
Trader->QueuePacket(outapp);
|
Trader->QueuePacket(outapp);
|
||||||
|
|
||||||
|
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
safe_delete(outapp2);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendBazaarWelcome()
|
void Client::SendBazaarWelcome()
|
||||||
@ -1619,7 +1690,15 @@ void Client::SendBazaarWelcome()
|
|||||||
if (results.Success() && results.RowCount() == 1){
|
if (results.Success() && results.RowCount() == 1){
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
EQApplicationPacket* outapp = nullptr;
|
||||||
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BazaarWelcome_Struct));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
||||||
|
}
|
||||||
|
|
||||||
memset(outapp->pBuffer,0,outapp->size);
|
memset(outapp->pBuffer,0,outapp->size);
|
||||||
|
|
||||||
@ -1630,6 +1709,11 @@ void Client::SendBazaarWelcome()
|
|||||||
bws->Traders = atoi(row[0]);
|
bws->Traders = atoi(row[0]);
|
||||||
bws->Items = atoi(row[1]);
|
bws->Items = atoi(row[1]);
|
||||||
|
|
||||||
|
if (GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
bws->Unknown012 = GetID();
|
||||||
|
}
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
|
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@ -2000,6 +2084,15 @@ static void UpdateTraderCustomerPriceChanged(uint32 CustomerID, TraderCharges_St
|
|||||||
for(int i = 0; i < 80; i++) {
|
for(int i = 0; i < 80; i++) {
|
||||||
|
|
||||||
if(gis->ItemID[i] == ItemID) {
|
if(gis->ItemID[i] == ItemID) {
|
||||||
|
if (Customer->GetClientVersion() >= ClientVersion::RoF)
|
||||||
|
{
|
||||||
|
// RoF+ use Item IDs for now
|
||||||
|
tdis->ItemID = gis->ItemID[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tdis->ItemID = gis->SerialNumber[i];
|
||||||
|
}
|
||||||
tdis->ItemID = gis->SerialNumber[i];
|
tdis->ItemID = gis->SerialNumber[i];
|
||||||
Log.Out(Logs::Detail, Logs::Trading, "Telling customer to remove item %i with %i charges and S/N %i",
|
Log.Out(Logs::Detail, Logs::Trading, "Telling customer to remove item %i with %i charges and S/N %i",
|
||||||
ItemID, Charges, gis->SerialNumber[i]);
|
ItemID, Charges, gis->SerialNumber[i]);
|
||||||
|
|||||||
@ -142,7 +142,7 @@ void Trap::Trigger(Mob* trigger)
|
|||||||
|
|
||||||
for (i = 0; i < effectvalue2; i++)
|
for (i = 0; i < effectvalue2; i++)
|
||||||
{
|
{
|
||||||
if ((tmp = database.GetNPCType(effectvalue)))
|
if ((tmp = database.LoadNPCTypesData(effectvalue)))
|
||||||
{
|
{
|
||||||
auto randomOffset = glm::vec4(zone->random.Int(-5, 5),zone->random.Int(-5, 5),zone->random.Int(-5, 5), zone->random.Int(0, 249));
|
auto randomOffset = glm::vec4(zone->random.Int(-5, 5),zone->random.Int(-5, 5),zone->random.Int(-5, 5), zone->random.Int(0, 249));
|
||||||
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
|
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
|
||||||
@ -165,7 +165,7 @@ void Trap::Trigger(Mob* trigger)
|
|||||||
|
|
||||||
for (i = 0; i < effectvalue2; i++)
|
for (i = 0; i < effectvalue2; i++)
|
||||||
{
|
{
|
||||||
if ((tmp = database.GetNPCType(effectvalue)))
|
if ((tmp = database.LoadNPCTypesData(effectvalue)))
|
||||||
{
|
{
|
||||||
auto randomOffset = glm::vec4(zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(0, 249));
|
auto randomOffset = glm::vec4(zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(0, 249));
|
||||||
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
|
auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f);
|
||||||
@ -294,7 +294,7 @@ void Trap::CreateHiddenTrigger()
|
|||||||
if(hiddenTrigger)
|
if(hiddenTrigger)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const NPCType *base_type = database.GetNPCType(500);
|
const NPCType *base_type = database.LoadNPCTypesData(500);
|
||||||
NPCType *make_npc = new NPCType;
|
NPCType *make_npc = new NPCType;
|
||||||
memcpy(make_npc, base_type, sizeof(NPCType));
|
memcpy(make_npc, base_type, sizeof(NPCType));
|
||||||
make_npc->max_hp = 100000;
|
make_npc->max_hp = 100000;
|
||||||
|
|||||||
@ -737,6 +737,7 @@ void Zone::LoadZoneDoors(const char* zone, int16 version)
|
|||||||
for(r = 0; r < count; r++, d++) {
|
for(r = 0; r < count; r++, d++) {
|
||||||
Doors* newdoor = new Doors(d);
|
Doors* newdoor = new Doors(d);
|
||||||
entity_list.AddDoor(newdoor);
|
entity_list.AddDoor(newdoor);
|
||||||
|
Log.Out(Logs::Detail, Logs::Doors, "Door Add to Entity List, index: %u db id: %u, door_id %u", r, dlist[r].db_id, dlist[r].door_id);
|
||||||
}
|
}
|
||||||
delete[] dlist;
|
delete[] dlist;
|
||||||
}
|
}
|
||||||
@ -933,6 +934,9 @@ bool Zone::Init(bool iStaticZone) {
|
|||||||
Log.Out(Logs::General, Logs::Error, "Loading World Objects failed. continuing.");
|
Log.Out(Logs::General, Logs::Error, "Loading World Objects failed. continuing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.Out(Logs::General, Logs::Status, "Flushing old respawn timers...");
|
||||||
|
database.QueryDatabase("DELETE FROM `respawn_times` WHERE (`start` + `duration`) < UNIX_TIMESTAMP(NOW())");
|
||||||
|
|
||||||
//load up the zone's doors (prints inside)
|
//load up the zone's doors (prints inside)
|
||||||
zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion());
|
zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion());
|
||||||
zone->LoadBlockedSpells(zone->GetZoneID());
|
zone->LoadBlockedSpells(zone->GetZoneID());
|
||||||
@ -1425,14 +1429,12 @@ bool Zone::Depop(bool StartSpawnTimer) {
|
|||||||
std::map<uint32,NPCType *>::iterator itr;
|
std::map<uint32,NPCType *>::iterator itr;
|
||||||
entity_list.Depop(StartSpawnTimer);
|
entity_list.Depop(StartSpawnTimer);
|
||||||
|
|
||||||
#ifdef DEPOP_INVALIDATES_NPC_TYPES_CACHE
|
/* Refresh npctable (cache), getting current info from database. */
|
||||||
// Refresh npctable, getting current info from database.
|
while(npctable.size()) {
|
||||||
while(npctable.size()) {
|
itr = npctable.begin();
|
||||||
itr=npctable.begin();
|
|
||||||
delete itr->second;
|
delete itr->second;
|
||||||
npctable.erase(itr);
|
npctable.erase(itr);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2164,7 +2166,7 @@ void Zone::DoAdventureActions()
|
|||||||
{
|
{
|
||||||
if(ds->assa_count >= RuleI(Adventure, NumberKillsForBossSpawn))
|
if(ds->assa_count >= RuleI(Adventure, NumberKillsForBossSpawn))
|
||||||
{
|
{
|
||||||
const NPCType* tmp = database.GetNPCType(ds->data_id);
|
const NPCType* tmp = database.LoadNPCTypesData(ds->data_id);
|
||||||
if(tmp)
|
if(tmp)
|
||||||
{
|
{
|
||||||
NPC* npc = new NPC(tmp, nullptr, glm::vec4(ds->assa_x, ds->assa_y, ds->assa_z, ds->assa_h), FlyMode3);
|
NPC* npc = new NPC(tmp, nullptr, glm::vec4(ds->assa_x, ds->assa_y, ds->assa_z, ds->assa_h), FlyMode3);
|
||||||
|
|||||||
762
zone/zonedb.cpp
762
zone/zonedb.cpp
@ -97,118 +97,178 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct
|
|||||||
*map_filename = new char[100];
|
*map_filename = new char[100];
|
||||||
zone_data->zone_id = zoneid;
|
zone_data->zone_id = zoneid;
|
||||||
|
|
||||||
std::string query = StringFormat("SELECT ztype, fog_red, fog_green, fog_blue, fog_minclip, fog_maxclip, " // 5
|
std::string query = StringFormat(
|
||||||
"fog_red2, fog_green2, fog_blue2, fog_minclip2, fog_maxclip2, " // 5
|
"SELECT "
|
||||||
"fog_red3, fog_green3, fog_blue3, fog_minclip3, fog_maxclip3, " // 5
|
"ztype, " // 0
|
||||||
"fog_red4, fog_green4, fog_blue4, fog_minclip4, fog_maxclip4, " // 5
|
"fog_red, " // 1
|
||||||
"fog_density, sky, zone_exp_multiplier, safe_x, safe_y, safe_z, underworld, " // 7
|
"fog_green, " // 2
|
||||||
"minclip, maxclip, time_type, canbind, cancombat, canlevitate, " // 6
|
"fog_blue, " // 3
|
||||||
"castoutdoor, hotzone, ruleset, suspendbuffs, map_file_name, short_name, " // 6
|
"fog_minclip, " // 4
|
||||||
"rain_chance1, rain_chance2, rain_chance3, rain_chance4, " // 4
|
"fog_maxclip, " // 5
|
||||||
"rain_duration1, rain_duration2, rain_duration3, rain_duration4, " // 4
|
"fog_red2, " // 6
|
||||||
"snow_chance1, snow_chance2, snow_chance3, snow_chance4, " // 4
|
"fog_green2, " // 7
|
||||||
"snow_duration1, snow_duration2, snow_duration3, snow_duration4 " // 4
|
"fog_blue2, " // 8
|
||||||
"FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id);
|
"fog_minclip2, " // 9
|
||||||
auto results = QueryDatabase(query);
|
"fog_maxclip2, " // 10
|
||||||
if (!results.Success()) {
|
"fog_red3, " // 11
|
||||||
strcpy(*map_filename, "default");
|
"fog_green3, " // 12
|
||||||
|
"fog_blue3, " // 13
|
||||||
|
"fog_minclip3, " // 14
|
||||||
|
"fog_maxclip3, " // 15
|
||||||
|
"fog_red4, " // 16
|
||||||
|
"fog_green4, " // 17
|
||||||
|
"fog_blue4, " // 18
|
||||||
|
"fog_minclip4, " // 19
|
||||||
|
"fog_maxclip4, " // 20
|
||||||
|
"fog_density, " // 21
|
||||||
|
"sky, " // 22
|
||||||
|
"zone_exp_multiplier, " // 23
|
||||||
|
"safe_x, " // 24
|
||||||
|
"safe_y, " // 25
|
||||||
|
"safe_z, " // 26
|
||||||
|
"underworld, " // 27
|
||||||
|
"minclip, " // 28
|
||||||
|
"maxclip, " // 29
|
||||||
|
"time_type, " // 30
|
||||||
|
"canbind, " // 31
|
||||||
|
"cancombat, " // 32
|
||||||
|
"canlevitate, " // 33
|
||||||
|
"castoutdoor, " // 34
|
||||||
|
"hotzone, " // 35
|
||||||
|
"ruleset, " // 36
|
||||||
|
"suspendbuffs, " // 37
|
||||||
|
"map_file_name, " // 38
|
||||||
|
"short_name, " // 39
|
||||||
|
"rain_chance1, " // 40
|
||||||
|
"rain_chance2, " // 41
|
||||||
|
"rain_chance3, " // 42
|
||||||
|
"rain_chance4, " // 43
|
||||||
|
"rain_duration1, " // 44
|
||||||
|
"rain_duration2, " // 45
|
||||||
|
"rain_duration3, " // 46
|
||||||
|
"rain_duration4, " // 47
|
||||||
|
"snow_chance1, " // 48
|
||||||
|
"snow_chance2, " // 49
|
||||||
|
"snow_chance3, " // 50
|
||||||
|
"snow_chance4, " // 51
|
||||||
|
"snow_duration1, " // 52
|
||||||
|
"snow_duration2, " // 53
|
||||||
|
"snow_duration3, " // 54
|
||||||
|
"snow_duration4, " // 55
|
||||||
|
"gravity " // 56
|
||||||
|
"FROM zone WHERE zoneidnumber = %i AND version = %i",
|
||||||
|
zoneid, instance_id);
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
strcpy(*map_filename, "default");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results.RowCount() == 0) {
|
if (results.RowCount() == 0) {
|
||||||
strcpy(*map_filename, "default");
|
strcpy(*map_filename, "default");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
memset(zone_data, 0, sizeof(NewZone_Struct));
|
memset(zone_data, 0, sizeof(NewZone_Struct));
|
||||||
zone_data->ztype = atoi(row[0]);
|
zone_data->ztype = atoi(row[0]);
|
||||||
zone_type = zone_data->ztype;
|
zone_type = zone_data->ztype;
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
for(index = 0; index < 4; index++) {
|
for (index = 0; index < 4; index++) {
|
||||||
zone_data->fog_red[index]=atoi(row[1 + index * 5]);
|
zone_data->fog_red[index] = atoi(row[1 + index * 5]);
|
||||||
zone_data->fog_green[index]=atoi(row[2 + index * 5]);
|
zone_data->fog_green[index] = atoi(row[2 + index * 5]);
|
||||||
zone_data->fog_blue[index]=atoi(row[3 + index * 5]);
|
zone_data->fog_blue[index] = atoi(row[3 + index * 5]);
|
||||||
zone_data->fog_minclip[index]=atof(row[4 + index * 5]);
|
zone_data->fog_minclip[index] = atof(row[4 + index * 5]);
|
||||||
zone_data->fog_maxclip[index]=atof(row[5 + index * 5]);
|
zone_data->fog_maxclip[index] = atof(row[5 + index * 5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
zone_data->fog_density = atof(row[21]);
|
zone_data->fog_density = atof(row[21]);
|
||||||
zone_data->sky=atoi(row[22]);
|
zone_data->sky = atoi(row[22]);
|
||||||
zone_data->zone_exp_multiplier=atof(row[23]);
|
zone_data->zone_exp_multiplier = atof(row[23]);
|
||||||
zone_data->safe_x=atof(row[24]);
|
zone_data->safe_x = atof(row[24]);
|
||||||
zone_data->safe_y=atof(row[25]);
|
zone_data->safe_y = atof(row[25]);
|
||||||
zone_data->safe_z=atof(row[26]);
|
zone_data->safe_z = atof(row[26]);
|
||||||
zone_data->underworld=atof(row[27]);
|
zone_data->underworld = atof(row[27]);
|
||||||
zone_data->minclip=atof(row[28]);
|
zone_data->minclip = atof(row[28]);
|
||||||
zone_data->maxclip=atof(row[29]);
|
zone_data->maxclip = atof(row[29]);
|
||||||
zone_data->time_type=atoi(row[30]);
|
zone_data->time_type = atoi(row[30]);
|
||||||
|
|
||||||
//not in the DB yet:
|
//not in the DB yet:
|
||||||
zone_data->gravity = 0.4;
|
zone_data->gravity = atof(row[56]);
|
||||||
allow_mercs = true;
|
Log.Out(Logs::General, Logs::Debug, "Zone Gravity is %f", zone_data->gravity);
|
||||||
|
allow_mercs = true;
|
||||||
|
|
||||||
int bindable = 0;
|
int bindable = 0;
|
||||||
bindable = atoi(row[31]);
|
bindable = atoi(row[31]);
|
||||||
|
|
||||||
can_bind = bindable == 0? false: true;
|
can_bind = bindable == 0 ? false : true;
|
||||||
is_city = bindable == 2? true: false;
|
is_city = bindable == 2 ? true : false;
|
||||||
can_combat = atoi(row[32]) == 0? false: true;
|
can_combat = atoi(row[32]) == 0 ? false : true;
|
||||||
can_levitate = atoi(row[33]) == 0? false: true;
|
can_levitate = atoi(row[33]) == 0 ? false : true;
|
||||||
can_castoutdoor = atoi(row[34]) == 0? false: true;
|
can_castoutdoor = atoi(row[34]) == 0 ? false : true;
|
||||||
is_hotzone = atoi(row[35]) == 0? false: true;
|
is_hotzone = atoi(row[35]) == 0 ? false : true;
|
||||||
|
|
||||||
|
|
||||||
ruleset = atoi(row[36]);
|
ruleset = atoi(row[36]);
|
||||||
zone_data->SuspendBuffs = atoi(row[37]);
|
zone_data->SuspendBuffs = atoi(row[37]);
|
||||||
|
|
||||||
char *file = row[38];
|
char *file = row[38];
|
||||||
if(file)
|
if (file)
|
||||||
strcpy(*map_filename, file);
|
strcpy(*map_filename, file);
|
||||||
else
|
else
|
||||||
strcpy(*map_filename, row[39]);
|
strcpy(*map_filename, row[39]);
|
||||||
|
|
||||||
for(index = 0; index < 4; index++)
|
for (index = 0; index < 4; index++)
|
||||||
zone_data->rain_chance[index]=atoi(row[40 + index]);
|
zone_data->rain_chance[index] = atoi(row[40 + index]);
|
||||||
|
|
||||||
for(index = 0; index < 4; index++)
|
for (index = 0; index < 4; index++)
|
||||||
zone_data->rain_duration[index]=atoi(row[44 + index]);
|
zone_data->rain_duration[index] = atoi(row[44 + index]);
|
||||||
|
|
||||||
for(index = 0; index < 4; index++)
|
for (index = 0; index < 4; index++)
|
||||||
zone_data->snow_chance[index]=atoi(row[48 + index]);
|
zone_data->snow_chance[index] = atoi(row[48 + index]);
|
||||||
|
|
||||||
for(index = 0; index < 4; index++)
|
for (index = 0; index < 4; index++)
|
||||||
zone_data->snow_duration[index]=atof(row[52 + index]);
|
zone_data->snow_duration[index] = atof(row[52 + index]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//updates or clears the respawn time in the database for the current spawn id
|
void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint32 time_left)
|
||||||
void ZoneDatabase::UpdateSpawn2Timeleft(uint32 id, uint16 instance_id, uint32 timeleft)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
timeval tv;
|
timeval tv;
|
||||||
gettimeofday(&tv, nullptr);
|
gettimeofday(&tv, nullptr);
|
||||||
uint32 cur = tv.tv_sec;
|
uint32 current_time = tv.tv_sec;
|
||||||
|
|
||||||
//if we pass timeleft as 0 that means we clear from respawn time
|
/* If we pass timeleft as 0 that means we clear from respawn time
|
||||||
//otherwise we update with a REPLACE INTO
|
otherwise we update with a REPLACE INTO
|
||||||
if(timeleft == 0) {
|
*/
|
||||||
std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu "
|
|
||||||
"AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id);
|
|
||||||
auto results = QueryDatabase(query);
|
|
||||||
if (!results.Success())
|
|
||||||
|
|
||||||
|
if(time_left == 0) {
|
||||||
|
std::string query = StringFormat("DELETE FROM `respawn_times` WHERE `id` = %u AND `instance_id` = %u", spawn2_id, instance_id);
|
||||||
|
QueryDatabase(query);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string query = StringFormat("REPLACE INTO respawn_times (id, start, duration, instance_id) "
|
std::string query = StringFormat(
|
||||||
"VALUES (%lu, %lu, %lu, %lu)",
|
"REPLACE INTO `respawn_times` "
|
||||||
(unsigned long)id, (unsigned long)cur,
|
"(id, "
|
||||||
(unsigned long)timeleft, (unsigned long)instance_id);
|
"start, "
|
||||||
auto results = QueryDatabase(query);
|
"duration, "
|
||||||
if (!results.Success())
|
"instance_id) "
|
||||||
|
"VALUES "
|
||||||
|
"(%u, "
|
||||||
|
"%u, "
|
||||||
|
"%u, "
|
||||||
|
"%u)",
|
||||||
|
spawn2_id,
|
||||||
|
current_time,
|
||||||
|
time_left,
|
||||||
|
instance_id
|
||||||
|
);
|
||||||
|
QueryDatabase(query);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1107,29 +1167,47 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
r = 0;
|
r = 0;
|
||||||
i = atoi(row[r]); /* Slot */ r++;
|
i = atoi(row[r]); /* Slot */ r++;
|
||||||
pp->item_tint[i].rgb.blue = atoi(row[r]); r++;
|
pp->item_tint[i].RGB.Blue = atoi(row[r]); r++;
|
||||||
pp->item_tint[i].rgb.green = atoi(row[r]); r++;
|
pp->item_tint[i].RGB.Green = atoi(row[r]); r++;
|
||||||
pp->item_tint[i].rgb.red = atoi(row[r]); r++;
|
pp->item_tint[i].RGB.Red = atoi(row[r]); r++;
|
||||||
pp->item_tint[i].rgb.use_tint = atoi(row[r]);
|
pp->item_tint[i].RGB.UseTint = atoi(row[r]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp){
|
bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp)
|
||||||
std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id);
|
{
|
||||||
|
std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT %u",
|
||||||
|
character_id, EmuConstants::BANDOLIERS_SIZE);
|
||||||
auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0;
|
auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0;
|
||||||
for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++)
|
for (i = 0; i < EmuConstants::BANDOLIERS_SIZE; i++) {
|
||||||
for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++)
|
pp->bandoliers[i].Name[0] = '\0';
|
||||||
pp->bandoliers[i].items[si].icon = 0;
|
for (int si = 0; si < EmuConstants::BANDOLIER_ITEM_COUNT; si++) {
|
||||||
|
pp->bandoliers[i].Items[si].ID = 0;
|
||||||
|
pp->bandoliers[i].Items[si].Icon = 0;
|
||||||
|
pp->bandoliers[i].Items[si].Name[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
r = 0;
|
r = 0;
|
||||||
i = atoi(row[r]); /* Bandolier ID */ r++;
|
i = atoi(row[r]); /* Bandolier ID */ r++;
|
||||||
si = atoi(row[r]); /* Bandolier Slot */ r++;
|
si = atoi(row[r]); /* Bandolier Slot */ r++;
|
||||||
pp->bandoliers[i].items[si].item_id = atoi(row[r]); r++;
|
|
||||||
pp->bandoliers[i].items[si].icon = atoi(row[r]); r++;
|
const Item_Struct* item_data = database.GetItem(atoi(row[r]));
|
||||||
strcpy(pp->bandoliers[i].name, row[r]); r++;
|
if (item_data) {
|
||||||
si++;
|
pp->bandoliers[i].Items[si].ID = item_data->ID; r++;
|
||||||
|
pp->bandoliers[i].Items[si].Icon = atoi(row[r]); r++; // Must use db value in case an Ornamentation is assigned
|
||||||
|
strncpy(pp->bandoliers[i].Items[si].Name, item_data->Name, 64);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pp->bandoliers[i].Items[si].ID = 0; r++;
|
||||||
|
pp->bandoliers[i].Items[si].Icon = 0; r++;
|
||||||
|
pp->bandoliers[i].Items[si].Name[0] = '\0';
|
||||||
|
}
|
||||||
|
strcpy(pp->bandoliers[i].Name, row[r]); r++;
|
||||||
|
|
||||||
|
si++; // What is this for!?
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1153,26 +1231,27 @@ bool ZoneDatabase::LoadCharacterTribute(uint32 character_id, PlayerProfile_Struc
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp){
|
bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct *pp)
|
||||||
std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT 4", character_id);
|
{
|
||||||
auto results = database.QueryDatabase(query); int i = 0;
|
std::string query =
|
||||||
for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){
|
StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT %u",
|
||||||
pp->potionbelt.items[i].icon = 0;
|
character_id, EmuConstants::POTION_BELT_ITEM_COUNT);
|
||||||
pp->potionbelt.items[i].item_id = 0;
|
auto results = database.QueryDatabase(query);
|
||||||
strncpy(pp->potionbelt.items[i].item_name, "\0", 1);
|
int i = 0;
|
||||||
|
for (i = 0; i < EmuConstants::POTION_BELT_ITEM_COUNT; i++) {
|
||||||
|
pp->potionbelt.Items[i].Icon = 0;
|
||||||
|
pp->potionbelt.Items[i].ID = 0;
|
||||||
|
pp->potionbelt.Items[i].Name[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
i = atoi(row[0]); /* Potion belt slot number */
|
i = atoi(row[0]);
|
||||||
uint32 item_id = atoi(row[1]);
|
const Item_Struct *item_data = database.GetItem(atoi(row[1]));
|
||||||
const Item_Struct *item = database.GetItem(item_id);
|
if (!item_data)
|
||||||
|
|
||||||
if(!item)
|
|
||||||
continue;
|
continue;
|
||||||
|
pp->potionbelt.Items[i].ID = item_data->ID;
|
||||||
pp->potionbelt.items[i].item_id = item_id;
|
pp->potionbelt.Items[i].Icon = atoi(row[2]);
|
||||||
pp->potionbelt.items[i].icon = atoi(row[2]);
|
strncpy(pp->potionbelt.Items[i].Name, item_data->Name, 64);
|
||||||
strncpy(pp->potionbelt.items[i].item_name, item->Name, 64);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1266,7 +1345,8 @@ bool ZoneDatabase::SaveCharacterTribute(uint32 character_id, PlayerProfile_Struc
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name){
|
bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name)
|
||||||
|
{
|
||||||
char bandolier_name_esc[64];
|
char bandolier_name_esc[64];
|
||||||
DoEscapeString(bandolier_name_esc, bandolier_name, strlen(bandolier_name));
|
DoEscapeString(bandolier_name_esc, bandolier_name, strlen(bandolier_name));
|
||||||
std::string query = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%u, %u, %u, %u, %u,'%s')", character_id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name_esc);
|
std::string query = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%u, %u, %u, %u, %u,'%s')", character_id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name_esc);
|
||||||
@ -1275,7 +1355,8 @@ bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_i
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneDatabase::SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon) {
|
bool ZoneDatabase::SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon)
|
||||||
|
{
|
||||||
std::string query = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%u, %u, %u, %u)", character_id, potion_id, item_id, icon);
|
std::string query = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%u, %u, %u, %u)", character_id, potion_id, item_id, icon);
|
||||||
auto results = QueryDatabase(query);
|
auto results = QueryDatabase(query);
|
||||||
return true;
|
return true;
|
||||||
@ -1709,166 +1790,240 @@ bool ZoneDatabase::NoRentExpired(const char* name){
|
|||||||
return (seconds>1800);
|
return (seconds>1800);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Searches npctable for matching id, and returns the item if found,
|
const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)
|
||||||
* or nullptr otherwise. If id passed is 0, loads all npc_types for
|
{
|
||||||
* the current zone, returning the last item added.
|
const NPCType *npc = nullptr;
|
||||||
*/
|
|
||||||
const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
|
||||||
const NPCType *npc=nullptr;
|
|
||||||
|
|
||||||
// If NPC is already in tree, return it.
|
/* If there is a cached NPC entry, load it */
|
||||||
auto itr = zone->npctable.find(id);
|
auto itr = zone->npctable.find(npc_type_id);
|
||||||
if(itr != zone->npctable.end())
|
if(itr != zone->npctable.end())
|
||||||
return itr->second;
|
return itr->second;
|
||||||
|
|
||||||
// Otherwise, get NPCs from database.
|
std::string where_condition = "";
|
||||||
|
|
||||||
|
if (bulk_load){
|
||||||
|
Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load");
|
||||||
|
where_condition = StringFormat(
|
||||||
|
"INNER JOIN spawnentry ON npc_types.id = spawnentry.npcID "
|
||||||
|
"INNER JOIN spawn2 ON spawnentry.spawngroupID = spawn2.spawngroupID "
|
||||||
|
"WHERE spawn2.zone = '%s' and spawn2.version = %u GROUP BY npc_types.id", zone->GetShortName(), zone->GetInstanceVersion());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
where_condition = StringFormat("WHERE id = %u", npc_type_id);
|
||||||
|
}
|
||||||
|
|
||||||
// If id is 0, load all npc_types for the current zone,
|
std::string query = StringFormat("SELECT "
|
||||||
// according to spawn2.
|
"npc_types.id, "
|
||||||
std::string query = StringFormat("SELECT npc_types.id, npc_types.name, npc_types.level, npc_types.race, "
|
"npc_types.name, "
|
||||||
"npc_types.class, npc_types.hp, npc_types.mana, npc_types.gender, "
|
"npc_types.level, "
|
||||||
"npc_types.texture, npc_types.helmtexture, npc_types.herosforgemodel, npc_types.size, "
|
"npc_types.race, "
|
||||||
"npc_types.loottable_id, npc_types.merchant_id, npc_types.alt_currency_id, "
|
"npc_types.class, "
|
||||||
"npc_types.adventure_template_id, npc_types.trap_template, npc_types.attack_speed, "
|
"npc_types.hp, "
|
||||||
"npc_types.STR, npc_types.STA, npc_types.DEX, npc_types.AGI, npc_types._INT, "
|
"npc_types.mana, "
|
||||||
"npc_types.WIS, npc_types.CHA, npc_types.MR, npc_types.CR, npc_types.DR, "
|
"npc_types.gender, "
|
||||||
"npc_types.FR, npc_types.PR, npc_types.Corrup, npc_types.PhR, "
|
"npc_types.texture, "
|
||||||
"npc_types.mindmg, npc_types.maxdmg, npc_types.attack_count, npc_types.special_abilities, "
|
"npc_types.helmtexture, "
|
||||||
"npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_melee_texture1, "
|
"npc_types.herosforgemodel, "
|
||||||
"npc_types.d_melee_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type, "
|
"npc_types.size, "
|
||||||
"npc_types.sec_melee_type, npc_types.ranged_type, npc_types.runspeed, npc_types.findable, "
|
"npc_types.loottable_id, "
|
||||||
"npc_types.trackable, npc_types.hp_regen_rate, npc_types.mana_regen_rate, "
|
"npc_types.merchant_id, "
|
||||||
"npc_types.aggroradius, npc_types.assistradius, npc_types.bodytype, npc_types.npc_faction_id, "
|
"npc_types.alt_currency_id, "
|
||||||
"npc_types.face, npc_types.luclin_hairstyle, npc_types.luclin_haircolor, "
|
"npc_types.adventure_template_id, "
|
||||||
"npc_types.luclin_eyecolor, npc_types.luclin_eyecolor2, npc_types.luclin_beardcolor,"
|
"npc_types.trap_template, "
|
||||||
"npc_types.luclin_beard, npc_types.drakkin_heritage, npc_types.drakkin_tattoo, "
|
"npc_types.attack_speed, "
|
||||||
"npc_types.drakkin_details, npc_types.armortint_id, "
|
"npc_types.STR, "
|
||||||
"npc_types.armortint_red, npc_types.armortint_green, npc_types.armortint_blue, "
|
"npc_types.STA, "
|
||||||
"npc_types.see_invis, npc_types.see_invis_undead, npc_types.lastname, "
|
"npc_types.DEX, "
|
||||||
"npc_types.qglobal, npc_types.AC, npc_types.npc_aggro, npc_types.spawn_limit, "
|
"npc_types.AGI, "
|
||||||
"npc_types.see_hide, npc_types.see_improved_hide, npc_types.ATK, npc_types.Accuracy, "
|
"npc_types._INT, "
|
||||||
"npc_types.Avoidance, npc_types.slow_mitigation, npc_types.maxlevel, npc_types.scalerate, "
|
"npc_types.WIS, "
|
||||||
"npc_types.private_corpse, npc_types.unique_spawn_by_name, npc_types.underwater, "
|
"npc_types.CHA, "
|
||||||
"npc_types.emoteid, npc_types.spellscale, npc_types.healscale, npc_types.no_target_hotkey, "
|
"npc_types.MR, "
|
||||||
"npc_types.raid_target, npc_types.attack_delay, npc_types.light FROM npc_types WHERE id = %d", id);
|
"npc_types.CR, "
|
||||||
|
"npc_types.DR, "
|
||||||
|
"npc_types.FR, "
|
||||||
|
"npc_types.PR, "
|
||||||
|
"npc_types.Corrup, "
|
||||||
|
"npc_types.PhR, "
|
||||||
|
"npc_types.mindmg, "
|
||||||
|
"npc_types.maxdmg, "
|
||||||
|
"npc_types.attack_count, "
|
||||||
|
"npc_types.special_abilities, "
|
||||||
|
"npc_types.npc_spells_id, "
|
||||||
|
"npc_types.npc_spells_effects_id, "
|
||||||
|
"npc_types.d_melee_texture1, "
|
||||||
|
"npc_types.d_melee_texture2, "
|
||||||
|
"npc_types.ammo_idfile, "
|
||||||
|
"npc_types.prim_melee_type, "
|
||||||
|
"npc_types.sec_melee_type, "
|
||||||
|
"npc_types.ranged_type, "
|
||||||
|
"npc_types.runspeed, "
|
||||||
|
"npc_types.findable, "
|
||||||
|
"npc_types.trackable, "
|
||||||
|
"npc_types.hp_regen_rate, "
|
||||||
|
"npc_types.mana_regen_rate, "
|
||||||
|
"npc_types.aggroradius, "
|
||||||
|
"npc_types.assistradius, "
|
||||||
|
"npc_types.bodytype, "
|
||||||
|
"npc_types.npc_faction_id, "
|
||||||
|
"npc_types.face, "
|
||||||
|
"npc_types.luclin_hairstyle, "
|
||||||
|
"npc_types.luclin_haircolor, "
|
||||||
|
"npc_types.luclin_eyecolor, "
|
||||||
|
"npc_types.luclin_eyecolor2, "
|
||||||
|
"npc_types.luclin_beardcolor, "
|
||||||
|
"npc_types.luclin_beard, "
|
||||||
|
"npc_types.drakkin_heritage, "
|
||||||
|
"npc_types.drakkin_tattoo, "
|
||||||
|
"npc_types.drakkin_details, "
|
||||||
|
"npc_types.armortint_id, "
|
||||||
|
"npc_types.armortint_red, "
|
||||||
|
"npc_types.armortint_green, "
|
||||||
|
"npc_types.armortint_blue, "
|
||||||
|
"npc_types.see_invis, "
|
||||||
|
"npc_types.see_invis_undead, "
|
||||||
|
"npc_types.lastname, "
|
||||||
|
"npc_types.qglobal, "
|
||||||
|
"npc_types.AC, "
|
||||||
|
"npc_types.npc_aggro, "
|
||||||
|
"npc_types.spawn_limit, "
|
||||||
|
"npc_types.see_hide, "
|
||||||
|
"npc_types.see_improved_hide, "
|
||||||
|
"npc_types.ATK, "
|
||||||
|
"npc_types.Accuracy, "
|
||||||
|
"npc_types.Avoidance, "
|
||||||
|
"npc_types.slow_mitigation, "
|
||||||
|
"npc_types.maxlevel, "
|
||||||
|
"npc_types.scalerate, "
|
||||||
|
"npc_types.private_corpse, "
|
||||||
|
"npc_types.unique_spawn_by_name, "
|
||||||
|
"npc_types.underwater, "
|
||||||
|
"npc_types.emoteid, "
|
||||||
|
"npc_types.spellscale, "
|
||||||
|
"npc_types.healscale, "
|
||||||
|
"npc_types.no_target_hotkey, "
|
||||||
|
"npc_types.raid_target, "
|
||||||
|
"npc_types.attack_delay, "
|
||||||
|
"npc_types.light "
|
||||||
|
"FROM npc_types %s",
|
||||||
|
where_condition.c_str()
|
||||||
|
);
|
||||||
|
|
||||||
auto results = QueryDatabase(query);
|
auto results = QueryDatabase(query);
|
||||||
if (!results.Success()) {
|
if (!results.Success()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
NPCType *tmpNPCType;
|
NPCType *temp_npctype_data;
|
||||||
tmpNPCType = new NPCType;
|
temp_npctype_data = new NPCType;
|
||||||
memset (tmpNPCType, 0, sizeof *tmpNPCType);
|
memset (temp_npctype_data, 0, sizeof *temp_npctype_data);
|
||||||
|
|
||||||
tmpNPCType->npc_id = atoi(row[0]);
|
temp_npctype_data->npc_id = atoi(row[0]);
|
||||||
|
|
||||||
strn0cpy(tmpNPCType->name, row[1], 50);
|
strn0cpy(temp_npctype_data->name, row[1], 50);
|
||||||
|
|
||||||
tmpNPCType->level = atoi(row[2]);
|
temp_npctype_data->level = atoi(row[2]);
|
||||||
tmpNPCType->race = atoi(row[3]);
|
temp_npctype_data->race = atoi(row[3]);
|
||||||
tmpNPCType->class_ = atoi(row[4]);
|
temp_npctype_data->class_ = atoi(row[4]);
|
||||||
tmpNPCType->max_hp = atoi(row[5]);
|
temp_npctype_data->max_hp = atoi(row[5]);
|
||||||
tmpNPCType->cur_hp = tmpNPCType->max_hp;
|
temp_npctype_data->cur_hp = temp_npctype_data->max_hp;
|
||||||
tmpNPCType->Mana = atoi(row[6]);
|
temp_npctype_data->Mana = atoi(row[6]);
|
||||||
tmpNPCType->gender = atoi(row[7]);
|
temp_npctype_data->gender = atoi(row[7]);
|
||||||
tmpNPCType->texture = atoi(row[8]);
|
temp_npctype_data->texture = atoi(row[8]);
|
||||||
tmpNPCType->helmtexture = atoi(row[9]);
|
temp_npctype_data->helmtexture = atoi(row[9]);
|
||||||
tmpNPCType->herosforgemodel = atoul(row[10]);
|
temp_npctype_data->herosforgemodel = atoul(row[10]);
|
||||||
tmpNPCType->size = atof(row[11]);
|
temp_npctype_data->size = atof(row[11]);
|
||||||
tmpNPCType->loottable_id = atoi(row[12]);
|
temp_npctype_data->loottable_id = atoi(row[12]);
|
||||||
tmpNPCType->merchanttype = atoi(row[13]);
|
temp_npctype_data->merchanttype = atoi(row[13]);
|
||||||
tmpNPCType->alt_currency_type = atoi(row[14]);
|
temp_npctype_data->alt_currency_type = atoi(row[14]);
|
||||||
tmpNPCType->adventure_template = atoi(row[15]);
|
temp_npctype_data->adventure_template = atoi(row[15]);
|
||||||
tmpNPCType->trap_template = atoi(row[16]);
|
temp_npctype_data->trap_template = atoi(row[16]);
|
||||||
tmpNPCType->attack_speed = atof(row[17]);
|
temp_npctype_data->attack_speed = atof(row[17]);
|
||||||
tmpNPCType->STR = atoi(row[18]);
|
temp_npctype_data->STR = atoi(row[18]);
|
||||||
tmpNPCType->STA = atoi(row[19]);
|
temp_npctype_data->STA = atoi(row[19]);
|
||||||
tmpNPCType->DEX = atoi(row[20]);
|
temp_npctype_data->DEX = atoi(row[20]);
|
||||||
tmpNPCType->AGI = atoi(row[21]);
|
temp_npctype_data->AGI = atoi(row[21]);
|
||||||
tmpNPCType->INT = atoi(row[22]);
|
temp_npctype_data->INT = atoi(row[22]);
|
||||||
tmpNPCType->WIS = atoi(row[23]);
|
temp_npctype_data->WIS = atoi(row[23]);
|
||||||
tmpNPCType->CHA = atoi(row[24]);
|
temp_npctype_data->CHA = atoi(row[24]);
|
||||||
tmpNPCType->MR = atoi(row[25]);
|
temp_npctype_data->MR = atoi(row[25]);
|
||||||
tmpNPCType->CR = atoi(row[26]);
|
temp_npctype_data->CR = atoi(row[26]);
|
||||||
tmpNPCType->DR = atoi(row[27]);
|
temp_npctype_data->DR = atoi(row[27]);
|
||||||
tmpNPCType->FR = atoi(row[28]);
|
temp_npctype_data->FR = atoi(row[28]);
|
||||||
tmpNPCType->PR = atoi(row[29]);
|
temp_npctype_data->PR = atoi(row[29]);
|
||||||
tmpNPCType->Corrup = atoi(row[30]);
|
temp_npctype_data->Corrup = atoi(row[30]);
|
||||||
tmpNPCType->PhR = atoi(row[31]);
|
temp_npctype_data->PhR = atoi(row[31]);
|
||||||
tmpNPCType->min_dmg = atoi(row[32]);
|
temp_npctype_data->min_dmg = atoi(row[32]);
|
||||||
tmpNPCType->max_dmg = atoi(row[33]);
|
temp_npctype_data->max_dmg = atoi(row[33]);
|
||||||
tmpNPCType->attack_count = atoi(row[34]);
|
temp_npctype_data->attack_count = atoi(row[34]);
|
||||||
|
|
||||||
if (row[35] != nullptr)
|
if (row[35] != nullptr)
|
||||||
strn0cpy(tmpNPCType->special_abilities, row[35], 512);
|
strn0cpy(temp_npctype_data->special_abilities, row[35], 512);
|
||||||
else
|
else
|
||||||
tmpNPCType->special_abilities[0] = '\0';
|
temp_npctype_data->special_abilities[0] = '\0';
|
||||||
|
|
||||||
tmpNPCType->npc_spells_id = atoi(row[36]);
|
temp_npctype_data->npc_spells_id = atoi(row[36]);
|
||||||
tmpNPCType->npc_spells_effects_id = atoi(row[37]);
|
temp_npctype_data->npc_spells_effects_id = atoi(row[37]);
|
||||||
tmpNPCType->d_melee_texture1 = atoi(row[38]);
|
temp_npctype_data->d_melee_texture1 = atoi(row[38]);
|
||||||
tmpNPCType->d_melee_texture2 = atoi(row[39]);
|
temp_npctype_data->d_melee_texture2 = atoi(row[39]);
|
||||||
strn0cpy(tmpNPCType->ammo_idfile, row[40], 30);
|
strn0cpy(temp_npctype_data->ammo_idfile, row[40], 30);
|
||||||
tmpNPCType->prim_melee_type = atoi(row[41]);
|
temp_npctype_data->prim_melee_type = atoi(row[41]);
|
||||||
tmpNPCType->sec_melee_type = atoi(row[42]);
|
temp_npctype_data->sec_melee_type = atoi(row[42]);
|
||||||
tmpNPCType->ranged_type = atoi(row[43]);
|
temp_npctype_data->ranged_type = atoi(row[43]);
|
||||||
tmpNPCType->runspeed= atof(row[44]);
|
temp_npctype_data->runspeed= atof(row[44]);
|
||||||
tmpNPCType->findable = atoi(row[45]) == 0? false : true;
|
temp_npctype_data->findable = atoi(row[45]) == 0? false : true;
|
||||||
tmpNPCType->trackable = atoi(row[46]) == 0? false : true;
|
temp_npctype_data->trackable = atoi(row[46]) == 0? false : true;
|
||||||
tmpNPCType->hp_regen = atoi(row[47]);
|
temp_npctype_data->hp_regen = atoi(row[47]);
|
||||||
tmpNPCType->mana_regen = atoi(row[48]);
|
temp_npctype_data->mana_regen = atoi(row[48]);
|
||||||
|
|
||||||
// set default value for aggroradius
|
// set default value for aggroradius
|
||||||
tmpNPCType->aggroradius = (int32)atoi(row[49]);
|
temp_npctype_data->aggroradius = (int32)atoi(row[49]);
|
||||||
if (tmpNPCType->aggroradius <= 0)
|
if (temp_npctype_data->aggroradius <= 0)
|
||||||
tmpNPCType->aggroradius = 70;
|
temp_npctype_data->aggroradius = 70;
|
||||||
|
|
||||||
tmpNPCType->assistradius = (int32)atoi(row[50]);
|
temp_npctype_data->assistradius = (int32)atoi(row[50]);
|
||||||
if (tmpNPCType->assistradius <= 0)
|
if (temp_npctype_data->assistradius <= 0)
|
||||||
tmpNPCType->assistradius = tmpNPCType->aggroradius;
|
temp_npctype_data->assistradius = temp_npctype_data->aggroradius;
|
||||||
|
|
||||||
if (row[51] && strlen(row[51]))
|
if (row[51] && strlen(row[51]))
|
||||||
tmpNPCType->bodytype = (uint8)atoi(row[51]);
|
temp_npctype_data->bodytype = (uint8)atoi(row[51]);
|
||||||
else
|
else
|
||||||
tmpNPCType->bodytype = 0;
|
temp_npctype_data->bodytype = 0;
|
||||||
|
|
||||||
tmpNPCType->npc_faction_id = atoi(row[52]);
|
temp_npctype_data->npc_faction_id = atoi(row[52]);
|
||||||
|
|
||||||
tmpNPCType->luclinface = atoi(row[53]);
|
temp_npctype_data->luclinface = atoi(row[53]);
|
||||||
tmpNPCType->hairstyle = atoi(row[54]);
|
temp_npctype_data->hairstyle = atoi(row[54]);
|
||||||
tmpNPCType->haircolor = atoi(row[55]);
|
temp_npctype_data->haircolor = atoi(row[55]);
|
||||||
tmpNPCType->eyecolor1 = atoi(row[56]);
|
temp_npctype_data->eyecolor1 = atoi(row[56]);
|
||||||
tmpNPCType->eyecolor2 = atoi(row[57]);
|
temp_npctype_data->eyecolor2 = atoi(row[57]);
|
||||||
tmpNPCType->beardcolor = atoi(row[58]);
|
temp_npctype_data->beardcolor = atoi(row[58]);
|
||||||
tmpNPCType->beard = atoi(row[59]);
|
temp_npctype_data->beard = atoi(row[59]);
|
||||||
tmpNPCType->drakkin_heritage = atoi(row[60]);
|
temp_npctype_data->drakkin_heritage = atoi(row[60]);
|
||||||
tmpNPCType->drakkin_tattoo = atoi(row[61]);
|
temp_npctype_data->drakkin_tattoo = atoi(row[61]);
|
||||||
tmpNPCType->drakkin_details = atoi(row[62]);
|
temp_npctype_data->drakkin_details = atoi(row[62]);
|
||||||
|
|
||||||
uint32 armor_tint_id = atoi(row[63]);
|
uint32 armor_tint_id = atoi(row[63]);
|
||||||
|
|
||||||
tmpNPCType->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16;
|
temp_npctype_data->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16;
|
||||||
tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8;
|
temp_npctype_data->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8;
|
||||||
tmpNPCType->armor_tint[0] |= (atoi(row[66]) & 0xFF);
|
temp_npctype_data->armor_tint[0] |= (atoi(row[66]) & 0xFF);
|
||||||
tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
|
temp_npctype_data->armor_tint[0] |= (temp_npctype_data->armor_tint[0]) ? (0xFF << 24) : 0;
|
||||||
|
|
||||||
if (armor_tint_id != 0)
|
if (armor_tint_id != 0) {
|
||||||
{
|
std::string armortint_query = StringFormat(
|
||||||
std::string armortint_query = StringFormat("SELECT red1h, grn1h, blu1h, "
|
"SELECT red1h, grn1h, blu1h, "
|
||||||
"red2c, grn2c, blu2c, "
|
"red2c, grn2c, blu2c, "
|
||||||
"red3a, grn3a, blu3a, "
|
"red3a, grn3a, blu3a, "
|
||||||
"red4b, grn4b, blu4b, "
|
"red4b, grn4b, blu4b, "
|
||||||
"red5g, grn5g, blu5g, "
|
"red5g, grn5g, blu5g, "
|
||||||
"red6l, grn6l, blu6l, "
|
"red6l, grn6l, blu6l, "
|
||||||
"red7f, grn7f, blu7f, "
|
"red7f, grn7f, blu7f, "
|
||||||
"red8x, grn8x, blu8x, "
|
"red8x, grn8x, blu8x, "
|
||||||
"red9x, grn9x, blu9x "
|
"red9x, grn9x, blu9x "
|
||||||
"FROM npc_types_tint WHERE id = %d",
|
"FROM npc_types_tint WHERE id = %d",
|
||||||
armor_tint_id);
|
armor_tint_id);
|
||||||
auto armortint_results = QueryDatabase(armortint_query);
|
auto armortint_results = QueryDatabase(armortint_query);
|
||||||
if (!armortint_results.Success() || armortint_results.RowCount() == 0)
|
if (!armortint_results.Success() || armortint_results.RowCount() == 0)
|
||||||
armor_tint_id = 0;
|
armor_tint_id = 0;
|
||||||
@ -1876,60 +2031,59 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
|||||||
auto armorTint_row = armortint_results.begin();
|
auto armorTint_row = armortint_results.begin();
|
||||||
|
|
||||||
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) {
|
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) {
|
||||||
tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
|
temp_npctype_data->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
|
||||||
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
|
temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
|
||||||
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
|
temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
|
||||||
tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0;
|
temp_npctype_data->armor_tint[index] |= (temp_npctype_data->armor_tint[index]) ? (0xFF << 24) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Try loading npc_types tint fields if armor tint is 0 or query failed to get results
|
// Try loading npc_types tint fields if armor tint is 0 or query failed to get results
|
||||||
if (armor_tint_id == 0)
|
if (armor_tint_id == 0) {
|
||||||
{
|
for (int index = MaterialChest; index < _MaterialCount; index++) {
|
||||||
for (int index = MaterialChest; index < _MaterialCount; index++)
|
temp_npctype_data->armor_tint[index] = temp_npctype_data->armor_tint[0];
|
||||||
{
|
|
||||||
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpNPCType->see_invis = atoi(row[67]);
|
temp_npctype_data->see_invis = atoi(row[67]);
|
||||||
tmpNPCType->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag
|
temp_npctype_data->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag
|
||||||
if (row[69] != nullptr)
|
|
||||||
strn0cpy(tmpNPCType->lastname, row[69], 32);
|
|
||||||
|
|
||||||
tmpNPCType->qglobal = atoi(row[70]) == 0? false: true; // qglobal
|
if (row[69] != nullptr)
|
||||||
tmpNPCType->AC = atoi(row[71]);
|
strn0cpy(temp_npctype_data->lastname, row[69], 32);
|
||||||
tmpNPCType->npc_aggro = atoi(row[72]) == 0? false: true;
|
|
||||||
tmpNPCType->spawn_limit = atoi(row[73]);
|
temp_npctype_data->qglobal = atoi(row[70]) == 0? false: true; // qglobal
|
||||||
tmpNPCType->see_hide = atoi(row[74]) == 0? false: true;
|
temp_npctype_data->AC = atoi(row[71]);
|
||||||
tmpNPCType->see_improved_hide = atoi(row[75]) == 0? false: true;
|
temp_npctype_data->npc_aggro = atoi(row[72]) == 0? false: true;
|
||||||
tmpNPCType->ATK = atoi(row[76]);
|
temp_npctype_data->spawn_limit = atoi(row[73]);
|
||||||
tmpNPCType->accuracy_rating = atoi(row[77]);
|
temp_npctype_data->see_hide = atoi(row[74]) == 0? false: true;
|
||||||
tmpNPCType->avoidance_rating = atoi(row[78]);
|
temp_npctype_data->see_improved_hide = atoi(row[75]) == 0? false: true;
|
||||||
tmpNPCType->slow_mitigation = atoi(row[79]);
|
temp_npctype_data->ATK = atoi(row[76]);
|
||||||
tmpNPCType->maxlevel = atoi(row[80]);
|
temp_npctype_data->accuracy_rating = atoi(row[77]);
|
||||||
tmpNPCType->scalerate = atoi(row[81]);
|
temp_npctype_data->avoidance_rating = atoi(row[78]);
|
||||||
tmpNPCType->private_corpse = atoi(row[82]) == 1 ? true: false;
|
temp_npctype_data->slow_mitigation = atoi(row[79]);
|
||||||
tmpNPCType->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false;
|
temp_npctype_data->maxlevel = atoi(row[80]);
|
||||||
tmpNPCType->underwater = atoi(row[84]) == 1 ? true: false;
|
temp_npctype_data->scalerate = atoi(row[81]);
|
||||||
tmpNPCType->emoteid = atoi(row[85]);
|
temp_npctype_data->private_corpse = atoi(row[82]) == 1 ? true: false;
|
||||||
tmpNPCType->spellscale = atoi(row[86]);
|
temp_npctype_data->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false;
|
||||||
tmpNPCType->healscale = atoi(row[87]);
|
temp_npctype_data->underwater = atoi(row[84]) == 1 ? true: false;
|
||||||
tmpNPCType->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
|
temp_npctype_data->emoteid = atoi(row[85]);
|
||||||
tmpNPCType->raid_target = atoi(row[89]) == 0 ? false: true;
|
temp_npctype_data->spellscale = atoi(row[86]);
|
||||||
tmpNPCType->attack_delay = atoi(row[90]);
|
temp_npctype_data->healscale = atoi(row[87]);
|
||||||
tmpNPCType->light = (atoi(row[91]) & 0x0F);
|
temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
|
||||||
|
temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false: true;
|
||||||
|
temp_npctype_data->attack_delay = atoi(row[90]);
|
||||||
|
temp_npctype_data->light = (atoi(row[91]) & 0x0F);
|
||||||
|
|
||||||
// If NPC with duplicate NPC id already in table,
|
// If NPC with duplicate NPC id already in table,
|
||||||
// free item we attempted to add.
|
// free item we attempted to add.
|
||||||
if (zone->npctable.find(tmpNPCType->npc_id) != zone->npctable.end()) {
|
if (zone->npctable.find(temp_npctype_data->npc_id) != zone->npctable.end()) {
|
||||||
std::cerr << "Error loading duplicate NPC " << tmpNPCType->npc_id << std::endl;
|
std::cerr << "Error loading duplicate NPC " << temp_npctype_data->npc_id << std::endl;
|
||||||
delete tmpNPCType;
|
delete temp_npctype_data;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
zone->npctable[tmpNPCType->npc_id]=tmpNPCType;
|
zone->npctable[temp_npctype_data->npc_id] = temp_npctype_data;
|
||||||
npc = tmpNPCType;
|
npc = temp_npctype_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return npc;
|
return npc;
|
||||||
@ -3246,7 +3400,7 @@ bool ZoneDatabase::LoadFactionData()
|
|||||||
|
|
||||||
auto row = results.begin();
|
auto row = results.begin();
|
||||||
|
|
||||||
max_faction = atoi(row[0]);
|
max_faction = row[0] ? atoi(row[0]) : 0;
|
||||||
faction_array = new Faction*[max_faction+1];
|
faction_array = new Faction*[max_faction+1];
|
||||||
for(unsigned int index=0; index<max_faction; index++)
|
for(unsigned int index=0; index<max_faction; index++)
|
||||||
faction_array[index] = nullptr;
|
faction_array[index] = nullptr;
|
||||||
@ -3396,9 +3550,9 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c
|
|||||||
dbpc->plat, dbpc->haircolor, dbpc->beardcolor, dbpc->eyecolor1,
|
dbpc->plat, dbpc->haircolor, dbpc->beardcolor, dbpc->eyecolor1,
|
||||||
dbpc->eyecolor2, dbpc->hairstyle, dbpc->face, dbpc->beard,
|
dbpc->eyecolor2, dbpc->hairstyle, dbpc->face, dbpc->beard,
|
||||||
dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details,
|
dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details,
|
||||||
dbpc->item_tint[0].color, dbpc->item_tint[1].color, dbpc->item_tint[2].color,
|
dbpc->item_tint[0].Color, dbpc->item_tint[1].Color, dbpc->item_tint[2].Color,
|
||||||
dbpc->item_tint[3].color, dbpc->item_tint[4].color, dbpc->item_tint[5].color,
|
dbpc->item_tint[3].Color, dbpc->item_tint[4].Color, dbpc->item_tint[5].Color,
|
||||||
dbpc->item_tint[6].color, dbpc->item_tint[7].color, dbpc->item_tint[8].color,
|
dbpc->item_tint[6].Color, dbpc->item_tint[7].Color, dbpc->item_tint[8].Color,
|
||||||
db_id);
|
db_id);
|
||||||
auto results = QueryDatabase(query);
|
auto results = QueryDatabase(query);
|
||||||
|
|
||||||
@ -3489,15 +3643,15 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
|
|||||||
dbpc->drakkin_heritage,
|
dbpc->drakkin_heritage,
|
||||||
dbpc->drakkin_tattoo,
|
dbpc->drakkin_tattoo,
|
||||||
dbpc->drakkin_details,
|
dbpc->drakkin_details,
|
||||||
dbpc->item_tint[0].color,
|
dbpc->item_tint[0].Color,
|
||||||
dbpc->item_tint[1].color,
|
dbpc->item_tint[1].Color,
|
||||||
dbpc->item_tint[2].color,
|
dbpc->item_tint[2].Color,
|
||||||
dbpc->item_tint[3].color,
|
dbpc->item_tint[3].Color,
|
||||||
dbpc->item_tint[4].color,
|
dbpc->item_tint[4].Color,
|
||||||
dbpc->item_tint[5].color,
|
dbpc->item_tint[5].Color,
|
||||||
dbpc->item_tint[6].color,
|
dbpc->item_tint[6].Color,
|
||||||
dbpc->item_tint[7].color,
|
dbpc->item_tint[7].Color,
|
||||||
dbpc->item_tint[8].color
|
dbpc->item_tint[8].Color
|
||||||
);
|
);
|
||||||
auto results = QueryDatabase(query);
|
auto results = QueryDatabase(query);
|
||||||
uint32 last_insert_id = results.LastInsertedID();
|
uint32 last_insert_id = results.LastInsertedID();
|
||||||
@ -3669,15 +3823,15 @@ bool ZoneDatabase::LoadCharacterCorpseData(uint32 corpse_id, PlayerCorpse_Struct
|
|||||||
pcs->drakkin_heritage = atoul(row[i++]); // drakkin_heritage,
|
pcs->drakkin_heritage = atoul(row[i++]); // drakkin_heritage,
|
||||||
pcs->drakkin_tattoo = atoul(row[i++]); // drakkin_tattoo,
|
pcs->drakkin_tattoo = atoul(row[i++]); // drakkin_tattoo,
|
||||||
pcs->drakkin_details = atoul(row[i++]); // drakkin_details,
|
pcs->drakkin_details = atoul(row[i++]); // drakkin_details,
|
||||||
pcs->item_tint[0].color = atoul(row[i++]); // wc_1,
|
pcs->item_tint[0].Color = atoul(row[i++]); // wc_1,
|
||||||
pcs->item_tint[1].color = atoul(row[i++]); // wc_2,
|
pcs->item_tint[1].Color = atoul(row[i++]); // wc_2,
|
||||||
pcs->item_tint[2].color = atoul(row[i++]); // wc_3,
|
pcs->item_tint[2].Color = atoul(row[i++]); // wc_3,
|
||||||
pcs->item_tint[3].color = atoul(row[i++]); // wc_4,
|
pcs->item_tint[3].Color = atoul(row[i++]); // wc_4,
|
||||||
pcs->item_tint[4].color = atoul(row[i++]); // wc_5,
|
pcs->item_tint[4].Color = atoul(row[i++]); // wc_5,
|
||||||
pcs->item_tint[5].color = atoul(row[i++]); // wc_6,
|
pcs->item_tint[5].Color = atoul(row[i++]); // wc_6,
|
||||||
pcs->item_tint[6].color = atoul(row[i++]); // wc_7,
|
pcs->item_tint[6].Color = atoul(row[i++]); // wc_7,
|
||||||
pcs->item_tint[7].color = atoul(row[i++]); // wc_8,
|
pcs->item_tint[7].Color = atoul(row[i++]); // wc_8,
|
||||||
pcs->item_tint[8].color = atoul(row[i++]); // wc_9
|
pcs->item_tint[8].Color = atoul(row[i++]); // wc_9
|
||||||
}
|
}
|
||||||
query = StringFormat(
|
query = StringFormat(
|
||||||
"SELECT \n"
|
"SELECT \n"
|
||||||
|
|||||||
@ -365,7 +365,7 @@ public:
|
|||||||
bool PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay = 0);
|
bool PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay = 0);
|
||||||
Spawn2* LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft);
|
Spawn2* LoadSpawn2(LinkedList<Spawn2*> &spawn2_list, uint32 spawn2id, uint32 timeleft);
|
||||||
bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value);
|
bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value);
|
||||||
void UpdateSpawn2Timeleft(uint32 id, uint16 instance_id,uint32 timeleft);
|
void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft);
|
||||||
uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id);
|
uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id);
|
||||||
void UpdateSpawn2Status(uint32 id, uint8 new_status);
|
void UpdateSpawn2Status(uint32 id, uint8 new_status);
|
||||||
|
|
||||||
@ -405,7 +405,7 @@ public:
|
|||||||
|
|
||||||
DBnpcspells_Struct* GetNPCSpells(uint32 iDBSpellsID);
|
DBnpcspells_Struct* GetNPCSpells(uint32 iDBSpellsID);
|
||||||
DBnpcspellseffects_Struct* GetNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
DBnpcspellseffects_Struct* GetNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
||||||
const NPCType* GetNPCType(uint32 id);
|
const NPCType* LoadNPCTypesData(uint32 id, bool bulk_load = false);
|
||||||
|
|
||||||
/* Mercs */
|
/* Mercs */
|
||||||
const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel);
|
const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel);
|
||||||
|
|||||||
@ -182,7 +182,7 @@ struct PlayerCorpse_Struct {
|
|||||||
struct Door {
|
struct Door {
|
||||||
uint32 db_id;
|
uint32 db_id;
|
||||||
uint8 door_id;
|
uint8 door_id;
|
||||||
char zone_name[16];
|
char zone_name[32];
|
||||||
char door_name[32];
|
char door_name[32];
|
||||||
float pos_x;
|
float pos_x;
|
||||||
float pos_y;
|
float pos_y;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user