Compare commits

...

16 Commits

Author SHA1 Message Date
Akkadius de4f5ae491 [Release] 22.23.0 2023-07-31 20:17:17 -05:00
Alex King fb20d92166 [Bug Fix] Fix Appearance Issues (#3520)
* [Bug Fix] Fix Appearance Issues

# Notes
- Changing race, gender, or texture of a Mob could result in it changing sizes due to use not sending the size as part of the appearance packet.
- Also converts the parameterized method to a struct parameter so that we can optionally send things without back-filling multiple arguments.

* Gender cleanup.

* Fix.

* Formatting.
2023-07-31 20:15:13 -05:00
Paul Coene 6cff433d23 [Scaling/Bug Fix] Scaling where min and max damage was bugged (#3514)
* [Scaling/Bug Fix] Scaling where min and max damage were both 0 tossed out min_dmg

* Clamp values so independant calls dont leave us in odd state
2023-07-31 20:00:48 -05:00
Alex King 2da7ddad57 [Bug Fix] Fix NPC Cast Events not parsing properly. (#3518)
* [Bug Fix] Fix NPC Cast Events not parsing properly.

# Notes
- We were not using separated values.

* Update lua_parser_events.cpp
2023-07-31 19:59:56 -05:00
Chris Miles 55161e18c8 [Databuckets] Improvements to distributed cache, reload commands (#3519)
* [Databuckets] Improvements to distributed cache, reload commands

* Add to reload_types
2023-07-31 19:58:57 -05:00
Alex King 063d4fbd1a [Bug Fix] Fix #gm top level alias for #set gm (#3517)
# Notes
- Typo lead to `#gm on` and `#gm off` not functioning.
2023-07-30 13:20:17 -04:00
Akkadius c25cb0cc23 [Release] 22.22.1 2023-07-30 01:36:49 -05:00
Chris Miles ddac326239 [Doors] Add door blacklist (#3516)
* [Doors] Add door blacklist

* Renaming to simplify
2023-07-30 01:35:44 -05:00
Akkadius 14fe396510 [Database] Hotfix: Add command_subsettings to server tables 2023-07-28 22:22:43 -05:00
Chris Miles c968a0acdc [Release] 22.22.0 (#3513)
* [Release] 22.22.0

* Version other areas
2023-07-28 11:35:40 -05:00
Alex King 8c4cd34e01 [Quest API] Add GetMobTypeIdentifier() to Perl/Lua (#3512)
# Perl
- Add `$mob->GetMobTypeIdentifier()`.

# Lua
- Add `mob:GetMobTypeIdentifier()`.

# Notes
- Gets unique identifier independent of mob type.
2023-07-27 23:16:41 -05:00
Akkadius 0dbcf83a11 [Database] Fix console output in database:dump --dump-output-to-console 2023-07-25 11:45:26 -05:00
Alex King a75648f73f [Data Buckets] Distributed Databucket Caching (#3500)
* [Data Buckets] Zone-Based Data Bucket Caching

# Notes
- Adds a data bucket cache so we're not needlessly hitting the database every time we need to read a data bucket value.

* Cleanup and unify GetData access patterns

* Cache work

* Push

* Add to cache when we fetch and do a db hit

* Handle bucket misses in cache

* Formatting

* Logging

* [Data Buckets] Zone-Based Data Bucket Caching

- Adds a data bucket cache so we're not needlessly hitting the database every time we need to read a data bucket value.

* Cleanup and unify GetData access patterns

* Cache work

* Push

* Add to cache when we fetch and do a db hit

* Handle bucket misses in cache

* Formatting

* Remove redundant fetches from cache since GetData does the same thing

* Push progress

* Distributed cache work

* Logging

* Fix issue with scoping where same named keys could return overlapping results

* Misses cache tweak, logging, comments

* Add bot, client, and NPC bucket methods to Lua.

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-07-24 12:22:50 -05:00
Alex King 6c2886a71d [Cleanup] Fix casing in corpse money and decay time. (#3511)
# Notes
- These were uppercase and should be lowercase.
2023-07-23 16:19:07 -04:00
Alex King 1d96ddb60d [Bug Fix] Escape search string in #find item (#3510) 2023-07-22 18:20:00 -04:00
Vayle c30074be66 [Crash Fix] Guard against Spells:MaxTotalSlotsPET being set above client allowed maximum. (#3507)
* Guard against MaxTotalSlotsPET being set too high

This prevents a crash from MaxTotalSlotsPET being set too high.

* Tweak
2023-07-22 10:20:22 -04:00
62 changed files with 2003 additions and 813 deletions
+56
View File
@@ -1,3 +1,59 @@
## [22.23.0] - 07/31/2023
### Databuckets
* Improvements to distributed cache, reload commands ([#3519](https://github.com/EQEmu/Server/pull/3519)) @Akkadius 2023-08-01
### Fixes
* Fix #gm top level alias for #set gm ([#3517](https://github.com/EQEmu/Server/pull/3517)) @Kinglykrab 2023-07-30
* Fix Appearance Issues ([#3520](https://github.com/EQEmu/Server/pull/3520)) @Kinglykrab 2023-08-01
* Fix NPC Cast Events not parsing properly. ([#3518](https://github.com/EQEmu/Server/pull/3518)) @Kinglykrab 2023-08-01
### Scaling/Bug Fix
* Scaling where min and max damage was bugged ([#3514](https://github.com/EQEmu/Server/pull/3514)) @noudess 2023-08-01
## [22.22.1] - 07/30/2023
### Database
* Hotfix: Add command_subsettings to server tables @Akkadius 2023-07-29
### Doors
* Add door blacklist ([#3516](https://github.com/EQEmu/Server/pull/3516)) @Akkadius 2023-07-30
## [22.22.0] - 07/27/2023
### Code
* Fix casing in corpse money and decay time. ([#3511](https://github.com/EQEmu/Server/pull/3511)) @Kinglykrab 2023-07-23
### Crash Fix
* Guard against Spells:MaxTotalSlotsPET being set above client allowed maximum. ([#3507](https://github.com/EQEmu/Server/pull/3507)) @Valorith 2023-07-22
### Data Buckets
* Distributed Databucket Caching ([#3500](https://github.com/EQEmu/Server/pull/3500)) @Kinglykrab 2023-07-24
### Database
* Fix console output in database:dump --dump-output-to-console @Akkadius 2023-07-25
### Fixes
* Escape search string in #find item ([#3510](https://github.com/EQEmu/Server/pull/3510)) @Kinglykrab 2023-07-22
### Quest API
* Add GetMobTypeIdentifier() to Perl/Lua ([#3512](https://github.com/EQEmu/Server/pull/3512)) @Kinglykrab 2023-07-28
### Saylink
* Fix cases where saylinks were not being cached ([#3508](https://github.com/EQEmu/Server/pull/3508)) @Akkadius 2023-07-20
## [22.21.2] - 07/19/2023
### Databuckets
+3 -1
View File
@@ -324,7 +324,9 @@ void DatabaseDumpService::DatabaseDump()
}
}
LogSys.LoadLogSettingsDefaults();
if (!IsDumpOutputToConsole()) {
LogSys.LoadLogSettingsDefaults();
}
if (!pipe_file.empty()) {
std::string file = fmt::format("{}.sql", GetDumpFileNameWithPath());
+1
View File
@@ -258,6 +258,7 @@ namespace DatabaseSchema {
"chatchannels",
"chatchannel_reserved_names",
"command_settings",
"command_subsettings",
"content_flags",
"db_str",
"eqtime",
+2
View File
@@ -137,6 +137,7 @@ namespace Logs {
Bugs,
QuestErrors,
PlayerEvents,
DataBuckets,
MaxCategoryID /* Don't Remove this */
};
@@ -233,6 +234,7 @@ namespace Logs {
"Bugs",
"QuestErrors",
"PlayerEvents",
"DataBuckets",
};
}
+10
View File
@@ -794,6 +794,16 @@
OutF(LogSys, Logs::Detail, Logs::PlayerEvents, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogDataBuckets(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::DataBuckets))\
OutF(LogSys, Logs::General, Logs::DataBuckets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogDataBucketsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::DataBuckets))\
OutF(LogSys, Logs::Detail, Logs::DataBuckets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
+4 -2
View File
@@ -1594,11 +1594,13 @@ float GetRaceGenderDefaultHeight(int race, int gender)
const auto size = sizeof(male_height) / sizeof(male_height[0]);
if (race >= size)
if (race >= size) {
return 6.0f;
}
if (gender == 1)
if (gender == FEMALE) {
return female_height[race];
}
return male_height[race];
}
@@ -15,7 +15,7 @@
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
#include <cereal/cereal.hpp>
class BaseDataBucketsRepository {
public:
@@ -27,6 +27,21 @@ public:
int64_t character_id;
int64_t npc_id;
int64_t bot_id;
// cereal
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(id),
CEREAL_NVP(key_),
CEREAL_NVP(value),
CEREAL_NVP(expires),
CEREAL_NVP(character_id),
CEREAL_NVP(npc_id),
CEREAL_NVP(bot_id)
);
}
};
static std::string PrimaryKey()
+1 -1
View File
@@ -53,7 +53,7 @@ public:
auto query = fmt::format(
"SELECT `id` FROM {} WHERE LOWER(`name`) LIKE '%%{}%%' ORDER BY id ASC",
TableName(),
search_string
Strings::Escape(search_string)
);
if (query_limit >= 1) {
+8
View File
@@ -249,6 +249,7 @@
#define ServerOP_ReloadZonePoints 0x4122
#define ServerOP_ReloadDzTemplates 0x4123
#define ServerOP_ReloadZoneData 0x4124
#define ServerOP_ReloadDataBucketsCache 0x4125
#define ServerOP_CZDialogueWindow 0x4500
#define ServerOP_CZLDoNUpdate 0x4501
@@ -286,6 +287,8 @@
// player events
#define ServerOP_PlayerEvent 0x5100
#define ServerOP_DataBucketCacheUpdate 0x5200
enum {
CZUpdateType_Character,
CZUpdateType_Group,
@@ -1820,6 +1823,11 @@ struct ServerSendPlayerEvent_Struct {
char cereal_data[0];
};
struct ServerDataBucketCacheUpdate_Struct {
uint32_t cereal_size;
char cereal_data[0];
};
struct ServerFlagUpdate_Struct {
uint32 account_id;
int16 admin;
+1 -1
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.21.2-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.23.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.21.2",
"version": "22.23.0",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
@@ -112,6 +112,7 @@ if ($requested_table_to_generate ne "all") {
}
my @cereal_enabled_tables = (
"data_buckets",
"player_event_logs"
);
+1
View File
@@ -138,6 +138,7 @@ std::vector<Reload> reload_types = {
Reload{.command = "alternate_currencies", .opcode = ServerOP_ReloadAlternateCurrencies, .desc = "Alternate Currencies"},
Reload{.command = "blocked_spells", .opcode = ServerOP_ReloadBlockedSpells, .desc = "Blocked Spells"},
Reload{.command = "commands", .opcode = ServerOP_ReloadCommands, .desc = "Commands"},
Reload{.command = "data_buckets_cache", .opcode = ServerOP_ReloadDataBucketsCache, .desc = "Data Buckets Cache"},
Reload{.command = "doors", .opcode = ServerOP_ReloadDoors, .desc = "Doors"},
Reload{.command = "dztemplates", .opcode = ServerOP_ReloadDzTemplates, .desc = "Dynamic Zone Templates"},
Reload{.command = "ground_spawns", .opcode = ServerOP_ReloadGroundSpawns, .desc = "Ground Spawns"},
+7
View File
@@ -46,6 +46,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/repositories/player_event_logs_repository.h"
#include "../common/events/player_event_logs.h"
#include "../common/patches/patches.h"
#include "../zone/data_bucket.h"
extern ClientList client_list;
extern GroupLFPList LFPGroupList;
@@ -1342,6 +1343,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
case ServerOP_ReloadBlockedSpells:
case ServerOP_ReloadCommands:
case ServerOP_ReloadDoors:
case ServerOP_ReloadDataBucketsCache:
case ServerOP_ReloadGroundSpawns:
case ServerOP_ReloadLevelEXPMods:
case ServerOP_ReloadMerchants:
@@ -1468,6 +1470,11 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
DynamicZone::HandleZoneMessage(pack);
break;
}
case ServerOP_DataBucketCacheUpdate: {
zoneserver_list.SendPacket(pack);
break;
}
default: {
LogInfo("Unknown ServerOPcode from zone {:#04x}, size [{}]", pack->opcode, pack->size);
DumpPacket(pack->pBuffer, pack->size);
+1 -1
View File
@@ -6036,7 +6036,7 @@ float Mob::CheckHeroicBonusesDataBuckets(std::string bucket_name)
DataBucketKey k = GetScopedBucketKeys();
k.key = bucket_name;
if (IsOfClientBot()) {
bucket_value = DataBucket::CheckBucketKey(this, k);
bucket_value = DataBucket::GetData(k).value;
}
if (bucket_value.empty() || !Strings::IsNumber(bucket_value)) {
+44 -21
View File
@@ -268,26 +268,48 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
case SE_IllusionCopy:
case SE_Illusion: {
if (spell.base_value[x1] == -1) {
if (gender == 1)
gender = 0;
else if (gender == 0)
gender = 1;
SendIllusionPacket(GetRace(), gender, 0xFF, 0xFF);
}
else if (spell.base_value[x1] == -2) // WTF IS THIS
if (gender == FEMALE) {
gender = MALE;
} else if (gender == MALE) {
gender = FEMALE;
}
SendIllusionPacket(
AppearanceStruct{
.gender_id = gender,
.race_id = GetRace(),
}
);
} else if (spell.base_value[x1] == -2) // WTF IS THIS
{
if (GetRace() == IKSAR || GetRace() == VAHSHIR || GetRace() <= GNOME) {
SendIllusionPacket(GetRace(), GetGender(), spell.limit_value[x1], spell.max_value[x1]);
SendIllusionPacket(
AppearanceStruct{
.gender_id = GetGender(),
.helmet_texture = static_cast<uint8>(spell.max_value[x1]),
.race_id = GetRace(),
.texture = static_cast<uint8>(spell.limit_value[x1]),
}
);
}
} else if (spell.max_value[x1] > 0) {
SendIllusionPacket(
AppearanceStruct{
.helmet_texture = static_cast<uint8>(spell.max_value[x1]),
.race_id = static_cast<uint16>(spell.base_value[x1]),
.texture = static_cast<uint8>(spell.limit_value[x1]),
}
);
} else {
SendIllusionPacket(
AppearanceStruct{
.helmet_texture = static_cast<uint8>(spell.max_value[x1]),
.race_id = static_cast<uint16>(spell.base_value[x1]),
.texture = static_cast<uint8>(spell.limit_value[x1]),
}
);
}
else if (spell.max_value[x1] > 0)
{
SendIllusionPacket(spell.base_value[x1], 0xFF, spell.limit_value[x1], spell.max_value[x1]);
}
else
{
SendIllusionPacket(spell.base_value[x1], 0xFF, 0xFF, 0xFF);
}
switch (spell.base_value[x1]) {
case OGRE:
SendAppearancePacket(AT_Size, 9);
@@ -427,6 +449,7 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
Bot::~Bot() {
AI_Stop();
LeaveHealRotationMemberPool();
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Bot, GetBotID());
if (HasPet()) {
GetPet()->Depop();
@@ -8197,18 +8220,18 @@ bool Bot::CheckDataBucket(std::string bucket_name, const std::string& bucket_val
DataBucketKey k = GetScopedBucketKeys();
k.key = bucket_name;
auto player_value = DataBucket::CheckBucketKey(this, k);
if (player_value.empty() && GetBotOwner()) {
auto b = DataBucket::GetData(k);
if (b.value.empty() && GetBotOwner()) {
// fetch from owner
k = GetBotOwner()->GetScopedBucketKeys();
player_value = DataBucket::CheckBucketKey(GetBotOwner(), k);
if (player_value.empty()) {
b = DataBucket::GetData(k);
if (b.value.empty()) {
return false;
}
}
if (zone->CompareDataBucket(bucket_comparison, bucket_value, player_value)) {
if (zone->CompareDataBucket(bucket_comparison, bucket_value, b.value)) {
return true;
}
}
+22 -19
View File
@@ -63,6 +63,7 @@
#include "water_map.h"
#include "worldserver.h"
#include "dialogue_window.h"
#include "mob.h"
#include <fmt/format.h>
@@ -8819,26 +8820,28 @@ void helper_bot_appearance_form_final(Client *bot_owner, Bot *my_bot)
void helper_bot_appearance_form_update(Bot *my_bot)
{
if (!my_bot)
if (!my_bot) {
return;
}
my_bot->SendIllusionPacket(
my_bot->GetRace(),
my_bot->GetGender(),
0xFF, //my_bot->GetTexture(), // 0xFF - change back if issues arise
0xFF, //my_bot->GetHelmTexture(), // 0xFF - change back if issues arise
my_bot->GetHairColor(),
my_bot->GetBeardColor(),
my_bot->GetEyeColor1(),
my_bot->GetEyeColor2(),
my_bot->GetHairStyle(),
my_bot->GetLuclinFace(),
my_bot->GetBeard(),
0xFF, // aa_title (0xFF)
my_bot->GetDrakkinHeritage(),
my_bot->GetDrakkinTattoo(),
my_bot->GetDrakkinDetails(),
my_bot->GetSize()
AppearanceStruct{
.beard = my_bot->GetBeard(),
.beard_color = my_bot->GetBeardColor(),
.drakkin_details = my_bot->GetDrakkinDetails(),
.drakkin_heritage = my_bot->GetDrakkinHeritage(),
.drakkin_tattoo = my_bot->GetDrakkinTattoo(),
.eye_color_one = my_bot->GetEyeColor1(),
.eye_color_two = my_bot->GetEyeColor2(),
.face = my_bot->GetLuclinFace(),
.gender_id = my_bot->GetGender(),
.hair = my_bot->GetHairStyle(),
.hair_color = my_bot->GetHairColor(),
.helmet_texture = my_bot->GetHelmTexture(),
.race_id = my_bot->GetRace(),
.size = my_bot->GetSize(),
.texture = my_bot->GetTexture(),
}
);
}
@@ -10002,7 +10005,7 @@ void bot_command_pickpocket(Client *c, const Seperator *sep)
if (helper_command_disabled(c, RuleB(Bots, AllowPickpocketCommand), "pickpocket")) {
return;
}
if (helper_command_alias_fail(c, "bot_command_pickpocket", sep->arg[0], "pickpocket")) {
return;
}
@@ -10037,7 +10040,7 @@ void bot_command_pickpocket(Client *c, const Seperator *sep)
float mob_xy_distance = ((mob_distance.x * mob_distance.x) + (mob_distance.y * mob_distance.y));
float mob_z_distance = (mob_distance.z * mob_distance.z);
float z_offset_diff = target_mob->GetZOffset() - c->GetZOffset();
if (mob_z_distance >= (35-z_offset_diff) || mob_xy_distance > 250) {
c->Message(Chat::White, "You must be closer to an enemy to use this command");
return;
+14 -1
View File
@@ -381,6 +381,8 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
Client::~Client() {
mMovementManager->RemoveClient(this);
DataBucket::DeleteCachedBuckets(DataBucketLoadType::Client, CharacterID());
if (RuleB(Bots, Enabled)) {
Bot::ProcessBotOwnerRefDelete(this);
}
@@ -8881,7 +8883,8 @@ void Client::ShowDevToolsMenu()
menu_reload_two += Saylink::Silent("#reload commands", "Commands");
menu_reload_two += " | " + Saylink::Silent("#reload content_flags", "Content Flags");
menu_reload_three += Saylink::Silent("#reload doors", "Doors");
menu_reload_three += Saylink::Silent("#reload data_buckets_cache", "Databuckets");
menu_reload_three += " | " + Saylink::Silent("#reload doors", "Doors");
menu_reload_three += " | " + Saylink::Silent("#reload ground_spawns", "Ground Spawns");
menu_reload_four += Saylink::Silent("#reload logs", "Level Based Experience Modifiers");
@@ -10835,6 +10838,16 @@ void Client::SendReloadCommandMessages() {
).c_str()
);
auto data_buckets_link = Saylink::Silent("#reload data_buckets_cache");
Message(
Chat::White,
fmt::format(
"Usage: {} - Reloads data buckets cache globally",
data_buckets_link
).c_str()
);
auto dztemplates_link = Saylink::Silent("#reload dztemplates");
Message(Chat::White, fmt::format("Usage: {} - Reloads Dynamic Zone Templates globally", dztemplates_link).c_str());
+2 -2
View File
@@ -5224,12 +5224,12 @@ void Client::Handle_OP_ConsiderCorpse(const EQApplicationPacket *app)
uint32 decay_time = t->GetDecayTime();
if (decay_time) {
auto time_string = Strings::SecondsToTime(decay_time, true);
const std::string& time_string = Strings::SecondsToTime(decay_time, true);
Message(
Chat::NPCQuestSay,
fmt::format(
"This corpse will decay in {}.",
time_string
Strings::ToLower(time_string)
).c_str()
);
+3 -3
View File
@@ -857,12 +857,12 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
DataBucketKey k = GetScopedBucketKeys();
k.key = bucket_name;
auto const& player_value = DataBucket::CheckBucketKey(this, k);
if (player_value.empty()) {
auto b = DataBucket::GetData(k);
if (b.value.empty()) {
continue;
}
if (!zone->CompareDataBucket(ml.bucket_comparison, bucket_value, player_value)) {
if (!zone->CompareDataBucket(ml.bucket_comparison, bucket_value, b.value)) {
continue;
}
}
+1
View File
@@ -30,6 +30,7 @@ uint8 GetCommandStatus(std::string command_name);
void ListModifyNPCStatMap(Client *c);
std::map<std::string, std::string> GetModifyNPCStatMap();
std::string GetModifyNPCStatDescription(std::string stat);
void SendFeatureSubCommands(Client *c);
void SendNPCEditSubCommands(Client *c);
void SendRuleSubCommands(Client *c);
void SendGuildSubCommands(Client *c);
+2 -2
View File
@@ -1207,7 +1207,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
client->Message(
Chat::Yellow,
fmt::format(
"This corpse Contains {}.",
"This corpse contains {}.",
Strings::Money(
GetPlatinum(),
GetGold(),
@@ -1217,7 +1217,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
).c_str()
);
} else {
client->Message(Chat::Yellow, "This corpse Contains no money.");
client->Message(Chat::Yellow, "This corpse contains no money.");
}
auto outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct));
+506 -53
View File
@@ -1,9 +1,14 @@
#include "data_bucket.h"
#include "entity.h"
#include "zonedb.h"
#include "mob.h"
#include "worldserver.h"
#include <ctime>
#include <cctype>
#include "../common/repositories/data_buckets_repository.h"
extern WorldServer worldserver;
std::vector<DataBucketCacheEntry> g_data_bucket_cache = {};
void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time)
{
@@ -22,40 +27,67 @@ void DataBucket::SetData(const std::string &bucket_key, const std::string &bucke
void DataBucket::SetData(const DataBucketKey &k)
{
auto b = DataBucketsRepository::NewEntity();
auto r = GetData(k);
auto r = GetData(k, true);
// if we have an entry, use it
if (r.id > 0) {
b = r;
}
// add scoping to bucket
if (k.character_id > 0) {
b.character_id = k.character_id;
} else if (k.npc_id > 0) {
}
else if (k.npc_id > 0) {
b.npc_id = k.npc_id;
} else if (k.bot_id > 0) {
}
else if (k.bot_id > 0) {
b.bot_id = k.bot_id;
}
uint64 bucket_id = b.id;
long long expires_time_unix = 0;
const uint64 bucket_id = b.id;
int64 expires_time_unix = 0;
if (!k.expires.empty()) {
expires_time_unix = (long long) std::time(nullptr) + Strings::ToInt(k.expires);
expires_time_unix = static_cast<int64>(std::time(nullptr)) + Strings::ToInt(k.expires);
if (isalpha(k.expires[0]) || isalpha(k.expires[k.expires.length() - 1])) {
expires_time_unix = (long long) std::time(nullptr) + Strings::TimeToSeconds(k.expires);
expires_time_unix = static_cast<int64>(std::time(nullptr)) + Strings::TimeToSeconds(k.expires);
}
}
if (bucket_id > 0) {
b.expires = expires_time_unix;
b.value = k.value;
b.expires = expires_time_unix;
b.value = k.value;
if (bucket_id) {
// loop cache and update cache value and timestamp
for (auto &ce: g_data_bucket_cache) {
if (CheckBucketMatch(ce.e, k)) {
ce.e = b;
ce.updated_time = GetCurrentTimeUNIX();
ce.update_action = DataBucketCacheUpdateAction::Upsert;
SendDataBucketCacheUpdate(ce);
break;
}
}
DataBucketsRepository::UpdateOne(database, b);
}
else {
b.expires = expires_time_unix;
b.key_ = k.key;
b.value = k.value;
DataBucketsRepository::InsertOne(database, b);
b.key_ = k.key;
b = DataBucketsRepository::InsertOne(database, b);
if (!ExistsInCache(b)) {
// add data bucket and timestamp to cache
auto ce = DataBucketCacheEntry{
.e = b,
.updated_time = DataBucket::GetCurrentTimeUNIX(),
.update_action = DataBucketCacheUpdateAction::Upsert
};
g_data_bucket_cache.emplace_back(ce);
SendDataBucketCacheUpdate(ce);
DeleteFromMissesCache(b);
}
}
}
@@ -66,8 +98,39 @@ std::string DataBucket::GetData(const std::string &bucket_key)
return GetData(k).value;
}
DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k)
// GetData fetches bucket data from the database or cache if it exists
// if the bucket doesn't exist, it will be added to the cache as a miss
// if ignore_misses_cache is true, the bucket will not be added to the cache as a miss
// the only place we should be ignoring the misses cache is on the initial read during SetData
DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, bool ignore_misses_cache)
{
LogDataBuckets(
"Getting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
k.key,
k.bot_id,
k.character_id,
k.npc_id
);
for (const auto &ce: g_data_bucket_cache) {
if (CheckBucketMatch(ce.e, k)) {
if (ce.e.expires > 0 && ce.e.expires < std::time(nullptr)) {
LogDataBuckets("Attempted to read expired key [{}] removing from cache", ce.e.key_);
DeleteData(k);
return DataBucketsRepository::NewEntity();
}
// this is a bucket miss, return empty entity
// we still cache bucket misses, so we don't have to hit the database
if (ce.e.id == 0) {
return DataBucketsRepository::NewEntity();
}
LogDataBuckets("Returning key [{}] value [{}] from cache", ce.e.key_, ce.e.value);
return ce.e;
}
}
auto r = DataBucketsRepository::GetWhere(
database,
fmt::format(
@@ -78,6 +141,40 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k)
);
if (r.empty()) {
// if we're ignoring the misses cache, don't add to the cache
// the only place this is ignored is during the initial read of SetData
if (!ignore_misses_cache) {
size_t size_before = g_data_bucket_cache.size();
// cache bucket misses, so we don't have to hit the database
// when scripts try to read a bucket that doesn't exist
g_data_bucket_cache.emplace_back(
DataBucketCacheEntry{
.e = DataBucketsRepository::DataBuckets{
.id = 0,
.key_ = k.key,
.value = "",
.expires = 0,
.character_id = k.character_id,
.npc_id = k.npc_id,
.bot_id = k.bot_id
},
.updated_time = DataBucket::GetCurrentTimeUNIX()
}
);
LogDataBuckets(
"Key [{}] not found in database, adding to cache as a miss character_id [{}] npc_id [{}] bot_id [{}] cache size before [{}] after [{}]",
k.key,
k.character_id,
k.npc_id,
k.bot_id,
size_before,
g_data_bucket_cache.size()
);
}
return {};
}
@@ -87,6 +184,24 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k)
return {};
}
bool has_cache = false;
for (auto &ce: g_data_bucket_cache) {
if (ce.e.id == r[0].id) {
has_cache = true;
break;
}
}
if (!has_cache) {
// add data bucket and timestamp to cache
g_data_bucket_cache.emplace_back(
DataBucketCacheEntry{
.e = r[0],
.updated_time = DataBucket::GetCurrentTimeUNIX()
}
);
}
return r[0];
}
@@ -107,57 +222,68 @@ std::string DataBucket::GetDataRemaining(const std::string &bucket_key)
bool DataBucket::DeleteData(const std::string &bucket_key)
{
DataBucketKey r = {};
r.key = bucket_key;
return DeleteData(r);
DataBucketKey k = {};
k.key = bucket_key;
return DeleteData(k);
}
// GetDataBuckets bulk loads all data buckets for a mob
bool DataBucket::GetDataBuckets(Mob *mob)
{
DataBucketKey k = mob->GetScopedBucketKeys();
auto l = BaseDataBucketsRepository::GetWhere(
database,
fmt::format(
"{} (`expires` > {} OR `expires` = 0)",
DataBucket::GetScopedDbFilters(k),
(long long) std::time(nullptr)
)
);
DataBucketLoadType::Type t;
const uint32 id = mob->GetMobTypeIdentifier();
if (l.empty()) {
if (!id) {
return false;
}
mob->m_data_bucket_cache.clear();
DataBucketCache d;
for (const auto &e: l) {
d.bucket_id = e.id;
d.bucket_key = e.key_;
d.bucket_value = e.value;
d.bucket_expires = e.expires;
mob->m_data_bucket_cache.emplace_back(d);
if (mob->IsBot()) {
t = DataBucketLoadType::Bot;
}
else if (mob->IsClient()) {
t = DataBucketLoadType::Client;
}
else if (mob->IsNPC()) {
t = DataBucketLoadType::NPC;
}
BulkLoadEntities(t, {id});
return true;
}
std::string DataBucket::CheckBucketKey(const Mob *mob, const DataBucketKey &k)
{
std::string bucket_value;
for (const auto &d: mob->m_data_bucket_cache) {
if (d.bucket_key == k.key) {
bucket_value = d.bucket_value;
break;
}
}
return bucket_value;
}
bool DataBucket::DeleteData(const DataBucketKey &k)
{
size_t size_before = g_data_bucket_cache.size();
// delete from cache where contents match
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketCacheEntry &ce) {
bool match = CheckBucketMatch(ce.e, k);
if (match) {
ce.update_action = DataBucketCacheUpdateAction::Delete;
SendDataBucketCacheUpdate(ce);
}
return match;
}
),
g_data_bucket_cache.end()
);
LogDataBuckets(
"Deleting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
k.key,
k.bot_id,
k.character_id,
k.npc_id,
size_before,
g_data_bucket_cache.size()
);
return DataBucketsRepository::DeleteWhere(
database,
fmt::format(
@@ -170,16 +296,32 @@ bool DataBucket::DeleteData(const DataBucketKey &k)
std::string DataBucket::GetDataExpires(const DataBucketKey &k)
{
LogDataBuckets(
"Getting bucket expiration key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
k.key,
k.bot_id,
k.character_id,
k.npc_id
);
auto r = GetData(k);
if (r.id == 0) {
return {};
}
return fmt::format("{}", r.expires);
return std::to_string(r.expires);
}
std::string DataBucket::GetDataRemaining(const DataBucketKey &k)
{
LogDataBuckets(
"Getting bucket remaining key [{}] bot_id [{}] character_id [{}] npc_id [{}]",
k.key,
k.bot_id,
k.character_id,
k.npc_id
);
auto r = GetData(k);
if (r.id == 0) {
return "0";
@@ -218,3 +360,314 @@ std::string DataBucket::GetScopedDbFilters(const DataBucketKey &k)
!query.empty() ? "AND" : ""
);
}
bool DataBucket::CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe, const DataBucketKey &k)
{
return (
dbe.key_ == k.key &&
dbe.bot_id == k.bot_id &&
dbe.character_id == k.character_id &&
dbe.npc_id == k.npc_id
);
}
void DataBucket::BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32> ids)
{
if (ids.empty()) {
return;
}
if (ids.size() == 1) {
bool has_cache = false;
for (const auto &ce: g_data_bucket_cache) {
if (t == DataBucketLoadType::Bot) {
has_cache = ce.e.bot_id == ids[0];
}
else if (t == DataBucketLoadType::Client) {
has_cache = ce.e.character_id == ids[0];
}
else if (t == DataBucketLoadType::NPC) {
has_cache = ce.e.npc_id == ids[0];
}
}
if (has_cache) {
LogDataBucketsDetail("LoadType [{}] ID [{}] has cache", DataBucketLoadType::Name[t], ids[0]);
return;
}
}
std::string column;
switch (t) {
case DataBucketLoadType::Bot:
column = "bot_id";
break;
case DataBucketLoadType::Client:
column = "character_id";
break;
case DataBucketLoadType::NPC:
column = "npc_id";
break;
default:
LogError("Incorrect LoadType [{}]", t);
break;
}
const auto &l = DataBucketsRepository::GetWhere(
database,
fmt::format(
"{} IN ({}) AND (`expires` > {} OR `expires` = 0)",
column,
Strings::Join(ids, ", "),
(long long) std::time(nullptr)
)
);
if (l.empty()) {
return;
}
size_t size_before = g_data_bucket_cache.size();
LogDataBucketsDetail("cache size before [{}] l size [{}]", g_data_bucket_cache.size(), l.size());
uint32 added_count = 0;
for (const auto &e: l) {
if (!ExistsInCache(e)) {
added_count++;
}
}
g_data_bucket_cache.reserve(g_data_bucket_cache.size() + added_count);
for (const auto &e: l) {
if (!ExistsInCache(e)) {
LogDataBucketsDetail("bucket id [{}] bucket key [{}] bucket value [{}]", e.id, e.key_, e.value);
g_data_bucket_cache.emplace_back(
DataBucketCacheEntry{
.e = e,
.updated_time = GetCurrentTimeUNIX()
}
);
}
}
LogDataBucketsDetail("cache size after [{}]", g_data_bucket_cache.size());
LogDataBuckets(
"Bulk Loaded ids [{}] column [{}] new cache size is [{}]",
ids.size(),
column,
g_data_bucket_cache.size()
);
}
void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id)
{
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketCacheEntry &ce) {
return (
(t == DataBucketLoadType::Bot && ce.e.bot_id == id) ||
(t == DataBucketLoadType::Client && ce.e.character_id == id) ||
(t == DataBucketLoadType::NPC && ce.e.npc_id == id)
);
}
),
g_data_bucket_cache.end()
);
LogDataBuckets(
"LoadType [{}] id [{}] cache size before [{}] after [{}]",
DataBucketLoadType::Name[t],
id,
size_before,
g_data_bucket_cache.size()
);
}
int64_t DataBucket::GetCurrentTimeUNIX()
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count();
}
bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &e)
{
for (const auto &ce: g_data_bucket_cache) {
if (ce.e.id == e.id) {
return true;
}
}
return false;
}
bool DataBucket::SendDataBucketCacheUpdate(const DataBucketCacheEntry &e)
{
if (!e.e.id) {
return false;
}
EQ::Net::DynamicPacket p;
p.PutSerialize(0, e);
auto pack_size = sizeof(ServerDataBucketCacheUpdate_Struct) + p.Length();
auto pack = new ServerPacket(ServerOP_DataBucketCacheUpdate, static_cast<uint32_t>(pack_size));
auto buf = reinterpret_cast<ServerDataBucketCacheUpdate_Struct *>(pack->pBuffer);
buf->cereal_size = static_cast<uint32_t>(p.Length());
memcpy(buf->cereal_data, p.Data(), p.Length());
worldserver.SendPacket(pack);
return true;
}
void DataBucket::HandleWorldMessage(ServerPacket *p)
{
DataBucketCacheEntry n;
auto s = (ServerDataBucketCacheUpdate_Struct *) p->pBuffer;
EQ::Util::MemoryStreamReader ss(s->cereal_data, s->cereal_size);
cereal::BinaryInputArchive archive(ss);
archive(n);
LogDataBucketsDetail(
"Received cache packet for id [{}] key [{}] value [{}] action [{}]",
n.e.id,
n.e.key_,
n.e.value,
n.update_action
);
// delete
if (n.update_action == DataBucketCacheUpdateAction::Delete) {
DeleteFromMissesCache(n.e);
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketCacheEntry &ce) {
bool match = n.e.id > 0 && ce.e.id == n.e.id;
if (match) {
LogDataBuckets(
"[delete] cache key [{}] id [{}] cache_size before [{}] after [{}]",
ce.e.key_,
ce.e.id,
g_data_bucket_cache.size(),
g_data_bucket_cache.size() - 1
);
}
return match;
}
),
g_data_bucket_cache.end()
);
return;
}
// update
bool has_key = false;
for (auto &ce: g_data_bucket_cache) {
// update cache
if (ce.e.id == n.e.id) {
// reject old updates
int64 time_delta = ce.updated_time - n.updated_time;
if (ce.updated_time >= n.updated_time) {
LogDataBuckets(
"Attempted to update older cache key [{}] rejecting old time [{}] new time [{}] delta [{}] cache_size [{}]",
ce.e.key_,
ce.updated_time,
n.updated_time,
time_delta,
g_data_bucket_cache.size()
);
return;
}
DeleteFromMissesCache(n.e);
LogDataBuckets(
"[update] cache id [{}] key [{}] value [{}] old time [{}] new time [{}] delta [{}] cache_size [{}]",
ce.e.id,
ce.e.key_,
n.e.value,
ce.updated_time,
n.updated_time,
time_delta,
g_data_bucket_cache.size()
);
ce.e = n.e;
ce.updated_time = n.updated_time;
has_key = true;
break;
}
}
// create
if (!has_key) {
DeleteFromMissesCache(n.e);
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.emplace_back(
DataBucketCacheEntry{
.e = n.e,
.updated_time = GetCurrentTimeUNIX()
}
);
LogDataBuckets(
"[create] Adding new cache id [{}] key [{}] value [{}] cache size before [{}] after [{}]",
n.e.id,
n.e.key_,
n.e.value,
size_before,
g_data_bucket_cache.size()
);
}
}
void DataBucket::DeleteFromMissesCache(DataBucketsRepository::DataBuckets e)
{
// delete from cache where there might have been a written bucket miss to the cache
// this is to prevent the cache from growing too large
size_t size_before = g_data_bucket_cache.size();
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketCacheEntry &ce) {
return ce.e.id == 0 && ce.e.key_ == e.key_ &&
ce.e.character_id == e.character_id &&
ce.e.npc_id == e.npc_id &&
ce.e.bot_id == e.bot_id;
}
),
g_data_bucket_cache.end()
);
LogDataBucketsDetail(
"Deleted bucket misses from cache where key [{}] size before [{}] after [{}]",
e.key_,
size_before,
g_data_bucket_cache.size()
);
}
void DataBucket::ClearCache()
{
g_data_bucket_cache.clear();
LogInfo("Cleared data buckets cache");
}
+63 -13
View File
@@ -9,7 +9,29 @@
#include "../common/types.h"
#include "../common/repositories/data_buckets_repository.h"
#include "mob.h"
#include "../common/json/json_archive_single_line.h"
#include "../common/servertalk.h"
enum DataBucketCacheUpdateAction : uint8 {
Upsert,
Delete
};
struct DataBucketCacheEntry {
DataBucketsRepository::DataBuckets e;
int64_t updated_time{};
DataBucketCacheUpdateAction update_action{};
template<class Archive>
void serialize(Archive &ar)
{
ar(
CEREAL_NVP(e),
CEREAL_NVP(updated_time),
CEREAL_NVP(update_action)
);
}
};
struct DataBucketKey {
std::string key;
@@ -20,25 +42,53 @@ struct DataBucketKey {
int64_t bot_id;
};
namespace DataBucketLoadType {
enum Type : uint8 {
Bot,
Client,
NPC,
MaxType
};
static const std::string Name[Type::MaxType] = {
"Bot",
"Client",
"NPC",
};
}
class DataBucket {
public:
// non-scoped bucket methods (for global buckets)
static void SetData(const std::string& bucket_key, const std::string& bucket_value, std::string expires_time = "");
static bool DeleteData(const std::string& bucket_key);
static std::string GetData(const std::string& bucket_key);
static std::string GetDataExpires(const std::string& bucket_key);
static std::string GetDataRemaining(const std::string& bucket_key);
static void SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time = "");
static bool DeleteData(const std::string &bucket_key);
static std::string GetData(const std::string &bucket_key);
static std::string GetDataExpires(const std::string &bucket_key);
static std::string GetDataRemaining(const std::string &bucket_key);
static bool GetDataBuckets(Mob* mob);
static bool GetDataBuckets(Mob *mob);
static int64_t GetCurrentTimeUNIX();
// scoped bucket methods
static void SetData(const DataBucketKey& k);
static bool DeleteData(const DataBucketKey& k);
static DataBucketsRepository::DataBuckets GetData(const DataBucketKey& k);
static std::string GetDataExpires(const DataBucketKey& k);
static std::string GetDataRemaining(const DataBucketKey& k);
static std::string CheckBucketKey(const Mob* mob, const DataBucketKey& k);
static std::string GetScopedDbFilters(const DataBucketKey& k);
static void SetData(const DataBucketKey &k);
static bool DeleteData(const DataBucketKey &k);
static DataBucketsRepository::DataBuckets GetData(const DataBucketKey &k, bool ignore_misses_cache = false);
static std::string GetDataExpires(const DataBucketKey &k);
static std::string GetDataRemaining(const DataBucketKey &k);
static std::string GetScopedDbFilters(const DataBucketKey &k);
// bucket repository versus key matching
static bool CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe, const DataBucketKey &k);
static bool ExistsInCache(const DataBucketsRepository::DataBuckets &e);
static void BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32> ids);
static void DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id);
static bool SendDataBucketCacheUpdate(const DataBucketCacheEntry &e);
static void HandleWorldMessage(ServerPacket *p);
static void DeleteFromMissesCache(DataBucketsRepository::DataBuckets e);
static void ClearCache();
};
#endif //EQEMU_DATABUCKET_H
+26
View File
@@ -83,6 +83,8 @@ Doors::Doors(const DoorsRepository::Doors &door) :
m_close_timer.Disable();
m_disable_timer = (door.disable_timer == 1 ? true : false);
m_is_blacklisted_to_open = GetIsDoorBlacklisted();
}
Doors::Doors(const char *model, const glm::vec4 &position, uint8 open_type, uint16 size) :
@@ -901,3 +903,27 @@ bool Doors::IsDestinationZoneSame() const
{
return m_same_destination_zone;
}
// IsDoorBlacklisted has a static list of doors that are blacklisted
// from being opened by NPCs. This is used to prevent NPCs from opening
// doors that are not meant to be opened by NPCs.
bool Doors::GetIsDoorBlacklisted()
{
std::vector<std::string> blacklist = {
"TOGGLE",
"PNDRESSER101",
};
for (auto& name : blacklist) {
std::string door_name = GetDoorName();
if (name == door_name) {
return true;
}
}
return false;
}
bool Doors::IsDoorBlacklisted() {
return m_is_blacklisted_to_open;
}
+4
View File
@@ -69,7 +69,10 @@ public:
bool HasDestinationZone() const;
bool IsDestinationZoneSame() const;
bool IsDoorBlacklisted();
private:
bool GetIsDoorBlacklisted();
bool m_has_destination_zone = false;
bool m_same_destination_zone = false;
@@ -99,5 +102,6 @@ private:
uint8 m_is_ldon_door;
int m_dz_switch_id = 0;
uint32 m_client_version_mask;
bool m_is_blacklisted_to_open = false; // is door blacklisted to open by npcs
};
#endif
+9 -9
View File
@@ -1047,42 +1047,42 @@ void Perl__processmobswhilezoneempty(bool on)
quest_manager.processmobswhilezoneempty(on);
}
void Perl__npcrace(int race_id)
void Perl__npcrace(uint16 race_id)
{
quest_manager.npcrace(race_id);
}
void Perl__npcgender(int gender_id)
void Perl__npcgender(uint8 gender_id)
{
quest_manager.npcgender(gender_id);
}
void Perl__npcsize(int size)
void Perl__npcsize(float size)
{
quest_manager.npcsize(size);
}
void Perl__npctexture(int texture_id)
void Perl__npctexture(uint8 texture_id)
{
quest_manager.npctexture(texture_id);
}
void Perl__playerrace(int race_id)
void Perl__playerrace(uint16 race_id)
{
quest_manager.playerrace(race_id);
}
void Perl__playergender(int gender_id)
void Perl__playergender(uint8 gender_id)
{
quest_manager.playergender(gender_id);
}
void Perl__playersize(int newsize)
void Perl__playersize(float size)
{
quest_manager.playersize(newsize);
quest_manager.playersize(size);
}
void Perl__playertexture(int texture_id)
void Perl__playertexture(uint8 texture_id)
{
quest_manager.playertexture(texture_id);
}
+18 -17
View File
@@ -67,23 +67,24 @@ void command_appearanceeffects(Client *c, const Seperator *sep)
);
} else if (is_remove) {
t->SendIllusionPacket(
t->GetRace(),
t->GetGender(),
t->GetTexture(),
t->GetHelmTexture(),
t->GetHairColor(),
t->GetBeardColor(),
t->GetEyeColor1(),
t->GetEyeColor2(),
t->GetHairStyle(),
t->GetLuclinFace(),
t->GetBeard(),
0xFF,
t->GetDrakkinHeritage(),
t->GetDrakkinTattoo(),
t->GetDrakkinDetails(),
t->GetSize(),
false
AppearanceStruct{
.beard = t->GetBeard(),
.beard_color = t->GetBeardColor(),
.drakkin_details = t->GetDrakkinDetails(),
.drakkin_heritage = t->GetDrakkinHeritage(),
.drakkin_tattoo = t->GetDrakkinTattoo(),
.eye_color_one = t->GetEyeColor1(),
.eye_color_two = t->GetEyeColor2(),
.face = t->GetLuclinFace(),
.gender_id = t->GetGender(),
.hair = t->GetHairStyle(),
.hair_color = t->GetHairColor(),
.helmet_texture = t->GetHelmTexture(),
.race_id = t->GetRace(),
.send_effects = false,
.size = t->GetSize(),
.texture = t->GetTexture(),
}
);
t->ClearAppearenceEffects();
c->Message(
+116 -126
View File
@@ -2,55 +2,35 @@
void command_feature(Client *c, const Seperator *sep)
{
// nested command aliasing
std::string command = sep->arg[0] ? sep->arg[0] : "";
bool is_size_alias = sep->arg[0] && Strings::Contains(command, "#size");
bool is_nested_alias = (is_size_alias);
const bool is_size_alias = sep->arg[0] && Strings::Contains(command, "#size");
const bool is_nested_alias = is_size_alias;
int arguments = sep->argnum;
const auto arguments = sep->argnum;
if ((arguments < 2 || !sep->IsNumber(2)) && !is_nested_alias) {
auto feature_save_link = Saylink::Silent("#npcedit featuresave");
c->Message(Chat::White, "Usage: #feature beard [Beard] - Change your or your target's Beard");
c->Message(Chat::White, "Usage: #feature beardcolor [Beard Color] - Change your or your target's Beard Color");
c->Message(Chat::White, "Usage: #feature details [Details] - Change your or your target's Drakkin Details");
c->Message(Chat::White, "Usage: #feature eyes [Eye Color] - Change your or your target's Eyes");
c->Message(Chat::White, "Usage: #feature face [Face] - Change your or your target's Face");
c->Message(Chat::White, "Usage: #feature gender [Gender] - Change your or your target's Gender");
c->Message(Chat::White, "Usage: #feature hair [Hair] - Change your or your target's Hair");
c->Message(Chat::White, "Usage: #feature haircolor [Hair Color] - Change your or your target's Hair Color");
c->Message(Chat::White, "Usage: #feature helm [Helmet Texture] - Change your or your target's Helmet Texture");
c->Message(Chat::White, "Usage: #feature heritage [Heritage] - Change your or your target's Drakkin Heritage");
c->Message(Chat::White, "Usage: #feature race [Race ID] - Change your or your target's Race");
c->Message(Chat::White, "Usage: #feature size [Size] - Change your or your target's Size (Valid values are 0 to 255, decimal increments are allowed.)");
c->Message(Chat::White, "Usage: #feature tattoo [Tattoo] - Change your or your target's Drakkin Tattoos");
c->Message(Chat::White, "Usage: #feature texture [Texture] - Change your or your target's Texture");
c->Message(
Chat::White,
fmt::format(
"Note: All features are temporary. If your target is an NPC, you can save these features to the database using {}.",
feature_save_link
).c_str()
);
SendFeatureSubCommands(c);
return;
}
Mob* target = c->GetTarget() ? c->GetTarget() : c;
Mob* t = c;
if (c->GetTarget()) {
t = c->GetTarget();
}
bool is_beard = !strcasecmp(sep->arg[1], "beard");
bool is_beard_color = !strcasecmp(sep->arg[1], "beardcolor");
bool is_details = !strcasecmp(sep->arg[1], "details");
bool is_eyes = !strcasecmp(sep->arg[1], "eyes");
bool is_face = !strcasecmp(sep->arg[1], "face");
bool is_gender = !strcasecmp(sep->arg[1], "gender");
bool is_hair = !strcasecmp(sep->arg[1], "hair");
bool is_hair_color = !strcasecmp(sep->arg[1], "haircolor");
bool is_helm = !strcasecmp(sep->arg[1], "helm");
bool is_heritage = !strcasecmp(sep->arg[1], "heritage");
bool is_race = !strcasecmp(sep->arg[1], "race");
bool is_size = !strcasecmp(sep->arg[1], "size") || is_size_alias;
bool is_tattoo = !strcasecmp(sep->arg[1], "tattoo");
bool is_texture = !strcasecmp(sep->arg[1], "texture");
const bool is_beard = !strcasecmp(sep->arg[1], "beard");
const bool is_beard_color = !strcasecmp(sep->arg[1], "beardcolor");
const bool is_details = !strcasecmp(sep->arg[1], "details");
const bool is_eyes = !strcasecmp(sep->arg[1], "eyes");
const bool is_face = !strcasecmp(sep->arg[1], "face");
const bool is_gender = !strcasecmp(sep->arg[1], "gender");
const bool is_hair = !strcasecmp(sep->arg[1], "hair");
const bool is_hair_color = !strcasecmp(sep->arg[1], "haircolor");
const bool is_helm = !strcasecmp(sep->arg[1], "helm");
const bool is_heritage = !strcasecmp(sep->arg[1], "heritage");
const bool is_race = !strcasecmp(sep->arg[1], "race");
const bool is_size = !strcasecmp(sep->arg[1], "size") || is_size_alias;
const bool is_tattoo = !strcasecmp(sep->arg[1], "tattoo");
const bool is_texture = !strcasecmp(sep->arg[1], "texture");
if (
!is_beard &&
@@ -68,103 +48,82 @@ void command_feature(Client *c, const Seperator *sep)
!is_tattoo &&
!is_texture
) {
auto feature_save_link = Saylink::Silent("#npcedit featuresave");
c->Message(Chat::White, "Usage: #feature beard [Beard] - Change your or your target's Beard");
c->Message(Chat::White, "Usage: #feature beardcolor [Beard Color] - Change your or your target's Beard Color");
c->Message(Chat::White, "Usage: #feature details [Details] - Change your or your target's Drakkin Details");
c->Message(Chat::White, "Usage: #feature eyes [Eye Color] - Change your or your target's Eyes");
c->Message(Chat::White, "Usage: #feature face [Face] - Change your or your target's Face");
c->Message(Chat::White, "Usage: #feature gender [Gender] - Change your or your target's Gender");
c->Message(Chat::White, "Usage: #feature hair [Hair] - Change your or your target's Hair");
c->Message(Chat::White, "Usage: #feature haircolor [Hair Color] - Change your or your target's Hair Color");
c->Message(Chat::White, "Usage: #feature helm [Helmet Texture] - Change your or your target's Helmet Texture");
c->Message(Chat::White, "Usage: #feature heritage [Heritage] - Change your or your target's Drakkin Heritage");
c->Message(Chat::White, "Usage: #feature race [Race ID] - Change your or your target's Race");
c->Message(Chat::White, "Usage: #feature size [Size] - Change your or your target's Size (Valid values are 0 to 255, decimal increments are allowed.)");
c->Message(Chat::White, "Usage: #feature tattoo [Tattoo] - Change your or your target's Drakkin Tattoos");
c->Message(Chat::White, "Usage: #feature texture [Texture] - Change your or your target's Texture");
c->Message(
Chat::White,
fmt::format(
"Note: All features are temporary. If your target is an NPC, you can save these features to the database using {}.",
feature_save_link
).c_str()
);
SendFeatureSubCommands(c);
return;
}
FaceChange_Struct face{};
face.haircolor = target->GetHairColor();
face.beardcolor = target->GetBeardColor();
face.eyecolor1 = target->GetEyeColor1();
face.eyecolor2 = target->GetEyeColor2();
face.hairstyle = target->GetHairStyle();
face.face = target->GetLuclinFace();
face.beard = target->GetBeard();
face.drakkin_heritage = target->GetDrakkinHeritage();
face.drakkin_tattoo = target->GetDrakkinTattoo();
face.drakkin_details = target->GetDrakkinDetails();
FaceChange_Struct f{
.haircolor = t->GetHairColor(),
.beardcolor = t->GetBeardColor(),
.eyecolor1 = t->GetEyeColor1(),
.eyecolor2 = t->GetEyeColor2(),
.hairstyle = t->GetHairStyle(),
.beard = t->GetBeard(),
.face = t->GetLuclinFace(),
.drakkin_heritage = t->GetDrakkinHeritage(),
.drakkin_tattoo = t->GetDrakkinTattoo(),
.drakkin_details = t->GetDrakkinDetails(),
};
auto gender = target->GetGender();
auto helm_texture = target->GetHelmTexture();
auto race = target->GetModel();
auto size = target->GetSize();
auto texture = target->GetTexture();
uint8 gender = t->GetGender();
uint8 helm_texture = t->GetHelmTexture();
uint16 race = t->GetModel();
float size = t->GetSize();
uint8 texture = t->GetTexture();
std::string feature_changed;
float value_changed = 0.0f;
if (is_beard) {
face.beard = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.beard = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Beard";
value_changed = face.beard;
value_changed = f.beard;
} else if (is_beard_color) {
face.beardcolor = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.beardcolor = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Beard Color";
value_changed = face.beardcolor;
value_changed = f.beardcolor;
} else if (is_details) {
if (target->GetRace() != DRAKKIN) {
if (t->GetRace() != DRAKKIN) {
c->Message(Chat::White, "You must target a Drakkin to use this command.");
return;
}
face.drakkin_details = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.drakkin_details = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Drakkin Details";
value_changed = static_cast<float>(face.drakkin_details);
value_changed = static_cast<float>(f.drakkin_details);
} else if (is_eyes) {
face.eyecolor1 = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.eyecolor1 = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Eyes";
value_changed = face.eyecolor1; // eyecolor2 isn't used
value_changed = f.eyecolor1; // eyecolor2 isn't used
} else if (is_face) {
face.face = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.face = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Face";
value_changed = face.face;
value_changed = f.face;
} else if (is_gender) {
gender = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Gender";
value_changed = gender;
} else if (is_hair) {
face.hairstyle = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.hairstyle = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Hair";
value_changed = face.hairstyle;
value_changed = f.hairstyle;
} else if (is_hair_color) {
face.haircolor = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.haircolor = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Hair Color";
value_changed = face.haircolor;
value_changed = f.haircolor;
} else if (is_helm) {
helm_texture = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Helmet Texture";
value_changed = helm_texture;
} else if (is_heritage) {
if (target->GetRace() != DRAKKIN) {
if (t->GetRace() != DRAKKIN) {
c->Message(Chat::White, "You must target a Drakkin to use this command.");
return;
}
face.drakkin_heritage = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.drakkin_heritage = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Drakkin Heritage";
value_changed = static_cast<float>(face.drakkin_heritage);
value_changed = static_cast<float>(f.drakkin_heritage);
} else if (is_race) {
race = static_cast<uint16>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Race";
@@ -189,14 +148,14 @@ void command_feature(Client *c, const Seperator *sep)
feature_changed = "Size";
value_changed = size;
} else if (is_tattoo) {
if (target->GetRace() != DRAKKIN) {
if (t->GetRace() != DRAKKIN) {
c->Message(Chat::White, "You must target a Drakkin to use this command.");
return;
}
face.drakkin_tattoo = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
f.drakkin_tattoo = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Drakkin Tattoos";
value_changed = static_cast<float>(face.drakkin_tattoo);
value_changed = static_cast<float>(f.drakkin_tattoo);
} else if (is_texture) {
texture = static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[2]));
feature_changed = "Texture";
@@ -206,29 +165,34 @@ void command_feature(Client *c, const Seperator *sep)
// For now face number is not set through SetFace. This is because the
// client may not update face features after being set to an invalid face
// until a specific valid face number is re-sent (needs more research)
if (!is_gender && !is_helm && !is_race && !is_size && !is_texture && !is_face)
{
target->SetFaceAppearance(face);
}
else
{
target->SendIllusionPacket(
race,
gender,
texture,
helm_texture,
face.haircolor,
face.beardcolor,
target->GetEyeColor1(),
target->GetEyeColor2(),
face.hairstyle,
face.face,
face.beard,
0xFF,
face.drakkin_heritage,
face.drakkin_tattoo,
face.drakkin_details,
size
if (
!is_face &&
!is_gender &&
!is_helm &&
!is_race &&
!is_size &&
!is_texture
) {
t->SetFaceAppearance(f);
} else {
t->SendIllusionPacket(
AppearanceStruct{
.beard = f.beard,
.beard_color = f.beardcolor,
.drakkin_details = f.drakkin_details,
.drakkin_heritage = f.drakkin_heritage,
.drakkin_tattoo = f.drakkin_tattoo,
.eye_color_one = t->GetEyeColor1(),
.eye_color_two = t->GetEyeColor2(),
.face = f.face,
.gender_id = gender,
.hair = f.hairstyle,
.hair_color = f.haircolor,
.helmet_texture = helm_texture,
.race_id = race,
.size = size,
.texture = texture,
}
);
}
@@ -237,7 +201,7 @@ void command_feature(Client *c, const Seperator *sep)
fmt::format(
"{} set for {} to {}.",
feature_changed,
c->GetTargetDescription(target),
c->GetTargetDescription(t),
(
is_size ?
fmt::format(
@@ -253,3 +217,29 @@ void command_feature(Client *c, const Seperator *sep)
);
}
void SendFeatureSubCommands(Client *c)
{
const std::string& feature_save_link = Saylink::Silent("#npcedit featuresave");
c->Message(Chat::White, "Usage: #feature beard [Beard] - Change your or your target's Beard");
c->Message(Chat::White, "Usage: #feature beardcolor [Beard Color] - Change your or your target's Beard Color");
c->Message(Chat::White, "Usage: #feature details [Details] - Change your or your target's Drakkin Details");
c->Message(Chat::White, "Usage: #feature eyes [Eye Color] - Change your or your target's Eyes");
c->Message(Chat::White, "Usage: #feature face [Face] - Change your or your target's Face");
c->Message(Chat::White, "Usage: #feature gender [Gender] - Change your or your target's Gender");
c->Message(Chat::White, "Usage: #feature hair [Hair] - Change your or your target's Hair");
c->Message(Chat::White, "Usage: #feature haircolor [Hair Color] - Change your or your target's Hair Color");
c->Message(Chat::White, "Usage: #feature helm [Helmet Texture] - Change your or your target's Helmet Texture");
c->Message(Chat::White, "Usage: #feature heritage [Heritage] - Change your or your target's Drakkin Heritage");
c->Message(Chat::White, "Usage: #feature race [Race ID] - Change your or your target's Race");
c->Message(Chat::White, "Usage: #feature size [Size] - Change your or your target's Size (Valid values are 0 to 255, decimal increments are allowed.)");
c->Message(Chat::White, "Usage: #feature tattoo [Tattoo] - Change your or your target's Drakkin Tattoos");
c->Message(Chat::White, "Usage: #feature texture [Texture] - Change your or your target's Texture");
c->Message(
Chat::White,
fmt::format(
"Note: All features are temporary. If your target is an NPC, you can save these features to the database using {}.",
feature_save_link
).c_str()
);
}
+20 -7
View File
@@ -60,11 +60,11 @@ void command_fixmob(Client *c, const Seperator *sep)
ChangeSetting = Race;
}
else if (strcasecmp(command, "gender") == 0) {
if (Gender == 0 && codeMove == 'p') {
Gender = 2;
if (Gender == MALE && codeMove == 'p') {
Gender = NEUTER;
}
else if (Gender >= 2 && codeMove != 'p') {
Gender = 0;
else if (Gender >= NEUTER && codeMove != 'p') {
Gender = MALE;
}
else {
Gender += Adjustment;
@@ -238,9 +238,22 @@ void command_fixmob(Client *c, const Seperator *sep)
}
else {
target->SendIllusionPacket(
Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
DrakkinHeritage, DrakkinTattoo, DrakkinDetails
AppearanceStruct{
.beard = Beard,
.beard_color = BeardColor,
.drakkin_details = DrakkinDetails,
.drakkin_heritage = DrakkinHeritage,
.drakkin_tattoo = DrakkinTattoo,
.eye_color_one = EyeColor1,
.eye_color_two = EyeColor2,
.face = LuclinFace,
.gender_id = Gender,
.hair = HairStyle,
.hair_color = HairColor,
.helmet_texture = HelmTexture,
.race_id = Race,
.texture = Texture,
}
);
c->Message(Chat::White, "%s=%i", ChangeType, ChangeSetting);
+5
View File
@@ -18,6 +18,7 @@ void command_reload(Client *c, const Seperator *sep)
bool is_blocked_spells = !strcasecmp(sep->arg[1], "blocked_spells");
bool is_commands = !strcasecmp(sep->arg[1], "commands");
bool is_content_flags = !strcasecmp(sep->arg[1], "content_flags");
bool is_data_buckets = !strcasecmp(sep->arg[1], "data_buckets_cache");
bool is_doors = !strcasecmp(sep->arg[1], "doors");
bool is_dztemplates = !strcasecmp(sep->arg[1], "dztemplates");
bool is_ground_spawns = !strcasecmp(sep->arg[1], "ground_spawns");
@@ -46,6 +47,7 @@ void command_reload(Client *c, const Seperator *sep)
!is_blocked_spells &&
!is_commands &&
!is_content_flags &&
!is_data_buckets &&
!is_doors &&
!is_dztemplates &&
!is_ground_spawns &&
@@ -92,6 +94,9 @@ void command_reload(Client *c, const Seperator *sep)
} else if (is_doors) {
c->Message(Chat::White, "Attempting to reload Doors globally.");
pack = new ServerPacket(ServerOP_ReloadDoors, 0);
} else if (is_data_buckets) {
c->Message(Chat::White, "Attempting to flush data buckets cache globally.");
pack = new ServerPacket(ServerOP_ReloadDataBucketsCache, 0);
} else if (is_dztemplates) {
c->Message(Chat::White, "Attempting to reload Dynamic Zone Templates globally.");
pack = new ServerPacket(ServerOP_ReloadDzTemplates, 0);
+1 -1
View File
@@ -82,7 +82,7 @@ void command_set(Client *c, const Seperator *sep)
Cmd{.cmd = "frozen", .u = "frozen [on|off]", .fn = SetFrozen, .a = {"#freeze", "#unfreeze"}},
Cmd{.cmd = "gender", .u = "gender [Gender ID]", .fn = SetGender, .a = {"#gender"}},
Cmd{.cmd = "gender_permanent", .u = "gender_permanent [Gender ID]", .fn = SetGenderPermanent, .a = {"#permagender"}},
Cmd{.cmd = "gm", .u = "gm [on|off]", .fn = SetGM, .a = {"#flymode"}},
Cmd{.cmd = "gm", .u = "gm [on|off]", .fn = SetGM, .a = {"#gm"}},
Cmd{.cmd = "gm_speed", .u = "gm_speed [on|off]", .fn = SetGMSpeed, .a = {"#gmspeed"}},
Cmd{.cmd = "gm_status", .u = "gm_status [GM Status] [Account]", .fn = SetGMStatus, .a = {"#flag"}},
Cmd{.cmd = "god_mode", .u = "god_mode [on|off]", .fn = SetGodMode, .a = {"#godmode"}},
+5 -2
View File
@@ -22,8 +22,11 @@ void SetGender(Client *c, const Seperator *sep)
}
t->SendIllusionPacket(
t->GetRace(),
gender_id
AppearanceStruct{
.gender_id = gender_id,
.race_id = t->GetRace(),
.size = t->GetSize(),
}
);
c->Message(
+7 -1
View File
@@ -30,7 +30,13 @@ void SetGenderPermanent(Client *c, const Seperator *sep)
t->SetBaseGender(gender_id);
t->Save();
t->SendIllusionPacket(t->GetRace(), gender_id);
t->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = t->GetRace(),
.size = t->GetSize(),
}
);
c->Message(
Chat::White,
+6 -1
View File
@@ -37,7 +37,12 @@ void SetRace(Client *c, const Seperator *sep)
return;
}
t->SendIllusionPacket(race_id);
t->SendIllusionPacket(
AppearanceStruct{
.race_id = race_id,
.size = t->GetSize(),
}
);
c->Message(
Chat::White,
+7 -1
View File
@@ -31,7 +31,13 @@ void SetRacePermanent(Client *c, const Seperator *sep)
t->SetBaseRace(race_id);
t->SetBaseGender(gender_id);
t->Save();
t->SendIllusionPacket(race_id, gender_id);
t->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = race_id,
.size = t->GetSize()
}
);
c->Message(
Chat::White,
+8 -6
View File
@@ -8,8 +8,8 @@ void SetTexture(Client *c, const Seperator *sep)
return;
}
const uint16 texture = Strings::ToUnsignedInt(sep->arg[2]);
const uint8 helmet_texture = (
const uint8 texture = Strings::ToUnsignedInt(sep->arg[2]);
const uint8 helmet_texture = (
sep->IsNumber(3) ?
Strings::ToUnsignedInt(sep->arg[3]) :
0
@@ -30,10 +30,12 @@ void SetTexture(Client *c, const Seperator *sep)
}
} else { // Non-Player Races only need Illusion Packets to be sent for texture
t->SendIllusionPacket(
t->GetModel(),
t->GetGender(),
texture,
helmet_texture
AppearanceStruct{
.gender_id = t->GetGender(),
.helmet_texture = helmet_texture,
.race_id = t->GetModel(),
.texture = texture,
}
);
}
+42
View File
@@ -504,6 +504,42 @@ std::string Lua_Bot::GetRaceAbbreviation() {
return GetPlayerRaceAbbreviation(self->GetBaseRace());
}
void Lua_Bot::DeleteBucket(std::string bucket_name)
{
Lua_Safe_Call_Void();
self->DeleteBucket(bucket_name);
}
std::string Lua_Bot::GetBucket(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucket(bucket_name);
}
std::string Lua_Bot::GetBucketExpires(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucketExpires(bucket_name);
}
std::string Lua_Bot::GetBucketRemaining(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucketRemaining(bucket_name);
}
void Lua_Bot::SetBucket(std::string bucket_name, std::string bucket_value)
{
Lua_Safe_Call_Void();
self->SetBucket(bucket_name, bucket_value);
}
void Lua_Bot::SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration)
{
Lua_Safe_Call_Void();
self->SetBucket(bucket_name, bucket_value, expiration);
}
luabind::scope lua_register_bot() {
return luabind::class_<Lua_Bot, Lua_Mob>("Bot")
.def(luabind::constructor<>())
@@ -531,6 +567,7 @@ luabind::scope lua_register_bot() {
.def("Camp", (void(Lua_Bot::*)(bool))&Lua_Bot::Camp)
.def("CountBotItem", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountBotItem)
.def("CountItemEquippedByID", (int(Lua_Bot::*)(uint32))&Lua_Bot::CountItemEquippedByID)
.def("DeleteBucket", (void(Lua_Bot::*)(std::string))&Lua_Bot::DeleteBucket)
.def("Escape", (void(Lua_Bot::*)(void))&Lua_Bot::Escape)
.def("Fling", (void(Lua_Bot::*)(float,float,float))&Lua_Bot::Fling)
.def("Fling", (void(Lua_Bot::*)(float,float,float,bool))&Lua_Bot::Fling)
@@ -551,6 +588,9 @@ luabind::scope lua_register_bot() {
.def("GetBotID", (uint32(Lua_Bot::*)(void))&Lua_Bot::GetBotID)
.def("GetBotItem", (Lua_ItemInst(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItem)
.def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot)
.def("GetBucket", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucket)
.def("GetBucketExpires", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketExpires)
.def("GetBucketRemaining", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketRemaining)
.def("GetClassAbbreviation", (std::string(Lua_Bot::*)(void))&Lua_Bot::GetClassAbbreviation)
.def("GetExpansionBitmask", (int(Lua_Bot::*)(void))&Lua_Bot::GetExpansionBitmask)
.def("GetGroup", (Lua_Group(Lua_Bot::*)(void))&Lua_Bot::GetGroup)
@@ -576,6 +616,8 @@ luabind::scope lua_register_bot() {
.def("ReloadBotSpellSettings", (void(Lua_Bot::*)(void))&Lua_Bot::ReloadBotSpellSettings)
.def("RemoveBotItem", (void(Lua_Bot::*)(uint32))&Lua_Bot::RemoveBotItem)
.def("SendSpellAnim", (void(Lua_Bot::*)(uint16,uint16))&Lua_Bot::SendSpellAnim)
.def("SetBucket", (void(Lua_Bot::*)(std::string,std::string))&Lua_Bot::SetBucket)
.def("SetBucket", (void(Lua_Bot::*)(std::string,std::string,std::string))&Lua_Bot::SetBucket)
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int))&Lua_Bot::SetExpansionBitmask)
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int,bool))&Lua_Bot::SetExpansionBitmask)
.def("SetSpellDuration", (void(Lua_Bot::*)(int))&Lua_Bot::SetSpellDuration)
+6
View File
@@ -68,6 +68,12 @@ public:
void SendSpellAnim(uint16 target_id, uint16 spell_id);
std::string GetClassAbbreviation();
std::string GetRaceAbbreviation();
void DeleteBucket(std::string bucket_name);
std::string GetBucket(std::string bucket_name);
std::string GetBucketExpires(std::string bucket_name);
std::string GetBucketRemaining(std::string bucket_name);
void SetBucket(std::string bucket_name, std::string bucket_value);
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration);
void ApplySpell(int spell_id);
void ApplySpell(int spell_id, int duration);
+42
View File
@@ -3098,6 +3098,42 @@ void Lua_Client::SetLDoNPoints(uint32 theme_id, uint32 points)
self->SetLDoNPoints(theme_id, points);
}
void Lua_Client::DeleteBucket(std::string bucket_name)
{
Lua_Safe_Call_Void();
self->DeleteBucket(bucket_name);
}
std::string Lua_Client::GetBucket(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucket(bucket_name);
}
std::string Lua_Client::GetBucketExpires(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucketExpires(bucket_name);
}
std::string Lua_Client::GetBucketRemaining(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucketRemaining(bucket_name);
}
void Lua_Client::SetBucket(std::string bucket_name, std::string bucket_value)
{
Lua_Safe_Call_Void();
self->SetBucket(bucket_name, bucket_value);
}
void Lua_Client::SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration)
{
Lua_Safe_Call_Void();
self->SetBucket(bucket_name, bucket_value, expiration);
}
luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>())
@@ -3175,6 +3211,7 @@ luabind::scope lua_register_client() {
.def("CreateExpeditionFromTemplate", &Lua_Client::CreateExpeditionFromTemplate)
.def("CreateTaskDynamicZone", &Lua_Client::CreateTaskDynamicZone)
.def("DecreaseByID", (bool(Lua_Client::*)(uint32,int))&Lua_Client::DecreaseByID)
.def("DeleteBucket", (void(Lua_Client::*)(std::string))&Lua_Client::DeleteBucket)
.def("DeleteItemInInventory", (void(Lua_Client::*)(int,int))&Lua_Client::DeleteItemInInventory)
.def("DeleteItemInInventory", (void(Lua_Client::*)(int,int,bool))&Lua_Client::DeleteItemInInventory)
.def("DiaWind", (void(Lua_Client::*)(std::string))&Lua_Client::DialogueWindow)
@@ -3249,6 +3286,9 @@ luabind::scope lua_register_client() {
.def("GetBotRequiredLevel", (int(Lua_Client::*)(uint8))&Lua_Client::GetBotRequiredLevel)
.def("GetBotSpawnLimit", (int(Lua_Client::*)(void))&Lua_Client::GetBotSpawnLimit)
.def("GetBotSpawnLimit", (int(Lua_Client::*)(uint8))&Lua_Client::GetBotSpawnLimit)
.def("GetBucket", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucket)
.def("GetBucketExpires", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucketExpires)
.def("GetBucketRemaining", (std::string(Lua_Client::*)(std::string))&Lua_Client::GetBucketRemaining)
.def("GetCarriedMoney", (uint64(Lua_Client::*)(void))&Lua_Client::GetCarriedMoney)
.def("GetCarriedPlatinum", (uint32(Lua_Client::*)(void))&Lua_Client::GetCarriedPlatinum)
.def("GetCharacterFactionLevel", (int(Lua_Client::*)(int))&Lua_Client::GetCharacterFactionLevel)
@@ -3517,6 +3557,8 @@ luabind::scope lua_register_client() {
.def("SetBotRequiredLevel", (void(Lua_Client::*)(int,uint8))&Lua_Client::SetBotRequiredLevel)
.def("SetBotSpawnLimit", (void(Lua_Client::*)(int))&Lua_Client::SetBotSpawnLimit)
.def("SetBotSpawnLimit", (void(Lua_Client::*)(int,uint8))&Lua_Client::SetBotSpawnLimit)
.def("SetBucket", (void(Lua_Client::*)(std::string,std::string))&Lua_Client::SetBucket)
.def("SetBucketExpires", (void(Lua_Client::*)(std::string,std::string,std::string))&Lua_Client::SetBucket)
.def("SetClientMaxLevel", (void(Lua_Client::*)(int))&Lua_Client::SetClientMaxLevel)
.def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption)
.def("SetDeity", (void(Lua_Client::*)(int))&Lua_Client::SetDeity)
+6
View File
@@ -474,6 +474,12 @@ public:
std::string GetClassAbbreviation();
std::string GetRaceAbbreviation();
void SetLDoNPoints(uint32 theme_id, uint32 points);
void DeleteBucket(std::string bucket_name);
std::string GetBucket(std::string bucket_name);
std::string GetBucketExpires(std::string bucket_name);
std::string GetBucketRemaining(std::string bucket_name);
void SetBucket(std::string bucket_name, std::string bucket_value);
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration);
void ApplySpell(int spell_id);
void ApplySpell(int spell_id, int duration);
+50 -27
View File
@@ -1554,19 +1554,33 @@ void Lua_Mob::SetFlyMode(int in) {
self->SetFlyMode(static_cast<GravityBehavior>(in));
}
void Lua_Mob::SetTexture(int in) {
void Lua_Mob::SetTexture(uint8 texture) {
Lua_Safe_Call_Void();
self->SendIllusionPacket(self->GetRace(), 0xFF, in);
self->SendIllusionPacket(
AppearanceStruct{
.race_id = self->GetRace(),
.texture = texture
}
);
}
void Lua_Mob::SetRace(int in) {
void Lua_Mob::SetRace(uint16 race_id) {
Lua_Safe_Call_Void();
self->SendIllusionPacket(in);
self->SendIllusionPacket(
AppearanceStruct{
.race_id = race_id
}
);
}
void Lua_Mob::SetGender(int in) {
void Lua_Mob::SetGender(uint8 gender_id) {
Lua_Safe_Call_Void();
self->SendIllusionPacket(self->GetRace(), in);
self->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = self->GetRace(),
}
);
}
void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) {
@@ -1740,24 +1754,26 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) {
}
self->SendIllusionPacket(
race,
gender,
texture,
helmtexture,
haircolor,
beardcolor,
eyecolor1,
eyecolor2,
hairstyle,
luclinface,
beard,
aa_title,
drakkin_heritage,
drakkin_tattoo,
drakkin_details,
size,
send_appearance_effects,
target
AppearanceStruct{
.aa_title = aa_title,
.beard = beard,
.beard_color = beardcolor,
.drakkin_details = drakkin_details,
.drakkin_heritage = drakkin_heritage,
.drakkin_tattoo = drakkin_tattoo,
.eye_color_one = eyecolor1,
.eye_color_two = eyecolor2,
.face = luclinface,
.gender_id = gender,
.hair = hairstyle,
.hair_color = haircolor,
.helmet_texture = helmtexture,
.race_id = race,
.send_effects = send_appearance_effects,
.size = size,
.target = target,
.texture = texture,
}
);
}
@@ -3133,6 +3149,12 @@ bool Lua_Mob::IsTemporaryPet()
return self->IsTempPet();
}
uint32 Lua_Mob::GetMobTypeIdentifier()
{
Lua_Safe_Call_Int();
return self->GetMobTypeIdentifier();
}
luabind::scope lua_register_mob() {
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
.def(luabind::constructor<>())
@@ -3429,6 +3451,7 @@ luabind::scope lua_register_mob() {
.def("GetMeleeDamageMod_SE", &Lua_Mob::GetMeleeDamageMod_SE)
.def("GetMeleeMinDamageMod_SE", &Lua_Mob::GetMeleeMinDamageMod_SE)
.def("GetMeleeMitigation", (int32(Lua_Mob::*)(void))&Lua_Mob::GetMeleeMitigation)
.def("GetMobTypeIdentifier", (uint32(Lua_Mob::*)(void))&Lua_Mob::GetMobTypeIdentifier)
.def("GetModSkillDmgTaken", (int(Lua_Mob::*)(int))&Lua_Mob::GetModSkillDmgTaken)
.def("GetModVulnerability", (int(Lua_Mob::*)(int))&Lua_Mob::GetModVulnerability)
.def("GetNPCTypeID", &Lua_Mob::GetNPCTypeID)
@@ -3598,7 +3621,7 @@ luabind::scope lua_register_mob() {
.def("SetExtraHaste", (void(Lua_Mob::*)(int))&Lua_Mob::SetExtraHaste)
.def("SetFlurryChance", (void(Lua_Mob::*)(int))&Lua_Mob::SetFlurryChance)
.def("SetFlyMode", (void(Lua_Mob::*)(int))&Lua_Mob::SetFlyMode)
.def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender)
.def("SetGender", (void(Lua_Mob::*)(uint8))&Lua_Mob::SetGender)
.def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*))&Lua_Mob::SetGlobal)
.def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*,Lua_Mob))&Lua_Mob::SetGlobal)
.def("SetHP", &Lua_Mob::SetHP)
@@ -3615,14 +3638,14 @@ luabind::scope lua_register_mob() {
.def("SetPet", &Lua_Mob::SetPet)
.def("SetPetOrder", (void(Lua_Mob::*)(int))&Lua_Mob::SetPetOrder)
.def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot)
.def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace)
.def("SetRace", (void(Lua_Mob::*)(uint16))&Lua_Mob::SetRace)
.def("SetRunning", (void(Lua_Mob::*)(bool))&Lua_Mob::SetRunning)
.def("SetSlotTint", (void(Lua_Mob::*)(int,int,int,int))&Lua_Mob::SetSlotTint)
.def("SetSpecialAbility", (void(Lua_Mob::*)(int,int))&Lua_Mob::SetSpecialAbility)
.def("SetSpecialAbilityParam", (void(Lua_Mob::*)(int,int,int))&Lua_Mob::SetSpecialAbilityParam)
.def("SetTarget", &Lua_Mob::SetTarget)
.def("SetTargetable", (void(Lua_Mob::*)(bool))&Lua_Mob::SetTargetable)
.def("SetTexture", (void(Lua_Mob::*)(int))&Lua_Mob::SetTexture)
.def("SetTexture", (void(Lua_Mob::*)(uint8))&Lua_Mob::SetTexture)
.def("SetTimer", &Lua_Mob::SetTimer)
.def("SetTimerMS", &Lua_Mob::SetTimerMS)
.def("StopAllTimers", &Lua_Mob::StopAllTimers)
+4 -3
View File
@@ -351,9 +351,9 @@ public:
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5);
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Lua_Client specific_target);
void SetFlyMode(int in);
void SetTexture(int in);
void SetRace(int in);
void SetGender(int in);
void SetTexture(uint8 texture);
void SetRace(uint16 race_id);
void SetGender(uint8 gender_id);
void SendIllusionPacket(luabind::adl::object illusion);
void ChangeRace(int in);
void ChangeGender(int in);
@@ -557,6 +557,7 @@ public:
std::string GetClassPlural();
std::string GetRacePlural();
bool IsTemporaryPet();
uint32 GetMobTypeIdentifier();
};
#endif
+42
View File
@@ -777,6 +777,42 @@ bool Lua_NPC::HasSpecialAbilities() {
return self->HasSpecialAbilities();
}
void Lua_NPC::DeleteBucket(std::string bucket_name)
{
Lua_Safe_Call_Void();
self->DeleteBucket(bucket_name);
}
std::string Lua_NPC::GetBucket(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucket(bucket_name);
}
std::string Lua_NPC::GetBucketExpires(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucketExpires(bucket_name);
}
std::string Lua_NPC::GetBucketRemaining(std::string bucket_name)
{
Lua_Safe_Call_String();
return self->GetBucketRemaining(bucket_name);
}
void Lua_NPC::SetBucket(std::string bucket_name, std::string bucket_value)
{
Lua_Safe_Call_Void();
self->SetBucket(bucket_name, bucket_value);
}
void Lua_NPC::SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration)
{
Lua_Safe_Call_Void();
self->SetBucket(bucket_name, bucket_value, expiration);
}
luabind::scope lua_register_npc() {
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
.def(luabind::constructor<>())
@@ -804,12 +840,16 @@ luabind::scope lua_register_npc() {
.def("ClearLastName", (void(Lua_NPC::*)(void))&Lua_NPC::ClearLastName)
.def("CountItem", (uint16(Lua_NPC::*)(uint32))&Lua_NPC::CountItem)
.def("CountLoot", (int(Lua_NPC::*)(void))&Lua_NPC::CountLoot)
.def("DeleteBucket", (void(Lua_NPC::*)(std::string))&Lua_NPC::DeleteBucket)
.def("DisplayWaypointInfo", (void(Lua_NPC::*)(Lua_Client))&Lua_NPC::DisplayWaypointInfo)
.def("DoClassAttacks", (void(Lua_NPC::*)(Lua_Mob))&Lua_NPC::DoClassAttacks)
.def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating)
.def("GetAttackDelay", (int(Lua_NPC::*)(void))&Lua_NPC::GetAttackDelay)
.def("GetAttackSpeed", (float(Lua_NPC::*)(void))&Lua_NPC::GetAttackSpeed)
.def("GetAvoidanceRating", &Lua_NPC::GetAvoidanceRating)
.def("GetBucket", (std::string(Lua_NPC::*)(std::string))&Lua_NPC::GetBucket)
.def("GetBucketExpires", (std::string(Lua_NPC::*)(std::string))&Lua_NPC::GetBucketExpires)
.def("GetBucketRemaining", (std::string(Lua_NPC::*)(std::string))&Lua_NPC::GetBucketRemaining)
.def("GetCopper", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetCopper)
.def("GetFirstSlotByItemID", (uint16(Lua_NPC::*)(uint32))&Lua_NPC::GetFirstSlotByItemID)
.def("GetFollowCanRun", (bool(Lua_NPC::*)(void))&Lua_NPC::GetFollowCanRun)
@@ -894,6 +934,8 @@ luabind::scope lua_register_npc() {
.def("ScaleNPC", (void(Lua_NPC::*)(uint8,bool))&Lua_NPC::ScaleNPC)
.def("SendPayload", (void(Lua_NPC::*)(int))&Lua_NPC::SendPayload)
.def("SendPayload", (void(Lua_NPC::*)(int,std::string))&Lua_NPC::SendPayload)
.def("SetBucket", (void(Lua_NPC::*)(std::string,std::string))&Lua_NPC::SetBucket)
.def("SetBucket", (void(Lua_NPC::*)(std::string,std::string,std::string))&Lua_NPC::SetBucket)
.def("SetCopper", (void(Lua_NPC::*)(uint32))&Lua_NPC::SetCopper)
.def("SetFollowCanRun", (void(Lua_NPC::*)(bool))&Lua_NPC::SetFollowCanRun)
.def("SetFollowDistance", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowDistance)
+6
View File
@@ -176,6 +176,12 @@ public:
void ScaleNPC(uint8 npc_level, bool override_special_abilities);
bool IsUnderwaterOnly();
bool HasSpecialAbilities();
void DeleteBucket(std::string bucket_name);
std::string GetBucket(std::string bucket_name);
std::string GetBucketExpires(std::string bucket_name);
std::string GetBucketRemaining(std::string bucket_name);
void SetBucket(std::string bucket_name, std::string bucket_value);
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration);
};
#endif
+43 -51
View File
@@ -231,7 +231,7 @@ void handle_npc_hate(
l_mob_o.push(L);
lua_setfield(L, -2, "other");
lua_pushboolean(L, Strings::ToInt(data) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(data));
lua_setfield(L, -2, "joined");
}
@@ -301,8 +301,8 @@ void handle_npc_death(
lua_pushinteger(L, Strings::ToInt(sep.arg[1]));
lua_setfield(L, -2, "damage");
int spell_id = Strings::ToInt(sep.arg[2]);
if(IsValidSpell(spell_id)) {
const uint32 spell_id = Strings::ToUnsignedInt(sep.arg[2]);
if (IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
@@ -317,16 +317,14 @@ void handle_npc_death(
lua_pushinteger(L, Strings::ToInt(sep.arg[3]));
lua_setfield(L, -2, "skill_id");
if (extra_pointers && extra_pointers->size() >= 1)
{
if (extra_pointers && extra_pointers->size() >= 1) {
Lua_Corpse l_corpse(std::any_cast<Corpse*>(extra_pointers->at(0)));
luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse);
l_corpse_o.push(L);
lua_setfield(L, -2, "corpse");
}
if (extra_pointers && extra_pointers->size() >= 2)
{
if (extra_pointers && extra_pointers->size() >= 2) {
Lua_NPC l_npc(std::any_cast<NPC*>(extra_pointers->at(1)));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L);
@@ -343,18 +341,19 @@ void handle_npc_cast(
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
int spell_id = Strings::ToInt(data);
if(IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
lua_setfield(L, -2, "spell");
} else {
Lua_Spell l_spell(nullptr);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
lua_setfield(L, -2, "spell");
}
Seperator sep(data.c_str());
const uint32 spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell(IsValidSpell(spell_id) ? &spells[spell_id] : nullptr);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
lua_setfield(L, -2, "spell");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "caster_id");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[2]));
lua_setfield(L, -2, "caster_level");
}
void handle_npc_area(
@@ -462,16 +461,16 @@ void handle_npc_damage(
lua_pushnumber(L, Strings::ToInt(sep.arg[3]));
lua_setfield(L, -2, "skill_id");
lua_pushboolean(L, Strings::ToInt(sep.arg[4]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[4]));
lua_setfield(L, -2, "is_damage_shield");
lua_pushboolean(L, Strings::ToInt(sep.arg[5]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[5]));
lua_setfield(L, -2, "is_avoidable");
lua_pushnumber(L, Strings::ToInt(sep.arg[6]));
lua_setfield(L, -2, "buff_slot");
lua_pushboolean(L, Strings::ToInt(sep.arg[7]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[7]));
lua_setfield(L, -2, "is_buff_tic");
lua_pushnumber(L, Strings::ToInt(sep.arg[8]));
@@ -711,10 +710,10 @@ void handle_player_cast(
lua_setfield(L, -2, "spell");
lua_pushinteger(L, Strings::ToInt(sep.arg[1]));
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "caster_id");
lua_pushinteger(L, Strings::ToInt(sep.arg[2]));
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[2]));
lua_setfield(L, -2, "caster_level");
}
@@ -933,7 +932,7 @@ void handle_player_respawn(
lua_pushinteger(L, Strings::ToInt(data));
lua_setfield(L, -2, "option");
lua_pushboolean(L, extra_data == 1 ? true : false);
lua_pushboolean(L, Strings::ToBool(std::to_string(extra_data)));
lua_setfield(L, -2, "resurrect");
}
@@ -950,7 +949,7 @@ void handle_player_packet(
l_packet_o.push(L);
lua_setfield(L, -2, "packet");
lua_pushboolean(L, extra_data == 1 ? true : false);
lua_pushboolean(L, Strings::ToBool(std::to_string(extra_data)));
lua_setfield(L, -2, "connecting");
}
@@ -1270,16 +1269,16 @@ void handle_player_damage(
lua_pushnumber(L, Strings::ToInt(sep.arg[3]));
lua_setfield(L, -2, "skill_id");
lua_pushboolean(L, Strings::ToInt(sep.arg[4]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[4]));
lua_setfield(L, -2, "is_damage_shield");
lua_pushboolean(L, Strings::ToInt(sep.arg[5]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[5]));
lua_setfield(L, -2, "is_avoidable");
lua_pushnumber(L, Strings::ToInt(sep.arg[6]));
lua_setfield(L, -2, "buff_slot");
lua_pushboolean(L, Strings::ToInt(sep.arg[7]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[7]));
lua_setfield(L, -2, "is_buff_tic");
lua_pushnumber(L, Strings::ToInt(sep.arg[8]));
@@ -1606,7 +1605,7 @@ void handle_spell_event(
Lua_Mob l_mob(mob);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L);
} else if(client) {
} else if (client) {
Lua_Mob l_client(client);
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
@@ -1623,13 +1622,13 @@ void handle_spell_event(
Seperator sep(data.c_str());
lua_pushinteger(L, Strings::ToInt(sep.arg[0]));
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[0]));
lua_setfield(L, -2, "caster_id");
lua_pushinteger(L, Strings::ToInt(sep.arg[1]));
lua_setfield(L, -2, "tics_remaining");
lua_pushinteger(L, Strings::ToInt(sep.arg[2]));
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[2]));
lua_setfield(L, -2, "caster_level");
lua_pushinteger(L, Strings::ToInt(sep.arg[3]));
@@ -1655,7 +1654,7 @@ void handle_translocate_finish(
Lua_Mob l_mob(mob);
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L);
} else if(client) {
} else if (client) {
Lua_Mob l_client(client);
luabind::adl::object l_client_o = luabind::adl::object(L, l_client);
l_client_o.push(L);
@@ -1945,23 +1944,16 @@ void handle_bot_cast(
) {
Seperator sep(data.c_str());
int spell_id = Strings::ToInt(sep.arg[0]);
if (IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
} else {
Lua_Spell l_spell(nullptr);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
}
const uint32 spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell(IsValidSpell(spell_id) ? &spells[spell_id] : nullptr);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
l_spell_o.push(L);
lua_setfield(L, -2, "spell");
lua_pushinteger(L, Strings::ToInt(sep.arg[1]));
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "caster_id");
lua_pushinteger(L, Strings::ToInt(sep.arg[2]));
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[2]));
lua_setfield(L, -2, "caster_level");
}
@@ -1979,7 +1971,7 @@ void handle_bot_combat(
l_mob_o.push(L);
lua_setfield(L, -2, "other");
lua_pushboolean(L, Strings::ToInt(data) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(data));
lua_setfield(L, -2, "joined");
}
@@ -2003,7 +1995,7 @@ void handle_bot_death(
lua_pushinteger(L, Strings::ToInt(sep.arg[1]));
lua_setfield(L, -2, "damage");
int spell_id = Strings::ToInt(sep.arg[2]);
const uint32 spell_id = Strings::ToUnsignedInt(sep.arg[2]);
if (IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
@@ -2257,16 +2249,16 @@ void handle_bot_damage(
lua_pushnumber(L, Strings::ToInt(sep.arg[3]));
lua_setfield(L, -2, "skill_id");
lua_pushboolean(L, Strings::ToInt(sep.arg[4]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[4]));
lua_setfield(L, -2, "is_damage_shield");
lua_pushboolean(L, Strings::ToInt(sep.arg[5]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[5]));
lua_setfield(L, -2, "is_avoidable");
lua_pushnumber(L, Strings::ToInt(sep.arg[6]));
lua_setfield(L, -2, "buff_slot");
lua_pushboolean(L, Strings::ToInt(sep.arg[7]) == 0 ? false : true);
lua_pushboolean(L, Strings::ToBool(sep.arg[7]));
lua_setfield(L, -2, "is_buff_tic");
lua_pushnumber(L, Strings::ToInt(sep.arg[8]));
+2 -2
View File
@@ -4323,7 +4323,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id,
npc_type->race = merc_template->RaceID;
// Use the Gender and Size of the Merchant if possible
uint8 tmpgender = 0;
uint8 tmpgender = MALE;
float tmpsize = 6.0f;
if(merchant_id > 0)
{
@@ -5624,7 +5624,7 @@ void Client::SetMerc(Merc* newmerc) {
GetMercInfo().myTemplate = nullptr;
GetMercInfo().IsSuspended = false;
GetMercInfo().SuspendedTime = 0;
GetMercInfo().Gender = 0;
GetMercInfo().Gender = MALE;
GetMercInfo().State = 0;
memset(GetMercInfo().merc_name, 0, 64);
Log(Logs::General, Logs::Mercenaries, "SetMerc No Merc for %s.", GetName());
+171 -145
View File
@@ -3518,135 +3518,100 @@ void Mob::GMMove(const glm::vec4 &position) {
}
}
void Mob::SendIllusionPacket(
uint16 in_race,
uint8 in_gender,
uint8 in_texture,
uint8 in_helmtexture,
uint8 in_haircolor,
uint8 in_beardcolor,
uint8 in_eyecolor1,
uint8 in_eyecolor2,
uint8 in_hairstyle,
uint8 in_luclinface,
uint8 in_beard,
uint8 in_aa_title,
uint32 in_drakkin_heritage,
uint32 in_drakkin_tattoo,
uint32 in_drakkin_details,
float in_size,
bool send_appearance_effects,
Client* target
)
void Mob::SendIllusionPacket(const AppearanceStruct& a)
{
uint8 new_texture = in_texture;
uint8 new_helmtexture = in_helmtexture;
uint8 new_haircolor;
uint8 new_beardcolor;
uint8 new_eyecolor1;
uint8 new_eyecolor2;
uint8 new_hairstyle;
uint8 new_luclinface;
uint8 new_beard;
uint8 new_aa_title;
uint32 new_drakkin_heritage;
uint32 new_drakkin_tattoo;
uint32 new_drakkin_details;
uint16 new_race = (
a.race_id != RACE_DOUG_0 ?
a.race_id :
(use_model ? use_model : GetBaseRace())
);
race = in_race;
if (race == 0) {
race = use_model ? use_model : GetBaseRace();
}
uint8 new_gender = (
a.gender_id != UINT8_MAX ?
a.gender_id :
(a.race_id ? GetDefaultGender(a.race_id, a.gender_id) : GetBaseGender())
);
if (in_gender != 0xFF) {
gender = in_gender;
}
else {
gender = in_race ? GetDefaultGender(race, gender) : GetBaseGender();
}
float new_size = a.size <= 0.0f ? GetRaceGenderDefaultHeight(race, gender) : a.size;
if (in_texture == 0xFF && !IsPlayerRace(race)) {
new_texture = GetTexture();
}
uint8 new_texture = a.texture == UINT8_MAX && !IsPlayerRace(a.race_id) ? GetTexture() : a.texture;
uint8 new_helmet_texture = a.helmet_texture == UINT8_MAX && !IsPlayerRace(race) ? GetHelmTexture() : a.helmet_texture;
if (in_helmtexture == 0xFF && !IsPlayerRace(race)) {
new_helmtexture = GetHelmTexture();
}
uint8 new_hair = a.hair == UINT8_MAX ? GetHairStyle() : a.hair;
uint8 new_hair_color = a.hair_color == UINT8_MAX ? GetHairColor() : a.hair_color;
new_haircolor = (in_haircolor == 0xFF) ? GetHairColor() : in_haircolor;
new_beardcolor = (in_beardcolor == 0xFF) ? GetBeardColor() : in_beardcolor;
new_eyecolor1 = (in_eyecolor1 == 0xFF) ? GetEyeColor1() : in_eyecolor1;
new_eyecolor2 = (in_eyecolor2 == 0xFF) ? GetEyeColor2() : in_eyecolor2;
new_hairstyle = (in_hairstyle == 0xFF) ? GetHairStyle() : in_hairstyle;
new_luclinface = (in_luclinface == 0xFF) ? GetLuclinFace() : in_luclinface;
new_beard = (in_beard == 0xFF) ? GetBeard() : in_beard;
new_drakkin_heritage = (in_drakkin_heritage == 0xFFFFFFFF) ? GetDrakkinHeritage() : in_drakkin_heritage;
new_drakkin_tattoo = (in_drakkin_tattoo == 0xFFFFFFFF) ? GetDrakkinTattoo() : in_drakkin_tattoo;
new_drakkin_details = (in_drakkin_details == 0xFFFFFFFF) ? GetDrakkinDetails() : in_drakkin_details;
new_aa_title = in_aa_title;
uint8 new_beard = a.beard == UINT8_MAX ? GetBeard() : a.beard;
uint8 new_beard_color = a.beard_color == UINT8_MAX ? GetBeardColor() : a.beard_color;
uint8 new_eye_color_one = a.eye_color_one == UINT8_MAX ? GetEyeColor1() : a.eye_color_one;
uint8 new_eye_color_two = a.eye_color_two == UINT8_MAX ? GetEyeColor2() : a.eye_color_two;
uint8 new_face = a.face == UINT8_MAX ? GetLuclinFace() : a.face;
uint32 new_drakkin_details = a.drakkin_details == UINT32_MAX ? GetDrakkinDetails() : a.drakkin_details;
uint32 new_drakkin_heritage = a.drakkin_heritage == UINT32_MAX ? GetDrakkinHeritage() : a.drakkin_heritage;
uint32 new_drakkin_tattoo = a.drakkin_tattoo == UINT32_MAX ? GetDrakkinTattoo() : a.drakkin_tattoo;
// Reset features to Base from the Player Profile
if (IsClient() && in_race == 0) {
race = CastToClient()->GetBaseRace();
gender = CastToClient()->GetBaseGender();
new_texture = texture = 0xFF;
new_helmtexture = helmtexture = 0xFF;
new_haircolor = haircolor = CastToClient()->GetBaseHairColor();
new_beardcolor = beardcolor = CastToClient()->GetBaseBeardColor();
new_eyecolor1 = eyecolor1 = CastToClient()->GetBaseEyeColor();
new_eyecolor2 = eyecolor2 = CastToClient()->GetBaseEyeColor();
new_hairstyle = hairstyle = CastToClient()->GetBaseHairStyle();
new_luclinface = luclinface = CastToClient()->GetBaseFace();
new_beard = beard = CastToClient()->GetBaseBeard();
new_aa_title = aa_title = 0xFF;
new_drakkin_heritage = drakkin_heritage = CastToClient()->GetBaseHeritage();
new_drakkin_tattoo = drakkin_tattoo = CastToClient()->GetBaseTattoo();
new_drakkin_details = drakkin_details = CastToClient()->GetBaseDetails();
if (IsClient() && a.race_id == RACE_DOUG_0) {
new_beard = CastToClient()->GetBaseBeard();
new_beard_color = CastToClient()->GetBaseBeardColor();
new_drakkin_details = CastToClient()->GetBaseDetails();
new_drakkin_heritage = CastToClient()->GetBaseHeritage();
new_drakkin_tattoo = CastToClient()->GetBaseTattoo();
new_eye_color_one = CastToClient()->GetBaseEyeColor();
new_eye_color_two = CastToClient()->GetBaseEyeColor();
new_face = CastToClient()->GetBaseFace();
new_gender = CastToClient()->GetBaseGender();
new_helmet_texture = UINT8_MAX;
new_hair = CastToClient()->GetBaseHairStyle();
new_hair_color = CastToClient()->GetBaseHairColor();
new_race = CastToClient()->GetBaseRace();
new_size = CastToClient()->GetSize();
new_texture = UINT8_MAX;
}
// update internal values for mob
size = (in_size <= 0.0f) ? GetRaceGenderDefaultHeight(race, gender) : in_size;
if (new_texture != 0xFF) {
texture = new_texture;
}
if (new_helmtexture != 0xFF) {
helmtexture = new_helmtexture;
}
haircolor = new_haircolor;
beardcolor = new_beardcolor;
eyecolor1 = new_eyecolor1;
eyecolor2 = new_eyecolor2;
hairstyle = new_hairstyle;
luclinface = new_luclinface;
beard = new_beard;
beardcolor = new_beard_color;
drakkin_heritage = new_drakkin_heritage;
drakkin_tattoo = new_drakkin_tattoo;
drakkin_details = new_drakkin_details;
eyecolor1 = new_eye_color_one;
eyecolor2 = new_eye_color_two;
luclinface = new_face;
gender = new_gender;
hairstyle = new_hair;
haircolor = new_hair_color;
helmtexture = new_helmet_texture;
race = new_race;
size = new_size;
texture = new_texture;
auto outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct));
auto is = (Illusion_Struct *) outapp->pBuffer;
auto outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct));
Illusion_Struct *is = (Illusion_Struct *) outapp->pBuffer;
is->spawnid = GetID();
strcpy(is->charname, GetCleanName());
is->race = race;
is->gender = gender;
is->texture = new_texture;
is->helmtexture = new_helmtexture;
is->haircolor = new_haircolor;
is->beardcolor = new_beardcolor;
strn0cpy(is->charname, GetCleanName(), sizeof(is->charname));
is->beardcolor = new_beard_color;
is->beard = new_beard;
is->eyecolor1 = new_eyecolor1;
is->eyecolor2 = new_eyecolor2;
is->hairstyle = new_hairstyle;
is->face = new_luclinface;
is->drakkin_heritage = new_drakkin_heritage;
is->drakkin_tattoo = new_drakkin_tattoo;
is->drakkin_details = new_drakkin_details;
is->size = size;
is->eyecolor1 = new_eye_color_one;
is->eyecolor2 = new_eye_color_two;
is->face = new_face;
is->gender = new_gender;
is->hairstyle = new_hair;
is->haircolor = new_hair_color;
is->helmtexture = new_helmet_texture;
is->race = new_race;
is->size = new_size;
is->texture = new_texture;
if (!target) {
if (!a.target) {
entity_list.QueueClients(this, outapp);
} else {
target->QueuePacket(outapp, false);
a.target->QueuePacket(outapp, false);
}
safe_delete(outapp);
@@ -3654,7 +3619,7 @@ void Mob::SendIllusionPacket(
/* Refresh armor and tints after send illusion packet */
SendArmorAppearance();
if (send_appearance_effects) {
if (a.send_effects) {
SendSavedAppearenceEffects(nullptr);
}
@@ -3663,17 +3628,17 @@ void Mob::SendIllusionPacket(
race,
gender,
new_texture,
new_helmtexture,
new_haircolor,
new_beardcolor,
new_eyecolor1,
new_eyecolor2,
new_hairstyle,
new_luclinface,
new_helmet_texture,
new_hair_color,
new_beard_color,
new_eye_color_one,
new_eye_color_two,
new_hair,
new_face,
new_drakkin_heritage,
new_drakkin_tattoo,
new_drakkin_details,
size,
new_size,
target ? target->GetCleanName() : "No Target"
);
}
@@ -3903,21 +3868,22 @@ bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables)
if (send_illusion) {
SendIllusionPacket(
GetRace(),
current_gender,
new_texture,
new_helm_texture,
new_hair_color,
new_beard_color,
new_eye_color_one,
new_eye_color_two,
new_hair_style,
new_luclin_face,
new_beard,
0xFF,
new_drakkin_heritage,
new_drakkin_tattoo,
new_drakkin_details
AppearanceStruct{
.beard = new_beard,
.beard_color = new_beard_color,
.drakkin_details = new_drakkin_details,
.drakkin_heritage = new_drakkin_heritage,
.drakkin_tattoo = new_drakkin_tattoo,
.eye_color_one = new_eye_color_one,
.eye_color_two = new_eye_color_two,
.face = new_luclin_face,
.gender_id = current_gender,
.hair = new_hair_style,
.hair_color = new_hair_color,
.helmet_texture = new_helm_texture,
.race_id = GetRace(),
.texture = new_texture,
}
);
}
@@ -8153,21 +8119,23 @@ void Mob::CloneAppearance(Mob* other, bool clone_name)
}
SendIllusionPacket(
other->GetRace(),
other->GetGender(),
other->GetTexture(),
other->GetHelmTexture(),
other->GetHairColor(),
other->GetBeardColor(),
other->GetEyeColor1(),
other->GetEyeColor2(),
other->GetHairStyle(),
other->GetBeard(),
0xFF,
other->GetRace() == DRAKKIN ? other->GetDrakkinHeritage() : 0xFFFFFFFF,
other->GetRace() == DRAKKIN ? other->GetDrakkinTattoo() : 0xFFFFFFFF,
other->GetRace() == DRAKKIN ? other->GetDrakkinDetails() : 0xFFFFFFFF,
other->GetSize()
AppearanceStruct{
.beard = other->GetBeard(),
.beard_color = other->GetBeardColor(),
.drakkin_details = other->GetDrakkinDetails(),
.drakkin_heritage = other->GetDrakkinHeritage(),
.drakkin_tattoo = other->GetDrakkinTattoo(),
.eye_color_one = other->GetEyeColor1(),
.eye_color_two = other->GetEyeColor2(),
.face = other->GetLuclinFace(),
.gender_id = other->GetGender(),
.hair = other->GetHairStyle(),
.hair_color = other->GetHairColor(),
.helmet_texture = other->GetHelmTexture(),
.race_id = other->GetRace(),
.size = other->GetSize(),
.texture = other->GetTexture(),
}
);
for (
@@ -8352,3 +8320,61 @@ DataBucketKey Mob::GetScopedBucketKeys()
return k;
}
uint32 Mob::GetMobTypeIdentifier()
{
if (IsClient()) {
return CastToClient()->CharacterID();
} else if (IsNPC()) {
return GetNPCTypeID();
} else if (IsBot()) {
return CastToBot()->GetBotID();
}
return 0;
}
void Mob::HandleDoorOpen()
{
for (auto e : entity_list.GetDoorsList()) {
Doors *d = e.second;
if (d->GetKeyItem()) {
continue;
}
if (d->GetLockpick()) {
continue;
}
if (d->IsDoorOpen()) {
continue;
}
if (d->IsDoorBlacklisted()) {
continue;
}
// If the door is a trigger door, check if the trigger door is open
if (d->GetTriggerDoorID() > 0) {
auto td = entity_list.GetDoorsByDoorID(d->GetTriggerDoorID());
if (td) {
if (Strings::RemoveNumbers(d->GetDoorName()) != Strings::RemoveNumbers(td->GetDoorName())) {
continue;
}
}
}
if (d->GetDoorParam() > 0) {
continue;
}
float distance = DistanceSquared(m_Position, d->GetPosition());
float distance_scan_door_open = 20;
if (distance <= (distance_scan_door_open * distance_scan_door_open)) {
// Make sure we're opening a door within height relevance and not platforms above or below us
if (std::abs(m_Position.z - d->GetPosition().z) > 10) {
continue;
}
d->ForceOpen(this);
}
}
}
+25 -22
View File
@@ -69,6 +69,27 @@ enum class eSpecialAttacks : int {
ChaoticStab
};
struct AppearanceStruct {
uint8 aa_title = UINT8_MAX;
uint8 beard = UINT8_MAX;
uint8 beard_color = UINT8_MAX;
uint32 drakkin_details = UINT32_MAX;
uint32 drakkin_heritage = UINT32_MAX;
uint32 drakkin_tattoo = UINT32_MAX;
uint8 eye_color_one = UINT8_MAX;
uint8 eye_color_two = UINT8_MAX;
uint8 face = UINT8_MAX;
uint8 gender_id = UINT8_MAX;
uint8 hair = UINT8_MAX;
uint8 hair_color = UINT8_MAX;
uint8 helmet_texture = UINT8_MAX;
uint16 race_id = RACE_DOUG_0;
bool send_effects = true;
float size = -1.0f;
Client *target = nullptr;
uint8 texture = UINT8_MAX;
};
class DataBucketKey;
class Mob : public Entity {
public:
@@ -889,26 +910,7 @@ public:
int64 CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, bool best_focus=false, uint16 casterid = 0, Mob *caster = nullptr);
uint8 IsFocusEffect(uint16 spellid, int effect_index, bool AA=false,uint32 aa_effect=0);
void SendIllusionPacket(
uint16 in_race,
uint8 in_gender = 0xFF,
uint8 in_texture = 0xFF,
uint8 in_helmtexture = 0xFF,
uint8 in_haircolor = 0xFF,
uint8 in_beardcolor = 0xFF,
uint8 in_eyecolor1 = 0xFF,
uint8 in_eyecolor2 = 0xFF,
uint8 in_hairstyle = 0xFF,
uint8 in_luclinface = 0xFF,
uint8 in_beard = 0xFF,
uint8 in_aa_title = 0xFF,
uint32 in_drakkin_heritage = 0xFFFFFFFF,
uint32 in_drakkin_tattoo = 0xFFFFFFFF,
uint32 in_drakkin_details = 0xFFFFFFFF,
float in_size = -1.0f,
bool send_appearance_effects = true,
Client* target = nullptr
);
void SendIllusionPacket(const AppearanceStruct& a);
void CloneAppearance(Mob* other, bool clone_name = false);
void SetFaceAppearance(const FaceChange_Struct& face, bool skip_sender = false);
bool RandomizeFeatures(bool send_illusion = true, bool set_variables = true);
@@ -1408,8 +1410,6 @@ public:
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
inline bool GetFeigned() const { return(feigned); }
std::vector<DataBucketCache> m_data_bucket_cache;
// Data Bucket Methods
void DeleteBucket(std::string bucket_name);
std::string GetBucket(std::string bucket_name);
@@ -1417,6 +1417,8 @@ public:
std::string GetBucketRemaining(std::string bucket_name);
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration = "");
uint32 GetMobTypeIdentifier();
// Heroic Stat Benefits
float CheckHeroicBonusesDataBuckets(std::string bucket_name);
@@ -1866,6 +1868,7 @@ private:
void SetHeroicWisBonuses(StatBonuses* n);
void DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana);
void HandleDoorOpen();
};
#endif
+1 -46
View File
@@ -981,52 +981,7 @@ void Mob::AI_Process() {
if (moving && CanOpenDoors()) {
if (AI_scan_door_open_timer->Check()) {
auto &door_list = entity_list.GetDoorsList();
for (auto itr : door_list) {
Doors *door = itr.second;
if (door->GetKeyItem()) {
continue;
}
if (door->GetLockpick()) {
continue;
}
if (door->IsDoorOpen()) {
continue;
}
if (door->GetTriggerDoorID() > 0) {
auto trigger_door = entity_list.GetDoorsByDoorID(door->GetTriggerDoorID());
if (trigger_door) {
if (Strings::RemoveNumbers(door->GetDoorName()) !=
Strings::RemoveNumbers(trigger_door->GetDoorName())) {
continue;
}
}
}
if (door->GetDoorParam() > 0) {
continue;
}
float distance = DistanceSquared(m_Position, door->GetPosition());
float distance_scan_door_open = 20;
if (distance <= (distance_scan_door_open * distance_scan_door_open)) {
/**
* Make sure we're opening a door within height relevance and not platforms
* above or below
*/
if (std::abs(m_Position.z - door->GetPosition().z) > 10) {
continue;
}
door->ForceOpen(this);
}
}
HandleDoorOpen();
}
}
+5 -19
View File
@@ -1219,7 +1219,7 @@ void NPC::SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_id, int32 grid_
npc_type->current_hp = 4000000;
npc_type->max_hp = 4000000;
npc_type->race = 2254;
npc_type->gender = 2;
npc_type->gender = NEUTER;
npc_type->class_ = 9;
npc_type->deity = 1;
npc_type->level = 200;
@@ -2583,30 +2583,16 @@ void NPC::ModifyNPCStat(const std::string& stat, const std::string& value)
}
else if (stat_lower == "min_hit") {
min_dmg = Strings::ToInt(value);
// TODO: fix DB
if (min_dmg > max_dmg) {
const auto temporary_damage = max_dmg;
max_dmg = min_dmg;
min_dmg = temporary_damage;
}
// Clamp max_dmg to be >= min_dmg
max_dmg = std::max(min_dmg, max_dmg);
base_damage = round((max_dmg - min_dmg) / 1.9);
min_damage = min_dmg - round(base_damage / 10.0);
return;
}
else if (stat_lower == "max_hit") {
max_dmg = Strings::ToInt(value);
// TODO: fix DB
if (max_dmg < min_dmg) {
const auto temporary_damage = min_dmg;
min_dmg = max_dmg;
max_dmg = temporary_damage;
}
// Clamp min_dmg to be <= max_dmg
min_dmg = std::min(min_dmg, max_dmg);
base_damage = round((max_dmg - min_dmg) / 1.9);
min_damage = min_dmg - round(base_damage / 10.0);
return;
+9 -16
View File
@@ -135,31 +135,24 @@ void NpcScaleManager::ScaleNPC(
npc->ModifyNPCStat("phr", std::to_string(scale_data.physical_resist));
}
auto min_damage_set = false;
// If either is scaled, both need to be. The values for base_damage and min_damage will be in flux until
// both are complete.
if (always_scale || npc->GetMinDMG() == 0) {
if (always_scale || npc->GetMinDMG() == 0 || npc->GetMaxDMG() == 0) {
int64 min_dmg = scale_data.min_dmg;
int64 max_dmg = scale_data.max_dmg;
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
uint32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
min_dmg = (min_dmg * class_level_damage_mod) / 220;
LogNPCScaling("ClassLevelDamageMod::min_dmg base: [{}] calc: [{}]", scale_data.min_dmg, min_dmg);
max_dmg = (max_dmg * class_level_damage_mod) / 220;
}
npc->ModifyNPCStat("min_hit", std::to_string(min_dmg));
min_damage_set = true;
}
if (always_scale || npc->GetMaxDMG() == 0 || min_damage_set) {
int64 max_dmg = scale_data.max_dmg;
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
uint32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
max_dmg = (scale_data.max_dmg * class_level_damage_mod) / 220;
LogNPCScaling("ClassLevelDamageMod::max_dmg base: [{}] calc: [{}]", scale_data.max_dmg, max_dmg);
}
npc->ModifyNPCStat("max_hit", std::to_string(max_dmg));
LogNPCScaling("ClassLevelDamageMod::min_dmg base: [{}] calc: [{}]", scale_data.min_dmg, min_dmg);
LogNPCScaling("ClassLevelDamageMod::max_dmg base: [{}] calc: [{}]", scale_data.max_dmg, max_dmg);
}
if (always_scale || (npc->GetHPRegen() == 0 && is_auto_scaled)) {
+1 -1
View File
@@ -529,7 +529,7 @@ void PathfinderWaypoint::ShowNode(const Node &n) {
npc_type->current_hp = 4000000;
npc_type->max_hp = 4000000;
npc_type->race = 2254;
npc_type->gender = 2;
npc_type->gender = NEUTER;
npc_type->class_ = 9;
npc_type->deity = 1;
npc_type->level = 75;
+378 -74
View File
@@ -1809,10 +1809,26 @@ void Perl_Mob_SendAppearanceEffectGround(Mob* self, int32 parm1, int32 parm2, in
void Perl_Mob_RemoveAllAppearanceEffects(Mob* self) // @categories Script Utility
{
self->SendIllusionPacket(self->GetRace(), self->GetGender(), self->GetTexture(), self->GetHelmTexture(),
self->GetHairColor(), self->GetBeardColor(), self->GetEyeColor1(), self->GetEyeColor2(),
self->GetHairStyle(), self->GetLuclinFace(), self->GetBeard(), 0xFF,
self->GetDrakkinHeritage(), self->GetDrakkinTattoo(), self->GetDrakkinDetails(), self->GetSize(), false);
self->SendIllusionPacket(
AppearanceStruct{
.beard = self->GetBeard(),
.beard_color = self->GetBeardColor(),
.drakkin_details = self->GetDrakkinDetails(),
.drakkin_heritage = self->GetDrakkinHeritage(),
.drakkin_tattoo = self->GetDrakkinTattoo(),
.eye_color_one = self->GetEyeColor1(),
.eye_color_two = self->GetEyeColor2(),
.face = self->GetLuclinFace(),
.gender_id = self->GetGender(),
.hair = self->GetHairStyle(),
.hair_color = self->GetHairColor(),
.helmet_texture = self->GetHelmTexture(),
.race_id = self->GetRace(),
.send_effects = false,
.size = self->GetSize(),
.texture = self->GetTexture(),
}
);
self->ClearAppearenceEffects();
}
@@ -1821,134 +1837,416 @@ void Perl_Mob_SetFlyMode(Mob* self, int flymode) // @categories Script Utility
self->SetFlyMode(static_cast<GravityBehavior>(flymode));
}
void Perl_Mob_SetTexture(Mob* self, int32 texture) // @categories Stats and Attributes
void Perl_Mob_SetTexture(Mob* self, uint8 texture) // @categories Stats and Attributes
{
self->SendIllusionPacket(self->GetRace(), 0xFF, texture);
self->SendIllusionPacket(
AppearanceStruct{
.race_id = self->GetRace(),
.texture = texture,
}
);
}
void Perl_Mob_SetRace(Mob* self, int32 race) // @categories Stats and Attributes
void Perl_Mob_SetRace(Mob* self, uint16 race_id) // @categories Stats and Attributes
{
self->SendIllusionPacket(race);
self->SendIllusionPacket(
AppearanceStruct{
.race_id = race_id,
}
);
}
void Perl_Mob_SetGender(Mob* self, int32 gender) // @categories Stats and Attributes
void Perl_Mob_SetGender(Mob* self, uint8 gender_id) // @categories Stats and Attributes
{
self->SendIllusionPacket(self->GetRace(), gender);
self->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = self->GetRace(),
}
);
}
// todo: SendIllusion should be sent in a hash like lua
void Perl_Mob_SendIllusion(Mob* self, uint16 race) // @categories Script Utility
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id) // @categories Script Utility
{
self->SendIllusionPacket(race);
self->SendIllusionPacket(
AppearanceStruct{
.race_id = race_id,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender) // @categories Script Utility
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id) // @categories Script Utility
{
self->SendIllusionPacket(race, gender);
self->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = race_id,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture) // @categories Script Utility
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture);
self->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture);
self->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, face);
self->SendIllusionPacket(
AppearanceStruct{
.face = face,
.gender_id = gender_id,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, 0xFF, 0xFF, 0xFF, 0xFF, hairstyle, face);
self->SendIllusionPacket(
AppearanceStruct{
.face = face,
.gender_id = gender_id,
.hair = hair,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, 0xFF, 0xFF, 0xFF, hairstyle, face);
self->SendIllusionPacket(
AppearanceStruct{
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor, uint8 beard) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color,
uint8 beard
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, 0xFF, 0xFF, 0xFF, hairstyle, face, beard);
self->SendIllusionPacket(
AppearanceStruct{
.beard = beard,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor, uint8 beard, uint8 beardcolor) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color,
uint8 beard,
uint8 beard_color
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, beardcolor, 0xFF, 0xFF, hairstyle, face, beard);
self->SendIllusionPacket(
AppearanceStruct{
.beard = beard,
.beard_color = beard_color,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor, uint8 beard, uint8 beardcolor, uint32 drakkin_heritage) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color,
uint8 beard,
uint8 beard_color,
uint32 drakkin_heritage
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, beardcolor, 0xFF, 0xFF, hairstyle, face, beard, 0xFF, drakkin_heritage);
self->SendIllusionPacket(
AppearanceStruct{
.beard = beard,
.beard_color = beard_color,
.drakkin_heritage = drakkin_heritage,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor, uint8 beard, uint8 beardcolor, uint32 drakkin_heritage, uint32 drakkin_tattoo) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color,
uint8 beard,
uint8 beard_color,
uint32 drakkin_heritage,
uint32 drakkin_tattoo
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, beardcolor, 0xFF, 0xFF, hairstyle, face, beard, 0xFF, drakkin_heritage, drakkin_tattoo);
self->SendIllusionPacket(
AppearanceStruct{
.beard = beard,
.beard_color = beard_color,
.drakkin_heritage = drakkin_heritage,
.drakkin_tattoo = drakkin_tattoo,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor, uint8 beard, uint8 beardcolor, uint32 drakkin_heritage, uint32 drakkin_tattoo, uint32 drakkin_details) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color,
uint8 beard,
uint8 beard_color,
uint32 drakkin_heritage,
uint32 drakkin_tattoo,
uint32 drakkin_details
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, beardcolor, 0xFF, 0xFF, hairstyle, face, beard, 0xFF, drakkin_heritage, drakkin_tattoo, drakkin_details);
self->SendIllusionPacket(
AppearanceStruct{
.beard = beard,
.beard_color = beard_color,
.drakkin_details = drakkin_details,
.drakkin_heritage = drakkin_heritage,
.drakkin_tattoo = drakkin_tattoo,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor, uint8 beard, uint8 beardcolor, uint32 drakkin_heritage, uint32 drakkin_tattoo, uint32 drakkin_details, float size) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color,
uint8 beard,
uint8 beard_color,
uint32 drakkin_heritage,
uint32 drakkin_tattoo,
uint32 drakkin_details,
float size
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, beardcolor, 0xFF, 0xFF, hairstyle, face, beard, 0xFF, drakkin_heritage, drakkin_tattoo, drakkin_details, size);
self->SendIllusionPacket(
AppearanceStruct{
.beard = beard,
.beard_color = beard_color,
.drakkin_details = drakkin_details,
.drakkin_heritage = drakkin_heritage,
.drakkin_tattoo = drakkin_tattoo,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.size = size,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusion(Mob* self, uint16 race, uint8 gender, uint8 texture, uint8 helmtexture, uint8 face, uint8 hairstyle, uint8 haircolor, uint8 beard, uint8 beardcolor, uint32 drakkin_heritage, uint32 drakkin_tattoo, uint32 drakkin_details, float size, Client* target) // @categories Script Utility
void Perl_Mob_SendIllusion(
Mob *self,
uint16 race_id,
uint8 gender_id,
uint8 texture,
uint8 helmet_texture,
uint8 face,
uint8 hair,
uint8 hair_color,
uint8 beard,
uint8 beard_color,
uint32 drakkin_heritage,
uint32 drakkin_tattoo,
uint32 drakkin_details,
float size,
Client *target
) // @categories Script Utility
{
self->SendIllusionPacket(race, gender, texture, helmtexture, haircolor, beardcolor, 0xFF, 0xFF, hairstyle, face, beard, 0xFF, drakkin_heritage, drakkin_tattoo, drakkin_details, size, true, target);
self->SendIllusionPacket(
AppearanceStruct{
.beard = beard,
.beard_color = beard_color,
.drakkin_details = drakkin_details,
.drakkin_heritage = drakkin_heritage,
.drakkin_tattoo = drakkin_tattoo,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.size = size,
.target = target,
.texture = texture,
}
);
}
void Perl_Mob_SendIllusionPacket(Mob* self, perl::reference table_ref)
{
perl::hash table = table_ref;
uint16 race = table.exists("race") ? table["race"] : self->GetRace();
uint8 gender = table.exists("gender") ? table["gender"] : self->GetGender();
uint8 texture = table.exists("texture") ? table["texture"] : self->GetTexture();
uint8 helmtexture = table.exists("helmtexture") ? table["helmtexture"] : self->GetHelmTexture();
uint8 haircolor = table.exists("haircolor") ? table["haircolor"] : self->GetHairColor();
uint8 beardcolor = table.exists("beardcolor") ? table["beardcolor"] : self->GetBeardColor();
uint8 eyecolor1 = table.exists("eyecolor1") ? table["eyecolor1"] : self->GetEyeColor1();
uint8 eyecolor2 = table.exists("eyecolor2") ? table["eyecolor2"] : self->GetEyeColor2();
uint8 hairstyle = table.exists("hairstyle") ? table["hairstyle"] : self->GetHairStyle();
uint8 luclinface = table.exists("luclinface") ? table["luclinface"] : self->GetLuclinFace();
uint8 beard = table.exists("beard") ? table["beard"] : self->GetBeard();
uint8 aa_title = table.exists("aa_title") ? table["aa_title"] : 255;
uint32 drakkin_heritage = table.exists("drakkin_heritage") ? table["drakkin_heritage"] : self->GetDrakkinHeritage();
uint32 drakkin_tattoo = table.exists("drakkin_tattoo") ? table["drakkin_tattoo"] : self->GetDrakkinTattoo();
uint32 drakkin_details = table.exists("drakkin_details") ? table["drakkin_details"] : self->GetDrakkinDetails();
float size = table.exists("size") ? table["size"] : self->GetSize();
bool send_appearance_effects = table.exists("send_appearance_effects") ? table["send_appearance_effects"] : true;
Client* target = table.exists("target") ? static_cast<Client *>(table["target"]) : nullptr;
uint16 race_id = table.exists("race") ? table["race"] : self->GetRace();
uint8 gender_id = table.exists("gender") ? table["gender"] : self->GetGender();
uint8 texture = table.exists("texture") ? table["texture"] : self->GetTexture();
uint8 helmet_texture = table.exists("helmtexture") ? table["helmtexture"] : self->GetHelmTexture();
uint8 hair_color = table.exists("haircolor") ? table["haircolor"] : self->GetHairColor();
uint8 beard_color = table.exists("beardcolor") ? table["beardcolor"] : self->GetBeardColor();
uint8 eye_color_one = table.exists("eyecolor1") ? table["eyecolor1"] : self->GetEyeColor1();
uint8 eye_color_two = table.exists("eyecolor2") ? table["eyecolor2"] : self->GetEyeColor2();
uint8 hair = table.exists("hairstyle") ? table["hairstyle"] : self->GetHairStyle();
uint8 face = table.exists("luclinface") ? table["luclinface"] : self->GetLuclinFace();
uint8 beard = table.exists("beard") ? table["beard"] : self->GetBeard();
uint8 aa_title = table.exists("aa_title") ? table["aa_title"] : 255;
uint32 drakkin_heritage = table.exists("drakkin_heritage") ? table["drakkin_heritage"] : self->GetDrakkinHeritage();
uint32 drakkin_tattoo = table.exists("drakkin_tattoo") ? table["drakkin_tattoo"] : self->GetDrakkinTattoo();
uint32 drakkin_details = table.exists("drakkin_details") ? table["drakkin_details"] : self->GetDrakkinDetails();
float size = table.exists("size") ? table["size"] : self->GetSize();
bool send_appearance_effects = table.exists("send_appearance_effects") ? table["send_appearance_effects"] : true;
Client *target = table.exists("target") ? static_cast<Client *>(table["target"]) : nullptr;
self->SendIllusionPacket(
race,
gender,
texture,
helmtexture,
haircolor,
beardcolor,
eyecolor1,
eyecolor2,
hairstyle,
luclinface,
beard,
aa_title,
drakkin_heritage,
drakkin_tattoo,
drakkin_details,
size,
send_appearance_effects,
target
AppearanceStruct{
.beard = beard,
.beard_color = beard_color,
.drakkin_details = drakkin_details,
.drakkin_heritage = drakkin_heritage,
.drakkin_tattoo = drakkin_tattoo,
.face = face,
.gender_id = gender_id,
.hair = hair,
.hair_color = hair_color,
.helmet_texture = helmet_texture,
.race_id = race_id,
.send_effects = send_appearance_effects,
.size = size,
.target = target,
.texture = texture,
}
);
}
@@ -3113,6 +3411,11 @@ std::string Perl_Mob_GetClassPlural(Mob* self)
return self->GetClassPlural();
}
uint32 Perl_Mob_GetMobTypeIdentifier(Mob* self)
{
return self->GetMobTypeIdentifier();
}
std::string Perl_Mob_GetRacePlural(Mob* self)
{
return self->GetRacePlural();
@@ -3399,6 +3702,7 @@ void perl_register_mob()
package.add("GetMaxSTR", &Perl_Mob_GetMaxSTR);
package.add("GetMaxWIS", &Perl_Mob_GetMaxWIS);
package.add("GetMeleeMitigation", &Perl_Mob_GetMeleeMitigation);
package.add("GetMobTypeIdentifier", &Perl_Mob_GetMobTypeIdentifier);
package.add("GetModSkillDmgTaken", &Perl_Mob_GetModSkillDmgTaken);
package.add("GetModVulnerability", &Perl_Mob_GetModVulnerability);
package.add("GetNPCTypeID", &Perl_Mob_GetNPCTypeID);
+78 -48
View File
@@ -2187,7 +2187,7 @@ bool QuestManager::isdooropen(uint32 doorid) {
return false;
}
void QuestManager::npcrace(int race_id)
void QuestManager::npcrace(uint16 race_id)
{
QuestManagerCurrentQuestVars();
@@ -2195,10 +2195,14 @@ void QuestManager::npcrace(int race_id)
return;
}
owner->SendIllusionPacket(race_id);
owner->SendIllusionPacket(
AppearanceStruct{
.race_id = race_id,
}
);
}
void QuestManager::npcgender(int gender_id)
void QuestManager::npcgender(uint8 gender_id)
{
QuestManagerCurrentQuestVars();
@@ -2206,10 +2210,15 @@ void QuestManager::npcgender(int gender_id)
return;
}
owner->SendIllusionPacket(owner->GetRace(), gender_id);
owner->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = owner->GetRace(),
}
);
}
void QuestManager::npcsize(int newsize)
void QuestManager::npcsize(float size)
{
QuestManagerCurrentQuestVars();
@@ -2217,10 +2226,10 @@ void QuestManager::npcsize(int newsize)
return;
}
owner->ChangeSize(newsize, true);
owner->ChangeSize(size, true);
}
void QuestManager::npctexture(int newtexture)
void QuestManager::npctexture(uint8 texture)
{
QuestManagerCurrentQuestVars();
@@ -2228,10 +2237,15 @@ void QuestManager::npctexture(int newtexture)
return;
}
owner->SendIllusionPacket(owner->GetRace(), 0xFF, newtexture);
owner->SendIllusionPacket(
AppearanceStruct{
.race_id = owner->GetRace(),
.texture = texture,
}
);
}
void QuestManager::playerrace(int race_id)
void QuestManager::playerrace(uint16 race_id)
{
QuestManagerCurrentQuestVars();
@@ -2239,10 +2253,14 @@ void QuestManager::playerrace(int race_id)
return;
}
initiator->SendIllusionPacket(race_id);
initiator->SendIllusionPacket(
AppearanceStruct{
.race_id = race_id,
}
);
}
void QuestManager::playergender(int gender_id)
void QuestManager::playergender(uint8 gender_id)
{
QuestManagerCurrentQuestVars();
@@ -2250,10 +2268,15 @@ void QuestManager::playergender(int gender_id)
return;
}
initiator->SendIllusionPacket(initiator->GetRace(), gender_id);
initiator->SendIllusionPacket(
AppearanceStruct{
.gender_id = gender_id,
.race_id = initiator->GetRace(),
}
);
}
void QuestManager::playersize(int newsize)
void QuestManager::playersize(float size)
{
QuestManagerCurrentQuestVars();
@@ -2261,10 +2284,10 @@ void QuestManager::playersize(int newsize)
return;
}
initiator->ChangeSize(newsize, true);
initiator->ChangeSize(size, true);
}
void QuestManager::playertexture(int newtexture)
void QuestManager::playertexture(uint8 texture)
{
QuestManagerCurrentQuestVars();
@@ -2272,7 +2295,12 @@ void QuestManager::playertexture(int newtexture)
return;
}
initiator->SendIllusionPacket(initiator->GetRace(), 0xFF, newtexture);
initiator->SendIllusionPacket(
AppearanceStruct{
.race_id = initiator->GetRace(),
.texture = texture,
}
);
}
void QuestManager::playerfeature(const char* feature, int setting)
@@ -2334,22 +2362,23 @@ void QuestManager::playerfeature(const char* feature, int setting)
}
initiator->SendIllusionPacket(
Race,
Gender,
Texture,
HelmTexture,
HairColor,
BeardColor,
EyeColor1,
EyeColor2,
HairStyle,
LuclinFace,
Beard,
0xFF,
DrakkinHeritage,
DrakkinTattoo,
DrakkinDetails,
Size
AppearanceStruct{
.beard = Beard,
.beard_color = BeardColor,
.drakkin_details = DrakkinDetails,
.drakkin_heritage = DrakkinHeritage,
.drakkin_tattoo = DrakkinTattoo,
.eye_color_one = EyeColor1,
.eye_color_two = EyeColor2,
.face = LuclinFace,
.gender_id = Gender,
.hair = HairStyle,
.hair_color = HairColor,
.helmet_texture = HelmTexture,
.race_id = Race,
.size = Size,
.texture = Texture,
}
);
}
@@ -2412,22 +2441,23 @@ void QuestManager::npcfeature(const char* feature, int setting)
}
owner->SendIllusionPacket(
Race,
Gender,
Texture,
HelmTexture,
HairColor,
BeardColor,
EyeColor1,
EyeColor2,
HairStyle,
LuclinFace,
Beard,
0xFF,
DrakkinHeritage,
DrakkinTattoo,
DrakkinDetails,
Size
AppearanceStruct{
.beard = Beard,
.beard_color = BeardColor,
.drakkin_details = DrakkinDetails,
.drakkin_heritage = DrakkinHeritage,
.drakkin_tattoo = DrakkinTattoo,
.eye_color_one = EyeColor1,
.eye_color_two = EyeColor2,
.face = LuclinFace,
.gender_id = Gender,
.hair = HairStyle,
.hair_color = HairColor,
.helmet_texture = HelmTexture,
.race_id = Race,
.size = Size,
.texture = Texture,
}
);
}
+8 -7
View File
@@ -201,13 +201,14 @@ public:
void forcedoorclose(uint32 doorid, bool altmode);
void toggledoorstate(uint32 doorid);
bool isdooropen(uint32 doorid);
void npcrace(int race_id);
void npcgender(int gender_id); void npcsize(int newsize);
void npctexture(int newtexture);
void playerrace(int race_id);
void playergender(int gender_id);
void playersize(int newsize);
void playertexture(int newtexture);
void npcrace(uint16 race_id);
void npcgender(uint8 gender_id);
void npcsize(float size);
void npctexture(uint8 texture);
void playerrace(uint16 race_id);
void playergender(uint8 gender_id);
void playersize(float size);
void playertexture(uint8 texture);
void playerfeature(const char* feature, int setting);
void npcfeature(const char* feature, int setting);
void popup(const char *title, const char *text, uint32 popupid, uint32 buttons, uint32 Duration);
+56 -55
View File
@@ -1474,9 +1474,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
if(caster && caster->GetTarget()){
SendIllusionPacket
(
caster->GetTarget()->GetRace(),
caster->GetTarget()->GetGender(),
caster->GetTarget()->GetTexture()
AppearanceStruct{
.gender_id = caster->GetTarget()->GetGender(),
.race_id = caster->GetTarget()->GetRace(),
.texture = caster->GetTarget()->GetTexture(),
}
);
caster->SendAppearancePacket(AT_Size, static_cast<uint32>(caster->GetTarget()->GetSize()));
@@ -4265,7 +4267,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
case SE_IllusionCopy:
case SE_Illusion:
{
SendIllusionPacket(0, GetBaseGender());
SendIllusionPacket(AppearanceStruct{});
// The GetSize below works because the above setting race to zero sets size back.
SendAppearancePacket(AT_Size, GetSize());
@@ -10199,36 +10201,29 @@ void Mob::ApplySpellEffectIllusion(int32 spell_id, Mob *caster, int buffslot, in
if (base == -1) {
// Specific Gender Illusions
if (spell_id == SPELL_ILLUSION_MALE || spell_id == SPELL_ILLUSION_FEMALE) {
int specific_gender = -1;
// Male
if (spell_id == SPELL_ILLUSION_MALE)
specific_gender = 0;
// Female
else if (spell_id == SPELL_ILLUSION_FEMALE)
specific_gender = 1;
if (specific_gender > -1) {
if (caster && caster->GetTarget()) {
SendIllusionPacket
(
caster->GetTarget()->GetBaseRace(),
specific_gender,
caster->GetTarget()->GetTexture()
);
}
uint8 specific_gender = spell_id == SPELL_ILLUSION_MALE ? MALE : FEMALE;
if (caster && caster->GetTarget()) {
SendIllusionPacket(
AppearanceStruct{
.gender_id = specific_gender,
.race_id = caster->GetTarget()->GetBaseRace(),
.texture = caster->GetTarget()->GetTexture(),
}
);
}
}
// Change Gender Illusions
// Change Gender Illusions
else {
if (caster && caster->GetTarget()) {
int opposite_gender = 0;
if (caster->GetTarget()->GetGender() == 0)
opposite_gender = 1;
uint8 opposite_gender = caster->GetTarget()->GetGender() == MALE ? FEMALE : MALE;
SendIllusionPacket
(
caster->GetTarget()->GetRace(),
opposite_gender,
caster->GetTarget()->GetTexture()
SendIllusionPacket(
AppearanceStruct{
.gender_id = opposite_gender,
.race_id = caster->GetTarget()->GetRace(),
.texture = caster->GetTarget()->GetTexture(),
}
);
}
}
@@ -10254,46 +10249,52 @@ void Mob::ApplySpellEffectIllusion(int32 spell_id, Mob *caster, int buffslot, in
if (max > 0) {
if (limit == 0) {
SendIllusionPacket(
base,
gender_id
AppearanceStruct{
.gender_id = static_cast<uint8>(gender_id),
.race_id = static_cast<uint16>(base),
}
);
}
else {
} else {
if (max != 3) {
SendIllusionPacket(
base,
gender_id,
limit,
max
AppearanceStruct{
.gender_id = static_cast<uint8>(gender_id),
.helmet_texture = static_cast<uint8>(max),
.race_id = static_cast<uint16>(base),
.texture = static_cast<uint8>(limit),
}
);
}
else {
} else {
SendIllusionPacket(
base,
gender_id,
limit,
limit
AppearanceStruct{
.gender_id = static_cast<uint8>(gender_id),
.helmet_texture = static_cast<uint8>(limit),
.race_id = static_cast<uint16>(base),
.texture = static_cast<uint8>(limit),
}
);
}
}
}
else {
} else {
SendIllusionPacket(
base,
gender_id,
limit,
max
AppearanceStruct{
.gender_id = static_cast<uint8>(gender_id),
.helmet_texture = static_cast<uint8>(max),
.race_id = static_cast<uint16>(base),
.texture = static_cast<uint8>(limit),
}
);
}
}
else {
} else {
SendIllusionPacket(
base,
gender_id,
limit
AppearanceStruct{
.gender_id = static_cast<uint8>(gender_id),
.race_id = static_cast<uint16>(base),
.texture = static_cast<uint8>(limit),
}
);
}
SendAppearancePacket(AT_Size, race_size);
}
+1 -1
View File
@@ -5886,7 +5886,7 @@ bool Client::SpellBucketCheck(uint16 spell_id, uint32 character_id) {
spell_bucket_name
);
auto bucket_value = DataBucket::GetData(old_bucket_name);
std::string bucket_value = DataBucket::GetData(old_bucket_name);
if (!bucket_value.empty()) {
if (Strings::IsNumber(bucket_value) && Strings::IsNumber(spell_bucket_value)) {
if (Strings::ToInt(bucket_value) >= Strings::ToInt(spell_bucket_value)) {
+1 -1
View File
@@ -510,7 +510,7 @@ void Trap::CreateHiddenTrigger()
make_npc->runspeed = 0.0f;
make_npc->bodytype = BT_Special;
make_npc->race = 127;
make_npc->gender = 0;
make_npc->gender = MALE;
make_npc->loottable_id = 0;
make_npc->npc_spells_id = 0;
make_npc->d_melee_texture1 = 0;
+11
View File
@@ -2004,6 +2004,12 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true);
break;
}
case ServerOP_ReloadDataBucketsCache:
{
zone->SendReloadMessage("Data buckets cache");
DataBucket::ClearCache();
break;
}
case ServerOP_ReloadDoors:
case ServerOP_ReloadGroundSpawns:
case ServerOP_ReloadObjects:
@@ -3329,6 +3335,11 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
SharedTaskZoneMessaging::HandleWorldMessage(pack);
break;
}
case ServerOP_DataBucketCacheUpdate:
{
DataBucket::HandleWorldMessage(pack);
break;
}
default: {
LogInfo("Unknown ZS Opcode [{}] size [{}]", (int)pack->opcode, pack->size);
break;
+11 -1
View File
@@ -1927,6 +1927,8 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
);
}
std::vector<uint32> npc_ids;
for (NpcTypesRepository::NpcTypes &n : NpcTypesRepository::GetWhere((Database &) content_db, filter)) {
NPCType *t;
t = new NPCType;
@@ -2137,8 +2139,15 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
zone->npctable[t->npc_id] = t;
npc = t;
// If NPC ID is not in npc_ids, add to vector
if (!std::count(npc_ids.begin(), npc_ids.end(), t->npc_id)) {
npc_ids.emplace_back(t->npc_id);
}
}
DataBucket::BulkLoadEntities(DataBucketLoadType::NPC, npc_ids);
return npc;
}
@@ -3303,7 +3312,8 @@ void ZoneDatabase::SavePetInfo(Client *client)
// build pet buffs into struct
int pet_buff_count = 0;
int max_slots = RuleI(Spells, MaxTotalSlotsPET);
// Guard against setting the maximum pet slots above the client allowed maximum.
int max_slots = RuleI(Spells, MaxTotalSlotsPET) > PET_BUFF_COUNT ? PET_BUFF_COUNT : RuleI(Spells, MaxTotalSlotsPET);
// count pet buffs
for (int index = 0; index < max_slots; index++) {
+2 -1
View File
@@ -11,6 +11,7 @@
#include "aa_ability.h"
#include "event_codes.h"
#include "../common/repositories/doors_repository.h"
#include "../common/races.h"
#include "bot_database.h"
@@ -339,7 +340,7 @@ namespace BeastlordPetData {
uint16 race_id = WOLF;
uint8 texture = 0;
uint8 helm_texture = 0;
uint8 gender = 2;
uint8 gender = NEUTER;
float size_modifier = 1.0f;
uint8 face = 0;
};