mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-24 10:02:28 +00:00
Compare commits
68 Commits
v22.47.0
...
multiquest
| Author | SHA1 | Date | |
|---|---|---|---|
| caae34ac5e | |||
| 56c7db4cbf | |||
| 043eeced6f | |||
| e9a0c79301 | |||
| dc48c45421 | |||
| d7a8fb8691 | |||
| 3a5381d38a | |||
| e64f03fcc0 | |||
| d77966797e | |||
| 048aad437b | |||
| b2d9de8d96 | |||
| 42bfa4bb2e | |||
| 72ce7c8e91 | |||
| e306c86875 | |||
| 3ae7979a67 | |||
| b638795f9b | |||
| 9e3bf91374 | |||
| cd89926435 | |||
| e19f72f021 | |||
| df1dc5d1e4 | |||
| e11286164f | |||
| b946b800fb | |||
| ab8ac81df6 | |||
| 109940fc0c | |||
| a87496b0cf | |||
| f905ee70e4 | |||
| 52417023f8 | |||
| 20d9417628 | |||
| 4692799677 | |||
| cf7f0f4321 | |||
| 823a5956de | |||
| 6a8bd3c5d6 | |||
| 523ba30d81 | |||
| d7ea290b6b | |||
| 036309ebec | |||
| b400700d81 | |||
| 21cec87ac4 | |||
| abdec39cdd | |||
| d2372de982 | |||
| ea9b7841d4 | |||
| 8826d7b927 | |||
| e4157f0221 | |||
| 66cc947b2a | |||
| 5bfd8f5da2 | |||
| 96830b4a19 | |||
| 4bf60a6522 | |||
| 16cb7364e8 | |||
| f5050ab5dc | |||
| e32cbf19ee | |||
| ee12a7ad2e | |||
| e5bdbc4f1e | |||
| f829a99e6d | |||
| 82aa6a1587 | |||
| 161c13f457 | |||
| b29c26becb | |||
| e48dae2392 | |||
| 4b83a96f64 | |||
| 95cc22ffbb | |||
| 6ca11256c6 | |||
| d94493468c | |||
| 957b4f8821 | |||
| 5013459824 | |||
| 94af2843e3 | |||
| 3bfb148bdc | |||
| 96370e0298 | |||
| fef5108b0d | |||
| 6f883566f6 | |||
| 45b1501c8a |
@@ -1,3 +1,60 @@
|
||||
## [22.48.0] 3/23/2024
|
||||
|
||||
### Bots
|
||||
|
||||
* IsValidTarget Crash Fix ([#4187](https://github.com/EQEmu/Server/pull/4187)) @nytmyr 2024-03-12
|
||||
* Move BotGroupSay to Pet Response ([#4171](https://github.com/EQEmu/Server/pull/4171)) @nytmyr 2024-03-08
|
||||
|
||||
### Code
|
||||
|
||||
* Cleanup Zone Get Methods ([#4169](https://github.com/EQEmu/Server/pull/4169)) @Kinglykrab 2024-03-09
|
||||
|
||||
### Fixes
|
||||
|
||||
* An Update to Xtarget to exclude Bot owned Temp/Swarm Pets ([#4172](https://github.com/EQEmu/Server/pull/4172)) @MortimerGreenwald 2024-03-08
|
||||
* Fix #serverrules Command ([#4193](https://github.com/EQEmu/Server/pull/4193)) @Kinglykrab 2024-03-20
|
||||
* Fix Bot Cloning ([#4186](https://github.com/EQEmu/Server/pull/4186)) @Kinglykrab 2024-03-17
|
||||
* Fix Crash in ClientList::GetCLEIP ([#4173](https://github.com/EQEmu/Server/pull/4173)) @Kinglykrab 2024-03-10
|
||||
* Fix Default Value in `rule_values` table ([#4166](https://github.com/EQEmu/Server/pull/4166)) @Kinglykrab 2024-03-07
|
||||
* Fix EVENT_KILLED_MERIT firing before NPC removal ([#4185](https://github.com/EQEmu/Server/pull/4185)) @Kinglykrab 2024-03-17
|
||||
* Fix Empty Groups When Removing Bots ([#4178](https://github.com/EQEmu/Server/pull/4178)) @Kinglykrab 2024-03-14
|
||||
* Fix GetLeaderName() for Groups ([#4184](https://github.com/EQEmu/Server/pull/4184)) @Kinglykrab 2024-03-14
|
||||
* Fix Mob::CalculateDistance(mob) Typo ([#4183](https://github.com/EQEmu/Server/pull/4183)) @Kinglykrab 2024-03-10
|
||||
* Fix Proximity Say ([#4189](https://github.com/EQEmu/Server/pull/4189)) @Kinglykrab 2024-03-15
|
||||
* Fix ScaleNPC() in Perl ([#4196](https://github.com/EQEmu/Server/pull/4196)) @Kinglykrab 2024-03-23
|
||||
* Fix range_percent ([#4197](https://github.com/EQEmu/Server/pull/4197)) @Kinglykrab 2024-03-22
|
||||
* Fix reusing timers ([#4199](https://github.com/EQEmu/Server/pull/4199)) @joligario 2024-03-23
|
||||
|
||||
### Hot Fix
|
||||
|
||||
* Add bool return to fix Client::RemoveAAPoints ([#4176](https://github.com/EQEmu/Server/pull/4176)) @Kinglykrab 2024-03-09
|
||||
|
||||
### Loot
|
||||
|
||||
* Fix issue with nested data being loaded multiple times ([#4192](https://github.com/EQEmu/Server/pull/4192)) @Akkadius 2024-03-23
|
||||
|
||||
### Misc
|
||||
|
||||
* Windows preprocessor define in crash.cpp ([#4191](https://github.com/EQEmu/Server/pull/4191)) @joligario 2024-03-23
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add Buff Support to Perl/Lua ([#4182](https://github.com/EQEmu/Server/pull/4182)) @Kinglykrab 2024-03-14
|
||||
* Add DeleteBot() to Perl/Lua ([#4167](https://github.com/EQEmu/Server/pull/4167)) @nytmyr 2024-03-07
|
||||
* Add GetDeityName() to Perl/Lua ([#4180](https://github.com/EQEmu/Server/pull/4180)) @Kinglykrab 2024-03-14
|
||||
* Add RemoveAAPoints() and AA Loss Event to Perl/Lua ([#4174](https://github.com/EQEmu/Server/pull/4174)) @Kinglykrab 2024-03-09
|
||||
* Add RemoveAlternateCurrencyValue() to Perl/Lua ([#4190](https://github.com/EQEmu/Server/pull/4190)) @Kinglykrab 2024-03-17
|
||||
* Add Restore Methods for Health, Mana, and Endurance to Perl/Lua ([#4179](https://github.com/EQEmu/Server/pull/4179)) @Kinglykrab 2024-03-23
|
||||
* Add Silent Saylink Methods to Perl/Lua ([#4177](https://github.com/EQEmu/Server/pull/4177)) @Kinglykrab 2024-03-14
|
||||
|
||||
### Rules
|
||||
|
||||
* Add World:Rules Rule ([#4194](https://github.com/EQEmu/Server/pull/4194)) @Kinglykrab 2024-03-23
|
||||
|
||||
### Tradeskills
|
||||
|
||||
* Implement learning recipes from books ([#4170](https://github.com/EQEmu/Server/pull/4170)) @hgtw 2024-03-23
|
||||
|
||||
## [22.47.0] 3/5/2024
|
||||
|
||||
### Crash Fix
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "../../common/content/world_content_service.h"
|
||||
#include "../../common/zone_store.h"
|
||||
#include "../../common/path_manager.h"
|
||||
#include "../../common/repositories/skill_caps_repository.h"
|
||||
#include "../../common/file.h"
|
||||
|
||||
EQEmuLogSys LogSys;
|
||||
WorldContentService content_service;
|
||||
@@ -164,81 +166,76 @@ void ExportSpells(SharedDatabase *db)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
|
||||
bool SkillUsable(SharedDatabase* db, int skill_id, int class_id)
|
||||
{
|
||||
|
||||
bool res = false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT max(cap) FROM skill_caps WHERE class=%d AND skillID=%d",
|
||||
class_id, skill_id
|
||||
const auto& l = SkillCapsRepository::GetWhere(
|
||||
*db,
|
||||
fmt::format(
|
||||
"`class_id` = {} AND `skill_id` = {} ORDER BY `cap` DESC LIMIT 1",
|
||||
class_id,
|
||||
skill_id
|
||||
)
|
||||
);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
if (row[0] && Strings::ToInt(row[0]) > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !l.empty();
|
||||
}
|
||||
|
||||
int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
|
||||
uint32 GetSkill(SharedDatabase* db, int skill_id, int class_id, int level)
|
||||
{
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT cap FROM skill_caps WHERE class=%d AND skillID=%d AND level=%d",
|
||||
class_id, skill_id, level
|
||||
const auto& l = SkillCapsRepository::GetWhere(
|
||||
*db,
|
||||
fmt::format(
|
||||
"`class_id` = {} AND `skill_id` = {} AND `level` = {}",
|
||||
class_id,
|
||||
skill_id,
|
||||
level
|
||||
)
|
||||
);
|
||||
auto results = db->QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
|
||||
if (l.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
return 0;
|
||||
}
|
||||
auto e = l.front();
|
||||
|
||||
auto row = results.begin();
|
||||
return Strings::ToInt(row[0]);
|
||||
return e.cap;
|
||||
}
|
||||
|
||||
void ExportSkillCaps(SharedDatabase *db)
|
||||
void ExportSkillCaps(SharedDatabase* db)
|
||||
{
|
||||
LogInfo("Exporting Skill Caps");
|
||||
|
||||
std::string file = fmt::format("{}/export/SkillCaps.txt", path.GetServerPath());
|
||||
FILE *f = fopen(file.c_str(), "w");
|
||||
if (!f) {
|
||||
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
|
||||
if (!file || !file.is_open()) {
|
||||
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int cl = 1; cl <= 16; ++cl) {
|
||||
for (int skill = 0; skill <= 77; ++skill) {
|
||||
if (SkillUsable(db, skill, cl)) {
|
||||
int previous_cap = 0;
|
||||
for (int level = 1; level <= 100; ++level) {
|
||||
int cap = GetSkill(db, skill, cl, level);
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
|
||||
for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) {
|
||||
if (SkillUsable(db, skill_id, class_id)) {
|
||||
uint32 previous_cap = 0;
|
||||
for (uint8 level = 1; level <= skill_cap_max_level; level++) {
|
||||
uint32 cap = GetSkill(db, skill_id, class_id, level);
|
||||
if (cap < previous_cap) {
|
||||
cap = previous_cap;
|
||||
}
|
||||
|
||||
fprintf(f, "%d^%d^%d^%d^0\n", cl, skill, level, cap);
|
||||
file << fmt::format("{}^{}^{}^{}^0", class_id, skill_id, level, cap) << std::endl;
|
||||
|
||||
previous_cap = cap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ExportBaseData(SharedDatabase *db)
|
||||
|
||||
+11
-9
@@ -83,6 +83,7 @@ SET(common_sources
|
||||
shared_tasks.cpp
|
||||
shareddb.cpp
|
||||
skills.cpp
|
||||
skill_caps.cpp
|
||||
spdat.cpp
|
||||
strings.cpp
|
||||
struct_strategy.cpp
|
||||
@@ -492,7 +493,7 @@ SET(repositories
|
||||
repositories/zone_repository.h
|
||||
repositories/zone_points_repository.h
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
SET(common_headers
|
||||
additive_lagged_fibonacci_engine.h
|
||||
@@ -592,7 +593,7 @@ SET(common_headers
|
||||
ptimer.h
|
||||
queue.h
|
||||
races.h
|
||||
raid.h
|
||||
raid.h
|
||||
random.h
|
||||
rdtsc.h
|
||||
rulesys.h
|
||||
@@ -606,6 +607,7 @@ SET(common_headers
|
||||
shared_tasks.h
|
||||
shareddb.h
|
||||
skills.h
|
||||
skill_caps.h
|
||||
spdat.h
|
||||
strings.h
|
||||
struct_strategy.h
|
||||
@@ -681,13 +683,13 @@ SOURCE_GROUP(Event FILES
|
||||
event/event_loop.h
|
||||
event/timer.h
|
||||
event/task.h
|
||||
)
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Json FILES
|
||||
json/json.h
|
||||
json/jsoncpp.cpp
|
||||
json/json-forwards.h
|
||||
)
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Net FILES
|
||||
net/console_server.cpp
|
||||
@@ -724,7 +726,7 @@ SOURCE_GROUP(Net FILES
|
||||
net/websocket_server.h
|
||||
net/websocket_server_connection.cpp
|
||||
net/websocket_server_connection.h
|
||||
)
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Patches FILES
|
||||
patches/patches.h
|
||||
@@ -768,12 +770,12 @@ SOURCE_GROUP(Patches FILES
|
||||
patches/titanium_limits.cpp
|
||||
patches/uf.cpp
|
||||
patches/uf_limits.cpp
|
||||
)
|
||||
)
|
||||
|
||||
SOURCE_GROUP(StackWalker FILES
|
||||
StackWalker/StackWalker.h
|
||||
StackWalker/StackWalker.cpp
|
||||
)
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Util FILES
|
||||
util/memory_stream.h
|
||||
@@ -781,7 +783,7 @@ SOURCE_GROUP(Util FILES
|
||||
util/directory.h
|
||||
util/uuid.cpp
|
||||
util/uuid.h
|
||||
)
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker)
|
||||
|
||||
@@ -794,6 +796,6 @@ ENDIF (UNIX)
|
||||
|
||||
IF (WIN32 AND EQEMU_BUILD_PCH)
|
||||
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h)
|
||||
ENDIF()
|
||||
ENDIF ()
|
||||
|
||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
#if WINDOWS
|
||||
#ifdef _WINDOWS
|
||||
#define popen _popen
|
||||
#endif
|
||||
|
||||
|
||||
+1011
-1285
File diff suppressed because it is too large
Load Diff
+145
-139
@@ -18,8 +18,8 @@
|
||||
#ifndef EQEMU_DATABASE_H
|
||||
#define EQEMU_DATABASE_H
|
||||
|
||||
#define AUTHENTICATION_TIMEOUT 60
|
||||
#define INVALID_ID 0xFFFFFFFF
|
||||
#define AUTHENTICATION_TIMEOUT 60
|
||||
#define INVALID_ID 0xFFFFFFFF
|
||||
|
||||
#include "global_define.h"
|
||||
#include "eqemu_logsys.h"
|
||||
@@ -38,8 +38,7 @@
|
||||
class MySQLRequestResult;
|
||||
class Client;
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace EQ {
|
||||
class InventoryProfile;
|
||||
}
|
||||
|
||||
@@ -52,10 +51,11 @@ struct npcDecayTimes_Struct {
|
||||
|
||||
struct VarCache_Struct {
|
||||
std::map<std::string, std::string> m_cache;
|
||||
uint32 last_update;
|
||||
uint32 last_update;
|
||||
VarCache_Struct() : last_update(0) { }
|
||||
void Add(const std::string &key, const std::string &value) { m_cache[key] = value; }
|
||||
const std::string *Get(const std::string &key) {
|
||||
void Add(const std::string& key, const std::string& value) { m_cache[key] = value; }
|
||||
const std::string* Get(const std::string& key)
|
||||
{
|
||||
auto it = m_cache.find(key);
|
||||
return (it != m_cache.end() ? &it->second : nullptr);
|
||||
}
|
||||
@@ -76,37 +76,33 @@ class PTimerList;
|
||||
|
||||
#define SQL(...) #__VA_ARGS__
|
||||
|
||||
class LogSettings;
|
||||
class Database : public DBcore {
|
||||
public:
|
||||
Database();
|
||||
Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port, std::string connection_label = "default");
|
||||
Database(
|
||||
const std::string& host,
|
||||
const std::string& user,
|
||||
const std::string& password,
|
||||
const std::string& database,
|
||||
uint32 port
|
||||
);
|
||||
bool Connect(
|
||||
const std::string& host,
|
||||
const std::string& user,
|
||||
const std::string& password,
|
||||
const std::string& database,
|
||||
uint32 port,
|
||||
std::string connection_label = "default"
|
||||
);
|
||||
~Database();
|
||||
|
||||
/* Character Creation */
|
||||
|
||||
bool CreateCharacter(
|
||||
uint32 account_id,
|
||||
char *name,
|
||||
uint16 gender,
|
||||
uint16 race,
|
||||
uint16 class_,
|
||||
uint8 str,
|
||||
uint8 sta,
|
||||
uint8 cha,
|
||||
uint8 dex,
|
||||
uint8 int_,
|
||||
uint8 agi,
|
||||
uint8 wis,
|
||||
uint8 face
|
||||
);
|
||||
bool DeleteCharacter(char *character_name);
|
||||
bool MoveCharacterToZone(const char *charname, uint32 zone_id);
|
||||
bool DeleteCharacter(const std::string& name);
|
||||
bool MoveCharacterToZone(const std::string& name, uint32 zone_id);
|
||||
bool MoveCharacterToZone(uint32 character_id, uint32 zone_id);
|
||||
bool ReserveName(uint32 account_id, char *name);
|
||||
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp);
|
||||
bool UpdateName(const char *oldname, const char *newname);
|
||||
bool ReserveName(uint32 account_id, const std::string& name);
|
||||
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
|
||||
bool UpdateName(const std::string& old_name, const std::string& new_name);
|
||||
bool CopyCharacter(
|
||||
const std::string& source_character_name,
|
||||
const std::string& destination_character_name,
|
||||
@@ -114,161 +110,171 @@ public:
|
||||
);
|
||||
|
||||
/* General Information Queries */
|
||||
bool AddBannedIP(const std::string& banned_ip, const std::string& notes); //Add IP address to the banned_ips table.
|
||||
bool AddToNameFilter(const std::string& name);
|
||||
bool CheckBannedIPs(const std::string& login_ip); //Check incoming connection against banned IP table.
|
||||
bool CheckGMIPs(const std::string& login_ip, uint32 account_id);
|
||||
bool CheckNameFilter(const std::string& name, bool surname = false);
|
||||
bool IsNameUsed(const std::string& name);
|
||||
|
||||
bool AddBannedIP(std::string banned_ip, std::string notes); //Add IP address to the banned_ips table.
|
||||
bool AddToNameFilter(std::string name);
|
||||
bool CheckBannedIPs(std::string login_ip); //Check incoming connection against banned IP table.
|
||||
bool CheckGMIPs(std::string login_ip, uint32 account_id);
|
||||
bool CheckNameFilter(std::string name, bool surname = false);
|
||||
bool CheckUsedName(std::string name);
|
||||
uint32 GetAccountIDByChar(const std::string& name, uint32* character_id = 0);
|
||||
uint32 GetAccountIDByChar(uint32 character_id);
|
||||
uint32 GetAccountIDByName(const std::string& account_name, const std::string& loginserver, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetCharacterID(const std::string& name);
|
||||
uint32 GetGuildIDByCharID(uint32 character_id);
|
||||
uint32 GetGroupIDByCharID(uint32 character_id);
|
||||
uint32 GetRaidIDByCharID(uint32 character_id);
|
||||
|
||||
uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0);
|
||||
uint32 GetAccountIDByChar(uint32 char_id);
|
||||
uint32 GetAccountIDByName(std::string account_name, std::string loginserver, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetCharacterID(const std::string& name);
|
||||
uint32 GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id);
|
||||
uint32 GetGuildIDByCharID(uint32 char_id);
|
||||
uint32 GetGroupIDByCharID(uint32 char_id);
|
||||
uint32 GetRaidIDByCharID(uint32 char_id);
|
||||
|
||||
void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0);
|
||||
void GetCharName(uint32 char_id, char* name);
|
||||
std::string GetCharNameByID(uint32 char_id);
|
||||
std::string GetNPCNameByID(uint32 npc_id);
|
||||
std::string GetCleanNPCNameByID(uint32 npc_id);
|
||||
void LoginIP(uint32 account_id, std::string login_ip);
|
||||
const std::string GetAccountName(uint32 account_id, uint32* lsaccount_id = 0);
|
||||
const std::string GetCharName(uint32 character_id);
|
||||
const std::string GetCharNameByID(uint32 character_id);
|
||||
const std::string GetNPCNameByID(uint32 npc_id);
|
||||
const std::string GetCleanNPCNameByID(uint32 npc_id);
|
||||
void LoginIP(uint32 account_id, const std::string& login_ip);
|
||||
|
||||
/* Instancing */
|
||||
|
||||
bool AddClientToInstance(uint16 instance_id, uint32 character_id);
|
||||
bool CheckInstanceByCharID(uint16 instance_id, uint32 character_id);
|
||||
bool CheckInstanceExists(uint16 instance_id);
|
||||
bool CheckInstanceExpired(uint16 instance_id);
|
||||
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
|
||||
bool GetUnusedInstanceID(uint16 &instance_id);
|
||||
bool GetUnusedInstanceID(uint16& instance_id);
|
||||
bool IsGlobalInstance(uint16 instance_id);
|
||||
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
|
||||
bool RemoveClientsFromInstance(uint16 instance_id);
|
||||
bool VerifyInstanceAlive(uint16 instance_id, uint32 character_id);
|
||||
bool VerifyZoneInstance(uint32 zone_id, uint16 instance_id);
|
||||
|
||||
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
|
||||
uint16 GetInstanceID(uint32 zone, uint32 character_id, int16 version);
|
||||
std::vector<uint16> GetInstanceIDs(uint32 zone_id, uint32 character_id);
|
||||
uint8_t GetInstanceVersion(uint16 instance_id);
|
||||
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma);
|
||||
uint32 GetTimeRemainingInstance(uint16 instance_id, bool& is_perma);
|
||||
uint32 GetInstanceZoneID(uint16 instance_id);
|
||||
|
||||
void AssignGroupToInstance(uint32 gid, uint32 instance_id);
|
||||
void AssignRaidToInstance(uint32 rid, uint32 instance_id);
|
||||
void AssignGroupToInstance(uint32 group_id, uint32 instance_id);
|
||||
void AssignRaidToInstance(uint32 raid_id, uint32 instance_id);
|
||||
void DeleteInstance(uint16 instance_id);
|
||||
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 charid, uint32 group_id);
|
||||
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 charid, uint32 raid_id);
|
||||
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids);
|
||||
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id);
|
||||
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 raid_id);
|
||||
void GetCharactersInInstance(uint16 instance_id, std::list<uint32>& character_ids);
|
||||
void PurgeExpiredInstances();
|
||||
void SetInstanceDuration(uint16 instance_id, uint32 new_duration);
|
||||
void CleanupInstanceCorpses();
|
||||
|
||||
/* Adventure related. */
|
||||
|
||||
void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win = false, bool remove = false);
|
||||
bool GetAdventureStats(uint32 char_id, AdventureStats_Struct *as);
|
||||
void UpdateAdventureStatsEntry(uint32 character_id, uint8 theme_id, bool is_win = false, bool is_remove = false);
|
||||
bool GetAdventureStats(uint32 character_id, AdventureStats_Struct* as);
|
||||
|
||||
/* Account Related */
|
||||
const std::string GetLiveChar(uint32 account_id);
|
||||
bool SetAccountStatus(const std::string& account_name, int16 status);
|
||||
bool SetLocalPassword(uint32 account_id, const std::string& password);
|
||||
bool UpdateLiveChar(const std::string& name, uint32 account_id);
|
||||
int16 CheckStatus(uint32 account_id);
|
||||
void SetAccountCRCField(uint32 account_id, const std::string& field_name, uint64 checksum);
|
||||
uint32 CheckLogin(const std::string& name, const std::string& password, const std::string& loginserver, int16* status = 0);
|
||||
uint32 CreateAccount(
|
||||
const std::string& name,
|
||||
const std::string& password,
|
||||
int16 status,
|
||||
const std::string& loginserver,
|
||||
uint32 lsaccount_id
|
||||
);
|
||||
uint32 GetAccountIDFromLSID(
|
||||
const std::string& in_loginserver_id,
|
||||
uint32 in_loginserver_account_id,
|
||||
char* in_account_name = 0,
|
||||
int16* in_status = 0
|
||||
);
|
||||
|
||||
bool DeleteAccount(const char *name, const char* loginserver);
|
||||
bool GetLiveChar(uint32 account_id, char* cname);
|
||||
bool SetAccountStatus(const char* name, int16 status);
|
||||
bool SetAccountStatus(const std::string& account_name, int16 status);
|
||||
bool SetLocalPassword(uint32 accid, const char* password);
|
||||
bool UpdateLiveChar(char* charname, uint32 account_id);
|
||||
uint8 GetAgreementFlag(uint32 account_id);
|
||||
void SetAgreementFlag(uint32 account_id);
|
||||
|
||||
int16 CheckStatus(uint32 account_id);
|
||||
int GetIPExemption(const std::string& account_ip);
|
||||
void SetIPExemption(const std::string& account_ip, int exemption_amount);
|
||||
|
||||
void SetAccountCRCField(uint32 account_id, std::string field_name, uint64 checksum);
|
||||
|
||||
uint32 CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus = 0);
|
||||
uint32 CreateAccount(const char* name, const char* password, int16 status, const char* loginserver, uint32 lsaccount_id);
|
||||
uint32 GetAccountIDFromLSID(const std::string& in_loginserver_id, uint32 in_loginserver_account_id, char* in_account_name = 0, int16* in_status = 0);
|
||||
uint8 GetAgreementFlag(uint32 account_id);
|
||||
|
||||
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
|
||||
void SetAgreementFlag(uint32 account_id);
|
||||
|
||||
int GetIPExemption(std::string account_ip);
|
||||
void SetIPExemption(std::string account_ip, int exemption_amount);
|
||||
|
||||
int GetInstanceID(uint32 char_id, uint32 zone_id);
|
||||
int GetInstanceID(uint32 character_id, uint32 zone_id);
|
||||
|
||||
|
||||
/* Groups */
|
||||
|
||||
std::string GetGroupLeaderForLogin(std::string character_name);
|
||||
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
|
||||
|
||||
uint32 GetGroupID(const char* name);
|
||||
|
||||
void ClearGroup(uint32 gid = 0);
|
||||
void ClearGroupLeader(uint32 gid = 0);
|
||||
void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false);
|
||||
void SetGroupLeaderName(uint32 gid, const char* name);
|
||||
std::string GetGroupLeaderForLogin(const std::string& character_name);
|
||||
char* GetGroupLeadershipInfo(
|
||||
uint32 group_id,
|
||||
char* leaderbuf,
|
||||
char* maintank = nullptr,
|
||||
char* assist = nullptr,
|
||||
char* puller = nullptr,
|
||||
char* marknpc = nullptr,
|
||||
char* mentoree = nullptr,
|
||||
int* mentor_percent = nullptr,
|
||||
GroupLeadershipAA_Struct* GLAA = nullptr
|
||||
);
|
||||
std::string GetGroupLeaderName(uint32 group_id);
|
||||
uint32 GetGroupID(const std::string& name);
|
||||
void ClearGroup(uint32 group_id = 0);
|
||||
void ClearGroupLeader(uint32 group_id = 0);
|
||||
void SetGroupLeaderName(uint32 group_id, const std::string& name);
|
||||
|
||||
/* Raids */
|
||||
const std::string GetRaidLeaderName(uint32 raid_id);
|
||||
uint32 GetRaidID(const std::string& name);
|
||||
void ClearRaid(uint32 raid_id = 0);
|
||||
void ClearRaidDetails(uint32 raid_id = 0);
|
||||
void ClearRaidLeader(uint32 group_id = std::numeric_limits<uint32>::max(), uint32 raid_id = 0);
|
||||
void GetGroupLeadershipInfo(
|
||||
uint32 group_id,
|
||||
uint32 raid_id,
|
||||
char* maintank = nullptr,
|
||||
char* assist = nullptr,
|
||||
char* puller = nullptr,
|
||||
char* marknpc = nullptr,
|
||||
char* mentoree = nullptr,
|
||||
int* mentor_percent = nullptr,
|
||||
GroupLeadershipAA_Struct* GLAA = nullptr
|
||||
);
|
||||
void GetRaidLeadershipInfo(
|
||||
uint32 raid_id,
|
||||
char* maintank = nullptr,
|
||||
char* assist = nullptr,
|
||||
char* puller = nullptr,
|
||||
char* marknpc = nullptr,
|
||||
RaidLeadershipAA_Struct* RLAA = nullptr
|
||||
);
|
||||
void SetRaidGroupLeaderInfo(uint32 group_id, uint32 raid_id);
|
||||
|
||||
const char *GetRaidLeaderName(uint32 rid);
|
||||
|
||||
uint32 GetRaidID(const char* name);
|
||||
|
||||
void ClearRaid(uint32 rid = 0);
|
||||
void ClearRaidDetails(uint32 rid = 0);
|
||||
void ClearRaidLeader(uint32 gid = 0xFFFFFFFF, uint32 rid = 0);
|
||||
void GetGroupLeadershipInfo(uint32 gid, uint32 rid, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
|
||||
void GetRaidLeadershipInfo(uint32 rid, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, RaidLeadershipAA_Struct* RLAA = nullptr);
|
||||
void SetRaidGroupLeaderInfo(uint32 gid, uint32 rid);
|
||||
|
||||
void PurgeAllDeletedDataBuckets();
|
||||
void PurgeAllDeletedDataBuckets();
|
||||
|
||||
|
||||
/* Database Variables */
|
||||
bool GetVariable(const std::string& name, std::string& value);
|
||||
bool SetVariable(const std::string& name, const std::string& value);
|
||||
bool LoadVariables();
|
||||
|
||||
bool GetVariable(std::string varname, std::string &varvalue);
|
||||
bool SetVariable(const std::string& varname, const std::string &varvalue);
|
||||
bool LoadVariables();
|
||||
uint8 GetPEQZone(uint32 zone_id, uint32 version);
|
||||
uint32 GetServerType();
|
||||
void AddReport(const std::string& who, const std::string& against, const std::string& lines);
|
||||
struct TimeOfDay_Struct LoadTime(time_t& realtime);
|
||||
bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year);
|
||||
void ClearMerchantTemp();
|
||||
void ClearPTimers(uint32 character_id);
|
||||
void SetFirstLogon(uint32 character_id, uint8 first_logon);
|
||||
void SetLFG(uint32 character_id, bool is_lfg);
|
||||
void SetLFP(uint32 character_id, bool is_lfp);
|
||||
void SetLoginFlags(uint32 character_id, bool is_lfp, bool is_lfg, uint8 first_logon);
|
||||
|
||||
/* General Queries */
|
||||
int64 CountInvSnapshots();
|
||||
void ClearInvSnapshots(bool from_now = false);
|
||||
|
||||
bool GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0);
|
||||
bool LoadPTimers(uint32 charid, PTimerList &into);
|
||||
|
||||
uint8 GetPEQZone(uint32 zone_id, uint32 version);
|
||||
uint8 GetMinStatus(uint32 zone_id, uint32 instance_version);
|
||||
uint8 GetRaceSkill(uint8 skillid, uint8 in_race);
|
||||
uint8 GetServerType();
|
||||
uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level);
|
||||
|
||||
void AddReport(std::string who, std::string against, std::string lines);
|
||||
struct TimeOfDay_Struct LoadTime(time_t &realtime);
|
||||
bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year);
|
||||
void ClearMerchantTemp();
|
||||
void ClearPTimers(uint32 charid);
|
||||
void SetFirstLogon(uint32 CharID, uint8 firstlogon);
|
||||
void SetLFG(uint32 CharID, bool LFG);
|
||||
void SetLFP(uint32 CharID, bool LFP);
|
||||
void SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon);
|
||||
|
||||
int CountInvSnapshots();
|
||||
void ClearInvSnapshots(bool from_now = false);
|
||||
|
||||
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
|
||||
void SourceSqlFromUrl(std::string url);
|
||||
void SourceDatabaseTableFromUrl(const std::string& table_name, const std::string& url);
|
||||
void SourceSqlFromUrl(const std::string& url);
|
||||
|
||||
private:
|
||||
|
||||
Mutex Mvarcache;
|
||||
Mutex Mvarcache;
|
||||
VarCache_Struct varcache;
|
||||
|
||||
/* Groups, utility methods. */
|
||||
void ClearAllGroupLeaders();
|
||||
void ClearAllGroups();
|
||||
void ClearAllGroupLeaders();
|
||||
void ClearAllGroups();
|
||||
|
||||
/* Raid, utility methods. */
|
||||
void ClearAllRaids();
|
||||
|
||||
@@ -5431,8 +5431,44 @@ ADD PRIMARY KEY (`id`);
|
||||
.match = "varchar(30)",
|
||||
.sql = R"(
|
||||
ALTER TABLE `rule_values`
|
||||
MODIFY COLUMN `rule_value` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '' AFTER `rule_name`;
|
||||
MODIFY COLUMN `rule_value` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `rule_name`;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9267,
|
||||
.description = "2024_02_18_group_id_bot_id.sql",
|
||||
.check = "SHOW COLUMNS FROM `group_id` LIKE 'bot_id'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `group_id`
|
||||
CHANGE COLUMN `groupid` `group_id` int(11) UNSIGNED NOT NULL DEFAULT 0 FIRST,
|
||||
CHANGE COLUMN `charid` `character_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `group_id`,
|
||||
CHANGE COLUMN `ismerc` `merc_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `name`,
|
||||
ADD COLUMN `bot_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `character_id`,
|
||||
MODIFY COLUMN `name` varchar(64) NOT NULL DEFAULT '' AFTER `character_id`,
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`group_id`, `character_id`, `bot_id`, `merc_id`) USING BTREE;
|
||||
ALTER TABLE `group_id`
|
||||
MODIFY COLUMN `character_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `name`;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9268,
|
||||
.description = "2024_03_23_skill_caps.sql",
|
||||
.check = "SHOW COLUMNS FROM `skill_caps` LIKE 'skill_id'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE `skill_caps`
|
||||
CHANGE COLUMN `skillID` `skill_id` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 FIRST,
|
||||
CHANGE COLUMN `class` `class_id` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `skill_id`,
|
||||
ADD COLUMN `id` int(3) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`id`) USING BTREE,
|
||||
ADD INDEX `level_skill_cap`(`skill_id`, `class_id`, `level`, `cap`);
|
||||
)",
|
||||
.content_schema_update = true,
|
||||
}
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
// ManifestEntry{
|
||||
|
||||
@@ -421,20 +421,25 @@ void Database::AssignGroupToInstance(uint32 group_id, uint32 instance_id)
|
||||
auto zone_id = GetInstanceZoneID(instance_id);
|
||||
auto version = GetInstanceVersion(instance_id);
|
||||
|
||||
auto l = GroupIdRepository::GetWhere(
|
||||
const auto& l = GroupIdRepository::GetWhere(
|
||||
*this,
|
||||
fmt::format(
|
||||
"groupid = {}",
|
||||
"`group_id` = {}",
|
||||
group_id
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& e : l) {
|
||||
if (!GetInstanceID(zone_id, e.charid, version)) {
|
||||
AddClientToInstance(instance_id, e.charid);
|
||||
if (!e.character_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GetInstanceID(zone_id, e.character_id, version)) {
|
||||
AddClientToInstance(instance_id, e.character_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,7 +509,7 @@ void Database::FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 ch
|
||||
return;
|
||||
}
|
||||
|
||||
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id));
|
||||
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id).c_str());
|
||||
auto raid_leader_instance_id = GetInstanceID(zone_id, raid_leader_id, version);
|
||||
|
||||
if (!raid_leader_instance_id) {
|
||||
|
||||
@@ -89,6 +89,8 @@ namespace EQ
|
||||
using RoF2::invslot::SLOT_INVALID;
|
||||
using RoF2::invslot::SLOT_BEGIN;
|
||||
|
||||
using RoF2::invslot::SLOT_QUEST;
|
||||
|
||||
using Titanium::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
|
||||
|
||||
const int16 SLOT_AUGMENT_GENERIC_RETURN = 1001; // clients don't appear to use this method... (internal inventory return value)
|
||||
|
||||
@@ -130,6 +130,11 @@ enum CrystalReclaimTypes
|
||||
Radiant = 4,
|
||||
};
|
||||
|
||||
namespace ItemStackSizeConstraint {
|
||||
constexpr int16 Minimum = 1;
|
||||
constexpr int16 Maximum = 1000;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
@@ -82,6 +82,10 @@ Zone extensions and features
|
||||
#define QUEST_GLOBAL_DIRECTORY "global"
|
||||
#endif
|
||||
|
||||
// Number of quest items a Quest NPC can hold
|
||||
#define MAX_NPC_QUEST_INVENTORY 24
|
||||
|
||||
|
||||
//the min ratio at which a mob's speed is reduced
|
||||
#define FLEE_HP_MINSPEED 22
|
||||
//number of tics to try to run straight away before looking again
|
||||
@@ -111,6 +115,7 @@ Zone extensions and features
|
||||
|
||||
#define SKILL_MAX_LEVEL 75
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Zone Numerical configuration
|
||||
|
||||
@@ -25,6 +25,8 @@ struct LootItem {
|
||||
uint16 trivial_max_level;
|
||||
uint16 npc_min_level;
|
||||
uint16 npc_max_level;
|
||||
uint8 quest;
|
||||
uint8 pet;
|
||||
};
|
||||
|
||||
typedef std::list<LootItem*> LootItems;
|
||||
|
||||
@@ -165,6 +165,8 @@ namespace RoF2
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
|
||||
const int16 SLOT_QUEST = 9999;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@@ -162,6 +162,8 @@ namespace RoF
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
|
||||
const int16 SLOT_QUEST = 9999;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@@ -152,6 +152,8 @@ namespace SoD
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 SLOT_QUEST = 9999;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@@ -152,6 +152,8 @@ namespace SoF
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 SLOT_QUEST = 9999;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@@ -151,6 +151,8 @@ namespace Titanium
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 SLOT_QUEST = 9999;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@@ -152,6 +152,8 @@ namespace UF
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 SLOT_QUEST = 9999;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
+1
-1
@@ -1379,7 +1379,7 @@ uint32 GetPlayerRaceValue(uint16 race_id) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetPlayerRaceBit(uint16 race_id) {
|
||||
uint16 GetPlayerRaceBit(uint16 race_id) {
|
||||
switch (race_id) {
|
||||
case HUMAN:
|
||||
return PLAYER_RACE_HUMAN_BIT;
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ bool IsPlayerRace(uint16 race_id);
|
||||
const std::string GetPlayerRaceAbbreviation(uint16 race_id);
|
||||
|
||||
uint32 GetPlayerRaceValue(uint16 race_id);
|
||||
uint32 GetPlayerRaceBit(uint16 race_id);
|
||||
uint16 GetPlayerRaceBit(uint16 race_id);
|
||||
|
||||
uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value);
|
||||
uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit);
|
||||
|
||||
@@ -44,7 +44,51 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static int16 GetAccountStatus(Database& db, const uint32 account_id)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"SELECT `status`, TIMESTAMPDIFF(SECOND, NOW(), `suspendeduntil`) FROM `{}` WHERE `{}` = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
account_id
|
||||
)
|
||||
);
|
||||
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
int16 status = static_cast<int16>(Strings::ToInt(row[0]));
|
||||
int date_diff = 0;
|
||||
|
||||
if (row[1]) {
|
||||
date_diff = Strings::ToInt(row[1]);
|
||||
}
|
||||
|
||||
if (date_diff > 0) {
|
||||
status = -1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static bool UpdatePassword(Database& db, const uint32 account_id, const std::string& password)
|
||||
{
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE `{}` SET `password` = MD5('{}') WHERE `{}` = {}",
|
||||
TableName(),
|
||||
password,
|
||||
PrimaryKey(),
|
||||
account_id
|
||||
)
|
||||
);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_ACCOUNT_REPOSITORY_H
|
||||
|
||||
@@ -44,7 +44,65 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static void UpdateAdventureStatsEntry(Database& db, uint32 character_id, uint8 theme_id, bool is_win, bool is_remove)
|
||||
{
|
||||
std::string field;
|
||||
|
||||
switch (theme_id) {
|
||||
case LDoNThemes::GUK: {
|
||||
field = "guk_";
|
||||
break;
|
||||
}
|
||||
case LDoNThemes::MIR: {
|
||||
field = "mir_";
|
||||
break;
|
||||
}
|
||||
case LDoNThemes::MMC: {
|
||||
field = "mmc_";
|
||||
break;
|
||||
}
|
||||
case LDoNThemes::RUJ: {
|
||||
field = "ruj_";
|
||||
break;
|
||||
}
|
||||
case LDoNThemes::TAK: {
|
||||
field = "tak_";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
field += is_win ? "wins" : "losses";
|
||||
|
||||
auto e = FindOne(db, character_id);
|
||||
|
||||
if (!e.player_id && !is_remove) {
|
||||
const std::string& query = fmt::format(
|
||||
"INSERT INTO `{}` SET `{}` = 1, `{}` = {}",
|
||||
TableName(),
|
||||
field,
|
||||
PrimaryKey(),
|
||||
character_id
|
||||
);
|
||||
|
||||
db.QueryDatabase(query);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& field_operation = is_remove ? "-" : "+";
|
||||
|
||||
const std::string& query = fmt::format(
|
||||
"UPDATE `{}` SET `{}` = {} {} 1 WHERE `{}` = {}",
|
||||
TableName(),
|
||||
field,
|
||||
field,
|
||||
field_operation,
|
||||
PrimaryKey(),
|
||||
character_id
|
||||
);
|
||||
|
||||
db.QueryDatabase(query);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_ADVENTURE_STATS_REPOSITORY_H
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
int32_t accid;
|
||||
std::string ip;
|
||||
int32_t count;
|
||||
std::string lastused;
|
||||
time_t lastused;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
"accid",
|
||||
"ip",
|
||||
"count",
|
||||
"lastused",
|
||||
"UNIX_TIMESTAMP(lastused)",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
e.accid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.ip = row[1] ? row[1] : "";
|
||||
e.count = row[2] ? static_cast<int32_t>(atoi(row[2])) : 1;
|
||||
e.lastused = row[3] ? row[3] : std::time(nullptr);
|
||||
e.lastused = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.accid));
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.ip) + "'");
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.count));
|
||||
v.push_back(columns[3] + " = '" + Strings::Escape(e.lastused) + "'");
|
||||
v.push_back(columns[3] + " = FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -192,7 +192,7 @@ public:
|
||||
v.push_back(std::to_string(e.accid));
|
||||
v.push_back("'" + Strings::Escape(e.ip) + "'");
|
||||
v.push_back(std::to_string(e.count));
|
||||
v.push_back("'" + Strings::Escape(e.lastused) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -225,7 +225,7 @@ public:
|
||||
v.push_back(std::to_string(e.accid));
|
||||
v.push_back("'" + Strings::Escape(e.ip) + "'");
|
||||
v.push_back(std::to_string(e.count));
|
||||
v.push_back("'" + Strings::Escape(e.lastused) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -262,7 +262,7 @@ public:
|
||||
e.accid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.ip = row[1] ? row[1] : "";
|
||||
e.count = row[2] ? static_cast<int32_t>(atoi(row[2])) : 1;
|
||||
e.lastused = row[3] ? row[3] : std::time(nullptr);
|
||||
e.lastused = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -290,7 +290,7 @@ public:
|
||||
e.accid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.ip = row[1] ? row[1] : "";
|
||||
e.count = row[2] ? static_cast<int32_t>(atoi(row[2])) : 1;
|
||||
e.lastused = row[3] ? row[3] : std::time(nullptr);
|
||||
e.lastused = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -368,7 +368,7 @@ public:
|
||||
v.push_back(std::to_string(e.accid));
|
||||
v.push_back("'" + Strings::Escape(e.ip) + "'");
|
||||
v.push_back(std::to_string(e.count));
|
||||
v.push_back("'" + Strings::Escape(e.lastused) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -394,7 +394,7 @@ public:
|
||||
v.push_back(std::to_string(e.accid));
|
||||
v.push_back("'" + Strings::Escape(e.ip) + "'");
|
||||
v.push_back(std::to_string(e.count));
|
||||
v.push_back("'" + Strings::Escape(e.lastused) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -19,34 +19,37 @@
|
||||
class BaseGroupIdRepository {
|
||||
public:
|
||||
struct GroupId {
|
||||
int32_t groupid;
|
||||
int32_t charid;
|
||||
uint32_t group_id;
|
||||
std::string name;
|
||||
int8_t ismerc;
|
||||
uint32_t character_id;
|
||||
uint32_t bot_id;
|
||||
uint32_t merc_id;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("groupid");
|
||||
return std::string("group_id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"groupid",
|
||||
"charid",
|
||||
"group_id",
|
||||
"name",
|
||||
"ismerc",
|
||||
"character_id",
|
||||
"bot_id",
|
||||
"merc_id",
|
||||
};
|
||||
}
|
||||
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"groupid",
|
||||
"charid",
|
||||
"group_id",
|
||||
"name",
|
||||
"ismerc",
|
||||
"character_id",
|
||||
"bot_id",
|
||||
"merc_id",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -87,10 +90,11 @@ public:
|
||||
{
|
||||
GroupId e{};
|
||||
|
||||
e.groupid = 0;
|
||||
e.charid = 0;
|
||||
e.name = "";
|
||||
e.ismerc = 0;
|
||||
e.group_id = 0;
|
||||
e.name = "";
|
||||
e.character_id = 0;
|
||||
e.bot_id = 0;
|
||||
e.merc_id = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -101,7 +105,7 @@ public:
|
||||
)
|
||||
{
|
||||
for (auto &group_id : group_ids) {
|
||||
if (group_id.groupid == group_id_id) {
|
||||
if (group_id.group_id == group_id_id) {
|
||||
return group_id;
|
||||
}
|
||||
}
|
||||
@@ -127,10 +131,11 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
GroupId e{};
|
||||
|
||||
e.groupid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.charid = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.name = row[2] ? row[2] : "";
|
||||
e.ismerc = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
|
||||
e.group_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.name = row[1] ? row[1] : "";
|
||||
e.character_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.bot_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.merc_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -164,10 +169,11 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.groupid));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.charid));
|
||||
v.push_back(columns[2] + " = '" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.ismerc));
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.group_id));
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.character_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.bot_id));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.merc_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -175,7 +181,7 @@ public:
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.groupid
|
||||
e.group_id
|
||||
)
|
||||
);
|
||||
|
||||
@@ -189,10 +195,11 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.groupid));
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.group_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(std::to_string(e.ismerc));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.merc_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -203,7 +210,7 @@ public:
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.groupid = results.LastInsertedID();
|
||||
e.group_id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -222,10 +229,11 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.groupid));
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.group_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(std::to_string(e.ismerc));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.merc_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -259,10 +267,11 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
GroupId e{};
|
||||
|
||||
e.groupid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.charid = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.name = row[2] ? row[2] : "";
|
||||
e.ismerc = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
|
||||
e.group_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.name = row[1] ? row[1] : "";
|
||||
e.character_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.bot_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.merc_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -287,10 +296,11 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
GroupId e{};
|
||||
|
||||
e.groupid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.charid = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
|
||||
e.name = row[2] ? row[2] : "";
|
||||
e.ismerc = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
|
||||
e.group_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.name = row[1] ? row[1] : "";
|
||||
e.character_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.bot_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.merc_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -365,10 +375,11 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.groupid));
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.group_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(std::to_string(e.ismerc));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.merc_id));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -391,10 +402,11 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.groupid));
|
||||
v.push_back(std::to_string(e.charid));
|
||||
v.push_back(std::to_string(e.group_id));
|
||||
v.push_back("'" + Strings::Escape(e.name) + "'");
|
||||
v.push_back(std::to_string(e.ismerc));
|
||||
v.push_back(std::to_string(e.character_id));
|
||||
v.push_back(std::to_string(e.bot_id));
|
||||
v.push_back(std::to_string(e.merc_id));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
e.gid = 0;
|
||||
e.leadername = "";
|
||||
e.marknpc = "";
|
||||
e.leadershipaa = 0;
|
||||
e.leadershipaa = "";
|
||||
e.maintank = "";
|
||||
e.assist = "";
|
||||
e.puller = "";
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
e.gid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.leadername = row[1] ? row[1] : "";
|
||||
e.marknpc = row[2] ? row[2] : "";
|
||||
e.leadershipaa = row[3] ? row[3] : 0;
|
||||
e.leadershipaa = row[3] ? row[3] : "";
|
||||
e.maintank = row[4] ? row[4] : "";
|
||||
e.assist = row[5] ? row[5] : "";
|
||||
e.puller = row[6] ? row[6] : "";
|
||||
@@ -302,7 +302,7 @@ public:
|
||||
e.gid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.leadername = row[1] ? row[1] : "";
|
||||
e.marknpc = row[2] ? row[2] : "";
|
||||
e.leadershipaa = row[3] ? row[3] : 0;
|
||||
e.leadershipaa = row[3] ? row[3] : "";
|
||||
e.maintank = row[4] ? row[4] : "";
|
||||
e.assist = row[5] ? row[5] : "";
|
||||
e.puller = row[6] ? row[6] : "";
|
||||
@@ -335,7 +335,7 @@ public:
|
||||
e.gid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
|
||||
e.leadername = row[1] ? row[1] : "";
|
||||
e.marknpc = row[2] ? row[2] : "";
|
||||
e.leadershipaa = row[3] ? row[3] : 0;
|
||||
e.leadershipaa = row[3] ? row[3] : "";
|
||||
e.maintank = row[4] ? row[4] : "";
|
||||
e.assist = row[5] ? row[5] : "";
|
||||
e.puller = row[6] ? row[6] : "";
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
class BaseSkillCapsRepository {
|
||||
public:
|
||||
struct SkillCaps {
|
||||
uint8_t skillID;
|
||||
uint8_t class_;
|
||||
uint32_t id;
|
||||
uint8_t skill_id;
|
||||
uint8_t class_id;
|
||||
uint8_t level;
|
||||
uint32_t cap;
|
||||
uint8_t class_;
|
||||
@@ -28,14 +29,15 @@ public:
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("skillID");
|
||||
return std::string("id");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"skillID",
|
||||
"`class`",
|
||||
"id",
|
||||
"skill_id",
|
||||
"class_id",
|
||||
"level",
|
||||
"cap",
|
||||
"class_",
|
||||
@@ -45,8 +47,9 @@ public:
|
||||
static std::vector<std::string> SelectColumns()
|
||||
{
|
||||
return {
|
||||
"skillID",
|
||||
"`class`",
|
||||
"id",
|
||||
"skill_id",
|
||||
"class_id",
|
||||
"level",
|
||||
"cap",
|
||||
"class_",
|
||||
@@ -90,11 +93,12 @@ public:
|
||||
{
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = 0;
|
||||
e.class_ = 0;
|
||||
e.level = 0;
|
||||
e.cap = 0;
|
||||
e.class_ = 0;
|
||||
e.id = 0;
|
||||
e.skill_id = 0;
|
||||
e.class_id = 0;
|
||||
e.level = 0;
|
||||
e.cap = 0;
|
||||
e.class_ = 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -105,7 +109,7 @@ public:
|
||||
)
|
||||
{
|
||||
for (auto &skill_caps : skill_capss) {
|
||||
if (skill_caps.skillID == skill_caps_id) {
|
||||
if (skill_caps.id == skill_caps_id) {
|
||||
return skill_caps;
|
||||
}
|
||||
}
|
||||
@@ -131,11 +135,12 @@ public:
|
||||
if (results.RowCount() == 1) {
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -169,11 +174,11 @@ public:
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
v.push_back(columns[0] + " = " + std::to_string(e.skillID));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.class_));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.level));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.cap));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.class_));
|
||||
v.push_back(columns[1] + " = " + std::to_string(e.skill_id));
|
||||
v.push_back(columns[2] + " = " + std::to_string(e.class_id));
|
||||
v.push_back(columns[3] + " = " + std::to_string(e.level));
|
||||
v.push_back(columns[4] + " = " + std::to_string(e.cap));
|
||||
v.push_back(columns[5] + " = " + std::to_string(e.class_));
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -181,7 +186,7 @@ public:
|
||||
TableName(),
|
||||
Strings::Implode(", ", v),
|
||||
PrimaryKey(),
|
||||
e.skillID
|
||||
e.id
|
||||
)
|
||||
);
|
||||
|
||||
@@ -195,8 +200,9 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
@@ -210,7 +216,7 @@ public:
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
e.skillID = results.LastInsertedID();
|
||||
e.id = results.LastInsertedID();
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -229,8 +235,9 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
@@ -267,11 +274,12 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -296,11 +304,12 @@ public:
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
SkillCaps e{};
|
||||
|
||||
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
|
||||
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -375,8 +384,9 @@ public:
|
||||
{
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
@@ -402,8 +412,9 @@ public:
|
||||
for (auto &e: entries) {
|
||||
std::vector<std::string> v;
|
||||
|
||||
v.push_back(std::to_string(e.skillID));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
v.push_back(std::to_string(e.id));
|
||||
v.push_back(std::to_string(e.skill_id));
|
||||
v.push_back(std::to_string(e.class_id));
|
||||
v.push_back(std::to_string(e.level));
|
||||
v.push_back(std::to_string(e.cap));
|
||||
v.push_back(std::to_string(e.class_));
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
std::string varname;
|
||||
std::string value;
|
||||
std::string information;
|
||||
std::string ts;
|
||||
time_t ts;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
"varname",
|
||||
"value",
|
||||
"information",
|
||||
"ts",
|
||||
"UNIX_TIMESTAMP(ts)",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
e.varname = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.information = row[3] ? row[3] : "";
|
||||
e.ts = row[4] ? row[4] : std::time(nullptr);
|
||||
e.ts = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||
|
||||
return e;
|
||||
}
|
||||
@@ -172,7 +172,7 @@ public:
|
||||
v.push_back(columns[1] + " = '" + Strings::Escape(e.varname) + "'");
|
||||
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
|
||||
v.push_back(columns[3] + " = '" + Strings::Escape(e.information) + "'");
|
||||
v.push_back(columns[4] + " = '" + Strings::Escape(e.ts) + "'");
|
||||
v.push_back(columns[4] + " = FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.varname) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.information) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.ts) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -232,7 +232,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.varname) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.information) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.ts) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
@@ -270,7 +270,7 @@ public:
|
||||
e.varname = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.information = row[3] ? row[3] : "";
|
||||
e.ts = row[4] ? row[4] : std::time(nullptr);
|
||||
e.ts = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -299,7 +299,7 @@ public:
|
||||
e.varname = row[1] ? row[1] : "";
|
||||
e.value = row[2] ? row[2] : "";
|
||||
e.information = row[3] ? row[3] : "";
|
||||
e.ts = row[4] ? row[4] : std::time(nullptr);
|
||||
e.ts = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||
|
||||
all_entries.push_back(e);
|
||||
}
|
||||
@@ -378,7 +378,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.varname) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.information) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.ts) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
fmt::format(
|
||||
@@ -405,7 +405,7 @@ public:
|
||||
v.push_back("'" + Strings::Escape(e.varname) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.value) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.information) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.ts) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
}
|
||||
|
||||
@@ -59,6 +59,24 @@ public:
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
// insert with ON DUPLICATE KEY UPDATE to leave rows that exist unchanged
|
||||
static int InsertUpdateMany(Database& db, const std::vector<CharRecipeList>& entries)
|
||||
{
|
||||
std::vector<std::string> values;
|
||||
values.reserve(entries.size());
|
||||
|
||||
for (const auto& e: entries)
|
||||
{
|
||||
values.emplace_back(fmt::format("({},{},{})", e.char_id, e.recipe_id, e.madecount));
|
||||
}
|
||||
|
||||
auto results = db.QueryDatabase(fmt::format(
|
||||
"INSERT INTO {0} (char_id, recipe_id, madecount) VALUES {1} ON DUPLICATE KEY UPDATE {2}={2}",
|
||||
TableName(), fmt::join(values, ","), PrimaryKey()));
|
||||
|
||||
return results.Success() ? results.RowsAffected() : 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_CHAR_RECIPE_LIST_REPOSITORY_H
|
||||
|
||||
@@ -44,7 +44,15 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
|
||||
static void ClearAllGroups(Database& db)
|
||||
{
|
||||
db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM `{}`",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_GROUP_ID_REPOSITORY_H
|
||||
|
||||
@@ -44,7 +44,15 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
|
||||
static void ClearAllGroupLeaders(Database& db)
|
||||
{
|
||||
db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM `{}`",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_GROUP_LEADERS_REPOSITORY_H
|
||||
|
||||
@@ -191,4 +191,5 @@ public:
|
||||
return UpdateOne(db, m);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_GUILD_MEMBERS_REPOSITORY_H
|
||||
|
||||
@@ -44,7 +44,30 @@ public:
|
||||
*/
|
||||
|
||||
// Custom extended repository methods here
|
||||
static int64 CountInventorySnapshots(Database& db)
|
||||
{
|
||||
const std::string& query = "SELECT COUNT(*) FROM (SELECT * FROM `inventory_snapshots` a GROUP BY `charid`, `time_index`) b";
|
||||
|
||||
auto results = db.QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
const int64 count = Strings::ToBigInt(row[0]);
|
||||
|
||||
if (count > std::numeric_limits<int>::max()) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_INVENTORY_SNAPSHOTS_REPOSITORY_H
|
||||
|
||||
@@ -66,6 +66,16 @@ public:
|
||||
|
||||
return results.Success() ? results.RowsAffected() : 0;
|
||||
}
|
||||
|
||||
static void ClearAllRaidDetails(Database& db)
|
||||
{
|
||||
db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM `{}`",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //EQEMU_RAID_DETAILS_REPOSITORY_H
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
#ifndef EQEMU_RAID_LEADERS_REPOSITORY_H
|
||||
#define EQEMU_RAID_LEADERS_REPOSITORY_H
|
||||
|
||||
#include "../database.h"
|
||||
#include "../strings.h"
|
||||
|
||||
class RaidLeadersRepository {
|
||||
public:
|
||||
struct RaidLeaders {
|
||||
int gid;
|
||||
int rid;
|
||||
std::string marknpc;
|
||||
std::string maintank;
|
||||
std::string assist;
|
||||
std::string puller;
|
||||
std::string leadershipaa;
|
||||
std::string mentoree;
|
||||
int mentor_percent;
|
||||
};
|
||||
|
||||
static std::string PrimaryKey()
|
||||
{
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
static std::vector<std::string> Columns()
|
||||
{
|
||||
return {
|
||||
"gid",
|
||||
"rid",
|
||||
"marknpc",
|
||||
"maintank",
|
||||
"assist",
|
||||
"puller",
|
||||
"leadershipaa",
|
||||
"mentoree",
|
||||
"mentor_percent",
|
||||
};
|
||||
}
|
||||
|
||||
static std::string ColumnsRaw()
|
||||
{
|
||||
return std::string(Strings::Implode(", ", Columns()));
|
||||
}
|
||||
|
||||
static std::string InsertColumnsRaw()
|
||||
{
|
||||
std::vector<std::string> insert_columns;
|
||||
|
||||
for (auto &column : Columns()) {
|
||||
if (column == PrimaryKey()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
insert_columns.push_back(column);
|
||||
}
|
||||
|
||||
return std::string(Strings::Implode(", ", insert_columns));
|
||||
}
|
||||
|
||||
static std::string TableName()
|
||||
{
|
||||
return std::string("raid_leaders");
|
||||
}
|
||||
|
||||
static std::string BaseSelect()
|
||||
{
|
||||
return fmt::format(
|
||||
"SELECT {} FROM {}",
|
||||
ColumnsRaw(),
|
||||
TableName()
|
||||
);
|
||||
}
|
||||
|
||||
static std::string BaseInsert()
|
||||
{
|
||||
return fmt::format(
|
||||
"INSERT INTO {} ({}) ",
|
||||
TableName(),
|
||||
InsertColumnsRaw()
|
||||
);
|
||||
}
|
||||
|
||||
static RaidLeaders NewEntity()
|
||||
{
|
||||
RaidLeaders entry{};
|
||||
|
||||
entry.gid = 0;
|
||||
entry.rid = 0;
|
||||
entry.marknpc = "";
|
||||
entry.maintank = "";
|
||||
entry.assist = "";
|
||||
entry.puller = "";
|
||||
entry.leadershipaa = 0;
|
||||
entry.mentoree = "";
|
||||
entry.mentor_percent = 0;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static RaidLeaders GetRaidLeadersEntry(
|
||||
const std::vector<RaidLeaders> &raid_leaderss,
|
||||
int raid_leaders_id
|
||||
)
|
||||
{
|
||||
for (auto &raid_leaders : raid_leaderss) {
|
||||
if (raid_leaders. == raid_leaders_id) {
|
||||
return raid_leaders;
|
||||
}
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static RaidLeaders FindOne(
|
||||
int raid_leaders_id
|
||||
)
|
||||
{
|
||||
auto results = database.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} WHERE id = {} LIMIT 1",
|
||||
BaseSelect(),
|
||||
raid_leaders_id
|
||||
)
|
||||
);
|
||||
|
||||
auto row = results.begin();
|
||||
if (results.RowCount() == 1) {
|
||||
RaidLeaders entry{};
|
||||
|
||||
entry.gid = atoi(row[0]);
|
||||
entry.rid = atoi(row[1]);
|
||||
entry.marknpc = row[2];
|
||||
entry.maintank = row[3];
|
||||
entry.assist = row[4];
|
||||
entry.puller = row[5];
|
||||
entry.leadershipaa = row[6];
|
||||
entry.mentoree = row[7];
|
||||
entry.mentor_percent = atoi(row[8]);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NewEntity();
|
||||
}
|
||||
|
||||
static int DeleteOne(
|
||||
int raid_leaders_id
|
||||
)
|
||||
{
|
||||
auto results = database.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM {} WHERE {} = {}",
|
||||
TableName(),
|
||||
PrimaryKey(),
|
||||
raid_leaders_id
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static int UpdateOne(
|
||||
RaidLeaders raid_leaders_entry
|
||||
)
|
||||
{
|
||||
std::vector<std::string> update_values;
|
||||
|
||||
auto columns = Columns();
|
||||
|
||||
update_values.push_back(columns[0] + " = " + std::to_string(raid_leaders_entry.gid));
|
||||
update_values.push_back(columns[1] + " = " + std::to_string(raid_leaders_entry.rid));
|
||||
update_values.push_back(columns[2] + " = '" + Strings::Escape(raid_leaders_entry.marknpc) + "'");
|
||||
update_values.push_back(columns[3] + " = '" + Strings::Escape(raid_leaders_entry.maintank) + "'");
|
||||
update_values.push_back(columns[4] + " = '" + Strings::Escape(raid_leaders_entry.assist) + "'");
|
||||
update_values.push_back(columns[5] + " = '" + Strings::Escape(raid_leaders_entry.puller) + "'");
|
||||
update_values.push_back(columns[6] + " = '" + Strings::Escape(raid_leaders_entry.leadershipaa) + "'");
|
||||
update_values.push_back(columns[7] + " = '" + Strings::Escape(raid_leaders_entry.mentoree) + "'");
|
||||
update_values.push_back(columns[8] + " = " + std::to_string(raid_leaders_entry.mentor_percent));
|
||||
|
||||
auto results = database.QueryDatabase(
|
||||
fmt::format(
|
||||
"UPDATE {} SET {} WHERE {} = {}",
|
||||
TableName(),
|
||||
Strings::Implode(", ", update_values),
|
||||
PrimaryKey(),
|
||||
raid_leaders_entry.
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static RaidLeaders InsertOne(
|
||||
RaidLeaders raid_leaders_entry
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_values;
|
||||
|
||||
insert_values.push_back(std::to_string(raid_leaders_entry.gid));
|
||||
insert_values.push_back(std::to_string(raid_leaders_entry.rid));
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.marknpc) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.maintank) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.assist) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.puller) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.leadershipaa) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.mentoree) + "'");
|
||||
insert_values.push_back(std::to_string(raid_leaders_entry.mentor_percent));
|
||||
|
||||
auto results = database.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES ({})",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", insert_values)
|
||||
)
|
||||
);
|
||||
|
||||
if (results.Success()) {
|
||||
raid_leaders_entry.id = results.LastInsertedID();
|
||||
return raid_leaders_entry;
|
||||
}
|
||||
|
||||
raid_leaders_entry = InstanceListRepository::NewEntity();
|
||||
|
||||
return raid_leaders_entry;
|
||||
}
|
||||
|
||||
static int InsertMany(
|
||||
std::vector<RaidLeaders> raid_leaders_entries
|
||||
)
|
||||
{
|
||||
std::vector<std::string> insert_chunks;
|
||||
|
||||
for (auto &raid_leaders_entry: raid_leaders_entries) {
|
||||
std::vector<std::string> insert_values;
|
||||
|
||||
insert_values.push_back(std::to_string(raid_leaders_entry.gid));
|
||||
insert_values.push_back(std::to_string(raid_leaders_entry.rid));
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.marknpc) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.maintank) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.assist) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.puller) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.leadershipaa) + "'");
|
||||
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.mentoree) + "'");
|
||||
insert_values.push_back(std::to_string(raid_leaders_entry.mentor_percent));
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", insert_values) + ")");
|
||||
}
|
||||
|
||||
std::vector<std::string> insert_values;
|
||||
|
||||
auto results = database.QueryDatabase(
|
||||
fmt::format(
|
||||
"{} VALUES {}",
|
||||
BaseInsert(),
|
||||
Strings::Implode(",", insert_chunks)
|
||||
)
|
||||
);
|
||||
|
||||
return (results.Success() ? results.RowsAffected() : 0);
|
||||
}
|
||||
|
||||
static std::vector<RaidLeaders> All()
|
||||
{
|
||||
std::vector<RaidLeaders> all_entries;
|
||||
|
||||
auto results = database.QueryDatabase(
|
||||
fmt::format(
|
||||
"{}",
|
||||
BaseSelect()
|
||||
)
|
||||
);
|
||||
|
||||
all_entries.reserve(results.RowCount());
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
RaidLeaders entry{};
|
||||
|
||||
entry.gid = atoi(row[0]);
|
||||
entry.rid = atoi(row[1]);
|
||||
entry.marknpc = row[2];
|
||||
entry.maintank = row[3];
|
||||
entry.assist = row[4];
|
||||
entry.puller = row[5];
|
||||
entry.leadershipaa = row[6];
|
||||
entry.mentoree = row[7];
|
||||
entry.mentor_percent = atoi(row[8]);
|
||||
|
||||
all_entries.push_back(entry);
|
||||
}
|
||||
|
||||
return all_entries;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //EQEMU_RAID_LEADERS_REPOSITORY_H
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
);
|
||||
return results.Success() ? results.RowsAffected() : 0;
|
||||
}
|
||||
|
||||
|
||||
static int UpdateRaidAssister(
|
||||
Database& db,
|
||||
int32_t raid_id,
|
||||
@@ -98,5 +98,15 @@ public:
|
||||
|
||||
return results.Success() ? results.RowsAffected() : 0;
|
||||
}
|
||||
|
||||
static void ClearAllRaids(Database& db)
|
||||
{
|
||||
db.QueryDatabase(
|
||||
fmt::format(
|
||||
"DELETE FROM `{}`",
|
||||
TableName()
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
#endif //EQEMU_RAID_MEMBERS_REPOSITORY_H
|
||||
|
||||
+4
-1
@@ -329,6 +329,7 @@ RULE_BOOL(World, UseItemLinksForKeyRing, false, "Uses item links for Key Ring Li
|
||||
RULE_BOOL(World, UseOldShadowKnightClassExport, true, "Disable to have Shadowknight show as Shadow Knight (live-like)")
|
||||
RULE_STRING(World, IPExemptionZones, "", "Comma-delimited list of zones to exclude from IP-limit checks. Empty string to disable.")
|
||||
RULE_STRING(World, MOTD, "", "Server MOTD sent on login, change from empty to have this be used instead of variables table 'motd' value")
|
||||
RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be used instead of variables table 'rules' value, lines are pipe (|) separated, example: A|B|C")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Zone)
|
||||
@@ -354,6 +355,7 @@ RULE_INT(Zone, GlobalLootMultiplier, 1, "Sets Global Loot drop multiplier for da
|
||||
RULE_BOOL(Zone, KillProcessOnDynamicShutdown, true, "When process has booted a zone and has hit its zone shut down timer, it will hard kill the process to free memory back to the OS")
|
||||
RULE_INT(Zone, SpawnEventMin, 3, "When strict is set in spawn_events, specifies the max EQ minutes into the trigger hour a spawn_event will fire. Going below 3 may cause the spawn_event to not fire.")
|
||||
RULE_INT(Zone, ForageChance, 25, "Chance of foraging from zone table vs global table")
|
||||
RULE_INT(Zone, FishingChance, 399, "Chance of fishing from zone table vs global table")
|
||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross zone spells (cast/remove) to affect bots")
|
||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
|
||||
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
|
||||
@@ -449,7 +451,8 @@ RULE_BOOL(Spells, Jun182014HundredHandsRevamp, false, "This should be true for i
|
||||
RULE_BOOL(Spells, SwarmPetTargetLock, false, "Use old method of swarm pets target locking till target dies then despawning")
|
||||
RULE_BOOL(Spells, NPC_UseFocusFromSpells, true, "Allow NPC to use most spell derived focus effects")
|
||||
RULE_BOOL(Spells, NPC_UseFocusFromItems, false, "Allow NPC to use most item derived focus effects")
|
||||
RULE_BOOL(Spells, UseAdditiveFocusFromWornSlot, false, "Allows an additive focus effect to be calculated from worn slot")
|
||||
RULE_BOOL(Spells, UseAdditiveFocusFromWornSlot, false, "Allows an additive focus effect to be calculated from worn slot. Does not apply limits checks. Can only have one additive focus rule be true.")
|
||||
RULE_BOOL(Spells, UseAdditiveFocusFromWornSlotWithLimits, false, "Allows an additive focus effect to be calculated from worn slot. Applies normal limit checks. Can only have one additive focus rule be true.")
|
||||
RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false, "Ignore Leadership Alternate Abilities level if true")
|
||||
RULE_BOOL(Spells, FlatItemExtraSpellAmt, false, "Allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc")
|
||||
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false, "Ignore the 5 level spread on applying SpellDmg")
|
||||
|
||||
+4
-3
@@ -348,7 +348,7 @@ std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
|
||||
if (ch != startpos)
|
||||
{
|
||||
std::string str(startpos, ch - startpos);
|
||||
new_message += EQ::SayLinkEngine::GenerateQuestSaylink(str, false, str);
|
||||
new_message += Saylink::Create(str);
|
||||
}
|
||||
in_bracket_state = false;
|
||||
}
|
||||
@@ -417,11 +417,12 @@ SaylinkRepository::Saylink EQ::SayLinkEngine::GetOrSaveSaylink(std::string sayli
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string Saylink::Create(const std::string &saylink_text, bool silent, const std::string &link_name)
|
||||
std::string Saylink::Create(const std::string& saylink_text, bool silent, const std::string& link_name)
|
||||
{
|
||||
return EQ::SayLinkEngine::GenerateQuestSaylink(saylink_text, silent, (link_name.empty() ? saylink_text : link_name));
|
||||
}
|
||||
|
||||
std::string Saylink::Silent(const std::string &saylink_text, const std::string &link_name) {
|
||||
std::string Saylink::Silent(const std::string& saylink_text, const std::string& link_name)
|
||||
{
|
||||
return EQ::SayLinkEngine::GenerateQuestSaylink(saylink_text, true, (link_name.empty() ? saylink_text : link_name));
|
||||
}
|
||||
|
||||
+1
-1
@@ -130,7 +130,7 @@ namespace EQ
|
||||
|
||||
class Saylink {
|
||||
public:
|
||||
static std::string Create(const std::string &saylink_text, bool silent, const std::string &link_name = "");
|
||||
static std::string Create(const std::string &saylink_text, bool silent = false, const std::string &link_name = "");
|
||||
static std::string Silent(const std::string &saylink_text, const std::string &link_name = "");
|
||||
};
|
||||
|
||||
|
||||
@@ -273,6 +273,7 @@
|
||||
#define ServerOP_ReloadFactions 0x4126
|
||||
#define ServerOP_ReloadLoot 0x4127
|
||||
#define ServerOP_ReloadBaseData 0x4128
|
||||
#define ServerOP_ReloadSkillCaps 0x4129
|
||||
|
||||
#define ServerOP_CZDialogueWindow 0x4500
|
||||
#define ServerOP_CZLDoNUpdate 0x4501
|
||||
|
||||
@@ -60,7 +60,7 @@ SharedTaskRequest SharedTask::GetRequestCharacters(Database &db, uint32_t reques
|
||||
request.group_type = SharedTaskRequestGroupType::Group;
|
||||
auto characters = CharacterDataRepository::GetWhere(
|
||||
db, fmt::format(
|
||||
"id IN (select charid from group_id where groupid = (select groupid from group_id where charid = {}))",
|
||||
"id IN (select character_id from group_id where group_id = (select group_id from group_id where character_id = {}))",
|
||||
requested_character_id
|
||||
)
|
||||
);
|
||||
|
||||
+4
-134
@@ -45,6 +45,7 @@
|
||||
#include "repositories/loottable_repository.h"
|
||||
#include "repositories/character_item_recast_repository.h"
|
||||
#include "repositories/character_corpses_repository.h"
|
||||
#include "repositories/skill_caps_repository.h"
|
||||
|
||||
namespace ItemField
|
||||
{
|
||||
@@ -793,8 +794,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
|
||||
}
|
||||
|
||||
if (cv_conflict) {
|
||||
char char_name[64] = "";
|
||||
GetCharName(char_id, char_name);
|
||||
const std::string& char_name = GetCharName(char_id);
|
||||
LogError("ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
|
||||
char_name,
|
||||
char_id,
|
||||
@@ -1626,136 +1626,6 @@ bool SharedDatabase::GetCommandSubSettings(std::vector<CommandSubsettingsReposit
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
|
||||
skill_caps_mmf.reset(nullptr);
|
||||
|
||||
try {
|
||||
const auto Config = EQEmuConfig::get();
|
||||
EQ::IPCMutex mutex("skill_caps");
|
||||
mutex.Lock();
|
||||
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("skill_caps"));
|
||||
LogInfo("Loading [{}]", file_name);
|
||||
skill_caps_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
|
||||
|
||||
LogInfo("Loaded skill caps via shared memory");
|
||||
|
||||
mutex.Unlock();
|
||||
} catch(std::exception &ex) {
|
||||
LogError("Error loading skill caps: {}", ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadSkillCaps(void *data) {
|
||||
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
const uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
uint16 *skill_caps_table = static_cast<uint16*>(data);
|
||||
|
||||
const std::string query = "SELECT skillID, class, level, cap FROM skill_caps ORDER BY skillID, class, level";
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogError("Error loading skill caps from database: {}", results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto& row = results.begin(); row != results.end(); ++row) {
|
||||
const uint8 skillID = Strings::ToUnsignedInt(row[0]);
|
||||
const uint8 class_ = Strings::ToUnsignedInt(row[1]) - 1;
|
||||
const uint8 level = Strings::ToUnsignedInt(row[2]);
|
||||
const uint16 cap = Strings::ToUnsignedInt(row[3]);
|
||||
|
||||
if(skillID >= skill_count || class_ >= class_count || level >= level_count)
|
||||
continue;
|
||||
|
||||
const uint32 index = (((class_ * skill_count) + skillID) * level_count) + level;
|
||||
skill_caps_table[index] = cap;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 SharedDatabase::GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const
|
||||
{
|
||||
if(!skill_caps_mmf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Class_ == 0)
|
||||
return 0;
|
||||
|
||||
int SkillMaxLevel = RuleI(Character, SkillCapMaxLevel);
|
||||
if(SkillMaxLevel < 1) {
|
||||
SkillMaxLevel = RuleI(Character, MaxLevel);
|
||||
}
|
||||
|
||||
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
const uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Level > static_cast<uint8>(SkillMaxLevel)){
|
||||
Level = static_cast<uint8>(SkillMaxLevel);
|
||||
}
|
||||
|
||||
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count) + Level;
|
||||
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
|
||||
return skill_caps_table[index];
|
||||
}
|
||||
|
||||
uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const
|
||||
{
|
||||
if(!skill_caps_mmf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Class_ == 0)
|
||||
return 0;
|
||||
|
||||
int SkillMaxLevel = RuleI(Character, SkillCapMaxLevel);
|
||||
if (SkillMaxLevel < 1) {
|
||||
SkillMaxLevel = RuleI(Character, MaxLevel);
|
||||
}
|
||||
|
||||
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
const uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 ret = 0;
|
||||
if(Level > static_cast<uint8>(SkillMaxLevel)) {
|
||||
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count);
|
||||
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
|
||||
for(uint8 x = 0; x < Level; x++){
|
||||
if(skill_caps_table[index + x]){
|
||||
ret = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count);
|
||||
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
|
||||
for(int x = 0; x < SkillMaxLevel; x++){
|
||||
if(skill_caps_table[index + x]){
|
||||
ret = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ret > GetSkillCap(Class_, Skill, Level))
|
||||
ret = static_cast<uint8>(GetSkillCap(Class_, Skill, Level));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID) {
|
||||
const std::string query = StringFormat("SELECT `spellid`, `type` FROM `damageshieldtypes` WHERE `spellid` > 0 "
|
||||
"AND `spellid` <= %i", iMaxSpellID);
|
||||
@@ -1984,9 +1854,9 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
sp[tempid].min_range = Strings::ToFloat(row[231]);
|
||||
sp[tempid].no_remove = Strings::ToBool(row[232]);
|
||||
sp[tempid].damage_shield_type = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LoadDamageShieldTypes(sp, max_spells);
|
||||
LoadDamageShieldTypes(sp, max_spells);
|
||||
}
|
||||
|
||||
void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message) {
|
||||
|
||||
@@ -160,14 +160,6 @@ public:
|
||||
uint32 GetSharedItemsCount() { return m_shared_items_count; }
|
||||
uint32 GetItemsCount();
|
||||
|
||||
/**
|
||||
* skills
|
||||
*/
|
||||
void LoadSkillCaps(void *data);
|
||||
bool LoadSkillCaps(const std::string &prefix);
|
||||
uint16 GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const;
|
||||
uint8 GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const;
|
||||
|
||||
/**
|
||||
* spells
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "skill_caps.h"
|
||||
|
||||
SkillCaps *SkillCaps::SetContentDatabase(Database *db)
|
||||
{
|
||||
m_content_database = db;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
SkillCapsRepository::SkillCaps SkillCaps::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
if (!IsPlayerClass(class_id)) {
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
for (const auto &e: m_skill_caps) {
|
||||
if (
|
||||
e.class_id == class_id &&
|
||||
e.level == level &&
|
||||
static_cast<EQ::skills::SkillType>(e.skill_id) == skill_id
|
||||
) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return SkillCapsRepository::NewEntity();
|
||||
}
|
||||
|
||||
uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
|
||||
{
|
||||
if (
|
||||
!IsPlayerClass(class_id) ||
|
||||
class_id > Class::PLAYER_CLASS_COUNT ||
|
||||
static_cast<uint32>(skill_id) > (EQ::skills::HIGHEST_SKILL + 1)
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8 skill_cap_max_level = (
|
||||
RuleI(Character, SkillCapMaxLevel) > 0 ?
|
||||
RuleI(Character, SkillCapMaxLevel) :
|
||||
RuleI(Character, MaxLevel)
|
||||
);
|
||||
|
||||
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
|
||||
|
||||
for (const auto &e: m_skill_caps) {
|
||||
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
|
||||
if (
|
||||
e.class_id == class_id &&
|
||||
static_cast<EQ::skills::SkillType>(e.skill_id) == skill_id &&
|
||||
e.level == current_level
|
||||
) {
|
||||
return current_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SkillCaps::LoadSkillCaps()
|
||||
{
|
||||
const auto &l = SkillCapsRepository::All(*m_content_database);
|
||||
|
||||
m_skill_caps.reserve(l.size());
|
||||
|
||||
for (const auto &e: l) {
|
||||
if (
|
||||
e.level < 1 ||
|
||||
!IsPlayerClass(e.class_id) ||
|
||||
static_cast<EQ::skills::SkillType>(e.skill_id) >= EQ::skills::SkillCount
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_skill_caps.emplace_back(e);
|
||||
}
|
||||
|
||||
LogInfo(
|
||||
"Loaded [{}] Skill Cap Entr{}",
|
||||
l.size(),
|
||||
l.size() != 1 ? "ies" : "y"
|
||||
);
|
||||
}
|
||||
|
||||
void SkillCaps::ReloadSkillCaps()
|
||||
{
|
||||
ClearSkillCaps();
|
||||
LoadSkillCaps();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef CODE_SKILL_CAPS_H
|
||||
#define CODE_SKILL_CAPS_H
|
||||
|
||||
#include "repositories/skill_caps_repository.h"
|
||||
#include "types.h"
|
||||
#include "classes.h"
|
||||
#include "skills.h"
|
||||
|
||||
class SkillCaps {
|
||||
public:
|
||||
inline void ClearSkillCaps() { m_skill_caps.clear(); }
|
||||
SkillCapsRepository::SkillCaps GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
uint8 GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
|
||||
void LoadSkillCaps();
|
||||
void ReloadSkillCaps();
|
||||
|
||||
SkillCaps *SetContentDatabase(Database *db);
|
||||
private:
|
||||
Database *m_content_database{};
|
||||
std::vector<SkillCapsRepository::SkillCaps> m_skill_caps = {};
|
||||
};
|
||||
|
||||
extern SkillCaps skill_caps;
|
||||
|
||||
|
||||
#endif //CODE_SKILL_CAPS_H
|
||||
+1
-1
@@ -18,10 +18,10 @@
|
||||
*/
|
||||
|
||||
#include "skills.h"
|
||||
#include "classes.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
bool EQ::skills::IsTradeskill(SkillType skill)
|
||||
{
|
||||
switch (skill) {
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace skills {
|
||||
|
||||
+1
-1
@@ -1257,7 +1257,7 @@ typedef enum {
|
||||
#define SE_Ff_Override_NotFocusable 460 // implemented, @Fc, Allow spell to be focused event if flagged with 'not_focusable' in spell table, base: 1
|
||||
#define SE_ImprovedDamage2 461 // implemented, @Fc, On Caster, spell damage mod pct, base: min pct, limit: max pct
|
||||
#define SE_FcDamageAmt2 462 // implemented, @Fc, On Caster, spell damage mod flat amt, base: amt
|
||||
//#define SE_Shield_Target 463 //
|
||||
#define SE_Shield_Target 463 // implemented, Base1 % damage shielded on target
|
||||
#define SE_PC_Pet_Rampage 464 // implemented - Base1 % chance to do rampage for base2 % of damage each melee round
|
||||
#define SE_PC_Pet_AE_Rampage 465 // implemented - Base1 % chance to do AE rampage for base2 % of damage each melee round
|
||||
#define SE_PC_Pet_Flurry_Chance 466 // implemented - Base1 % chance to do flurry from double attack hit.
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.47.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.48.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__
|
||||
@@ -42,7 +42,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9266
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9268
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9043
|
||||
|
||||
#endif
|
||||
|
||||
+225
-891
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.47.0",
|
||||
"version": "22.48.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Description
|
||||
|
||||
Please include a summary of the changes and the related issue (Why is this change necessary). Please also include relevant motivation and context. List any dependencies that are required for this change.
|
||||
|
||||
Fixes # (issue)
|
||||
|
||||
## Type of change
|
||||
|
||||
Please delete options that are not relevant.
|
||||
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] This change requires a documentation update
|
||||
|
||||
# Testing
|
||||
|
||||
Attach images and describe testing done to validate functionality.
|
||||
|
||||
Clients tested:
|
||||
|
||||
# Checklist
|
||||
|
||||
- [ ] I have tested my changes
|
||||
- [ ] I have performed a self-review of my code. Ensuring variables, functions and methods are named in a human-readable way, comments are added only where naming of variables, functions and methods can't give enough context.
|
||||
- [ ] I have made corresponding changes to the documentation (if applicable, if not delete this line)
|
||||
- [ ] I own the changes of my code and take responsibility for the potential issues that occur
|
||||
- [ ] If my changes make database schema changes, I have tested the changes on a local database (attach image). Updated version.h CURRENT_BINARY_DATABASE_VERSION to the new version. (Delete this if not applicable)
|
||||
@@ -4,13 +4,11 @@ SET(shared_memory_sources
|
||||
items.cpp
|
||||
main.cpp
|
||||
spells.cpp
|
||||
skill_caps.cpp
|
||||
)
|
||||
|
||||
SET(shared_memory_headers
|
||||
items.h
|
||||
spells.h
|
||||
skill_caps.h
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(shared_memory ${shared_memory_sources} ${shared_memory_headers})
|
||||
|
||||
+1
-17
@@ -28,7 +28,6 @@
|
||||
#include "../common/eqemu_exception.h"
|
||||
#include "../common/strings.h"
|
||||
#include "items.h"
|
||||
#include "skill_caps.h"
|
||||
#include "spells.h"
|
||||
#include "../common/content/world_content_service.h"
|
||||
#include "../common/zone_store.h"
|
||||
@@ -183,7 +182,6 @@ int main(int argc, char **argv)
|
||||
bool load_all = true;
|
||||
bool load_items = false;
|
||||
bool load_loot = false;
|
||||
bool load_skill_caps = false;
|
||||
bool load_spells = false;
|
||||
|
||||
if (argc > 1) {
|
||||
@@ -197,11 +195,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (strcasecmp("skill_caps", argv[i]) == 0) {
|
||||
load_skill_caps = true;
|
||||
load_all = false;
|
||||
}
|
||||
else if (strcasecmp("spells", argv[i]) == 0) {
|
||||
if (strcasecmp("spells", argv[i]) == 0) {
|
||||
load_spells = true;
|
||||
load_all = false;
|
||||
}
|
||||
@@ -236,16 +230,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (load_all || load_skill_caps) {
|
||||
LogInfo("Loading skill caps");
|
||||
try {
|
||||
LoadSkillCaps(&content_db, hotfix_name);
|
||||
} catch (std::exception &ex) {
|
||||
LogError("{}", ex.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (load_all || load_spells) {
|
||||
LogInfo("Loading spells");
|
||||
try {
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "skill_caps.h"
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/shareddb.h"
|
||||
#include "../common/ipc_mutex.h"
|
||||
#include "../common/memory_mapped_file.h"
|
||||
#include "../common/eqemu_exception.h"
|
||||
#include "../common/classes.h"
|
||||
#include "../common/features.h"
|
||||
|
||||
void LoadSkillCaps(SharedDatabase *database, const std::string &prefix) {
|
||||
EQ::IPCMutex mutex("skill_caps");
|
||||
mutex.Lock();
|
||||
|
||||
uint32 class_count = Class::PLAYER_CLASS_COUNT;
|
||||
uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
|
||||
uint32 level_count = HARD_LEVEL_CAP + 1;
|
||||
uint32 size = (class_count * skill_count * level_count * sizeof(uint16));
|
||||
|
||||
auto Config = EQEmuConfig::get();
|
||||
std::string file_name = Config->SharedMemDir + prefix + std::string("skill_caps");
|
||||
EQ::MemoryMappedFile mmf(file_name, size);
|
||||
mmf.ZeroFile();
|
||||
|
||||
void *ptr = mmf.Get();
|
||||
database->LoadSkillCaps(ptr);
|
||||
mutex.Unlock();
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __EQEMU_SHARED_MEMORY_SKILL_CAPS_H
|
||||
#define __EQEMU_SHARED_MEMORY_SKILL_CAPS_H
|
||||
|
||||
#include <string>
|
||||
#include "../common/eqemu_config.h"
|
||||
|
||||
class SharedDatabase;
|
||||
void LoadSkillCaps(SharedDatabase *database, const std::string &prefix);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -280,7 +280,7 @@ foreach my $table_to_generate (@tables) {
|
||||
|
||||
# column names (string)
|
||||
$column_names_quoted .= sprintf("\t\t\t\"%s\",\n", format_column_name_for_mysql($column_name));
|
||||
if ($data_type =~ /datetime/) {
|
||||
if ($data_type =~ /datetime|timestamp/) {
|
||||
$select_column_names_quoted .= sprintf("\t\t\t\"UNIX_TIMESTAMP(%s)\",\n", format_column_name_for_mysql($column_name));
|
||||
}
|
||||
else {
|
||||
@@ -293,7 +293,7 @@ foreach my $table_to_generate (@tables) {
|
||||
if ($data_type =~ /int|float|double|decimal/) {
|
||||
$query_value = sprintf('" + std::to_string(e.%s));', $column_name_formatted);
|
||||
}
|
||||
elsif ($data_type =~ /datetime/) {
|
||||
elsif ($data_type =~ /datetime|timestamp/) {
|
||||
$query_value = sprintf('FROM_UNIXTIME(" + (e.%s > 0 ? std::to_string(e.%s) : "null") + ")");', $column_name_formatted, $column_name_formatted);
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ foreach my $table_to_generate (@tables) {
|
||||
if ($data_type =~ /int|float|double|decimal/) {
|
||||
$value = sprintf('std::to_string(e.%s)', $column_name_formatted);
|
||||
}
|
||||
elsif ($data_type =~ /datetime/) {
|
||||
elsif ($data_type =~ /datetime|timestamp/) {
|
||||
$value = sprintf('"FROM_UNIXTIME(" + (e.%s > 0 ? std::to_string(e.%s) : "null") + ")"', $column_name_formatted, $column_name_formatted);
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ foreach my $table_to_generate (@tables) {
|
||||
$all_entries .= sprintf("\t\t\te.%-${longest_column_length}s = row[%s] ? strtoll(row[%s], nullptr, 10) : %s;\n", $column_name_formatted, $index, $index, $default_value);
|
||||
$find_one_entries .= sprintf("\t\t\te.%-${longest_column_length}s = row[%s] ? strtoll(row[%s], nullptr, 10) : %s;\n", $column_name_formatted, $index, $index, $default_value);
|
||||
}
|
||||
elsif ($data_type =~ /datetime/) {
|
||||
elsif ($data_type =~ /datetime|timestamp/) {
|
||||
$all_entries .= sprintf("\t\t\te.%-${longest_column_length}s = strtoll(row[%s] ? row[%s] : \"-1\", nullptr, 10);\n", $column_name_formatted, $index, $index);
|
||||
$find_one_entries .= sprintf("\t\t\te.%-${longest_column_length}s = strtoll(row[%s] ? row[%s] : \"-1\", nullptr, 10);\n", $column_name_formatted, $index, $index);
|
||||
}
|
||||
@@ -591,7 +591,7 @@ sub translate_mysql_data_type_to_c
|
||||
elsif ($mysql_data_type =~ /double/) {
|
||||
$struct_data_type = 'double';
|
||||
}
|
||||
elsif ($mysql_data_type =~ /datetime/) {
|
||||
elsif ($mysql_data_type =~ /datetime|timestamp/) {
|
||||
$struct_data_type = 'time_t';
|
||||
}
|
||||
|
||||
|
||||
+40
-12
@@ -53,6 +53,9 @@
|
||||
#include "../common/repositories/inventory_repository.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/content/world_content_service.h"
|
||||
#include "../common/repositories/group_id_repository.h"
|
||||
#include "../common/repositories/character_data_repository.h"
|
||||
#include "../common/skill_caps.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
@@ -190,9 +193,10 @@ bool Client::CanTradeFVNoDropItem()
|
||||
|
||||
void Client::SendEnterWorld(std::string name)
|
||||
{
|
||||
char char_name[64] = { 0 };
|
||||
if (is_player_zoning && database.GetLiveChar(GetAccountID(), char_name)) {
|
||||
if(database.GetAccountIDByChar(char_name) != GetAccountID()) {
|
||||
std::string live_name {};
|
||||
if (is_player_zoning) {
|
||||
live_name = database.GetLiveChar(GetAccountID());
|
||||
if(database.GetAccountIDByChar(live_name) != GetAccountID()) {
|
||||
eqs->Close();
|
||||
return;
|
||||
} else {
|
||||
@@ -200,8 +204,8 @@ void Client::SendEnterWorld(std::string name)
|
||||
}
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_EnterWorld, strlen(char_name) + 1);
|
||||
memcpy(outapp->pBuffer,char_name,strlen(char_name)+1);
|
||||
auto outapp = new EQApplicationPacket(OP_EnterWorld, live_name.length() + 1);
|
||||
memcpy(outapp->pBuffer, live_name.c_str(), live_name.length() + 1);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -764,9 +768,15 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
auto ew = (EnterWorld_Struct *) app->pBuffer;
|
||||
strn0cpy(char_name, ew->name, sizeof(char_name));
|
||||
|
||||
uint32 temporary_account_id = 0;
|
||||
charid = database.GetCharacterInfo(char_name, &temporary_account_id, &zone_id, &instance_id);
|
||||
if (!charid) {
|
||||
const auto& l = CharacterDataRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`name` = '{}' LIMIT 1",
|
||||
Strings::Escape(char_name)
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
LogInfo("Could not get CharInfo for [{}]", char_name);
|
||||
eqs->Close();
|
||||
return true;
|
||||
@@ -784,13 +794,24 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
instance_id = r.instance.id;
|
||||
}
|
||||
|
||||
const auto& e = l.front();
|
||||
|
||||
// Make sure this account owns this character
|
||||
if (temporary_account_id != account_id) {
|
||||
LogInfo("Account [{}] does not own the character named [{}] from account [{}]", account_id, char_name, temporary_account_id);
|
||||
if (e.account_id != account_id) {
|
||||
LogInfo(
|
||||
"Account [{}] does not own the character named [{}] from account [{}]",
|
||||
account_id,
|
||||
char_name,
|
||||
e.account_id
|
||||
);
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
charid = e.id;
|
||||
zone_id = e.zone_id;
|
||||
instance_id = e.zone_instance;
|
||||
|
||||
// This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above)
|
||||
// (This is a literal translation of the original process..I don't see why it can't be changed to a single-target query over account iteration)
|
||||
if (!is_player_zoning) {
|
||||
@@ -881,7 +902,14 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
if(!is_player_zoning) {
|
||||
database.SetGroupID(char_name, 0, charid);
|
||||
GroupIdRepository::DeleteWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`character_id` = {} AND `name` = '{}'",
|
||||
charid,
|
||||
Strings::Escape(char_name)
|
||||
)
|
||||
);
|
||||
database.SetLoginFlags(charid, false, false, 1);
|
||||
} else {
|
||||
auto group_id = database.GetGroupID(char_name);
|
||||
@@ -2107,7 +2135,7 @@ void Client::SetClassStartingSkills(PlayerProfile_Struct *pp)
|
||||
i == EQ::skills::SkillAlcoholTolerance || i == EQ::skills::SkillBindWound)
|
||||
continue;
|
||||
|
||||
pp->skills[i] = content_db.GetSkillCap(pp->class_, (EQ::skills::SkillType)i, 1);
|
||||
pp->skills[i] = skill_caps.GetSkillCap(pp->class_, (EQ::skills::SkillType)i, 1).cap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -344,7 +344,7 @@ bool ClientListEntry::CheckAuth(uint32 loginserver_account_id, const char *key_p
|
||||
|
||||
paccountid = database.CreateAccount(
|
||||
loginserver_account_name,
|
||||
0,
|
||||
std::string(),
|
||||
default_account_status,
|
||||
source_loginserver,
|
||||
LSID()
|
||||
|
||||
+12
-4
@@ -94,12 +94,20 @@ void ClientList::GetCLEIP(uint32 in_ip) {
|
||||
int count = 0;
|
||||
iterator.Reset();
|
||||
|
||||
const auto& zones = Strings::Split(RuleS(World, IPExemptionZones), ",");
|
||||
|
||||
while (iterator.MoreElements()) {
|
||||
cle = iterator.GetData();
|
||||
|
||||
const auto zones = Strings::Split(RuleS(World, IPExemptionZones), ",");
|
||||
for (const auto &z : zones) {
|
||||
if (Strings::ToUnsignedInt(z) == cle->zone()) {
|
||||
|
||||
if (!zones.empty() && cle->zone()) {
|
||||
auto it = std::ranges::find_if(
|
||||
zones,
|
||||
[cle](const auto& z) {
|
||||
return Strings::ToUnsignedInt(z) == cle->zone();
|
||||
}
|
||||
);
|
||||
|
||||
if (it != zones.end()) {
|
||||
iterator.Advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
+1
-2
@@ -57,8 +57,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string &username, const
|
||||
return ret;
|
||||
}
|
||||
|
||||
char account_name[64];
|
||||
database.GetAccountName(ret.account_id, account_name);
|
||||
const std::string& account_name = database.GetAccountName(ret.account_id);
|
||||
|
||||
ret.account_name = account_name;
|
||||
ret.status = database.CheckStatus(ret.account_id);
|
||||
|
||||
@@ -156,6 +156,7 @@ std::vector<Reload> reload_types = {
|
||||
Reload{.command = "opcodes", .opcode = ServerOP_ReloadOpcodes, .desc = "Opcodes"},
|
||||
Reload{.command = "perl_export", .opcode = ServerOP_ReloadPerlExportSettings, .desc = "Perl Event Export Settings"},
|
||||
Reload{.command = "rules", .opcode = ServerOP_ReloadRules, .desc = "Rules"},
|
||||
Reload{.command = "skill_caps", .opcode = ServerOP_ReloadSkillCaps, .desc = "Skill Caps"},
|
||||
Reload{.command = "static", .opcode = ServerOP_ReloadStaticZoneData, .desc = "Static Zone Data"},
|
||||
Reload{.command = "tasks", .opcode = ServerOP_ReloadTasks, .desc = "Tasks"},
|
||||
Reload{.command = "titles", .opcode = ServerOP_ReloadTitles, .desc = "Titles"},
|
||||
|
||||
+4
-1
@@ -86,8 +86,9 @@
|
||||
#include "world_boot.h"
|
||||
#include "../common/path_manager.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/skill_caps.h"
|
||||
|
||||
|
||||
SkillCaps skill_caps;
|
||||
ZoneStore zone_store;
|
||||
ClientList client_list;
|
||||
GroupLFPList LFPGroupList;
|
||||
@@ -193,6 +194,8 @@ int main(int argc, char **argv)
|
||||
->SetExpansionContext()
|
||||
->ReloadContentFlags();
|
||||
|
||||
skill_caps.SetContentDatabase(&content_db)->LoadSkillCaps();
|
||||
|
||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||
server_connection = std::make_unique<EQ::Net::ServertalkServer>();
|
||||
|
||||
|
||||
@@ -292,10 +292,6 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
|
||||
LogError("Error: Could not load item data. But ignoring");
|
||||
}
|
||||
|
||||
if (!content_db.LoadSkillCaps(std::string(hotfix_name))) {
|
||||
LogError("Error: Could not load skill cap data. But ignoring");
|
||||
}
|
||||
|
||||
guild_mgr.LoadGuilds();
|
||||
guild_mgr.LoadTributes();
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/patches/patches.h"
|
||||
#include "../zone/data_bucket.h"
|
||||
#include "../common/repositories/guild_tributes_repository.h"
|
||||
#include "../common/skill_caps.h"
|
||||
|
||||
extern ClientList client_list;
|
||||
extern GroupLFPList LFPGroupList;
|
||||
@@ -1436,6 +1437,11 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
case ServerOP_ReloadSkillCaps: {
|
||||
zoneserver_list.SendPacket(pack);
|
||||
skill_caps.ReloadSkillCaps();
|
||||
break;
|
||||
}
|
||||
case ServerOP_ReloadRules: {
|
||||
zoneserver_list.SendPacket(pack);
|
||||
RuleManager::Instance()->LoadRules(&database, "default", true);
|
||||
@@ -1496,11 +1502,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
LogInfo("Error: Could not load item data. But ignoring");
|
||||
}
|
||||
|
||||
LogInfo("Loading skill caps");
|
||||
if (!content_db.LoadSkillCaps(hotfix_name)) {
|
||||
LogInfo("Error: Could not load skill cap data. But ignoring");
|
||||
}
|
||||
|
||||
zoneserver_list.SendPacket(pack);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ SET(zone_sources
|
||||
loot.cpp
|
||||
lua_bot.cpp
|
||||
lua_bit.cpp
|
||||
lua_buff.cpp
|
||||
lua_corpse.cpp
|
||||
lua_client.cpp
|
||||
lua_door.cpp
|
||||
@@ -105,6 +106,7 @@ SET(zone_sources
|
||||
pathfinder_null.cpp
|
||||
pathing.cpp
|
||||
perl_bot.cpp
|
||||
perl_buff.cpp
|
||||
perl_client.cpp
|
||||
perl_doors.cpp
|
||||
perl_entity.cpp
|
||||
@@ -207,6 +209,7 @@ SET(zone_headers
|
||||
horse.h
|
||||
lua_bot.h
|
||||
lua_bit.h
|
||||
lua_buff.h
|
||||
lua_client.h
|
||||
lua_corpse.h
|
||||
lua_door.h
|
||||
|
||||
@@ -57,9 +57,7 @@ EQ::Net::WebsocketLoginStatus CheckLogin(
|
||||
return ret;
|
||||
}
|
||||
|
||||
char account_name[64];
|
||||
database.GetAccountName(static_cast<uint32>(ret.account_id), account_name);
|
||||
ret.account_name = account_name;
|
||||
ret.account_name = database.GetAccountName(static_cast<uint32>(ret.account_id));
|
||||
ret.logged_in = true;
|
||||
ret.status = database.CheckStatus(ret.account_id);
|
||||
return ret;
|
||||
|
||||
+109
-32
@@ -1687,13 +1687,6 @@ bool Mob::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
}
|
||||
}
|
||||
|
||||
//used by complete heal and #heal
|
||||
void Mob::Heal()
|
||||
{
|
||||
SetMaxHP();
|
||||
SendHPUpdate();
|
||||
}
|
||||
|
||||
void Client::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, eSpecialAttacks special)
|
||||
{
|
||||
if (dead || IsCorpse())
|
||||
@@ -2618,12 +2611,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
}
|
||||
|
||||
if (m.member) {
|
||||
m.member->RecordKilledNPCEvent(this);
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, m.member, "killed", 0);
|
||||
}
|
||||
|
||||
if (RuleB(NPC, EnableMeritBasedFaction)) {
|
||||
m.member->SetFactionLevel(
|
||||
m.member->CharacterID(),
|
||||
@@ -2683,18 +2670,11 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the EVENT_KILLED_MERIT event and update kill tasks
|
||||
* for all group members */
|
||||
/* Update kill tasks for all group members */
|
||||
for (const auto& m : killer_group->members) {
|
||||
if (m && m->IsClient()) {
|
||||
Client* c = m->CastToClient();
|
||||
|
||||
c->RecordKilledNPCEvent(this);
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, c, "killed", 0);
|
||||
}
|
||||
|
||||
if (RuleB(NPC, EnableMeritBasedFaction)) {
|
||||
c->SetFactionLevel(
|
||||
c->CharacterID(),
|
||||
@@ -2756,13 +2736,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the EVENT_KILLED_MERIT event */
|
||||
give_exp_client->RecordKilledNPCEvent(this);
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, give_exp_client, "killed", 0);
|
||||
}
|
||||
|
||||
if (RuleB(NPC, EnableMeritBasedFaction)) {
|
||||
give_exp_client->SetFactionLevel(
|
||||
give_exp_client->CharacterID(),
|
||||
@@ -2843,6 +2816,9 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
entity_list.RemoveFromAutoXTargets(this);
|
||||
|
||||
// Here we create the corpse.
|
||||
DeleteInvalidQuestLoot();
|
||||
|
||||
corpse = new Corpse(
|
||||
this,
|
||||
&m_loot_items,
|
||||
@@ -2991,6 +2967,17 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
m_combat_record.Stop();
|
||||
|
||||
if (give_exp_client && !IsCorpse()) {
|
||||
const auto& v = give_exp_client->GetRaidOrGroupOrSelf(true);
|
||||
for (const auto& m : v) {
|
||||
m->CastToClient()->RecordKilledNPCEvent(this);
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, m, "killed", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {} {} {} {} {} {} {}",
|
||||
@@ -3980,6 +3967,18 @@ bool Mob::CheckDoubleAttack()
|
||||
}
|
||||
|
||||
void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks special) {
|
||||
#ifdef LUA_EQEMU
|
||||
int64 lua_ret = 0;
|
||||
bool ignore_default = false;
|
||||
lua_ret = LuaParser::Instance()->CommonDamage(this, attacker, damage, spell_id, static_cast<int>(skill_used), avoidable, buffslot, iBuffTic, static_cast<int>(special), ignore_default);
|
||||
if (lua_ret != 0) {
|
||||
damage = lua_ret;
|
||||
}
|
||||
|
||||
if (ignore_default) {
|
||||
//return lua_ret;
|
||||
}
|
||||
#endif
|
||||
// This method is called with skill_used=ABJURE for Damage Shield damage.
|
||||
bool FromDamageShield = (skill_used == EQ::skills::SkillAbjuration);
|
||||
bool ignore_invul = false;
|
||||
@@ -4707,6 +4706,19 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
||||
|
||||
void Mob::HealDamage(uint64 amount, Mob* caster, uint16 spell_id)
|
||||
{
|
||||
#ifdef LUA_EQEMU
|
||||
uint64 lua_ret = 0;
|
||||
bool ignore_default = false;
|
||||
|
||||
lua_ret = LuaParser::Instance()->HealDamage(this, caster, amount, spell_id, ignore_default);
|
||||
if (lua_ret != 0) {
|
||||
amount = lua_ret;
|
||||
}
|
||||
|
||||
if (ignore_default) {
|
||||
//return lua_ret;
|
||||
}
|
||||
#endif
|
||||
int64 maxhp = GetMaxHP();
|
||||
int64 curhp = GetHP();
|
||||
uint64 acthealed = 0;
|
||||
@@ -6301,9 +6313,24 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
|
||||
hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + defender->GetPositionalDmgTakenAmt(this);
|
||||
|
||||
if (defender->GetShielderID()) {
|
||||
DoShieldDamageOnShielder(defender, hit.damage_done, hit.skill);
|
||||
hit.damage_done -= hit.damage_done * defender->GetShieldTargetMitigation() / 100; //Default shielded takes 50 pct damage
|
||||
if (defender->GetShielderID() || defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT]) {
|
||||
bool use_shield_ability = true;
|
||||
//If defender is being shielded by an ability AND has a shield spell effect buff use highest mitigation value.
|
||||
if ((defender->GetShieldTargetMitigation() && defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT]) &&
|
||||
(defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] >= defender->GetShieldTargetMitigation())){
|
||||
bool use_shield_ability = false;
|
||||
}
|
||||
|
||||
//use targeted /shield ability values
|
||||
if (defender->GetShielderID() && use_shield_ability) {
|
||||
DoShieldDamageOnShielder(defender, hit.damage_done, hit.skill);
|
||||
hit.damage_done -= hit.damage_done * defender->GetShieldTargetMitigation() / 100; //Default shielded takes 50 pct damage
|
||||
}
|
||||
//use spell effect SPA 463 values
|
||||
else if (defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT]){
|
||||
DoShieldDamageOnShielderSpellEffect(defender, hit.damage_done, hit.skill);
|
||||
hit.damage_done -= hit.damage_done * defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] / 100;
|
||||
}
|
||||
}
|
||||
|
||||
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
|
||||
@@ -6346,7 +6373,57 @@ void Mob::DoShieldDamageOnShielder(Mob *shield_target, int64 hit_damage_done, EQ
|
||||
|
||||
hit_damage_done -= hit_damage_done * mitigation / 100;
|
||||
shielder->Damage(this, hit_damage_done, SPELL_UNKNOWN, skillInUse, true, -1, false, m_specialattacks);
|
||||
shielder->CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
|
||||
}
|
||||
|
||||
void Mob::DoShieldDamageOnShielderSpellEffect(Mob* shield_target, int64 hit_damage_done, EQ::skills::SkillType skillInUse)
|
||||
{
|
||||
if (!shield_target) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
SPA 463 SE_SHIELD_TARGET
|
||||
|
||||
Live description: "Shields your target, taking a percentage of their damage".
|
||||
Only example spell on live is an NPC who uses it during a raid event "Laurion's Song" expansion. SPA 54492 'Guardian Stance' Described as 100% Melee Shielding
|
||||
|
||||
Example of mechanic. Base value = 70. Caster puts buff on target. Each melee hit Buff Target takes 70% less damage, Buff Caster receives 30% of the melee damage.
|
||||
Added mechanic to cause buff to fade if target or caster are seperated by a distance greater than the casting range of the spell. This allows similiar mechanics
|
||||
to the /shield ability, without a range removal mechanic it would be too easy to abuse if put on a player spell. *can not confirm live does this currently
|
||||
|
||||
Can not be cast on self.
|
||||
*/
|
||||
|
||||
if (shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT])
|
||||
{
|
||||
if (shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] >= 0)
|
||||
{
|
||||
Mob *shielder = entity_list.GetMob(shield_target->buffs[shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]].casterid);
|
||||
if (!shielder) {
|
||||
shield_target->BuffFadeBySlot(shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]);
|
||||
return;
|
||||
}
|
||||
|
||||
int shield_spell_id = shield_target->buffs[shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]].spellid;
|
||||
if (!IsValidSpell(shield_spell_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float max_range = spells[shield_spell_id].range;
|
||||
if (spells[shield_spell_id].aoe_range > max_range) {
|
||||
max_range = spells[shield_spell_id].aoe_range;
|
||||
}
|
||||
max_range += 5.0f; //small buffer in case casted at exactly max range.
|
||||
|
||||
if (shield_target->CalculateDistance(shielder->GetX(), shielder->GetY(), shielder->GetZ()) > max_range) {
|
||||
shield_target->BuffFadeBySlot(shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]);
|
||||
return;
|
||||
}
|
||||
|
||||
int mitigation = 100 - shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT];
|
||||
hit_damage_done -= hit_damage_done * mitigation / 100;
|
||||
shielder->Damage(this, hit_damage_done, SPELL_UNKNOWN, skillInUse, true, -1, false, m_specialattacks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::CommonBreakInvisibleFromCombat()
|
||||
|
||||
+24
-1
@@ -2090,7 +2090,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
if (focus)
|
||||
{
|
||||
if (WornType){
|
||||
if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) {
|
||||
if (RuleB(Spells, UseAdditiveFocusFromWornSlotWithLimits)) {
|
||||
new_bonus->FocusEffectsWornWithLimits[focus] = spells[spell_id].effect_id[i];
|
||||
}
|
||||
else if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) {
|
||||
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base_value[i];
|
||||
}
|
||||
}
|
||||
@@ -3298,6 +3301,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Shield_Target:
|
||||
{
|
||||
if (new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] < effect_value) {
|
||||
new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] = effect_value;
|
||||
new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] = buffslot;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_TriggerMeleeThreshold:
|
||||
new_bonus->TriggerMeleeThreshold = true;
|
||||
break;
|
||||
@@ -4989,6 +5001,7 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
|
||||
case SE_MaxHPChange:
|
||||
if (negate_spellbonus) { spellbonuses.MaxHPChange = effect_value; }
|
||||
if (negate_aabonus) { aabonuses.MaxHPChange = effect_value; }
|
||||
if (negate_aabonus) { aabonuses.MaxHP = effect_value; }
|
||||
if (negate_itembonus) { itembonuses.MaxHPChange = effect_value; }
|
||||
break;
|
||||
|
||||
@@ -5916,6 +5929,7 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
|
||||
if (negate_itembonus) { itembonuses.SkillProcSuccess[e] = effect_value; }
|
||||
if (negate_aabonus) { aabonuses.SkillProcSuccess[e] = effect_value; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SkillProcAttempt: {
|
||||
@@ -5925,6 +5939,15 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
|
||||
if (negate_itembonus) { itembonuses.SkillProc[e] = effect_value; }
|
||||
if (negate_aabonus) { aabonuses.SkillProc[e] = effect_value; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Shield_Target: {
|
||||
if (negate_spellbonus) {
|
||||
spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] = effect_value;
|
||||
spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] = effect_value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+179
-121
@@ -27,6 +27,7 @@
|
||||
#include "../common/repositories/bot_starting_items_repository.h"
|
||||
#include "../common/data_verification.h"
|
||||
#include "../common/repositories/criteria/content_filter_criteria.h"
|
||||
#include "../common/skill_caps.h"
|
||||
|
||||
// This constructor is used during the bot create command
|
||||
Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm::vec4(), Ground, false), rest_timer(1), ping_timer(1) {
|
||||
@@ -1171,7 +1172,7 @@ uint16 Bot::GetPrimarySkillValue() {
|
||||
}
|
||||
|
||||
uint16 Bot::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const {
|
||||
return(content_db.GetSkillCap(class_, skillid, level));
|
||||
return skill_caps.GetSkillCap(class_, skillid, level).cap;
|
||||
}
|
||||
|
||||
uint32 Bot::GetTotalATK() {
|
||||
@@ -2287,7 +2288,7 @@ bool Bot::TryMeditate() {
|
||||
if (!IsMoving() && !spellend_timer.Enabled()) {
|
||||
if (GetTarget() && AI_EngagedCastCheck()) {
|
||||
BotMeditate(false);
|
||||
} else if (GetArchetype() == ARCHETYPE_CASTER) {
|
||||
} else if (GetArchetype() == Archetype::Caster) {
|
||||
BotMeditate(true);
|
||||
}
|
||||
|
||||
@@ -2684,16 +2685,19 @@ bool Bot::IsValidTarget(
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool valid_target_state = (
|
||||
HOLDING ||
|
||||
bool invalid_target_state = false;
|
||||
if (HOLDING ||
|
||||
!tar->IsNPC() ||
|
||||
tar->IsMezzed() ||
|
||||
lo_distance > leash_distance ||
|
||||
tar_distance > leash_distance
|
||||
);
|
||||
const bool valid_target = !GetAttackingFlag() && !CheckLosFN(tar) && !leash_owner->CheckLosFN(tar);
|
||||
tar_distance > leash_distance ||
|
||||
(!GetAttackingFlag() && !CheckLosFN(tar) && !leash_owner->CheckLosFN(tar)) ||
|
||||
!IsAttackAllowed(tar)
|
||||
) {
|
||||
invalid_target_state = true;
|
||||
}
|
||||
|
||||
if (valid_target_state || valid_target || !IsAttackAllowed(tar)) {
|
||||
if (invalid_target_state) {
|
||||
// Normally, we wouldn't want to do this without class checks..but, too many issues can arise if we let enchanter animation pets run rampant
|
||||
if (HasPet()) {
|
||||
GetPet()->RemoveFromHateList(tar);
|
||||
@@ -2752,7 +2756,7 @@ Mob* Bot::GetBotTarget(Client* bot_owner)
|
||||
}
|
||||
}
|
||||
|
||||
if (GetArchetype() == ARCHETYPE_CASTER) {
|
||||
if (GetArchetype() == Archetype::Caster) {
|
||||
BotMeditate(true);
|
||||
}
|
||||
}
|
||||
@@ -3340,7 +3344,7 @@ void Bot::LoadAndSpawnAllZonedBots(Client* bot_owner) {
|
||||
}
|
||||
|
||||
if (bot_spawn_limit >= 0 && spawned_bots_count >= bot_spawn_limit) {
|
||||
database.SetGroupID(b->GetCleanName(), 0, b->GetBotID());
|
||||
Group::RemoveFromGroup(b);
|
||||
g->UpdatePlayer(bot_owner);
|
||||
continue;
|
||||
}
|
||||
@@ -3352,7 +3356,7 @@ void Bot::LoadAndSpawnAllZonedBots(Client* bot_owner) {
|
||||
bot_spawn_limit_class >= 0 &&
|
||||
spawned_bot_count_class >= bot_spawn_limit_class
|
||||
) {
|
||||
database.SetGroupID(b->GetCleanName(), 0, b->GetBotID());
|
||||
Group::RemoveFromGroup(b);
|
||||
g->UpdatePlayer(bot_owner);
|
||||
continue;
|
||||
}
|
||||
@@ -3372,7 +3376,7 @@ void Bot::LoadAndSpawnAllZonedBots(Client* bot_owner) {
|
||||
}
|
||||
|
||||
if (!bot_owner->HasGroup()) {
|
||||
database.SetGroupID(b->GetCleanName(), 0, b->GetBotID());
|
||||
Group::RemoveFromGroup(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3629,8 +3633,8 @@ bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) {
|
||||
bot->SetFollowID(0);
|
||||
if (group->DelMember(bot)) {
|
||||
group->DelMemberOOZ(bot->GetName());
|
||||
database.SetGroupID(bot->GetCleanName(), 0, bot->GetBotID());
|
||||
if (group->GroupCount() < 1) {
|
||||
Group::RemoveFromGroup(bot);
|
||||
if (group->GroupCount() < 2) {
|
||||
group->DisbandGroup();
|
||||
}
|
||||
}
|
||||
@@ -3643,7 +3647,7 @@ bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) {
|
||||
group->members[i]->SetFollowID(0);
|
||||
}
|
||||
group->DisbandGroup();
|
||||
database.SetGroupID(bot->GetCleanName(), 0, bot->GetBotID());
|
||||
Group::RemoveFromGroup(bot);
|
||||
}
|
||||
Result = true;
|
||||
}
|
||||
@@ -5186,31 +5190,26 @@ void Bot::ProcessBotOwnerRefDelete(Mob* botOwner) {
|
||||
}
|
||||
}
|
||||
|
||||
int64 Bot::CalcMaxMana() {
|
||||
switch(GetCasterClass()) {
|
||||
case 'I':
|
||||
max_mana = (GenerateBaseManaPoints() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
|
||||
max_mana += itembonuses.heroic_max_mana;
|
||||
case 'W': {
|
||||
max_mana = (GenerateBaseManaPoints() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
|
||||
max_mana += itembonuses.heroic_max_mana;
|
||||
break;
|
||||
}
|
||||
case 'N': {
|
||||
max_mana = 0;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogDebug("Invalid Class [{}] in CalcMaxMana", GetCasterClass());
|
||||
max_mana = 0;
|
||||
break;
|
||||
}
|
||||
int64 Bot::CalcMaxMana()
|
||||
{
|
||||
if (IsIntelligenceCasterClass() || IsWisdomCasterClass()) {
|
||||
max_mana = (
|
||||
GenerateBaseManaPoints() +
|
||||
itembonuses.Mana +
|
||||
spellbonuses.Mana +
|
||||
aabonuses.Mana +
|
||||
GroupLeadershipAAManaEnhancement()
|
||||
);
|
||||
max_mana += itembonuses.heroic_max_mana;
|
||||
} else {
|
||||
max_mana = 0;
|
||||
}
|
||||
|
||||
if (current_mana > max_mana)
|
||||
if (current_mana > max_mana) {
|
||||
current_mana = max_mana;
|
||||
else if (max_mana < 0)
|
||||
} else if (max_mana < 0) {
|
||||
max_mana = 0;
|
||||
}
|
||||
|
||||
return max_mana;
|
||||
}
|
||||
@@ -5525,87 +5524,107 @@ bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, EQ::spells::CastingSlot
|
||||
return Result;
|
||||
}
|
||||
|
||||
int32 Bot::GenerateBaseManaPoints() {
|
||||
int32 bot_mana = 0;
|
||||
int32 WisInt = 0;
|
||||
int32 Bot::GenerateBaseManaPoints()
|
||||
{
|
||||
int32 bot_mana = 0;
|
||||
int32 WisInt = 0;
|
||||
int32 MindLesserFactor, MindFactor;
|
||||
int wisint_mana = 0;
|
||||
int base_mana = 0;
|
||||
int ConvertedWisInt = 0;
|
||||
switch(GetCasterClass()) {
|
||||
case 'I':
|
||||
WisInt = INT;
|
||||
if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
if (WisInt > 100) {
|
||||
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
|
||||
if (WisInt > 201)
|
||||
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
|
||||
}
|
||||
else
|
||||
ConvertedWisInt = WisInt;
|
||||
int wisint_mana = 0;
|
||||
int base_mana = 0;
|
||||
int ConvertedWisInt = 0;
|
||||
|
||||
if (GetLevel() < 41) {
|
||||
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
|
||||
base_mana = (GetLevel() * 15);
|
||||
} else if (GetLevel() < 81) {
|
||||
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
|
||||
base_mana = (600 + ((GetLevel() - 40) * 30));
|
||||
} else {
|
||||
wisint_mana = (9 * ConvertedWisInt);
|
||||
base_mana = (1800 + ((GetLevel() - 80) * 18));
|
||||
if (IsIntelligenceCasterClass()) {
|
||||
WisInt = INT;
|
||||
|
||||
if (
|
||||
GetOwner() &&
|
||||
GetOwner()->CastToClient() &&
|
||||
GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD &&
|
||||
RuleB(Character, SoDClientUseSoDHPManaEnd)
|
||||
) {
|
||||
if (WisInt > 100) {
|
||||
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
|
||||
if (WisInt > 201) {
|
||||
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
|
||||
}
|
||||
bot_mana = (base_mana + wisint_mana);
|
||||
} else {
|
||||
if (((WisInt - 199) / 2) > 0)
|
||||
MindLesserFactor = ((WisInt - 199) / 2);
|
||||
else
|
||||
MindLesserFactor = 0;
|
||||
|
||||
MindFactor = WisInt - MindLesserFactor;
|
||||
if (WisInt > 100)
|
||||
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
else
|
||||
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
ConvertedWisInt = WisInt;
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
WisInt = WIS;
|
||||
if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
if (WisInt > 100) {
|
||||
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
|
||||
if (WisInt > 201)
|
||||
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
|
||||
} else
|
||||
ConvertedWisInt = WisInt;
|
||||
|
||||
if (GetLevel() < 41) {
|
||||
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
|
||||
base_mana = (GetLevel() * 15);
|
||||
} else if (GetLevel() < 81) {
|
||||
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
|
||||
base_mana = (600 + ((GetLevel() - 40) * 30));
|
||||
} else {
|
||||
wisint_mana = (9 * ConvertedWisInt);
|
||||
base_mana = (1800 + ((GetLevel() - 80) * 18));
|
||||
}
|
||||
bot_mana = (base_mana + wisint_mana);
|
||||
if (GetLevel() < 41) {
|
||||
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
|
||||
base_mana = (GetLevel() * 15);
|
||||
} else if (GetLevel() < 81) {
|
||||
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
|
||||
base_mana = (600 + ((GetLevel() - 40) * 30));
|
||||
} else {
|
||||
if (((WisInt - 199) / 2) > 0)
|
||||
MindLesserFactor = ((WisInt - 199) / 2);
|
||||
else
|
||||
MindLesserFactor = 0;
|
||||
|
||||
MindFactor = (WisInt - MindLesserFactor);
|
||||
if (WisInt > 100)
|
||||
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
else
|
||||
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
wisint_mana = (9 * ConvertedWisInt);
|
||||
base_mana = (1800 + ((GetLevel() - 80) * 18));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
bot_mana = 0;
|
||||
break;
|
||||
|
||||
bot_mana = (base_mana + wisint_mana);
|
||||
} else {
|
||||
if (((WisInt - 199) / 2) > 0) {
|
||||
MindLesserFactor = ((WisInt - 199) / 2);
|
||||
} else {
|
||||
MindLesserFactor = 0;
|
||||
}
|
||||
|
||||
MindFactor = WisInt - MindLesserFactor;
|
||||
if (WisInt > 100) {
|
||||
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
} else {
|
||||
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
}
|
||||
}
|
||||
} else if (IsWisdomCasterClass()) {
|
||||
WisInt = WIS;
|
||||
|
||||
if (
|
||||
GetOwner() &&
|
||||
GetOwner()->CastToClient() &&
|
||||
GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD &&
|
||||
RuleB(Character, SoDClientUseSoDHPManaEnd)
|
||||
) {
|
||||
if (WisInt > 100) {
|
||||
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
|
||||
if (WisInt > 201) {
|
||||
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
|
||||
}
|
||||
} else {
|
||||
ConvertedWisInt = WisInt;
|
||||
}
|
||||
|
||||
if (GetLevel() < 41) {
|
||||
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
|
||||
base_mana = (GetLevel() * 15);
|
||||
} else if (GetLevel() < 81) {
|
||||
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
|
||||
base_mana = (600 + ((GetLevel() - 40) * 30));
|
||||
} else {
|
||||
wisint_mana = (9 * ConvertedWisInt);
|
||||
base_mana = (1800 + ((GetLevel() - 80) * 18));
|
||||
}
|
||||
|
||||
bot_mana = (base_mana + wisint_mana);
|
||||
} else {
|
||||
if (((WisInt - 199) / 2) > 0) {
|
||||
MindLesserFactor = ((WisInt - 199) / 2);
|
||||
} else {
|
||||
MindLesserFactor = 0;
|
||||
}
|
||||
|
||||
MindFactor = (WisInt - MindLesserFactor);
|
||||
if (WisInt > 100) {
|
||||
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
} else {
|
||||
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bot_mana = 0;
|
||||
}
|
||||
|
||||
max_mana = bot_mana;
|
||||
return bot_mana;
|
||||
}
|
||||
@@ -6216,11 +6235,10 @@ int64 Bot::CalcMaxHP() {
|
||||
uint32 nd = 10000;
|
||||
bot_hp += (GenerateBaseHitPoints() + itembonuses.HP);
|
||||
bot_hp += itembonuses.heroic_max_hp;
|
||||
nd += aabonuses.MaxHP;
|
||||
nd += aabonuses.MaxHP + spellbonuses.MaxHPChange + itembonuses.MaxHPChange;
|
||||
bot_hp = ((float)bot_hp * (float)nd / (float)10000);
|
||||
bot_hp += (spellbonuses.HP + aabonuses.HP);
|
||||
bot_hp += GroupLeadershipAAHealthEnhancement();
|
||||
bot_hp += (bot_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f));
|
||||
max_hp = bot_hp;
|
||||
if (current_hp > max_hp)
|
||||
current_hp = max_hp;
|
||||
@@ -6582,14 +6600,14 @@ void Bot::ProcessBotGroupInvite(Client* c, std::string const& botName) {
|
||||
entity_list.AddGroup(g);
|
||||
database.SetGroupLeaderName(g->GetID(), c->GetName());
|
||||
g->SaveGroupLeaderAA();
|
||||
database.SetGroupID(c->GetName(), g->GetID(), c->CharacterID());
|
||||
database.SetGroupID(invitedBot->GetCleanName(), g->GetID(), invitedBot->GetBotID());
|
||||
g->AddToGroup(c);
|
||||
g->AddToGroup(invitedBot);
|
||||
} else {
|
||||
delete g;
|
||||
}
|
||||
} else {
|
||||
if (AddBotToGroup(invitedBot, c->GetGroup())) {
|
||||
database.SetGroupID(invitedBot->GetCleanName(), c->GetGroup()->GetID(), invitedBot->GetBotID());
|
||||
c->GetGroup()->AddToGroup(invitedBot);
|
||||
}
|
||||
}
|
||||
} else if (invitedBot->HasGroup()) {
|
||||
@@ -6740,7 +6758,7 @@ void Bot::CalcBotStats(bool showtext) {
|
||||
SetLevel(GetBotOwner()->GetLevel());
|
||||
|
||||
for (int sindex = 0; sindex <= EQ::skills::HIGHEST_SKILL; ++sindex) {
|
||||
skills[sindex] = content_db.GetSkillCap(GetClass(), (EQ::skills::SkillType)sindex, GetLevel());
|
||||
skills[sindex] = skill_caps.GetSkillCap(GetClass(), (EQ::skills::SkillType)sindex, GetLevel()).cap;
|
||||
}
|
||||
|
||||
taunt_timer.Start(1000);
|
||||
@@ -7640,18 +7658,58 @@ void Bot::SetDefaultBotStance() {
|
||||
_botStance = defaultStance;
|
||||
}
|
||||
|
||||
void Bot::BotGroupSay(Mob *speaker, const char *msg, ...) {
|
||||
void Bot::BotGroupSay(Mob* speaker, const char* msg, ...) {
|
||||
char buf[1000];
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vsnprintf(buf, 1000, msg, ap);
|
||||
va_end(ap);
|
||||
if (speaker->HasGroup()) {
|
||||
Group *g = speaker->GetGroup();
|
||||
if (g)
|
||||
g->GroupMessage(speaker->CastToMob(), Language::CommonTongue, Language::MaxValue, buf);
|
||||
} else
|
||||
speaker->Say("%s", buf);
|
||||
|
||||
if (speaker->IsRaidGrouped()) {
|
||||
Raid* r = entity_list.GetRaidByBotName(speaker->GetName());
|
||||
if (r) {
|
||||
for (const auto& m : r->members) {
|
||||
if (m.member && !m.is_bot) {
|
||||
m.member->FilteredMessageString(
|
||||
speaker,
|
||||
Chat::PetResponse,
|
||||
FilterSocials,
|
||||
GENERIC_SAY,
|
||||
speaker->GetCleanName(),
|
||||
buf
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (speaker->HasGroup()) {
|
||||
Group* g = speaker->GetGroup();
|
||||
if (g) {
|
||||
for (auto& m : g->members) {
|
||||
if (m && !m->IsBot()) {
|
||||
m->FilteredMessageString(
|
||||
speaker,
|
||||
Chat::PetResponse,
|
||||
FilterSocials,
|
||||
GENERIC_SAY,
|
||||
speaker->GetCleanName(),
|
||||
buf
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//speaker->Say("%s", buf);
|
||||
speaker->GetOwner()->FilteredMessageString(
|
||||
speaker,
|
||||
Chat::PetResponse,
|
||||
FilterSocials,
|
||||
GENERIC_SAY,
|
||||
speaker->GetCleanName(),
|
||||
buf
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
|
||||
+5
-32
@@ -184,35 +184,11 @@ bool BotDatabase::QueryNameAvailablity(const std::string& bot_name, bool& availa
|
||||
if (
|
||||
bot_name.empty() ||
|
||||
bot_name.size() > 60 ||
|
||||
!database.CheckUsedName(bot_name)
|
||||
database.IsNameUsed(bot_name)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& bot_data = BotDataRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`name` LIKE '{}' LIMIT 1",
|
||||
bot_name
|
||||
)
|
||||
);
|
||||
|
||||
if (!bot_data.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& character_data = CharacterDataRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`name` LIKE '{}' LIMIT 1",
|
||||
bot_name
|
||||
)
|
||||
);
|
||||
|
||||
if (!character_data.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
available_flag = true;
|
||||
|
||||
return true;
|
||||
@@ -1788,7 +1764,8 @@ bool BotDatabase::CreateCloneBotInventory(const uint32 bot_id, const uint32 clon
|
||||
}
|
||||
|
||||
for (auto& e : l) {
|
||||
e.bot_id = clone_id;
|
||||
e.inventories_index = 0;
|
||||
e.bot_id = clone_id;
|
||||
}
|
||||
|
||||
return BotInventoriesRepository::InsertMany(database, l);
|
||||
@@ -1921,18 +1898,14 @@ bool BotDatabase::LoadGroupedBotsByGroupID(const uint32 owner_id, const uint32 g
|
||||
const auto& l = GroupIdRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`groupid` = {} AND `name` IN (SELECT `name` FROM `bot_data` WHERE `owner_id` = {})",
|
||||
"`group_id` = {} AND `bot_id` != 0 AND `name` IN (SELECT `name` FROM `bot_data` WHERE `owner_id` = {})",
|
||||
group_id,
|
||||
owner_id
|
||||
)
|
||||
);
|
||||
|
||||
if (l.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& e : l) {
|
||||
group_list.push_back(e.charid);
|
||||
group_list.emplace_back(e.bot_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ void Raid::HandleBotGroupDisband(uint32 owner, uint32 gid)
|
||||
auto r_group_members = GetRaidGroupMembers(GetGroup(b->GetName()));
|
||||
auto g = new Group(b);
|
||||
entity_list.AddGroup(g);
|
||||
database.SetGroupID(b->GetCleanName(), g->GetID(), b->GetBotID());
|
||||
g->AddToGroup(b);
|
||||
database.SetGroupLeaderName(g->GetID(), b->GetName());
|
||||
|
||||
for (auto m: r_group_members) {
|
||||
|
||||
@@ -591,7 +591,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
//Only check archetype if spell is not a group spell
|
||||
//Hybrids get all buffs
|
||||
switch (tar->GetArchetype()) {
|
||||
case ARCHETYPE_CASTER:
|
||||
case Archetype::Caster:
|
||||
//TODO: probably more caster specific spell effects in here
|
||||
if (
|
||||
(
|
||||
@@ -606,7 +606,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ARCHETYPE_MELEE:
|
||||
case Archetype::Melee:
|
||||
if (
|
||||
(
|
||||
IsEffectInSpell(s.SpellId, SE_IncreaseSpellHaste) ||
|
||||
@@ -899,7 +899,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
|
||||
switch (tar->GetArchetype())
|
||||
{
|
||||
case ARCHETYPE_CASTER:
|
||||
case Archetype::Caster:
|
||||
//TODO: probably more caster specific spell effects in here
|
||||
if (IsEffectInSpell(s.SpellId, SE_AttackSpeed) || IsEffectInSpell(s.SpellId, SE_ATK) ||
|
||||
IsEffectInSpell(s.SpellId, SE_STR) || IsEffectInSpell(s.SpellId, SE_ReverseDS))
|
||||
@@ -907,7 +907,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ARCHETYPE_MELEE:
|
||||
case Archetype::Melee:
|
||||
if (IsEffectInSpell(s.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(s.SpellId, SE_ManaPool) ||
|
||||
IsEffectInSpell(s.SpellId, SE_CastingLevel) || IsEffectInSpell(s.SpellId, SE_ManaRegen_v2) ||
|
||||
IsEffectInSpell(s.SpellId, SE_CurrentMana))
|
||||
|
||||
+215
-58
@@ -57,6 +57,7 @@ extern volatile bool RunLoops;
|
||||
#include "queryserv.h"
|
||||
#include "mob_movement_manager.h"
|
||||
#include "cheat_manager.h"
|
||||
#include "lua_parser.h"
|
||||
|
||||
#include "../common/repositories/character_alternate_abilities_repository.h"
|
||||
#include "../common/repositories/account_flags_repository.h"
|
||||
@@ -68,10 +69,12 @@ extern volatile bool RunLoops;
|
||||
#include "../common/repositories/discovered_items_repository.h"
|
||||
#include "../common/repositories/inventory_repository.h"
|
||||
#include "../common/repositories/keyring_repository.h"
|
||||
#include "../common/repositories/tradeskill_recipe_repository.h"
|
||||
#include "../common/events/player_events.h"
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "dialogue_window.h"
|
||||
#include "../common/zone_store.h"
|
||||
#include "../common/skill_caps.h"
|
||||
|
||||
|
||||
extern QueryServ* QServ;
|
||||
@@ -2225,8 +2228,8 @@ void Client::ChangeLastName(std::string last_name) {
|
||||
bool Client::ChangeFirstName(const char* in_firstname, const char* gmname)
|
||||
{
|
||||
// check duplicate name
|
||||
bool usedname = database.CheckUsedName((const char*) in_firstname);
|
||||
if (!usedname) {
|
||||
bool used_name = database.IsNameUsed((const char*) in_firstname);
|
||||
if (used_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2294,29 +2297,23 @@ void Client::ReadBook(BookRequest_Struct *book) {
|
||||
|
||||
BookText_Struct *out = (BookText_Struct *) outapp->pBuffer;
|
||||
out->window = book->window;
|
||||
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF) {
|
||||
// SoF+ need to look up book type for the output message.
|
||||
const EQ::ItemInstance *inst = nullptr;
|
||||
|
||||
if (book->invslot <= EQ::invbag::GENERAL_BAGS_END)
|
||||
{
|
||||
inst = m_inv[book->invslot];
|
||||
}
|
||||
|
||||
if(inst)
|
||||
out->type = inst->GetItem()->Book;
|
||||
else
|
||||
out->type = book->type;
|
||||
}
|
||||
else {
|
||||
out->type = book->type;
|
||||
}
|
||||
out->type = book->type;
|
||||
out->invslot = book->invslot;
|
||||
out->target_id = book->target_id;
|
||||
out->can_cast = 0; // todo: implement
|
||||
out->can_scribe = 0; // todo: implement
|
||||
out->can_scribe = false;
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && book->invslot <= EQ::invbag::GENERAL_BAGS_END)
|
||||
{
|
||||
const EQ::ItemInstance* inst = m_inv[book->invslot];
|
||||
if (inst && inst->GetItem())
|
||||
{
|
||||
auto recipe = TradeskillRecipeRepository::GetWhere(content_db,
|
||||
fmt::format("learned_by_item_id = {} LIMIT 1", inst->GetItem()->ID));
|
||||
out->type = inst->GetItem()->Book;
|
||||
out->can_scribe = !recipe.empty();
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(out->booktext, booktxt2.c_str(), length);
|
||||
|
||||
@@ -2761,31 +2758,48 @@ void Client::CheckLanguageSkillIncrease(uint8 language_id, uint8 teacher_skill)
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::HasSkill(EQ::skills::SkillType skill_id) const {
|
||||
return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id));
|
||||
}
|
||||
|
||||
bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const {
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skill_id == EQ::skills::Skill1HPiercing)
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
|
||||
return(content_db.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0);
|
||||
//if you don't have it by max level, then odds are you never will?
|
||||
}
|
||||
|
||||
uint16 Client::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const {
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
|
||||
skillid = EQ::skills::Skill2HPiercing;
|
||||
|
||||
return(content_db.GetSkillCap(class_, skillid, level));
|
||||
}
|
||||
|
||||
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_)
|
||||
bool Client::HasSkill(EQ::skills::SkillType skill_id) const
|
||||
{
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
|
||||
skillid = EQ::skills::Skill2HPiercing;
|
||||
return GetSkill(skill_id) > 0 && CanHaveSkill(skill_id);
|
||||
}
|
||||
|
||||
return(content_db.GetTrainLevel(class_, skillid, RuleI(Character, MaxLevel)));
|
||||
bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
class_ == Class::Berserker &&
|
||||
skill_id == EQ::skills::Skill1HPiercing
|
||||
) {
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return skill_caps.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)).cap > 0;
|
||||
}
|
||||
|
||||
uint16 Client::MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
class_id == Class::Berserker &&
|
||||
skill_id == EQ::skills::Skill1HPiercing
|
||||
) {
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return skill_caps.GetSkillCap(class_id, skill_id, level).cap;
|
||||
}
|
||||
|
||||
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
|
||||
{
|
||||
if (
|
||||
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
|
||||
class_id == Class::Berserker &&
|
||||
skill_id == EQ::skills::Skill1HPiercing
|
||||
) {
|
||||
skill_id = EQ::skills::Skill2HPiercing;
|
||||
}
|
||||
|
||||
return skill_caps.GetTrainLevel(class_id, skill_id, RuleI(Character, MaxLevel));
|
||||
}
|
||||
|
||||
uint16 Client::GetMaxSkillAfterSpecializationRules(EQ::skills::SkillType skillid, uint16 maxSkill)
|
||||
@@ -3791,14 +3805,12 @@ void Client::GetRaidAAs(RaidLeadershipAA_Struct *into) const {
|
||||
|
||||
void Client::EnteringMessages(Client* client)
|
||||
{
|
||||
std::string rules;
|
||||
if (database.GetVariable("Rules", rules)) {
|
||||
uint8 flag = database.GetAgreementFlag(client->AccountID());
|
||||
std::string rules = RuleS(World, Rules);
|
||||
|
||||
if (!rules.empty() || database.GetVariable("Rules", rules)) {
|
||||
const uint8 flag = database.GetAgreementFlag(client->AccountID());
|
||||
if (!flag) {
|
||||
auto rules_link = Saylink::Silent(
|
||||
"#serverrules",
|
||||
"rules"
|
||||
);
|
||||
const std::string& rules_link = Saylink::Silent("#serverrules", "rules");
|
||||
|
||||
client->Message(
|
||||
Chat::White,
|
||||
@@ -3815,9 +3827,9 @@ void Client::EnteringMessages(Client* client)
|
||||
|
||||
void Client::SendRules()
|
||||
{
|
||||
std::string rules;
|
||||
std::string rules = RuleS(World, Rules);
|
||||
|
||||
if (!database.GetVariable("Rules", rules)) {
|
||||
if (rules.empty() && !database.GetVariable("Rules", rules)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4449,7 +4461,7 @@ bool Client::GroupFollow(Client* inviter) {
|
||||
}
|
||||
|
||||
//now we have a group id, can set inviter's id
|
||||
database.SetGroupID(inviter->GetName(), group->GetID(), inviter->CharacterID(), false);
|
||||
group->AddToGroup(inviter);
|
||||
database.SetGroupLeaderName(group->GetID(), inviter->GetName());
|
||||
group->UpdateGroupAAs();
|
||||
|
||||
@@ -6620,13 +6632,72 @@ void Client::SendAltCurrencies() {
|
||||
|
||||
void Client::SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount)
|
||||
{
|
||||
if (!zone->DoesAlternateCurrencyExist(currency_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32 current_amount = alternate_currency[currency_id];
|
||||
|
||||
const bool is_gain = new_amount > current_amount;
|
||||
|
||||
const uint32 change_amount = is_gain ? (new_amount - current_amount) : (current_amount - new_amount);
|
||||
|
||||
if (!change_amount) {
|
||||
return;
|
||||
}
|
||||
|
||||
alternate_currency[currency_id] = new_amount;
|
||||
database.UpdateAltCurrencyValue(CharacterID(), currency_id, new_amount);
|
||||
SendAlternateCurrencyValue(currency_id);
|
||||
|
||||
QuestEventID event_id = is_gain ? EVENT_ALT_CURRENCY_GAIN : EVENT_ALT_CURRENCY_LOSS;
|
||||
if (parse->PlayerHasQuestSub(event_id)) {
|
||||
const std::string &export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
currency_id,
|
||||
change_amount,
|
||||
new_amount
|
||||
);
|
||||
|
||||
parse->EventPlayer(event_id, this, export_string, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount)
|
||||
{
|
||||
if (!amount || !zone->DoesAlternateCurrencyExist(currency_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32 current_amount = alternate_currency[currency_id];
|
||||
if (current_amount < amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32 new_amount = (current_amount - amount);
|
||||
|
||||
alternate_currency[currency_id] = new_amount;
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_ALT_CURRENCY_LOSS)) {
|
||||
const std::string &export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
currency_id,
|
||||
amount,
|
||||
new_amount
|
||||
);
|
||||
|
||||
parse->EventPlayer(EVENT_ALT_CURRENCY_LOSS, this, export_string, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Client::AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted)
|
||||
{
|
||||
if (!zone->DoesAlternateCurrencyExist(currency_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Added via Quest, rest of the logging methods may be done inline due to information available in that area of the code */
|
||||
if (is_scripted) {
|
||||
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
|
||||
@@ -6665,7 +6736,6 @@ int Client::AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_sc
|
||||
SendAlternateCurrencyValue(currency_id);
|
||||
|
||||
QuestEventID event_id = amount > 0 ? EVENT_ALT_CURRENCY_GAIN : EVENT_ALT_CURRENCY_LOSS;
|
||||
|
||||
if (parse->PlayerHasQuestSub(event_id)) {
|
||||
const std::string &export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
@@ -6706,6 +6776,10 @@ void Client::SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null)
|
||||
|
||||
uint32 Client::GetAlternateCurrencyValue(uint32 currency_id) const
|
||||
{
|
||||
if (!zone->DoesAlternateCurrencyExist(currency_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto iter = alternate_currency.find(currency_id);
|
||||
|
||||
return iter == alternate_currency.end() ? 0 : (*iter).second;
|
||||
@@ -6775,7 +6849,7 @@ void Client::UpdateClientXTarget(Client *c)
|
||||
// IT IS NOT SAFE TO CALL THIS IF IT'S NOT INITIAL AGGRO
|
||||
void Client::AddAutoXTarget(Mob *m, bool send)
|
||||
{
|
||||
if (m->IsBot() || (m->IsPet() && m->IsPetOwnerBot())) {
|
||||
if (m->IsBot() || ((m->IsPet() || m->IsTempPet()) && m->IsPetOwnerBot())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9171,6 +9245,7 @@ void Client::ShowDevToolsMenu()
|
||||
menu_reload_six += " | " + Saylink::Silent("#reload quest", "Quests");
|
||||
|
||||
menu_reload_seven += Saylink::Silent("#reload rules", "Rules");
|
||||
menu_reload_seven += " | " + Saylink::Silent("#reload skill_caps", "Skill Caps");
|
||||
menu_reload_seven += " | " + Saylink::Silent("#reload static", "Static Zone Data");
|
||||
menu_reload_seven += " | " + Saylink::Silent("#reload tasks", "Tasks");
|
||||
|
||||
@@ -11298,6 +11373,16 @@ void Client::SendReloadCommandMessages() {
|
||||
).c_str()
|
||||
);
|
||||
|
||||
auto skill_caps_link = Saylink::Silent("#reload skill_caps");
|
||||
|
||||
Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Usage: {} - Reloads Skill Caps globally",
|
||||
skill_caps_link
|
||||
).c_str()
|
||||
);
|
||||
|
||||
auto static_link = Saylink::Silent("#reload static");
|
||||
|
||||
Message(
|
||||
@@ -11473,6 +11558,39 @@ void Client::SetLockSavePosition(bool lock_save_position)
|
||||
Client::m_lock_save_position = lock_save_position;
|
||||
}
|
||||
|
||||
void Client::SetAAPoints(uint32 points)
|
||||
{
|
||||
const uint32 current_points = m_pp.aapoints;
|
||||
|
||||
m_pp.aapoints = points;
|
||||
|
||||
QuestEventID event_id = points > current_points ? EVENT_AA_GAIN : EVENT_AA_LOSS;
|
||||
const uint32 change = event_id == EVENT_AA_GAIN ? points - current_points : current_points - points;
|
||||
|
||||
if (parse->PlayerHasQuestSub(event_id)) {
|
||||
parse->EventPlayer(event_id, this, std::to_string(change), 0);
|
||||
}
|
||||
|
||||
SendAlternateAdvancementStats();
|
||||
}
|
||||
|
||||
bool Client::RemoveAAPoints(uint32 points)
|
||||
{
|
||||
if (m_pp.aapoints < points) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pp.aapoints -= points;
|
||||
|
||||
if (parse->PlayerHasQuestSub(EVENT_AA_LOSS)) {
|
||||
parse->EventPlayer(EVENT_AA_LOSS, this, std::to_string(points), 0);
|
||||
}
|
||||
|
||||
SendAlternateAdvancementStats();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::AddAAPoints(uint32 points)
|
||||
{
|
||||
m_pp.aapoints += points;
|
||||
@@ -11530,6 +11648,14 @@ void Client::RegisterBug(BugReport_Struct* r) {
|
||||
b.bug_report = r->bug_report;
|
||||
b.system_info = r->system_info;
|
||||
|
||||
#ifdef LUA_EQEMU
|
||||
bool ignore_default = false;
|
||||
LuaParser::Instance()->RegisterBug(this, b, ignore_default);
|
||||
if (ignore_default) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto n = BugReportsRepository::InsertOne(database, b);
|
||||
if (!n.id) {
|
||||
Message(Chat::White, "Failed to created your bug report."); // Client sends success message
|
||||
@@ -11679,7 +11805,7 @@ void Client::MaxSkills()
|
||||
auto current_skill_value = (
|
||||
EQ::skills::IsSpecializedSkill(s.first) ?
|
||||
MAX_SPECIALIZED_SKILL :
|
||||
content_db.GetSkillCap(GetClass(), s.first, GetLevel())
|
||||
skill_caps.GetSkillCap(GetClass(), s.first, GetLevel()).cap
|
||||
);
|
||||
|
||||
if (GetSkill(s.first) < current_skill_value) {
|
||||
@@ -12225,3 +12351,34 @@ int Client::GetEXPPercentage()
|
||||
|
||||
return static_cast<int>(std::round(scaled * 100.0 / 330.0)); // unscaled pct
|
||||
}
|
||||
|
||||
std::vector<Mob*> Client::GetRaidOrGroupOrSelf(bool clients_only)
|
||||
{
|
||||
std::vector<Mob*> v;
|
||||
|
||||
if (IsRaidGrouped()) {
|
||||
Raid* r = GetRaid();
|
||||
|
||||
if (r) {
|
||||
for (const auto& m : r->members) {
|
||||
if (m.member && (!m.is_bot || !clients_only)) {
|
||||
v.emplace_back(m.member);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (IsGrouped()) {
|
||||
Group* g = GetGroup();
|
||||
|
||||
if (g) {
|
||||
for (const auto& m : g->members) {
|
||||
if (m && (m->IsClient() || !clients_only)) {
|
||||
v.emplace_back(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v.emplace_back(this);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
+9
-4
@@ -272,6 +272,8 @@ public:
|
||||
int GetQuiverHaste(int delay);
|
||||
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
|
||||
|
||||
std::vector<Mob*> GetRaidOrGroupOrSelf(bool clients_only = false);
|
||||
|
||||
void AI_Init();
|
||||
void AI_Start(uint32 iMoveDelay = 0);
|
||||
void AI_Stop();
|
||||
@@ -348,6 +350,7 @@ public:
|
||||
int GetRecipeMadeCount(uint32 recipe_id);
|
||||
bool HasRecipeLearned(uint32 recipe_id);
|
||||
bool CanIncreaseTradeskill(EQ::skills::SkillType tradeskill);
|
||||
void ScribeRecipes(uint32_t item_id) const;
|
||||
|
||||
bool GetRevoked() const { return revoked; }
|
||||
void SetRevoked(bool rev) { revoked = rev; }
|
||||
@@ -812,9 +815,9 @@ public:
|
||||
void SetHoTT(uint32 mobid);
|
||||
void ShowSkillsWindow();
|
||||
|
||||
uint16 MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const;
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
|
||||
uint8 SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_);
|
||||
uint16 MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const;
|
||||
inline uint16 MaxSkill(EQ::skills::SkillType skill_id) const { return MaxSkill(skill_id, GetClass(), GetLevel()); }
|
||||
uint8 SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id);
|
||||
void MaxSkills();
|
||||
|
||||
void SendTradeskillSearchResults(const std::string &query, unsigned long objtype, unsigned long someid);
|
||||
@@ -933,8 +936,9 @@ public:
|
||||
void ResetAlternateAdvancementTimers();
|
||||
void ResetOnDeathAlternateAdvancement();
|
||||
|
||||
void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAlternateAdvancementStats(); }
|
||||
void SetAAPoints(uint32 points);
|
||||
void AddAAPoints(uint32 points);
|
||||
bool RemoveAAPoints(uint32 points);
|
||||
int GetAAPoints() { return m_pp.aapoints; }
|
||||
int GetSpentAA() { return m_pp.aapoints_spent; }
|
||||
uint32 GetRequiredAAExperience();
|
||||
@@ -1539,6 +1543,7 @@ public:
|
||||
void SendAltCurrencies();
|
||||
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
|
||||
int AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted = false);
|
||||
bool RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount);
|
||||
void SendAlternateCurrencyValues();
|
||||
void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true);
|
||||
uint32 GetAlternateCurrencyValue(uint32 currency_id) const;
|
||||
|
||||
+86
-93
@@ -322,11 +322,12 @@ int64 Client::CalcMaxHP()
|
||||
//but the actual effect sent on live causes the client
|
||||
//to apply it to (basehp + itemhp).. I will oblige to the client's whims over
|
||||
//the aa description
|
||||
nd += aabonuses.MaxHP; //Natural Durability, Physical Enhancement, Planar Durability
|
||||
|
||||
nd += aabonuses.MaxHP + spellbonuses.MaxHPChange + itembonuses.MaxHPChange; //Natural Durability, Physical Enhancement, Planar Durability (MaxHP and MaxHPChange are SPA214)
|
||||
max_hp = (float)max_hp * (float)nd / (float)10000; //this is to fix the HP-above-495k issue
|
||||
max_hp += spellbonuses.HP + aabonuses.HP;
|
||||
|
||||
max_hp += GroupLeadershipAAHealthEnhancement();
|
||||
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
|
||||
if (current_hp > max_hp) {
|
||||
current_hp = max_hp;
|
||||
}
|
||||
@@ -523,28 +524,26 @@ int32 Client::GetRawItemAC()
|
||||
|
||||
int64 Client::CalcMaxMana()
|
||||
{
|
||||
switch (GetCasterClass()) {
|
||||
case 'I':
|
||||
case 'W': {
|
||||
max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
|
||||
break;
|
||||
}
|
||||
case 'N': {
|
||||
max_mana = 0;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LogSpells("Invalid Class [{}] in CalcMaxMana", GetCasterClass());
|
||||
max_mana = 0;
|
||||
break;
|
||||
}
|
||||
if (IsIntelligenceCasterClass() || IsWisdomCasterClass()) {
|
||||
max_mana = (
|
||||
CalcBaseMana() +
|
||||
itembonuses.Mana +
|
||||
spellbonuses.Mana +
|
||||
aabonuses.Mana +
|
||||
GroupLeadershipAAManaEnhancement()
|
||||
);
|
||||
} else {
|
||||
max_mana = 0;
|
||||
}
|
||||
|
||||
if (max_mana < 0) {
|
||||
max_mana = 0;
|
||||
}
|
||||
|
||||
if (current_mana > max_mana) {
|
||||
current_mana = max_mana;
|
||||
}
|
||||
|
||||
int mana_perc_cap = spellbonuses.ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP];
|
||||
if (mana_perc_cap) {
|
||||
int curMana_cap = (max_mana * mana_perc_cap) / 100;
|
||||
@@ -552,96 +551,90 @@ int64 Client::CalcMaxMana()
|
||||
current_mana = curMana_cap;
|
||||
}
|
||||
}
|
||||
|
||||
LogSpells("for [{}] returning [{}]", GetName(), max_mana);
|
||||
return max_mana;
|
||||
}
|
||||
|
||||
int64 Client::CalcBaseMana()
|
||||
{
|
||||
int ConvertedWisInt = 0;
|
||||
int MindLesserFactor, MindFactor;
|
||||
int WisInt = 0;
|
||||
int64 base_mana = 0;
|
||||
int wisint_mana = 0;
|
||||
int64 max_m = 0;
|
||||
switch (GetCasterClass()) {
|
||||
case 'I':
|
||||
WisInt = GetINT();
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
ConvertedWisInt = WisInt;
|
||||
int over200 = WisInt;
|
||||
if (WisInt > 100) {
|
||||
if (WisInt > 200) {
|
||||
over200 = (WisInt - 200) / -2 + WisInt;
|
||||
}
|
||||
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
|
||||
}
|
||||
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data.level == GetLevel()) {
|
||||
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
|
||||
int ConvertedWisInt = 0;
|
||||
int MindLesserFactor, MindFactor;
|
||||
int WisInt = 0;
|
||||
int64 base_mana = 0;
|
||||
int wisint_mana = 0;
|
||||
int64 max_m = 0;
|
||||
|
||||
if (IsIntelligenceCasterClass()) {
|
||||
WisInt = GetINT();
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
ConvertedWisInt = WisInt;
|
||||
|
||||
int over200 = WisInt;
|
||||
if (WisInt > 100) {
|
||||
if (WisInt > 200) {
|
||||
over200 = (WisInt - 200) / -2 + WisInt;
|
||||
}
|
||||
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
|
||||
}
|
||||
else {
|
||||
if ((( WisInt - 199 ) / 2) > 0) {
|
||||
MindLesserFactor = ( WisInt - 199 ) / 2;
|
||||
}
|
||||
else {
|
||||
MindLesserFactor = 0;
|
||||
}
|
||||
MindFactor = WisInt - MindLesserFactor;
|
||||
if (WisInt > 100) {
|
||||
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
}
|
||||
else {
|
||||
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
}
|
||||
|
||||
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data.level == GetLevel()) {
|
||||
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
WisInt = GetWIS();
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
ConvertedWisInt = WisInt;
|
||||
int over200 = WisInt;
|
||||
if (WisInt > 100) {
|
||||
if (WisInt > 200) {
|
||||
over200 = (WisInt - 200) / -2 + WisInt;
|
||||
}
|
||||
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
|
||||
}
|
||||
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data.level == GetLevel()) {
|
||||
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
|
||||
}
|
||||
} else {
|
||||
if (((WisInt - 199) / 2) > 0) {
|
||||
MindLesserFactor = (WisInt - 199) / 2;
|
||||
} else {
|
||||
MindLesserFactor = 0;
|
||||
}
|
||||
else {
|
||||
if ((( WisInt - 199 ) / 2) > 0) {
|
||||
MindLesserFactor = ( WisInt - 199 ) / 2;
|
||||
}
|
||||
else {
|
||||
MindLesserFactor = 0;
|
||||
}
|
||||
MindFactor = WisInt - MindLesserFactor;
|
||||
if (WisInt > 100) {
|
||||
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
}
|
||||
else {
|
||||
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
}
|
||||
|
||||
MindFactor = WisInt - MindLesserFactor;
|
||||
|
||||
if (WisInt > 100) {
|
||||
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
} else {
|
||||
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
}
|
||||
break;
|
||||
case 'N': {
|
||||
max_m = 0;
|
||||
break;
|
||||
}
|
||||
} else if (IsWisdomCasterClass()) {
|
||||
WisInt = GetWIS();
|
||||
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
|
||||
ConvertedWisInt = WisInt;
|
||||
|
||||
int over200 = WisInt;
|
||||
if (WisInt > 100) {
|
||||
if (WisInt > 200) {
|
||||
over200 = (WisInt - 200) / -2 + WisInt;
|
||||
}
|
||||
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
|
||||
}
|
||||
default: {
|
||||
LogDebug("Invalid Class [{}] in CalcMaxMana", GetCasterClass());
|
||||
max_m = 0;
|
||||
break;
|
||||
|
||||
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
|
||||
if (base_data.level == GetLevel()) {
|
||||
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
|
||||
}
|
||||
} else {
|
||||
if (((WisInt - 199) / 2) > 0) {
|
||||
MindLesserFactor = (WisInt - 199) / 2;
|
||||
} else {
|
||||
MindLesserFactor = 0;
|
||||
}
|
||||
|
||||
MindFactor = WisInt - MindLesserFactor;
|
||||
|
||||
if (WisInt > 100) {
|
||||
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
|
||||
} else {
|
||||
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
max_m = 0;
|
||||
}
|
||||
#if EQDEBUG >= 11
|
||||
LogDebug("Client::CalcBaseMana() called for [{}] - returning [{}]", GetName(), max_m);
|
||||
#endif
|
||||
|
||||
return max_m;
|
||||
}
|
||||
|
||||
|
||||
+22
-9
@@ -1530,8 +1530,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
}
|
||||
} //else, somebody from our group is already here...
|
||||
|
||||
if (!group)
|
||||
database.SetGroupID(GetName(), 0, CharacterID(), false); //cannot re-establish group, kill it
|
||||
if (!group) { //cannot re-establish group, kill it
|
||||
Group::RemoveFromGroup(this);
|
||||
}
|
||||
|
||||
}
|
||||
else { //no group id
|
||||
@@ -4168,10 +4169,11 @@ void Client::Handle_OP_BookButton(const EQApplicationPacket* app)
|
||||
BookButton_Struct* book = reinterpret_cast<BookButton_Struct*>(app->pBuffer);
|
||||
|
||||
const EQ::ItemInstance* const inst = GetInv().GetItem(book->invslot);
|
||||
if (inst && inst->GetItem()->Book)
|
||||
if (inst && inst->GetItem())
|
||||
{
|
||||
// todo: if scribe book learn recipes and delete book from inventory
|
||||
// todo: if cast book use its spell on target and delete book from inventory (unless reusable?)
|
||||
// todo: cast spell button (unknown if anything on live uses this)
|
||||
ScribeRecipes(inst->GetItem()->ID);
|
||||
DeleteItemInInventory(book->invslot, 1, true);
|
||||
}
|
||||
|
||||
EQApplicationPacket outapp(OP_FinishWindow, 0);
|
||||
@@ -5595,9 +5597,20 @@ void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
// Prevent the client from creating more than they have.
|
||||
const uint32 amount = EQ::ClampUpper(quantity, current_quantity);
|
||||
uint32 amount = EQ::ClampUpper(quantity, current_quantity);
|
||||
const uint32 item_id = is_radiant ? RuleI(Zone, RadiantCrystalItemID) : RuleI(Zone, EbonCrystalItemID);
|
||||
|
||||
const auto item = database.GetItem(item_id);
|
||||
// Prevent pulling more than max stack size or 1,000 (if stackable), whichever is lesser
|
||||
const uint32 max_reclaim_amount = EQ::Clamp(
|
||||
item && item->Stackable ? item->StackSize : ItemStackSizeConstraint::Minimum,
|
||||
ItemStackSizeConstraint::Minimum,
|
||||
ItemStackSizeConstraint::Maximum
|
||||
);
|
||||
if (amount > max_reclaim_amount) {
|
||||
amount = max_reclaim_amount;
|
||||
}
|
||||
|
||||
const bool success = SummonItem(item_id, amount);
|
||||
if (!success) {
|
||||
return;
|
||||
@@ -6862,7 +6875,7 @@ void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
|
||||
Client *c = entity_list.GetClientByName(gmn->oldname);
|
||||
LogInfo("GM([{}]) changeing players name. Old:[{}] New:[{}]", GetName(), gmn->oldname, gmn->newname);
|
||||
|
||||
const bool used_name = database.CheckUsedName(gmn->newname);
|
||||
const bool used_name = database.IsNameUsed(gmn->newname);
|
||||
if (!c) {
|
||||
Message(Chat::Red, fmt::format("{} not found for name change. Operation failed!", gmn->oldname).c_str());
|
||||
return;
|
||||
@@ -6873,7 +6886,7 @@ void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!used_name) {
|
||||
if (used_name) {
|
||||
Message(Chat::Red, fmt::format("{} is already in use. Operation failed!", gmn->newname).c_str());
|
||||
return;
|
||||
}
|
||||
@@ -7177,7 +7190,7 @@ void Client::Handle_OP_GroupCancelInvite(const EQApplicationPacket *app)
|
||||
|
||||
if (!GetMerc())
|
||||
{
|
||||
database.SetGroupID(GetName(), 0, CharacterID(), false);
|
||||
Group::RemoveFromGroup(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1064,9 +1064,9 @@ void Client::OPRezzAnswer(uint32 Action, uint32 SpellID, uint16 ZoneID, uint16 I
|
||||
);
|
||||
SpellOnTarget(resurrection_sickness_spell_id, this);
|
||||
} else if (SpellID == SPELL_DIVINE_REZ) {
|
||||
SetHP(GetMaxHP());
|
||||
SetMana(GetMaxMana());
|
||||
SetEndurance(GetMaxEndurance());
|
||||
RestoreHealth();
|
||||
RestoreMana();
|
||||
RestoreEndurance();
|
||||
} else {
|
||||
SetHP(GetMaxHP() / 20);
|
||||
SetMana(GetMaxMana() / 20);
|
||||
@@ -2177,9 +2177,9 @@ void Client::HandleRespawnFromHover(uint32 Option)
|
||||
FastQueuePacket(&outapp);
|
||||
|
||||
CalcBonuses();
|
||||
SetHP(GetMaxHP());
|
||||
SetMana(GetMaxMana());
|
||||
SetEndurance(GetMaxEndurance());
|
||||
RestoreHealth();
|
||||
RestoreMana();
|
||||
RestoreEndurance();
|
||||
|
||||
m_Position.x = chosen->x;
|
||||
m_Position.y = chosen->y;
|
||||
|
||||
@@ -208,6 +208,7 @@ int command_init(void)
|
||||
command_add("scribespells", "[Max level] [Min level] - Scribe all spells for you or your player target that are usable by them, up to level specified. (may freeze client for a few seconds)", AccountStatus::GMLeadAdmin, command_scribespells) ||
|
||||
command_add("sendzonespawns", "Refresh spawn list for all clients in zone", AccountStatus::GMLeadAdmin, command_sendzonespawns) ||
|
||||
command_add("sensetrap", "Analog for ldon sense trap for the newer clients since we still don't have it working.", AccountStatus::Player, command_sensetrap) ||
|
||||
command_add("serverrules", "Show server rules", AccountStatus::Player, command_serverrules) ||
|
||||
command_add("set", "Set command used to set various things", AccountStatus::Guide, command_set) ||
|
||||
command_add("show", "Show command used to show various things", AccountStatus::Guide, command_show) ||
|
||||
command_add("shutdown", "Shut this zone process down", AccountStatus::GMLeadAdmin, command_shutdown) ||
|
||||
@@ -897,6 +898,7 @@ void command_bot(Client *c, const Seperator *sep)
|
||||
#include "gm_commands/scribespells.cpp"
|
||||
#include "gm_commands/sendzonespawns.cpp"
|
||||
#include "gm_commands/sensetrap.cpp"
|
||||
#include "gm_commands/serverrules.cpp"
|
||||
#include "gm_commands/set.cpp"
|
||||
#include "gm_commands/show.cpp"
|
||||
#include "gm_commands/shutdown.cpp"
|
||||
|
||||
+14
-7
@@ -19,9 +19,11 @@
|
||||
#define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from
|
||||
#define SEE_POSITION 0.5f //ratio of GetSize() where NPCs try to see for LOS
|
||||
|
||||
#define ARCHETYPE_HYBRID 1
|
||||
#define ARCHETYPE_CASTER 2
|
||||
#define ARCHETYPE_MELEE 3
|
||||
namespace Archetype {
|
||||
constexpr uint8 Hybrid = 1;
|
||||
constexpr uint8 Caster = 2;
|
||||
constexpr uint8 Melee = 3;
|
||||
};
|
||||
|
||||
#define CON_GREEN 2
|
||||
#define CON_LIGHTBLUE 18
|
||||
@@ -285,7 +287,7 @@ struct StatBonuses {
|
||||
int32 AC;
|
||||
int64 HP;
|
||||
int64 HPRegen;
|
||||
int64 MaxHP;
|
||||
int64 MaxHP; //same bonus as MaxHPChange when applied to spells and item bonuses
|
||||
int64 ManaRegen;
|
||||
int64 EnduranceRegen;
|
||||
int64 Mana;
|
||||
@@ -411,7 +413,7 @@ struct StatBonuses {
|
||||
int32 MeleeLifetap; //i
|
||||
int32 Vampirism; //i
|
||||
int32 HealRate; // Spell effect that influences effectiveness of heals
|
||||
int32 MaxHPChange; // Spell Effect
|
||||
int32 MaxHPChange; // percent change in hit points (aabonuses use variable MaxHP)
|
||||
int16 SkillDmgTaken[EQ::skills::HIGHEST_SKILL + 2]; // All Skills + -1
|
||||
int32 HealAmt; // Item Effect
|
||||
int32 SpellDmg; // Item Effect
|
||||
@@ -443,7 +445,8 @@ struct StatBonuses {
|
||||
int32 SongRange; // increases range of beneficial bard songs
|
||||
uint32 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
||||
int32 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||
int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot
|
||||
int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot, limits do not apply
|
||||
int32 FocusEffectsWornWithLimits[HIGHEST_FOCUS + 1];// Optional to allow focus effects to be applied additively from worn slot, limits apply
|
||||
bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses)
|
||||
int32 SkillDamageAmount2[EQ::skills::HIGHEST_SKILL + 2]; // Adds skill specific damage
|
||||
uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit
|
||||
@@ -509,6 +512,7 @@ struct StatBonuses {
|
||||
uint8 invisibility; // invisibility level
|
||||
uint8 invisibility_verse_undead; // IVU level
|
||||
uint8 invisibility_verse_animal; // IVA level
|
||||
int32 ShieldTargetSpa[2]; // [0] base = % mitigation amount, [1] buff slot
|
||||
|
||||
// AAs
|
||||
int32 TrapCircumvention; // reduce chance to trigger a trap.
|
||||
@@ -654,6 +658,8 @@ namespace SBIndex {
|
||||
constexpr uint16 COMBAT_PROC_SPELL_ID = 1; // SPA
|
||||
constexpr uint16 COMBAT_PROC_RATE_MOD = 2; // SPA
|
||||
constexpr uint16 COMBAT_PROC_REUSE_TIMER = 3; // SPA
|
||||
constexpr uint16 SHIELD_TARGET_MITIGATION_PERCENT = 0; // SPA 463
|
||||
constexpr uint16 SHIELD_TARGET_BUFFSLOT = 1; // SPA 463
|
||||
};
|
||||
|
||||
|
||||
@@ -826,7 +832,8 @@ struct ExtraAttackOptions {
|
||||
armor_pen_percent(0.0f), armor_pen_flat(0),
|
||||
crit_percent(1.0f), crit_flat(0.0f),
|
||||
hate_percent(1.0f), hate_flat(0), hit_chance(0),
|
||||
melee_damage_bonus_flat(0), skilldmgtaken_bonus_flat(0)
|
||||
melee_damage_bonus_flat(0), skilldmgtaken_bonus_flat(0),
|
||||
range_percent(0)
|
||||
{ }
|
||||
|
||||
float damage_percent;
|
||||
|
||||
@@ -334,7 +334,7 @@ void DialogueWindow::Render(Client *c, std::string markdown)
|
||||
if (responses.size() > 1) {
|
||||
for (auto &r: responses) {
|
||||
bracket_responses.emplace_back(
|
||||
fmt::format("[{}]", Saylink::Create(r, false))
|
||||
fmt::format("[{}]", Saylink::Create(r))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ void perl_register_doors();
|
||||
void perl_register_expedition();
|
||||
void perl_register_expedition_lock_messages();
|
||||
void perl_register_bot();
|
||||
void perl_register_buff();
|
||||
#endif // EMBPERL_XS_CLASSES
|
||||
#endif // EMBPERL_XS
|
||||
|
||||
@@ -200,6 +201,8 @@ const char* QuestEventSubroutines[_LargestEventID] = {
|
||||
"EVENT_ENTITY_VARIABLE_DELETE",
|
||||
"EVENT_ENTITY_VARIABLE_SET",
|
||||
"EVENT_ENTITY_VARIABLE_UPDATE",
|
||||
"EVENT_AA_LOSS",
|
||||
"EVENT_SPELL_BLOCKED",
|
||||
|
||||
// Add new events before these or Lua crashes
|
||||
"EVENT_SPELL_EFFECT_BOT",
|
||||
@@ -1174,6 +1177,7 @@ void PerlembParser::MapFunctions()
|
||||
perl_register_expedition();
|
||||
perl_register_expedition_lock_messages();
|
||||
perl_register_bot();
|
||||
perl_register_buff();
|
||||
#endif // EMBPERL_XS_CLASSES
|
||||
}
|
||||
|
||||
@@ -1934,6 +1938,25 @@ void PerlembParser::ExportEventVariables(
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_SPELL_BLOCKED: {
|
||||
Seperator sep(data);
|
||||
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
|
||||
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[1]);
|
||||
|
||||
ExportVar(package_name.c_str(), "blocking_spell_id", blocking_spell_id);
|
||||
ExportVar(package_name.c_str(), "cast_spell_id", cast_spell_id);
|
||||
|
||||
if (IsValidSpell(blocking_spell_id)) {
|
||||
ExportVar(package_name.c_str(), "blocking_spell", "Spell", (void*) &spells[blocking_spell_id]);
|
||||
}
|
||||
|
||||
if (IsValidSpell(cast_spell_id)) {
|
||||
ExportVar(package_name.c_str(), "cast_spell", "Spell", (void*) &spells[cast_spell_id]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//tradeskill events
|
||||
case EVENT_COMBINE_SUCCESS:
|
||||
case EVENT_COMBINE_FAILURE: {
|
||||
@@ -2273,6 +2296,11 @@ void PerlembParser::ExportEventVariables(
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_AA_LOSS: {
|
||||
ExportVar(package_name.c_str(), "aa_lost", data);
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_AA_EXP_GAIN: {
|
||||
ExportVar(package_name.c_str(), "aa_exp_gained", data);
|
||||
break;
|
||||
|
||||
+45
-18
@@ -380,12 +380,12 @@ void Perl__settimer(std::string timer_name, uint32 seconds)
|
||||
|
||||
void Perl__settimer(std::string timer_name, uint32 seconds, Mob* m)
|
||||
{
|
||||
quest_manager.settimer(timer_name, seconds);
|
||||
quest_manager.settimer(timer_name, seconds, m);
|
||||
}
|
||||
|
||||
void Perl__settimer(std::string timer_name, uint32 seconds, EQ::ItemInstance* inst)
|
||||
{
|
||||
quest_manager.settimer(timer_name, seconds);
|
||||
quest_manager.settimerMS(timer_name, seconds * 1000, inst);
|
||||
}
|
||||
|
||||
void Perl__settimerMS(std::string timer_name, uint32 milliseconds)
|
||||
@@ -1579,9 +1579,7 @@ std::string Perl__GetCharactersInInstance(uint16 instance_id)
|
||||
char_id_string = fmt::format("{} player(s) in instance: ", character_ids.size());
|
||||
auto iter = character_ids.begin();
|
||||
while (iter != character_ids.end()) {
|
||||
char char_name[64];
|
||||
database.GetCharName(*iter, char_name);
|
||||
char_id_string += char_name;
|
||||
char_id_string += database.GetCharName(*iter);
|
||||
char_id_string += "(";
|
||||
char_id_string += itoa(*iter);
|
||||
char_id_string += ")";
|
||||
@@ -1654,20 +1652,19 @@ void Perl__FlagInstanceByRaidLeader(uint32 zone, uint16 version)
|
||||
quest_manager.FlagInstanceByRaidLeader(zone, version);
|
||||
}
|
||||
|
||||
std::string Perl__saylink(const char* text)
|
||||
std::string Perl__saylink(std::string text)
|
||||
{
|
||||
// const cast is safe since, target api doesn't modify it
|
||||
return quest_manager.saylink(const_cast<char*>(text), false, text);
|
||||
return Saylink::Create(text);
|
||||
}
|
||||
|
||||
std::string Perl__saylink(const char* text, bool silent)
|
||||
std::string Perl__saylink(std::string text, bool silent)
|
||||
{
|
||||
return quest_manager.saylink(const_cast<char*>(text), silent, text);
|
||||
return Saylink::Create(text, silent);
|
||||
}
|
||||
|
||||
std::string Perl__saylink(const char* text, bool silent, const char* link_name)
|
||||
std::string Perl__saylink(std::string text, bool silent, std::string link_name)
|
||||
{
|
||||
return quest_manager.saylink(const_cast<char*>(text), silent, link_name);
|
||||
return Saylink::Create(text, silent, link_name);
|
||||
}
|
||||
|
||||
std::string Perl__getcharnamebyid(uint32 char_id)
|
||||
@@ -5833,6 +5830,31 @@ uint16 Perl__GetBotRaceByID(uint32 bot_id)
|
||||
return database.botdb.GetBotRaceByID(bot_id);
|
||||
}
|
||||
|
||||
std::string Perl__silent_saylink(std::string text)
|
||||
{
|
||||
return Saylink::Silent(text);
|
||||
}
|
||||
|
||||
std::string Perl__silent_saylink(std::string text, std::string link_name)
|
||||
{
|
||||
return Saylink::Silent(text, link_name);
|
||||
}
|
||||
|
||||
uint16 Perl__get_class_bitmask(uint8 class_id)
|
||||
{
|
||||
return GetPlayerClassBit(class_id);
|
||||
}
|
||||
|
||||
uint32 Perl__get_deity_bitmask(uint16 deity_id)
|
||||
{
|
||||
return static_cast<uint32>(EQ::deity::GetDeityBitmask(static_cast<EQ::deity::DeityType>(deity_id)));
|
||||
}
|
||||
|
||||
uint16 Perl__get_race_bitmask(uint16 race_id)
|
||||
{
|
||||
return GetPlayerRaceBit(race_id);
|
||||
}
|
||||
|
||||
void perl_register_quest()
|
||||
{
|
||||
perl::interpreter perl(PERL_GET_THX);
|
||||
@@ -6479,9 +6501,11 @@ void perl_register_quest()
|
||||
package.add("getconsiderlevelname", &Perl__getconsiderlevelname);
|
||||
package.add("gethexcolorcode", &Perl__gethexcolorcode);
|
||||
package.add("getcurrencyid", &Perl__getcurrencyid);
|
||||
package.add("get_class_bitmask", &Perl__get_class_bitmask);
|
||||
package.add("get_data", &Perl__get_data);
|
||||
package.add("get_data_expires", &Perl__get_data_expires);
|
||||
package.add("get_data_remaining", &Perl__get_data_remaining);
|
||||
package.add("get_deity_bitmask", &Perl__get_deity_bitmask);
|
||||
package.add("get_dz_task_id", &Perl__get_dz_task_id);
|
||||
package.add("getexpmodifierbycharid", (double(*)(uint32, uint32))&Perl__getexpmodifierbycharid);
|
||||
package.add("getexpmodifierbycharid", (double(*)(uint32, uint32, int16))&Perl__getexpmodifierbycharid);
|
||||
@@ -6514,6 +6538,7 @@ void perl_register_quest()
|
||||
package.add("getgroupidbycharid", &Perl__getgroupidbycharid);
|
||||
package.add("getinventoryslotname", &Perl__getinventoryslotname);
|
||||
package.add("getraididbycharid", &Perl__getraididbycharid);
|
||||
package.add("get_race_bitmask", &Perl__get_race_bitmask);
|
||||
package.add("get_recipe_component_item_ids", &Perl__GetRecipeComponentItemIDs);
|
||||
package.add("get_recipe_container_item_ids", &Perl__GetRecipeContainerItemIDs);
|
||||
package.add("get_recipe_fail_item_ids", &Perl__GetRecipeFailItemIDs);
|
||||
@@ -6644,9 +6669,9 @@ void perl_register_quest()
|
||||
package.add("say", (void(*)(const char*, uint8, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, uint8, int, int))&Perl__say);
|
||||
package.add("say", (void(*)(const char*, uint8, int, int, int))&Perl__say);
|
||||
package.add("saylink", (std::string(*)(const char*))&Perl__saylink);
|
||||
package.add("saylink", (std::string(*)(const char*, bool))&Perl__saylink);
|
||||
package.add("saylink", (std::string(*)(const char*, bool, const char*))&Perl__saylink);
|
||||
package.add("saylink", (std::string(*)(std::string))&Perl__saylink);
|
||||
package.add("saylink", (std::string(*)(std::string, bool))&Perl__saylink);
|
||||
package.add("saylink", (std::string(*)(std::string, bool, std::string))&Perl__saylink);
|
||||
package.add("scribespells", (int(*)(int))&Perl__scribespells);
|
||||
package.add("scribespells", (int(*)(int, int))&Perl__scribespells);
|
||||
package.add("secondstotime", &Perl__secondstotime);
|
||||
@@ -6684,9 +6709,9 @@ void perl_register_quest()
|
||||
package.add("settarget", &Perl__settarget);
|
||||
package.add("settime", (void(*)(int, int))&Perl__settime);
|
||||
package.add("settime", (void(*)(int, int, bool))&Perl__settime);
|
||||
package.add("settimer", (void(*)(std::string, uint32))&Perl__settimer),
|
||||
package.add("settimer", (void(*)(std::string, uint32, EQ::ItemInstance*))&Perl__settimer),
|
||||
package.add("settimer", (void(*)(std::string, uint32, Mob*))&Perl__settimer),
|
||||
package.add("settimer", (void(*)(std::string, uint32))&Perl__settimer);
|
||||
package.add("settimer", (void(*)(std::string, uint32, EQ::ItemInstance*))&Perl__settimer);
|
||||
package.add("settimer", (void(*)(std::string, uint32, Mob*))&Perl__settimer);
|
||||
package.add("settimerMS", (void(*)(std::string, uint32))&Perl__settimerMS);
|
||||
package.add("settimerMS", (void(*)(std::string, uint32, EQ::ItemInstance*))&Perl__settimerMS);
|
||||
package.add("settimerMS", (void(*)(std::string, uint32, Mob*))&Perl__settimerMS);
|
||||
@@ -6698,6 +6723,8 @@ void perl_register_quest()
|
||||
package.add("signal", (void(*)(int, int))&Perl__signal);
|
||||
package.add("signalwith", (void(*)(int, int))&Perl__signalwith);
|
||||
package.add("signalwith", (void(*)(int, int, int))&Perl__signalwith);
|
||||
package.add("silent_saylink", (std::string(*)(std::string))&Perl__silent_saylink);
|
||||
package.add("silent_saylink", (std::string(*)(std::string, std::string))&Perl__silent_saylink);
|
||||
package.add("snow", &Perl__snow);
|
||||
package.add("spawn", &Perl__spawn);
|
||||
package.add("spawn2", &Perl__spawn2);
|
||||
|
||||
+8
-1
@@ -2152,7 +2152,7 @@ Group *EntityList::GetGroupByLeaderName(const char *leader)
|
||||
iterator = group_list.begin();
|
||||
|
||||
while (iterator != group_list.end()) {
|
||||
if (!strcmp((*iterator)->GetLeaderName(), leader))
|
||||
if (!strcmp((*iterator)->GetLeaderName().c_str(), leader))
|
||||
return *iterator;
|
||||
++iterator;
|
||||
}
|
||||
@@ -2675,6 +2675,10 @@ void EntityList::RemoveAllMobs()
|
||||
{
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
if (!it->second) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
safe_delete(it->second);
|
||||
free_ids.push(it->first);
|
||||
it = mob_list.erase(it);
|
||||
@@ -2812,6 +2816,9 @@ bool EntityList::RemoveMob(uint16 delete_id)
|
||||
|
||||
auto it = mob_list.find(delete_id);
|
||||
if (it != mob_list.end()) {
|
||||
if (!it->second) {
|
||||
return false;
|
||||
}
|
||||
if (npc_list.count(delete_id)) {
|
||||
entity_list.RemoveNPC(delete_id);
|
||||
}
|
||||
|
||||
@@ -142,6 +142,8 @@ typedef enum {
|
||||
EVENT_ENTITY_VARIABLE_DELETE,
|
||||
EVENT_ENTITY_VARIABLE_SET,
|
||||
EVENT_ENTITY_VARIABLE_UPDATE,
|
||||
EVENT_AA_LOSS,
|
||||
EVENT_SPELL_BLOCKED,
|
||||
|
||||
// Add new events before these or Lua crashes
|
||||
EVENT_SPELL_EFFECT_BOT,
|
||||
|
||||
@@ -125,7 +125,7 @@ bool ExpeditionRequest::CanGroupRequest(Group* group)
|
||||
}
|
||||
|
||||
// Group::GetLeaderName() is broken if group formed across zones, ask database instead
|
||||
m_leader_name = m_leader ? m_leader->GetName() : GetGroupLeaderName(group->GetID()); // group->GetLeaderName();
|
||||
m_leader_name = m_leader ? m_leader->GetName() : group->GetLeaderName();
|
||||
m_leader_id = m_leader ? m_leader->CharacterID() : database.GetCharacterID(m_leader_name);
|
||||
|
||||
std::vector<std::string> member_names;
|
||||
@@ -148,13 +148,6 @@ bool ExpeditionRequest::CanGroupRequest(Group* group)
|
||||
return CanMembersJoin(member_names);
|
||||
}
|
||||
|
||||
std::string ExpeditionRequest::GetGroupLeaderName(uint32_t group_id)
|
||||
{
|
||||
char leader_name_buffer[64] = { 0 };
|
||||
database.GetGroupLeadershipInfo(group_id, leader_name_buffer);
|
||||
return std::string(leader_name_buffer);
|
||||
}
|
||||
|
||||
bool ExpeditionRequest::CanMembersJoin(const std::vector<std::string>& member_names)
|
||||
{
|
||||
if (member_names.empty())
|
||||
|
||||
@@ -54,7 +54,6 @@ private:
|
||||
bool CanRaidRequest(Raid* raid);
|
||||
bool CanGroupRequest(Group* group);
|
||||
bool CheckMembersForConflicts(const std::vector<std::string>& member_names);
|
||||
std::string GetGroupLeaderName(uint32_t group_id);
|
||||
bool IsPlayerCountValidated();
|
||||
bool SaveLeaderLockouts(const std::vector<ExpeditionLockoutTimer>& leader_lockouts);
|
||||
void SendLeaderMemberInExpedition(const std::string& member_name, bool is_solo);
|
||||
|
||||
+32
-37
@@ -44,17 +44,14 @@ extern WorldServer worldserver;
|
||||
|
||||
struct NPCType;
|
||||
|
||||
//max number of items which can be in the foraging table
|
||||
//for a given zone.
|
||||
#define FORAGE_ITEM_LIMIT 50
|
||||
//max number of items which can be in the foraging
|
||||
// and fishing tables for a given zone.
|
||||
constexpr uint8 FORAGE_ITEM_LIMIT = 50;
|
||||
constexpr uint8 FISHING_ITEM_LIMIT = 50;
|
||||
|
||||
uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
|
||||
{
|
||||
uint32 forage_items[FORAGE_ITEM_LIMIT];
|
||||
|
||||
for (uint16 slot_id = 0; slot_id < FORAGE_ITEM_LIMIT; slot_id++) {
|
||||
forage_items[slot_id] = 0;
|
||||
}
|
||||
uint32 forage_items[FORAGE_ITEM_LIMIT] = {};
|
||||
|
||||
const auto& l = ForageRepository::GetWhere(
|
||||
*this,
|
||||
@@ -77,7 +74,7 @@ uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
|
||||
l.size() != 1 ? "s" : ""
|
||||
);
|
||||
|
||||
int forage_chances[FORAGE_ITEM_LIMIT];
|
||||
int forage_chances[FORAGE_ITEM_LIMIT] = {};
|
||||
|
||||
int current_chance = 0;
|
||||
uint32 item_id = 0;
|
||||
@@ -118,13 +115,8 @@ uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
|
||||
|
||||
uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_id, uint8 &npc_chance)
|
||||
{
|
||||
uint32 fishing_items[50];
|
||||
int fishing_chances[50];
|
||||
|
||||
for (uint16 slot_id = 0; slot_id < 50; slot_id++) {
|
||||
fishing_items[slot_id] = 0;
|
||||
fishing_chances[slot_id] = 0;
|
||||
}
|
||||
uint32 fishing_items[FISHING_ITEM_LIMIT] = {};
|
||||
int fishing_chances[FISHING_ITEM_LIMIT] = {};
|
||||
|
||||
const auto& l = FishingRepository::GetWhere(
|
||||
*this,
|
||||
@@ -146,15 +138,15 @@ uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_
|
||||
l.size() != 1 ? "s" : ""
|
||||
);
|
||||
|
||||
uint32 npc_ids[50];
|
||||
uint32 npc_chances[50];
|
||||
uint32 npc_ids[FISHING_ITEM_LIMIT] = {};
|
||||
uint32 npc_chances[FISHING_ITEM_LIMIT] = {};
|
||||
|
||||
int current_chance = 0;
|
||||
uint32 item_id = 0;
|
||||
uint8 count = 0;
|
||||
|
||||
for (const auto &e: l) {
|
||||
if (count >= 50) {
|
||||
if (count >= FISHING_ITEM_LIMIT) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -164,6 +156,8 @@ uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_
|
||||
npc_chances[count] = e.npc_chance;
|
||||
|
||||
current_chance = fishing_chances[count];
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
npc_id = 0;
|
||||
@@ -175,7 +169,7 @@ uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_
|
||||
|
||||
const int roll = zone->random.Int(1, current_chance);
|
||||
|
||||
for (uint16 i = 0; i < count; i++) {
|
||||
for (uint8 i = 0; i < count; i++) {
|
||||
if (roll > fishing_chances[i]) {
|
||||
continue;
|
||||
}
|
||||
@@ -269,32 +263,33 @@ void Client::GoFish(bool guarantee, bool use_bait)
|
||||
fishing_timer.Disable();
|
||||
|
||||
//we're doing this a second time (1st in Client::Handle_OP_Fishing) to make sure that, between when we started fishing & now, we're still able to fish (in case we move, change equip, etc)
|
||||
if (!CanFish()) //if we can't fish here, we don't need to bother with the rest
|
||||
if (!CanFish()) { //if we can't fish here, we don't need to bother with the rest
|
||||
return;
|
||||
}
|
||||
|
||||
//multiple entries yeilds higher probability of dropping...
|
||||
uint32 common_fish_ids[MAX_COMMON_FISH_IDS] = {
|
||||
1038, // Tattered Cloth Sandals
|
||||
1038, // Tattered Cloth Sandals
|
||||
1038, // Tattered Cloth Sandals
|
||||
1038, // Tattered Cloth Sandals
|
||||
1038, // Tattered Cloth Sandals
|
||||
1038, // Tattered Cloth Sandals
|
||||
13019, // Fresh Fish
|
||||
13076, // Fish Scales
|
||||
13076, // Fish Scales
|
||||
7007, // Rusty Dagger
|
||||
7007, // Rusty Dagger
|
||||
7007 // Rusty Dagger
|
||||
|
||||
7007, // Rusty Dagger
|
||||
7007, // Rusty Dagger
|
||||
7007 // Rusty Dagger
|
||||
};
|
||||
|
||||
//success formula is not researched at all
|
||||
|
||||
int fishing_skill = GetSkill(EQ::skills::SkillFishing); //will take into account skill bonuses on pole & bait
|
||||
uint16 fishing_skill = GetSkill(EQ::skills::SkillFishing); //will take into account skill bonuses on pole & bait
|
||||
|
||||
//make sure we still have a fishing pole on:
|
||||
int32 bslot = m_inv.HasItemByUse(EQ::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal);
|
||||
int16 bslot = m_inv.HasItemByUse(EQ::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal);
|
||||
const EQ::ItemInstance* Bait = nullptr;
|
||||
if (bslot != INVALID_INDEX)
|
||||
if (bslot != INVALID_INDEX) {
|
||||
Bait = m_inv.GetItem(bslot);
|
||||
}
|
||||
|
||||
//if the bait isnt equipped, need to add its skill bonus
|
||||
if (bslot >= EQ::invslot::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == EQ::skills::SkillFishing) {
|
||||
@@ -309,8 +304,8 @@ void Client::GoFish(bool guarantee, bool use_bait)
|
||||
if (guarantee || zone->random.Int(0,175) < fishing_skill) {
|
||||
uint32 food_id = 0;
|
||||
|
||||
//25% chance to fish an item.
|
||||
if (zone->random.Int(0, 399) <= fishing_skill ) {
|
||||
//chance to fish a zone item.
|
||||
if (zone->random.Int(0, RuleI(Zone, FishingChance)) <= fishing_skill ) {
|
||||
uint32 npc_id = 0;
|
||||
uint8 npc_chance = 0;
|
||||
food_id = content_db.LoadFishing(m_pp.zone_id, fishing_skill, npc_id, npc_chance);
|
||||
@@ -348,7 +343,7 @@ void Client::GoFish(bool guarantee, bool use_bait)
|
||||
DeleteItemInInventory(bslot, 1, true); //do we need client update?
|
||||
}
|
||||
|
||||
if(food_id == 0) {
|
||||
if (food_id == 0) {
|
||||
int index = zone->random.Int(0, MAX_COMMON_FISH_IDS-1);
|
||||
food_id = (RuleB(Character, UseNoJunkFishing) ? 13019 : common_fish_ids[index]);
|
||||
}
|
||||
@@ -449,9 +444,9 @@ void Client::ForageItem(bool guarantee) {
|
||||
13419, // Vegetables
|
||||
13048, // Rabbit Meat
|
||||
13047, // Roots
|
||||
13044, // Pod Of Water
|
||||
14905, // mushroom
|
||||
13106 // Fishing Grubs
|
||||
13044, // Pod of Water
|
||||
14905, // Mushroom
|
||||
13106 // Fishing Grubs
|
||||
};
|
||||
|
||||
// these may need to be fine tuned, I am just guessing here
|
||||
|
||||
@@ -82,7 +82,7 @@ void command_logs(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
gmsay.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
Saylink::Create(
|
||||
fmt::format("#logs set gmsay {} {}", index, i), false, std::to_string(i)
|
||||
)
|
||||
);
|
||||
@@ -96,7 +96,7 @@ void command_logs(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
file.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
Saylink::Create(
|
||||
fmt::format("#logs set file {} {}", index, i), false, std::to_string(i)
|
||||
)
|
||||
);
|
||||
@@ -110,7 +110,7 @@ void command_logs(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
console.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
Saylink::Create(
|
||||
fmt::format("#logs set console {} {}", index, i), false, std::to_string(i)
|
||||
)
|
||||
);
|
||||
@@ -124,7 +124,7 @@ void command_logs(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
discord.emplace_back(
|
||||
EQ::SayLinkEngine::GenerateQuestSaylink(
|
||||
Saylink::Create(
|
||||
fmt::format("#logs set discord {} {}", index, i), false, std::to_string(i)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -116,13 +116,13 @@ void command_lootsim(Client *c, const Seperator *sep)
|
||||
c->Message(Chat::White, fmt::format("# Global Loot Table ID [{}]", id).c_str());
|
||||
c->SendChatLineBreak();
|
||||
|
||||
loot_table = zone->GetLootTable(loottable_id);
|
||||
loot_table = zone->GetLootTable(id);
|
||||
if (!loot_table) {
|
||||
c->Message(Chat::Red, fmt::format("Global Loot table not found [{}]", id).c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
le = zone->GetLootTableEntries(loottable_id);
|
||||
le = zone->GetLootTableEntries(id);
|
||||
|
||||
// translate above for loop using loot_table_entries
|
||||
for (auto &e: le) {
|
||||
|
||||
@@ -53,7 +53,7 @@ void command_movechar(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
const bool moved = database.MoveCharacterToZone(character_name.c_str(), zone_id);
|
||||
const bool moved = database.MoveCharacterToZone(character_name, zone_id);
|
||||
std::string moved_string = moved ? "Succeeded" : "Failed";
|
||||
c->Message(
|
||||
Chat::White,
|
||||
|
||||
@@ -34,6 +34,7 @@ void command_reload(Client *c, const Seperator *sep)
|
||||
bool is_perl_export = !strcasecmp(sep->arg[1], "perl_export");
|
||||
bool is_quest = !strcasecmp(sep->arg[1], "quest") || (is_rq_alias);
|
||||
bool is_rules = !strcasecmp(sep->arg[1], "rules");
|
||||
bool is_skill_caps = !strcasecmp(sep->arg[1], "skill_caps");
|
||||
bool is_static = !strcasecmp(sep->arg[1], "static");
|
||||
bool is_tasks = !strcasecmp(sep->arg[1], "tasks");
|
||||
bool is_titles = !strcasecmp(sep->arg[1], "titles");
|
||||
@@ -66,6 +67,7 @@ void command_reload(Client *c, const Seperator *sep)
|
||||
!is_perl_export &&
|
||||
!is_quest &&
|
||||
!is_rules &&
|
||||
!is_skill_caps &&
|
||||
!is_static &&
|
||||
!is_tasks &&
|
||||
!is_titles &&
|
||||
@@ -161,6 +163,9 @@ void command_reload(Client *c, const Seperator *sep)
|
||||
} else if (is_rules) {
|
||||
c->Message(Chat::White, "Attempting to reload Rules globally.");
|
||||
pack = new ServerPacket(ServerOP_ReloadRules, 0);
|
||||
} else if (is_skill_caps) {
|
||||
c->Message(Chat::White, "Attempting to reload Skill Caps globally.");
|
||||
pack = new ServerPacket(ServerOP_ReloadSkillCaps, 0);
|
||||
} else if (is_static) {
|
||||
c->Message(Chat::White, "Attempting to reload Static Zone Data globally.");
|
||||
pack = new ServerPacket(ServerOP_ReloadStaticZoneData, 0);
|
||||
|
||||
@@ -7,7 +7,7 @@ void SetHPFull(Client *c, const Seperator *sep)
|
||||
t = c->GetTarget();
|
||||
}
|
||||
|
||||
t->Heal();
|
||||
t->RestoreHealth();
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
|
||||
+183
-135
@@ -203,155 +203,141 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
|
||||
}
|
||||
}
|
||||
|
||||
bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 CharacterID, bool ismerc)
|
||||
bool Group::AddMember(Mob* new_member, std::string new_member_name, uint32 character_id, bool is_merc)
|
||||
{
|
||||
bool InZone = true;
|
||||
bool in_zone = true;
|
||||
|
||||
// This method should either be passed a Mob*, if the new member is in this zone, or a nullptr Mob*
|
||||
// and the name and CharacterID of the new member, if they are out of zone.
|
||||
if(!newmember && !NewMemberName)
|
||||
{
|
||||
// and the name and character_id of the new member, if they are out of zone.
|
||||
if (!new_member && new_member_name.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(GroupCount() >= MAX_GROUP_MEMBERS) //Sanity check for merging groups together.
|
||||
{
|
||||
if (GroupCount() >= MAX_GROUP_MEMBERS) { //Sanity check for merging groups together.
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!newmember)
|
||||
{
|
||||
InZone = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
NewMemberName = newmember->GetCleanName();
|
||||
if (!new_member) {
|
||||
in_zone = false;
|
||||
} else {
|
||||
new_member_name = new_member->GetCleanName();
|
||||
|
||||
if(newmember->IsClient())
|
||||
{
|
||||
CharacterID = newmember->CastToClient()->CharacterID();
|
||||
if (new_member->IsClient()) {
|
||||
character_id = new_member->CastToClient()->CharacterID();
|
||||
}
|
||||
if(newmember->IsMerc())
|
||||
{
|
||||
Client* owner = newmember->CastToMerc()->GetMercenaryOwner();
|
||||
if(owner)
|
||||
{
|
||||
CharacterID = owner->CastToClient()->CharacterID();
|
||||
|
||||
if (new_member->IsMerc()) {
|
||||
Client* o = new_member->CastToMerc()->GetMercenaryOwner();
|
||||
if (o) {
|
||||
character_id = o->CastToClient()->CharacterID();
|
||||
}
|
||||
ismerc = true;
|
||||
|
||||
is_merc = true;
|
||||
}
|
||||
}
|
||||
|
||||
// See if they are already in the group
|
||||
uint32 i = 0;
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
{
|
||||
if (!strcasecmp(membername[i], NewMemberName))
|
||||
{
|
||||
for (const auto& m : membername) {
|
||||
if (Strings::EqualFold(m, new_member_name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Put them in the group
|
||||
for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
{
|
||||
if (membername[i][0] == '\0')
|
||||
{
|
||||
if(InZone)
|
||||
{
|
||||
members[i] = newmember;
|
||||
for (int slot_id = 0; slot_id < MAX_GROUP_MEMBERS; ++slot_id) {
|
||||
if (membername[slot_id][0] == '\0') {
|
||||
if (in_zone) {
|
||||
members[slot_id] = new_member;
|
||||
}
|
||||
strcpy(membername[i], NewMemberName);
|
||||
MemberRoles[i] = 0;
|
||||
|
||||
strcpy(membername[slot_id], new_member_name.c_str());
|
||||
MemberRoles[slot_id] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Is this even possible based on the above loops? Remove?
|
||||
if (i == MAX_GROUP_MEMBERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int x=1;
|
||||
int x = 1;
|
||||
|
||||
//build the template join packet
|
||||
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
|
||||
GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer;
|
||||
strcpy(gj->membername, NewMemberName);
|
||||
gj->action = groupActJoin;
|
||||
|
||||
auto gj = (GroupJoin_Struct*) outapp->pBuffer;
|
||||
|
||||
strcpy(gj->membername, new_member_name.c_str());
|
||||
|
||||
gj->action = groupActJoin;
|
||||
gj->leader_aas = LeaderAbilities;
|
||||
|
||||
for (i = 0;i < MAX_GROUP_MEMBERS; i++)
|
||||
{
|
||||
if (members[i] != nullptr && members[i] != newmember)
|
||||
{
|
||||
for (int slot_id = 0; slot_id < MAX_GROUP_MEMBERS; slot_id++) {
|
||||
if (members[slot_id] && members[slot_id] != new_member) {
|
||||
//fill in group join & send it
|
||||
strcpy(gj->yourname, members[i]->GetCleanName());
|
||||
if(members[i]->IsClient())
|
||||
{
|
||||
members[i]->CastToClient()->QueuePacket(outapp);
|
||||
strcpy(gj->yourname, members[slot_id]->GetCleanName());
|
||||
if (members[slot_id]->IsClient()) {
|
||||
members[slot_id]->CastToClient()->QueuePacket(outapp);
|
||||
|
||||
//put new member into existing group members' list(s)
|
||||
strcpy(members[i]->CastToClient()->GetPP().groupMembers[GroupCount()-1], NewMemberName);
|
||||
strcpy(
|
||||
members[slot_id]->CastToClient()->GetPP().groupMembers[GroupCount() - 1],
|
||||
new_member_name.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
//put existing group member(s) into the new member's list
|
||||
if(InZone && newmember && newmember->IsClient())
|
||||
{
|
||||
if(IsLeader(members[i]))
|
||||
{
|
||||
strcpy(newmember->CastToClient()->GetPP().groupMembers[0], members[i]->GetCleanName());
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(newmember->CastToClient()->GetPP().groupMembers[x], members[i]->GetCleanName());
|
||||
if (in_zone && new_member && new_member->IsClient()) {
|
||||
if (IsLeader(members[slot_id])) {
|
||||
strcpy(new_member->CastToClient()->GetPP().groupMembers[0], members[slot_id]->GetCleanName());
|
||||
} else {
|
||||
strcpy(new_member->CastToClient()->GetPP().groupMembers[x], members[slot_id]->GetCleanName());
|
||||
++x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(InZone && newmember)
|
||||
{
|
||||
if (in_zone && new_member) {
|
||||
//put new member in his own list.
|
||||
newmember->SetGrouped(true);
|
||||
new_member->SetGrouped(true);
|
||||
|
||||
if(newmember->IsClient())
|
||||
{
|
||||
strcpy(newmember->CastToClient()->GetPP().groupMembers[x], NewMemberName);
|
||||
newmember->CastToClient()->Save();
|
||||
database.SetGroupID(NewMemberName, GetID(), newmember->CastToClient()->CharacterID(), false);
|
||||
SendMarkedNPCsToMember(newmember->CastToClient());
|
||||
if (new_member->IsClient()) {
|
||||
strcpy(new_member->CastToClient()->GetPP().groupMembers[x], new_member_name.c_str());
|
||||
|
||||
NotifyMainTank(newmember->CastToClient(), 1);
|
||||
NotifyMainAssist(newmember->CastToClient(), 1);
|
||||
NotifyPuller(newmember->CastToClient(), 1);
|
||||
new_member->CastToClient()->Save();
|
||||
|
||||
AddToGroup(new_member);
|
||||
|
||||
SendMarkedNPCsToMember(new_member->CastToClient());
|
||||
|
||||
NotifyMainTank(new_member->CastToClient(), 1);
|
||||
NotifyMainAssist(new_member->CastToClient(), 1);
|
||||
NotifyPuller(new_member->CastToClient(), 1);
|
||||
}
|
||||
|
||||
if(newmember->IsMerc())
|
||||
{
|
||||
Client* owner = newmember->CastToMerc()->GetMercenaryOwner();
|
||||
if(owner)
|
||||
{
|
||||
database.SetGroupID(NewMemberName, GetID(), owner->CharacterID(), true);
|
||||
if (new_member->IsMerc()) {
|
||||
Client* o = new_member->CastToMerc()->GetMercenaryOwner();
|
||||
if (o) {
|
||||
AddToGroup(new_member);
|
||||
}
|
||||
}
|
||||
|
||||
Group* group = newmember->CastToClient()->GetGroup();
|
||||
if (group) {
|
||||
group->SendHPManaEndPacketsTo(newmember);
|
||||
group->SendHPPacketsFrom(newmember);
|
||||
Group* g = new_member->CastToClient()->GetGroup();
|
||||
if (g) {
|
||||
g->SendHPManaEndPacketsTo(new_member);
|
||||
g->SendHPPacketsFrom(new_member);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
database.SetGroupID(NewMemberName, GetID(), CharacterID, ismerc);
|
||||
} else {
|
||||
AddToGroup(
|
||||
AddToGroupRequest{
|
||||
.mob = nullptr,
|
||||
.member_name = new_member_name,
|
||||
.character_id = character_id,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (newmember && newmember->IsClient())
|
||||
newmember->CastToClient()->JoinGroupXTargets(this);
|
||||
if (new_member && new_member->IsClient()) {
|
||||
new_member->CastToClient()->JoinGroupXTargets(this);
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
@@ -362,20 +348,18 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
|
||||
return true;
|
||||
}
|
||||
|
||||
void Group::AddMember(const char *NewMemberName)
|
||||
void Group::AddMember(const std::string& new_member_name)
|
||||
{
|
||||
// This method should be called when both the new member and the group leader are in a different zone to this one.
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
if(!strcasecmp(membername[i], NewMemberName))
|
||||
{
|
||||
for (const auto& m : membername) {
|
||||
if (Strings::EqualFold(m, new_member_name)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
{
|
||||
if (membername[i][0] == '\0')
|
||||
{
|
||||
strcpy(membername[i], NewMemberName);
|
||||
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
|
||||
if (membername[i][0] == '\0') {
|
||||
strcpy(membername[i], new_member_name.c_str());
|
||||
MemberRoles[i] = 0;
|
||||
break;
|
||||
}
|
||||
@@ -620,7 +604,7 @@ bool Group::DelMemberOOZ(const char *Name) {
|
||||
if(!strcasecmp(Name, membername[i]))
|
||||
// This shouldn't be called if the member is in this zone.
|
||||
if(!members[i]) {
|
||||
if(!strncmp(GetLeaderName(), Name, 64))
|
||||
if(!strncmp(GetLeaderName().c_str(), Name, 64))
|
||||
{
|
||||
//TODO: Transfer leadership if leader disbands OOZ.
|
||||
UpdateGroupAAs();
|
||||
@@ -703,7 +687,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetLeaderName())
|
||||
if (GetLeaderName().empty())
|
||||
{
|
||||
DisbandGroup();
|
||||
return true;
|
||||
@@ -752,7 +736,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
|
||||
if(oldmember->IsClient())
|
||||
{
|
||||
database.SetGroupID(oldmember->GetCleanName(), 0, oldmember->CastToClient()->CharacterID(), false);
|
||||
RemoveFromGroup(oldmember);
|
||||
}
|
||||
|
||||
if(oldmember->IsMerc())
|
||||
@@ -760,7 +744,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
|
||||
Client* owner = oldmember->CastToMerc()->GetMercenaryOwner();
|
||||
if(owner)
|
||||
{
|
||||
database.SetGroupID(oldmember->GetCleanName(), 0, owner->CharacterID(), true);
|
||||
RemoveFromGroup(oldmember);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,7 +927,7 @@ void Group::DisbandGroup(bool joinraid) {
|
||||
}
|
||||
|
||||
strcpy(gu->yourname, members[i]->GetCleanName());
|
||||
database.SetGroupID(members[i]->GetCleanName(), 0, members[i]->CastToClient()->CharacterID(), false);
|
||||
RemoveFromGroup(members[i]);
|
||||
members[i]->CastToClient()->QueuePacket(outapp);
|
||||
SendMarkedNPCsToMember(members[i]->CastToClient(), true);
|
||||
if (!joinraid)
|
||||
@@ -955,7 +939,7 @@ void Group::DisbandGroup(bool joinraid) {
|
||||
Client* owner = members[i]->CastToMerc()->GetMercenaryOwner();
|
||||
if(owner)
|
||||
{
|
||||
database.SetGroupID(members[i]->GetCleanName(), 0, owner->CharacterID(), true);
|
||||
RemoveFromGroup(members[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1148,31 +1132,30 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float
|
||||
|
||||
bool Group::LearnMembers() {
|
||||
|
||||
auto rows = GroupIdRepository::GetWhere(
|
||||
const auto& l = GroupIdRepository::GetWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"groupid = {}",
|
||||
"`group_id` = {}",
|
||||
GetID()
|
||||
)
|
||||
);
|
||||
|
||||
if (rows.empty()) {
|
||||
if (l.empty()) {
|
||||
LogError(
|
||||
"Error getting group members for group [{}]",
|
||||
GetID()
|
||||
);
|
||||
}
|
||||
|
||||
for(int i = 0; i < MAX_GROUP_MEMBERS; ++i)
|
||||
{
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
|
||||
members[i] = nullptr;
|
||||
memset(membername[i],0,64);
|
||||
memset(membername[i], 0, 64);
|
||||
MemberRoles[i] = 0;
|
||||
}
|
||||
|
||||
int memberIndex = 0;
|
||||
for (const auto& member : rows) {
|
||||
if (memberIndex >= MAX_GROUP_MEMBERS) {
|
||||
int member_index = 0;
|
||||
for (const auto& e : l) {
|
||||
if (member_index >= MAX_GROUP_MEMBERS) {
|
||||
LogError(
|
||||
"Too many members in group [{}]",
|
||||
GetID()
|
||||
@@ -1180,14 +1163,15 @@ bool Group::LearnMembers() {
|
||||
break;
|
||||
}
|
||||
|
||||
if (member.name.empty()) {
|
||||
members[memberIndex] = nullptr;
|
||||
membername[memberIndex][0] = '\0';
|
||||
if (e.name.empty()) {
|
||||
members[member_index] = nullptr;
|
||||
membername[member_index][0] = '\0';
|
||||
} else {
|
||||
members[memberIndex] = nullptr;
|
||||
strn0cpy(membername[memberIndex], member.name.c_str(), 64);
|
||||
members[member_index] = nullptr;
|
||||
strn0cpy(membername[member_index], e.name.c_str(), 64);
|
||||
}
|
||||
++memberIndex;
|
||||
|
||||
++member_index;
|
||||
}
|
||||
|
||||
VerifyGroup();
|
||||
@@ -1264,10 +1248,10 @@ void Client::LeaveGroup() {
|
||||
else
|
||||
{
|
||||
//force things a little
|
||||
database.SetGroupID(GetCleanName(), 0, CharacterID(), false);
|
||||
if (GetMerc())
|
||||
{
|
||||
database.SetGroupID(GetMerc()->GetCleanName(), 0, CharacterID(), true);
|
||||
Group::RemoveFromGroup(this);
|
||||
|
||||
if (GetMerc()) {
|
||||
Group::RemoveFromGroup(GetMerc());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1676,7 +1660,7 @@ void Group::NotifyMainTank(Client *c, uint8 toggle)
|
||||
|
||||
strn0cpy(grs->Name1, MainTankName.c_str(), sizeof(grs->Name1));
|
||||
|
||||
strn0cpy(grs->Name2, GetLeaderName(), sizeof(grs->Name2));
|
||||
strn0cpy(grs->Name2, GetLeaderName().c_str(), sizeof(grs->Name2));
|
||||
|
||||
grs->RoleNumber = 1;
|
||||
|
||||
@@ -1729,7 +1713,7 @@ void Group::NotifyMainAssist(Client *c, uint8 toggle)
|
||||
|
||||
strn0cpy(grs->Name1, MainAssistName.c_str(), sizeof(grs->Name1));
|
||||
|
||||
strn0cpy(grs->Name2, GetLeaderName(), sizeof(grs->Name2));
|
||||
strn0cpy(grs->Name2, GetLeaderName().c_str(), sizeof(grs->Name2));
|
||||
|
||||
grs->RoleNumber = 2;
|
||||
|
||||
@@ -1771,7 +1755,7 @@ void Group::NotifyPuller(Client *c, uint8 toggle)
|
||||
|
||||
strn0cpy(grs->Name1, PullerName.c_str(), sizeof(grs->Name1));
|
||||
|
||||
strn0cpy(grs->Name2, GetLeaderName(), sizeof(grs->Name2));
|
||||
strn0cpy(grs->Name2, GetLeaderName().c_str(), sizeof(grs->Name2));
|
||||
|
||||
grs->RoleNumber = 3;
|
||||
|
||||
@@ -2511,8 +2495,72 @@ bool Group::IsLeader(const char* name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Group::GetGroupLeaderName(uint32 group_id) {
|
||||
char leader_name_buffer[64] = { 0 };
|
||||
database.GetGroupLeadershipInfo(group_id, leader_name_buffer);
|
||||
return std::string(leader_name_buffer);
|
||||
std::string Group::GetLeaderName() {
|
||||
return database.GetGroupLeaderName(GetID());
|
||||
}
|
||||
|
||||
void Group::RemoveFromGroup(Mob* m)
|
||||
{
|
||||
uint32 bot_id = 0;
|
||||
uint32 character_id = 0;
|
||||
uint32 merc_id = 0;
|
||||
|
||||
if (m->IsBot()) {
|
||||
bot_id = m->CastToBot()->GetBotID();
|
||||
} else if (m->IsClient()) {
|
||||
character_id = m->CastToClient()->CharacterID();
|
||||
} else if (m->IsMerc()) {
|
||||
merc_id = m->CastToMerc()->GetMercenaryID();
|
||||
}
|
||||
|
||||
GroupIdRepository::DeleteWhere(
|
||||
database,
|
||||
fmt::format(
|
||||
"`character_id` = {} AND `bot_id` = {} AND `merc_id` = {}",
|
||||
character_id,
|
||||
bot_id,
|
||||
merc_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void Group::AddToGroup(Mob* m)
|
||||
{
|
||||
AddToGroup(
|
||||
AddToGroupRequest{
|
||||
.mob = m
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Handles database-side, should eventually be consolidated to handle memory-based group stuff as well
|
||||
void Group::AddToGroup(AddToGroupRequest r)
|
||||
{
|
||||
uint32 bot_id = 0;
|
||||
uint32 character_id = r.character_id;
|
||||
uint32 merc_id = 0;
|
||||
std::string name = r.member_name;
|
||||
|
||||
if (r.mob) {
|
||||
if (r.mob->IsBot()) {
|
||||
bot_id = r.mob->CastToBot()->GetBotID();
|
||||
} else if (r.mob->IsClient()) {
|
||||
character_id = r.mob->CastToClient()->CharacterID();
|
||||
} else if (r.mob->IsMerc()) {
|
||||
merc_id = r.mob->CastToMerc()->GetMercenaryID();
|
||||
}
|
||||
|
||||
name = r.mob->GetCleanName();
|
||||
}
|
||||
|
||||
GroupIdRepository::ReplaceOne(
|
||||
database,
|
||||
GroupIdRepository::GroupId{
|
||||
.group_id = GetID(),
|
||||
.name = name,
|
||||
.character_id = character_id,
|
||||
.bot_id = bot_id,
|
||||
.merc_id = merc_id
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+13
-5
@@ -52,8 +52,15 @@ public:
|
||||
Group(uint32 gid);
|
||||
~Group();
|
||||
|
||||
bool AddMember(Mob* newmember, const char* NewMemberName = nullptr, uint32 CharacterID = 0, bool ismerc = false);
|
||||
void AddMember(const char* NewMemberName);
|
||||
struct AddToGroupRequest {
|
||||
Mob* mob = nullptr;
|
||||
// Only used cross-zone, otherwise use Mob* mob
|
||||
std::string member_name = std::string();
|
||||
uint32 character_id = 0;
|
||||
};
|
||||
|
||||
bool AddMember(Mob* new_member, std::string new_member_name = std::string(), uint32 character_id = 0, bool is_merc = false);
|
||||
void AddMember(const std::string& new_member_name);
|
||||
void SendUpdate(uint32 type,Mob* member);
|
||||
void SendLeadershipAAUpdate();
|
||||
void SendWorldGroup(uint32 zone_id,Mob* zoningmember);
|
||||
@@ -76,7 +83,7 @@ public:
|
||||
void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
|
||||
inline void SetLeader(Mob* c){ leader = c; };
|
||||
inline Mob* GetLeader() { return leader; };
|
||||
const char* GetLeaderName() { return GetGroupLeaderName(GetID()).c_str(); };
|
||||
std::string GetLeaderName();
|
||||
void SendHPManaEndPacketsTo(Mob* newmember);
|
||||
void SendHPPacketsFrom(Mob* member);
|
||||
void SendManaPacketFrom(Mob* member);
|
||||
@@ -145,6 +152,9 @@ public:
|
||||
void SetDirtyAutoHaters();
|
||||
inline XTargetAutoHaters *GetXTargetAutoMgr() { return &m_autohatermgr; }
|
||||
void JoinRaidXTarget(Raid *raid, bool first = false);
|
||||
void AddToGroup(AddToGroupRequest r);
|
||||
void AddToGroup(Mob* m);
|
||||
static void RemoveFromGroup(Mob* m);
|
||||
|
||||
void SetGroupMentor(int percent, char *name);
|
||||
void ClearGroupMentor();
|
||||
@@ -177,8 +187,6 @@ private:
|
||||
int mentor_percent;
|
||||
|
||||
XTargetAutoHaters m_autohatermgr;
|
||||
|
||||
std::string GetGroupLeaderName(uint32 group_id);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+32
-30
@@ -108,46 +108,48 @@ void HateList::SetHateAmountOnEnt(Mob* other, int64 in_hate, uint64 in_damage)
|
||||
|
||||
Mob* HateList::GetDamageTopOnHateList(Mob* hater)
|
||||
{
|
||||
Mob* current = nullptr;
|
||||
Group* grp = nullptr;
|
||||
Raid* r = nullptr;
|
||||
uint64 dmg_amt = 0;
|
||||
Mob* c = nullptr;
|
||||
Mob* m = nullptr;
|
||||
Group* g = nullptr;
|
||||
Raid* r = nullptr;
|
||||
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
grp = nullptr;
|
||||
uint64 damage = 0;
|
||||
|
||||
for (const auto& e : list) {
|
||||
c = e->entity_on_hatelist;
|
||||
|
||||
if (!c) {
|
||||
continue;
|
||||
}
|
||||
|
||||
g = nullptr;
|
||||
r = nullptr;
|
||||
|
||||
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient()){
|
||||
r = entity_list.GetRaidByClient((*iterator)->entity_on_hatelist->CastToClient());
|
||||
if (c->IsBot()) {
|
||||
r = entity_list.GetRaidByBot(c->CastToBot());
|
||||
} else if (c->IsClient()) {
|
||||
r = entity_list.GetRaidByClient(c->CastToClient());
|
||||
}
|
||||
|
||||
grp = entity_list.GetGroupByMob((*iterator)->entity_on_hatelist);
|
||||
g = entity_list.GetGroupByMob(c);
|
||||
|
||||
if ((*iterator)->entity_on_hatelist && r){
|
||||
if (r->GetTotalRaidDamage(hater) >= dmg_amt)
|
||||
{
|
||||
current = (*iterator)->entity_on_hatelist;
|
||||
dmg_amt = r->GetTotalRaidDamage(hater);
|
||||
if (r) {
|
||||
if (r->GetTotalRaidDamage(hater) >= damage) {
|
||||
m = c;
|
||||
damage = r->GetTotalRaidDamage(hater);
|
||||
}
|
||||
}
|
||||
else if ((*iterator)->entity_on_hatelist != nullptr && grp != nullptr)
|
||||
{
|
||||
if (grp->GetTotalGroupDamage(hater) >= dmg_amt)
|
||||
{
|
||||
current = (*iterator)->entity_on_hatelist;
|
||||
dmg_amt = grp->GetTotalGroupDamage(hater);
|
||||
} else if (g) {
|
||||
if (g->GetTotalGroupDamage(hater) >= damage) {
|
||||
m = c;
|
||||
damage = g->GetTotalGroupDamage(hater);
|
||||
}
|
||||
} else if (static_cast<uint64>(e->hatelist_damage) >= damage) {
|
||||
m = c;
|
||||
damage = static_cast<uint64>(e->hatelist_damage);
|
||||
}
|
||||
else if ((*iterator)->entity_on_hatelist != nullptr && (uint64)(*iterator)->hatelist_damage >= dmg_amt)
|
||||
{
|
||||
current = (*iterator)->entity_on_hatelist;
|
||||
dmg_amt = (*iterator)->hatelist_damage;
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
return current;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
Mob* HateList::GetClosestEntOnHateList(Mob *hater, bool skip_mezzed, EntityFilterType filter_type) {
|
||||
|
||||
+29
-1
@@ -601,7 +601,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
|
||||
inst->SetOrnamentHeroModel(ornament_hero_model);
|
||||
|
||||
// check to see if item is usable in requested slot
|
||||
if (enforce_usable && (to_slot >= EQ::invslot::EQUIPMENT_BEGIN && to_slot <= EQ::invslot::EQUIPMENT_END)) {
|
||||
if (enforce_usable && to_slot != EQ::invslot::SLOT_QUEST && (to_slot >= EQ::invslot::EQUIPMENT_BEGIN && to_slot <= EQ::invslot::EQUIPMENT_END)) {
|
||||
uint32 slottest = to_slot;
|
||||
if(!(slots & ((uint32)1 << slottest))) {
|
||||
Message(
|
||||
@@ -648,6 +648,34 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
|
||||
|
||||
RecordPlayerEventLog(PlayerEvent::ITEM_CREATION, e);
|
||||
}
|
||||
//We're coming from a quest method.
|
||||
if (to_slot == EQ::invslot::SLOT_QUEST) {
|
||||
bool stacking = TryStacking(inst);
|
||||
if (stacking) {
|
||||
safe_delete(inst);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
bool bag = false;
|
||||
if (inst->IsClassBag()) {
|
||||
bag = true;
|
||||
}
|
||||
to_slot = m_inv.FindFreeSlot(bag, true, item->Size);
|
||||
|
||||
//make sure we are not completely full...
|
||||
if (to_slot == EQ::invslot::slotCursor || to_slot == INVALID_INDEX) {
|
||||
if (inst->GetItem()->NoDrop == 0) {
|
||||
//If it's no drop, force it to the cursor. This carries the risk of deletion if the player already has this item on their cursor
|
||||
// or if the cursor queue is full. But in this situation, we have little other recourse.
|
||||
PushItemOnCursor(*inst);
|
||||
LogInventory("{} has a full inventory and {} is a no drop item. Forcing to cursor", GetName(), inst->GetItem()->Name);
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// put item into inventory
|
||||
if (to_slot == EQ::invslot::slotCursor) {
|
||||
|
||||
+411
-5
@@ -22,7 +22,7 @@ void NPC::AddLootTable(uint32 loottable_id, bool is_global)
|
||||
if (!npctype_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!is_global) {
|
||||
m_loot_copper = 0;
|
||||
m_loot_silver = 0;
|
||||
@@ -37,6 +37,14 @@ void NPC::AddLootTable(uint32 loottable_id, bool is_global)
|
||||
return;
|
||||
}
|
||||
|
||||
LogLootDetail(
|
||||
"Attempting to load loot [{}] loottable [{}] ({}) is_global [{}]",
|
||||
GetCleanName(),
|
||||
loottable_id,
|
||||
l->name,
|
||||
is_global
|
||||
);
|
||||
|
||||
auto content_flags = ContentFlags{
|
||||
.min_expansion = l->min_expansion,
|
||||
.max_expansion = l->max_expansion,
|
||||
@@ -106,7 +114,12 @@ void NPC::AddLootTable(uint32 loottable_id, bool is_global)
|
||||
}
|
||||
}
|
||||
|
||||
LogLootDetail("Loaded [{}] Loot Table [{}]", GetCleanName(), loottable_id);
|
||||
LogLootDetail(
|
||||
"Loaded [{}] Loot Table [{}] is_global [{}]",
|
||||
GetCleanName(),
|
||||
loottable_id,
|
||||
is_global
|
||||
);
|
||||
}
|
||||
|
||||
void NPC::AddLootDropTable(uint32 lootdrop_id, uint8 drop_limit, uint8 min_drop)
|
||||
@@ -128,10 +141,28 @@ void NPC::AddLootDropTable(uint32 lootdrop_id, uint8 drop_limit, uint8 min_drop)
|
||||
// if this lootdrop is droplimit=0 and mindrop 0, scan list once and return
|
||||
if (drop_limit == 0 && min_drop == 0) {
|
||||
for (const auto &e: le) {
|
||||
LogLootDetail(
|
||||
"-- NPC [{}] Lootdrop [{}] Item [{}] ({}_ Chance [{}] Multiplier [{}]",
|
||||
GetCleanName(),
|
||||
lootdrop_id,
|
||||
database.GetItem(e.item_id)->Name,
|
||||
e.item_id,
|
||||
e.chance,
|
||||
e.multiplier
|
||||
);
|
||||
for (int j = 0; j < e.multiplier; ++j) {
|
||||
if (zone->random.Real(0.0, 100.0) <= e.chance && MeetsLootDropLevelRequirements(e, true)) {
|
||||
const EQ::ItemData *database_item = database.GetItem(e.item_id);
|
||||
AddLootDrop(database_item, e);
|
||||
LogLootDetail(
|
||||
"---- NPC (Rolled) [{}] Lootdrop [{}] Item [{}] ({}) Chance [{}] Multiplier [{}]",
|
||||
GetCleanName(),
|
||||
lootdrop_id,
|
||||
database_item->Name,
|
||||
e.item_id,
|
||||
e.chance,
|
||||
e.multiplier
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,6 +285,8 @@ void NPC::AddLootDrop(
|
||||
const EQ::ItemData *item2,
|
||||
LootdropEntriesRepository::LootdropEntries loot_drop,
|
||||
bool wear_change,
|
||||
bool quest,
|
||||
bool pet,
|
||||
uint32 augment_one,
|
||||
uint32 augment_two,
|
||||
uint32 augment_three,
|
||||
@@ -266,6 +299,10 @@ void NPC::AddLootDrop(
|
||||
return;
|
||||
}
|
||||
|
||||
if (CountQuestItems() >= MAX_NPC_QUEST_INVENTORY) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto item = new LootItem;
|
||||
|
||||
if (LogSys.log_settings[Logs::Loot].is_category_enabled == 1) {
|
||||
@@ -287,6 +324,10 @@ void NPC::AddLootDrop(
|
||||
);
|
||||
}
|
||||
|
||||
if (quest || pet) {
|
||||
LogLoot("Adding {} to npc: {}. Wearchange: {} Multiquest: {} Pet: {}", item2->Name, GetName(), wear_change, quest, pet);
|
||||
}
|
||||
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
WearChange_Struct *p_wear_change_struct = nullptr;
|
||||
if (wear_change) {
|
||||
@@ -308,6 +349,8 @@ void NPC::AddLootDrop(
|
||||
item->trivial_min_level = loot_drop.trivial_min_level;
|
||||
item->trivial_max_level = loot_drop.trivial_max_level;
|
||||
item->equip_slot = EQ::invslot::SLOT_INVALID;
|
||||
item->quest = quest;
|
||||
item->pet = pet;
|
||||
|
||||
// unsure if required to equip, YOLO for now
|
||||
if (item2->ItemType == EQ::item::ItemTypeBow) {
|
||||
@@ -318,6 +361,11 @@ void NPC::AddLootDrop(
|
||||
SetArrowEquipped(true);
|
||||
}
|
||||
|
||||
if (pet && quest) {
|
||||
LogLoot("Error: Item {} is being added to {} as both a pet and a quest.", item2->Name, GetName());
|
||||
item->pet = 0;
|
||||
}
|
||||
|
||||
bool found = false; // track if we found an empty slot we fit into
|
||||
|
||||
int found_slot = INVALID_INDEX; // for multi-slot items
|
||||
@@ -510,20 +558,21 @@ void NPC::AddLootDrop(
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item)
|
||||
void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item, bool quest)
|
||||
{
|
||||
auto l = LootdropEntriesRepository::NewNpcEntity();
|
||||
|
||||
l.equip_item = static_cast<uint8>(equip_item ? 1 : 0);
|
||||
l.item_charges = charges;
|
||||
|
||||
AddLootDrop(item, l, true);
|
||||
AddLootDrop(item, l, equip_item, quest);
|
||||
}
|
||||
|
||||
void NPC::AddItem(
|
||||
uint32 item_id,
|
||||
uint16 charges,
|
||||
bool equip_item,
|
||||
bool quest,
|
||||
uint32 augment_one,
|
||||
uint32 augment_two,
|
||||
uint32 augment_three,
|
||||
@@ -545,7 +594,8 @@ void NPC::AddItem(
|
||||
AddLootDrop(
|
||||
item,
|
||||
l,
|
||||
true,
|
||||
equip_item,
|
||||
quest,
|
||||
augment_one,
|
||||
augment_two,
|
||||
augment_three,
|
||||
@@ -664,6 +714,50 @@ LootItem *NPC::GetItem(int slot_id)
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
LootItem *NPC::GetItemByItemID(int16 item_id)
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *item = *cur;
|
||||
if (item->item_id == item_id) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return(nullptr);
|
||||
}
|
||||
|
||||
void NPC::RemoveItem(LootItem *item_data, uint8 quantity) {
|
||||
if (!item_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *item = *cur;
|
||||
if (item != item_data) { continue; }
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->charges <= quantity) {
|
||||
m_loot_items.erase(cur);
|
||||
UpdateEquipmentLight();
|
||||
if (UpdateActiveLight()) { SendAppearancePacket(AppearanceType::Light, GetActiveLightType()); }
|
||||
}
|
||||
else {
|
||||
item->charges -= quantity;
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NPC::RemoveItem(uint32 item_id, uint16 quantity, uint16 slot)
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
@@ -910,3 +1004,315 @@ void NPC::RemoveLootCash()
|
||||
m_loot_gold = 0;
|
||||
m_loot_platinum = 0;
|
||||
}
|
||||
|
||||
bool NPC::HasQuestLootItem(int16 itemid)
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_item = *cur;
|
||||
if (quest_item && quest_item->quest == 1 && quest_item->item_id == itemid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NPC::HasQuestLoot()
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_loot = *cur;
|
||||
if (quest_loot && quest_loot->quest == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NPC::RemoveQuestLootItems(int16 itemid)
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_item = *cur;
|
||||
if (quest_item && quest_item->quest == 1) {
|
||||
if (itemid == 0 || itemid == quest_item->item_id) {
|
||||
RemoveItem(quest_item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NPC::HasRequiredQuestLoot(int16 itemid1, int16 itemid2, int16 itemid3, int16 itemid4)
|
||||
{
|
||||
if (itemid2 == 0 && itemid3 == 0 && itemid4 == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 item2count = 0, item3count = 0, item4count = 0, item1npc = 0, item2npc = 0, item3npc = 0, item4npc = 0;
|
||||
uint8 item1count = 1;
|
||||
if (itemid2 > 0) {
|
||||
item2count = 1;
|
||||
}
|
||||
if (itemid3 > 0) {
|
||||
item3count = 1;
|
||||
}
|
||||
if (itemid4 > 0) {
|
||||
item4count = 1;
|
||||
}
|
||||
|
||||
if (itemid1 == itemid2 && itemid2 > 0) {
|
||||
item2count = item1count;
|
||||
++item1count;
|
||||
++item2count;
|
||||
}
|
||||
if (itemid1 == itemid3 && itemid3 > 0) {
|
||||
item3count = item1count;
|
||||
++item1count;
|
||||
++item3count;
|
||||
}
|
||||
if (itemid1 == itemid4 && itemid4 > 0) {
|
||||
item4count = item1count;
|
||||
++item1count;
|
||||
++item4count;
|
||||
}
|
||||
if (itemid2 == itemid3 && itemid2 > 0 && itemid3 > 0) {
|
||||
item3count = item2count;
|
||||
++item2count;
|
||||
++item3count;
|
||||
}
|
||||
if (itemid2 == itemid4 && itemid2 > 0 && itemid4 > 0) {
|
||||
item4count = item2count;
|
||||
++item2count;
|
||||
++item4count;
|
||||
}
|
||||
if (itemid3 == itemid4 && itemid3 > 0 && itemid4 > 0) {
|
||||
item4count = item3count;
|
||||
++item3count;
|
||||
++item4count;
|
||||
}
|
||||
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *sitem = *cur;
|
||||
if (sitem && sitem->quest == 1) {
|
||||
if (sitem->item_id == itemid1) {
|
||||
++item1npc;
|
||||
}
|
||||
|
||||
if (sitem->item_id == itemid2 && itemid2 > 0) {
|
||||
++item2npc;
|
||||
}
|
||||
|
||||
if (sitem->item_id == itemid3 && itemid3 > 0) {
|
||||
++item3npc;
|
||||
}
|
||||
|
||||
if (sitem->item_id == itemid4 && itemid4 > 0) {
|
||||
++item4npc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item1npc < item1count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemid2 > 0 && item2npc < item2count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemid3 > 0 && item3npc < item3count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemid4 > 0 && item4npc < item4count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NPC::CleanQuestLootItems()
|
||||
{
|
||||
//Removes nodrop or multiple quest loot items from a NPC before sending the corpse items to the client.
|
||||
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
uint8 count = 0;
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_item = *cur;
|
||||
if (quest_item && (quest_item->quest == 1 || quest_item->pet == 1)) {
|
||||
uint8 count = CountQuestItem(quest_item->item_id);
|
||||
if (count > 1 && quest_item->pet != 1) {
|
||||
RemoveItem(quest_item);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
const EQ::ItemData *item = database.GetItem(quest_item->item_id);
|
||||
if (item && item->NoDrop == 0) {
|
||||
RemoveItem(quest_item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 NPC::CountQuestItem(uint16 itemid)
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
uint8 count = 0;
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_item = *cur;
|
||||
if (quest_item && quest_item->item_id == itemid) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8 NPC::CountQuestItems()
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
uint8 count = 0;
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_item = *cur;
|
||||
if (quest_item && quest_item->quest == 1) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool NPC::AddQuestLoot(int16 itemid, int8 charges) {
|
||||
auto l = LootdropEntriesRepository::NewNpcEntity();
|
||||
|
||||
const EQ::ItemData *item = database.GetItem(itemid);
|
||||
if (item) {
|
||||
l.item_charges = charges;
|
||||
l.equip_item = 0;
|
||||
AddLootDrop(item, l, false, false, true);
|
||||
LogLoot("Adding item {} to the NPC's loot marked as quest.", itemid);
|
||||
if (itemid > 0 && HasPetLootItem(itemid)) {
|
||||
LogLoot("Deleting quest item {} from NPC's pet loot.", itemid);
|
||||
RemovePetLootItems(itemid);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NPC::DeleteQuestLoot(int16 itemid1, int16 itemid2, int16 itemid3, int16 itemid4)
|
||||
{
|
||||
int16 items = m_loot_items.size();
|
||||
for (int i = 0; i < items; ++i) {
|
||||
if (itemid1 == 0) {
|
||||
if (!RemoveQuestLootItems(itemid1))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (itemid1 != 0) {
|
||||
RemoveQuestLootItems(itemid1);
|
||||
}
|
||||
if (itemid2 != 0) {
|
||||
RemoveQuestLootItems(itemid2);
|
||||
}
|
||||
if (itemid3 != 0) {
|
||||
RemoveQuestLootItems(itemid3);
|
||||
}
|
||||
if (itemid4 != 0) {
|
||||
RemoveQuestLootItems(itemid4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NPC::DeleteInvalidQuestLoot()
|
||||
{
|
||||
int16 items = m_loot_items.size();
|
||||
for (int i = 0; i < items; ++i) {
|
||||
CleanQuestLootItems();
|
||||
}
|
||||
}
|
||||
|
||||
bool NPC::AddPetLoot(int16 itemid, int8 charges, bool fromquest) {
|
||||
auto l = LootdropEntriesRepository::NewNpcEntity();
|
||||
|
||||
const EQ::ItemData *item = database.GetItem(itemid);
|
||||
bool IsCharmedPet = IsPet() && IsCharmed();
|
||||
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valid = (item->NoDrop != 0 && ( !IsCharmedPet || (IsCharmedPet && CountQuestItem(item->ID) == 0)));
|
||||
if (!fromquest || valid) {
|
||||
if (item) {
|
||||
l.item_charges = charges;
|
||||
AddLootDrop(item, l, true, true, false, true);
|
||||
LogLoot("Adding item {} to the NPC's loot marked as pet.", itemid);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogLoot("Item {} is a duplicate or no drop. Deleting...", itemid);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NPC::HasPetLootItem(int16 itemid)
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_item = *cur;
|
||||
if (quest_item && quest_item->pet == 1 && quest_item->item_id == itemid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NPC::RemovePetLootItems(int16 itemid)
|
||||
{
|
||||
LootItems::iterator cur, end;
|
||||
cur = m_loot_items.begin();
|
||||
end = m_loot_items.end();
|
||||
for (; cur != end; ++cur) {
|
||||
LootItem *quest_item = *cur;
|
||||
if (quest_item && quest_item->pet == 1) {
|
||||
if (itemid == 0 || itemid == quest_item->item_id) {
|
||||
RemoveItem(quest_item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -659,6 +659,11 @@ void Lua_Bot::SetBucket(std::string bucket_name, std::string bucket_value, std::
|
||||
self->SetBucket(bucket_name, bucket_value, expiration);
|
||||
}
|
||||
|
||||
void Lua_Bot::DeleteBot() {
|
||||
Lua_Safe_Call_Void();
|
||||
self->DeleteBot();
|
||||
}
|
||||
|
||||
luabind::scope lua_register_bot() {
|
||||
return luabind::class_<Lua_Bot, Lua_Mob>("Bot")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -698,6 +703,7 @@ luabind::scope lua_register_bot() {
|
||||
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::ClearSpellRecastTimer)
|
||||
.def("CountBotItem", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountBotItem)
|
||||
.def("CountItemEquippedByID", (int(Lua_Bot::*)(uint32))&Lua_Bot::CountItemEquippedByID)
|
||||
.def("DeleteBot", (void(Lua_Bot::*)(void))&Lua_Bot::DeleteBot)
|
||||
.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)
|
||||
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
uint32 GetBotID();
|
||||
void Camp();
|
||||
void Camp(bool save_to_database);
|
||||
void DeleteBot();
|
||||
Lua_ItemInst GetAugmentAt(int16 slot_id, uint8 augment_index);
|
||||
int GetAugmentIDAt(int16 slot_id, uint8 augment_index);
|
||||
luabind::object GetAugmentIDsBySlotID(lua_State* L, int16 slot_id) const;
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
#ifdef LUA_EQEMU
|
||||
|
||||
#include "lua.hpp"
|
||||
#include <luabind/luabind.hpp>
|
||||
#include <luabind/iterator_policy.hpp>
|
||||
|
||||
#include "lua_buff.h"
|
||||
|
||||
uint16 Lua_Buff::GetCasterID()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->casterid;
|
||||
}
|
||||
|
||||
uint8 Lua_Buff::GetCasterLevel()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->casterlevel;
|
||||
}
|
||||
|
||||
std::string Lua_Buff::GetCasterName()
|
||||
{
|
||||
Lua_Safe_Call_String();
|
||||
return self->caster_name;
|
||||
}
|
||||
|
||||
int Lua_Buff::GetCastOnX()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->caston_x;
|
||||
}
|
||||
|
||||
int Lua_Buff::GetCastOnY()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->caston_y;
|
||||
}
|
||||
|
||||
int Lua_Buff::GetCastOnZ()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->caston_z;
|
||||
}
|
||||
|
||||
uint32 Lua_Buff::GetCounters()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->counters;
|
||||
}
|
||||
|
||||
uint32 Lua_Buff::GetDOTRune()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->dot_rune;
|
||||
}
|
||||
|
||||
int Lua_Buff::GetExtraDIChance()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->ExtraDIChance;
|
||||
}
|
||||
|
||||
uint32 Lua_Buff::GetInstrumentModifier()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->instrument_mod;
|
||||
}
|
||||
|
||||
uint32 Lua_Buff::GetMagicRune()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->magic_rune;
|
||||
}
|
||||
|
||||
uint32 Lua_Buff::GetMeleeRune()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->melee_rune;
|
||||
}
|
||||
|
||||
uint32 Lua_Buff::GetNumberOfHits()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->hit_number;
|
||||
}
|
||||
|
||||
int16 Lua_Buff::GetRootBreakChance()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->RootBreakChance;
|
||||
}
|
||||
|
||||
uint16 Lua_Buff::GetSpellID()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->spellid;
|
||||
}
|
||||
|
||||
int Lua_Buff::GetTicsRemaining()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->ticsremaining;
|
||||
}
|
||||
|
||||
int Lua_Buff::GetVirusSpreadTime()
|
||||
{
|
||||
Lua_Safe_Call_Int();
|
||||
return self->virus_spread_time;
|
||||
}
|
||||
|
||||
bool Lua_Buff::IsCasterClient()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->client;
|
||||
}
|
||||
|
||||
bool Lua_Buff::IsPersistentBuff()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->persistant_buff;
|
||||
}
|
||||
|
||||
bool Lua_Buff::SendsClientUpdate()
|
||||
{
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->UpdateClient;
|
||||
}
|
||||
|
||||
luabind::scope lua_register_buff() {
|
||||
return luabind::class_<Lua_Buff>("Buff")
|
||||
.def(luabind::constructor<>())
|
||||
.def("GetCasterID", &Lua_Buff::GetCasterID)
|
||||
.def("GetCasterLevel", &Lua_Buff::GetCasterLevel)
|
||||
.def("GetCasterName", &Lua_Buff::GetCasterName)
|
||||
.def("GetCastOnX", &Lua_Buff::GetCastOnX)
|
||||
.def("GetCastOnY", &Lua_Buff::GetCastOnY)
|
||||
.def("GetCastOnZ", &Lua_Buff::GetCastOnZ)
|
||||
.def("GetCounters", &Lua_Buff::GetCounters)
|
||||
.def("GetDOTRune", &Lua_Buff::GetDOTRune)
|
||||
.def("GetExtraDIChance", &Lua_Buff::GetExtraDIChance)
|
||||
.def("GetInstrumentModifier", &Lua_Buff::GetInstrumentModifier)
|
||||
.def("GetMagicRune", &Lua_Buff::GetMagicRune)
|
||||
.def("GetMeleeRune", &Lua_Buff::GetMeleeRune)
|
||||
.def("GetNumberOfHits", &Lua_Buff::GetNumberOfHits)
|
||||
.def("GetRootBreakChance", &Lua_Buff::GetRootBreakChance)
|
||||
.def("GetSpellID", &Lua_Buff::GetSpellID)
|
||||
.def("GetTicsRemaining", &Lua_Buff::GetTicsRemaining)
|
||||
.def("GetVirusSpreadTime", &Lua_Buff::GetVirusSpreadTime)
|
||||
.def("IsCasterClient", &Lua_Buff::IsCasterClient)
|
||||
.def("IsPersistentBuff", &Lua_Buff::IsPersistentBuff)
|
||||
.def("SendsClientUpdate", &Lua_Buff::SendsClientUpdate);
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user