Compare commits

..

20 Commits

Author SHA1 Message Date
Akkadius c0a88de4fb pch 2023-12-16 21:03:58 -06:00
Akkadius 5117843089 Incremental 2023-12-16 19:44:33 -06:00
Akkadius 77c7ea191a Win gate 2023-12-16 19:36:42 -06:00
Akkadius 527798db92 Pull out includes in common 2023-12-16 19:28:55 -06:00
Akkadius 3ea644b732 Remove header only 2023-12-16 19:23:08 -06:00
Akkadius 3850343254 Update eqemu_logsys.h 2023-12-16 19:15:06 -06:00
Akkadius 77597c7868 !!!!! 2023-12-16 19:03:39 -06:00
Akkadius 8a0ef65373 WHAT 2023-12-16 18:59:11 -06:00
Akkadius 75d9e6ffaf FMT test 2023-12-16 18:54:25 -06:00
Akkadius e9ca2b4202 Without lua ? 2023-12-16 18:42:11 -06:00
Akkadius a29a2321f1 Without fmt ? 2023-12-16 18:33:15 -06:00
Akkadius 5ff9407e26 Test 2023-12-16 18:13:43 -06:00
Akkadius 20e135fbc4 PCH main zone primitives 2023-12-16 18:05:20 -06:00
Akkadius e21c386bda Lua headers 2023-12-16 18:00:04 -06:00
Akkadius 73a85135b2 Another one 2023-12-16 17:55:02 -06:00
Akkadius 87b1dc4b03 Another one 2023-12-16 17:48:22 -06:00
Akkadius b2bf1d2b6f Different test 2023-12-16 17:37:58 -06:00
Akkadius 4a8b89f93a GCC test 2023-12-16 17:28:31 -06:00
Akkadius 1cccca45a0 Another run 2023-12-16 17:18:54 -06:00
Akkadius 8af4fb2330 Experiment with PCH 2023-12-16 17:11:23 -06:00
136 changed files with 3715 additions and 15095 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ volumes:
steps:
- name: Build Linux X64
image: akkadius/eqemu-server:v14
image: akkadius/eqemu-server:v13
environment:
GITHUB_TOKEN:
from_secret: GH_RELEASE_GITHUB_API_TOKEN
-76
View File
@@ -1,79 +1,3 @@
## [22.38.0] - 12/26/2023
### Bots
* Remove unnecessary error on SetItemReuse ([#3795](https://github.com/EQEmu/Server/pull/3795)) @nytmyr 2023-12-20
### Code
* Consolidate GetHateRandom(), GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC() ([#3794](https://github.com/EQEmu/Server/pull/3794)) @Kinglykrab 2023-12-25
* Race constants refactor ([#3782](https://github.com/EQEmu/Server/pull/3782)) @Akkadius 2023-12-23
### Database
* Fix issue with saylinks query in MySQL 8.0+ ([#3800](https://github.com/EQEmu/Server/pull/3800)) @Akkadius 2023-12-24
* Update faction mods with Live data ([#3799](https://github.com/EQEmu/Server/pull/3799)) @joligario 2023-12-23
### Fixes
* Disable Hide/Improved Hide on Trap damage ([#3791](https://github.com/EQEmu/Server/pull/3791)) @Kinglykrab 2023-12-19
* Fix Bard Invisibility Songs breaking every 4 ticks ([#3783](https://github.com/EQEmu/Server/pull/3783)) @Kinglykrab 2023-12-19
* Fix can_riposte parameter in DoMeleeSkillAttackDmg ([#3792](https://github.com/EQEmu/Server/pull/3792)) @Kinglykrab 2023-12-19
### Forage
* Add a rule to disabled using common_food_ids from the list in forage.cpp. currently set to enabled. ([#3796](https://github.com/EQEmu/Server/pull/3796)) @regneq 2023-12-22
### NPC
* Support for multiple emotes per type, emote variables ([#3801](https://github.com/EQEmu/Server/pull/3801)) @regneq 2023-12-25
### Quest API
* Add GetHateTopBot(), GetHateTopClient(), and GetHateTopNPC() to Perl/Lua ([#3793](https://github.com/EQEmu/Server/pull/3793)) @Kinglykrab 2023-12-22
* Add SummonItemIntoInventory() to Perl/Lua ([#3797](https://github.com/EQEmu/Server/pull/3797)) @Kinglykrab 2023-12-22
### Repositories
* Add ReplaceOne and ReplaceMany ([#3802](https://github.com/EQEmu/Server/pull/3802)) @Akkadius 2023-12-26
## [22.37.0] - 12/18/2023
### Bots
* Add ScanCloseMobs support to fix AEs ([#3786](https://github.com/EQEmu/Server/pull/3786)) @nytmyr 2023-12-18
* Expand ^itemuse options ([#3756](https://github.com/EQEmu/Server/pull/3756)) @nytmyr 2023-12-17
* Fix ^defensive from checking aggressive disciplines. ([#3787](https://github.com/EQEmu/Server/pull/3787)) @nytmyr 2023-12-18
* Fix ^oo autodefend from sending bots/pets to invalid haters ([#3772](https://github.com/EQEmu/Server/pull/3772)) @nytmyr 2023-12-16
* Fix unnecessary failed to save timer error ([#3788](https://github.com/EQEmu/Server/pull/3788)) @nytmyr 2023-12-18
* [Quest API] Add ^clickitem, ^timer, fix GetBestBotSpellForCure ([#3755](https://github.com/EQEmu/Server/pull/3755)) @nytmyr 2023-12-17
### CI
* Switch to use clang for Linux builds (speed) ([#3777](https://github.com/EQEmu/Server/pull/3777)) @Akkadius 2023-12-17
### Compilation
* Use pre-compiled headers for Windows (speed) ([#3778](https://github.com/EQEmu/Server/pull/3778)) @Akkadius 2023-12-18
### Fixes
* Drop Invisibility when hit by traps ([#3785](https://github.com/EQEmu/Server/pull/3785)) @Kinglykrab 2023-12-18
* Fix NPCs routing to 0.0, 0.0 on #summon ([#3780](https://github.com/EQEmu/Server/pull/3780)) @Kinglykrab 2023-12-18
* Fix bad merge @Akkadius 2023-12-17
* Fix issue with HOTBonusHealingSplitOverDuration Rule ([#3776](https://github.com/EQEmu/Server/pull/3776)) @Kinglykrab 2023-12-17
* Fixed the discrepacy with time using command #time and in quests. ([#3767](https://github.com/EQEmu/Server/pull/3767)) @regneq 2023-12-17
* Send Entity ID in Death Events to resolve #3721 ([#3779](https://github.com/EQEmu/Server/pull/3779)) @Kinglykrab 2023-12-18
### Quest API
* Add EVENT_ALT_CURRENCY_GAIN and EVENT_ALT_CURRENCY_LOSS to Perl/Lua ([#3734](https://github.com/EQEmu/Server/pull/3734)) @Kinglykrab 2023-12-17
* Add EVENT_CRYSTAL_GAIN and EVENT_CRYSTAL_LOSS to Perl/Lua ([#3735](https://github.com/EQEmu/Server/pull/3735)) @Kinglykrab 2023-12-17
* Add EVENT_LDON_POINTS_GAIN and EVENT_LDON_POINTS_LOSS to Perl/Lua ([#3742](https://github.com/EQEmu/Server/pull/3742)) @Kinglykrab 2023-12-17
* Add EVENT_LEVEL_UP and EVENT_LEVEL_DOWN to Bots ([#3750](https://github.com/EQEmu/Server/pull/3750)) @Kinglykrab 2023-12-17
* Add EVENT_LOOT_ADDED to Perl/Lua ([#3739](https://github.com/EQEmu/Server/pull/3739)) @Kinglykrab 2023-12-17
* Add GetNPCAggro() and SetNPCAggro() to Perl/Lua ([#3781](https://github.com/EQEmu/Server/pull/3781)) @Kinglykrab 2023-12-18
## [22.36.0] - 12/16/2023
### Bots
-1
View File
@@ -17,7 +17,6 @@ SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)
OPTION(EQEMU_BUILD_STATIC "Build with static linking" OFF)
OPTION(EQEMU_BUILD_PCH "Build with precompiled headers (Windows)" ON)
IF (EQEMU_BUILD_STATIC)
SET(BUILD_SHARED_LIBS OFF)
+4 -3
View File
@@ -787,13 +787,14 @@ INCLUDE_DIRECTORIES(Patches SocketLib StackWalker)
ADD_LIBRARY(common ${common_sources} ${common_headers} ${repositories})
IF(WIN32)
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h)
ENDIF(WIN32)
IF (UNIX)
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
ENDIF (UNIX)
IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h)
ENDIF()
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+1 -1
View File
@@ -15,7 +15,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <fmt/format.h>
#include <fmt/core.h>
#include "../common/global_define.h"
#include "../common/classes.h"
#include "data_verification.h"
+1 -1
View File
@@ -18,7 +18,7 @@
*
*/
#include <fmt/format.h>
#include <fmt/core.h>
#include "eqemu_command_handler.h"
#include "terminal_color.hpp"
#include "../platform.h"
@@ -5133,16 +5133,6 @@ CHANGE COLUMN `slot` `inventory_slot` mediumint(9) NOT NULL DEFAULT -1 AFTER `st
ALTER TABLE `starting_items`
CHANGE COLUMN `temporary` `class_list` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `id`;
)"
},
ManifestEntry{
.version = 9248,
.description = "2023_12_22_drop_npc_emotes_index.sql",
.check = "show index from npc_emotes where key_name = 'emoteid'",
.condition = "not_empty",
.match = "",
.sql = R"(
ALTER TABLE `npc_emotes` DROP INDEX `emoteid`;
)"
}
@@ -82,28 +82,6 @@ CREATE TABLE `bot_starting_items` (
`content_flags_disabled` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci;
)",
},
ManifestEntry{
.version = 9041,
.description = "2023_12_04_bot_timers.sql",
.check = "SHOW COLUMNS FROM `bot_timers` LIKE 'recast_time'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `bot_timers`
ADD COLUMN `recast_time` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `timer_value`,
ADD COLUMN `is_spell` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `recast_time`,
ADD COLUMN `is_disc` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `is_spell`,
ADD COLUMN `spell_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_disc`,
ADD COLUMN `is_item` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0 AFTER `spell_id`,
ADD COLUMN `item_id` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_item`;
ALTER TABLE `bot_timers`
DROP FOREIGN KEY `FK_bot_timers_1`;
ALTER TABLE `bot_timers`
DROP PRIMARY KEY;
ALTER TABLE `bot_timers`
ADD PRIMARY KEY (`bot_id`, `timer_id`, `spell_id`, `item_id`);
)"
}
// -- template; copy/paste this when you need to create a new entry
-6
View File
@@ -124,12 +124,6 @@ struct LDoNTrapTemplate
uint8 locked;
};
enum CrystalReclaimTypes
{
Ebon = 5,
Radiant = 4,
};
///////////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -22,7 +22,7 @@
#include "linked_list.h"
#include "path_manager.h"
#include <fstream>
#include <fmt/format.h>
#include <fmt/core.h>
struct LoginConfig {
std::string LoginHost;
+3 -2
View File
@@ -33,9 +33,10 @@
#endif
#endif
#include <fmt/format.h>
#undef FMT_HEADER_ONLY
#include <fmt/core.h>
#include "types.h"
namespace Logs {
enum DebugLevel {
General = 1, // 1 - Low-Level general debugging, useful info on single line
@@ -2,7 +2,7 @@
#include "../repositories/character_data_repository.h"
#include "../json/json_archive_single_line.h"
#include <vector>
#include <fmt/format.h>
#include <fmt/core.h>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
+1
View File
@@ -22,6 +22,7 @@
#include "../common/strings.h"
#include "../common/rulesys.h"
#include "../common/util/uuid.h"
#include <fmt/core.h>
#include <fmt/format.h>
const char* const DZ_REPLAY_TIMER_NAME = "Replay Timer"; // see December 14, 2016 patch notes
+2 -2
View File
@@ -96,12 +96,12 @@ bool IsOfEqualRace(int r1, int r2)
// TODO: add more values
switch (r1) {
case DARK_ELF:
if (r2 == Race::NeriakCitizen) {
if (r2 == RACE_NERIAK_CITIZEN_77) {
return true;
}
break;
case BARBARIAN:
if (r2 == Race::HalasCitizen) {
if (r2 == RACE_HALAS_CITIZEN_90) {
return true;
}
}
+1 -1
View File
@@ -35,7 +35,7 @@
#endif
#include <fmt/format.h>
#include <fmt/core.h>
#include <filesystem>
#include <iostream>
+17 -18
View File
@@ -801,35 +801,34 @@ int16 EQ::InventoryProfile::HasItemByLoreGroup(uint32 loregroup, uint8 where)
// Returns slot_id when there's one available, else SLOT_INVALID
int16 EQ::InventoryProfile::FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size, bool is_arrow)
{
const int16 last_bag_slot = RuleI(World, ExpansionSettings) & EQ::expansions::bitHoT ? EQ::invslot::slotGeneral10 : EQ::invslot::slotGeneral8;
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) { // Check basic inventory
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
// Check basic inventory
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
continue;
}
if (!GetItem(i)) {
return i; // Found available slot in personal inventory
}
if (!GetItem(i))
// Found available slot in personal inventory
return i;
}
if (!for_bag) {
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) {
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
continue;
}
const auto *inst = GetItem(i);
if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size) {
if (inst->GetItem()->BagType == item::BagTypeQuiver &&
inst->GetItem()->ItemType != item::ItemTypeArrow) {
const ItemInstance* inst = GetItem(i);
if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size)
{
if (inst->GetItem()->BagType == item::BagTypeQuiver && inst->GetItem()->ItemType != item::ItemTypeArrow)
{
continue;
}
const int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
const uint8 slots = inst->GetItem()->BagSlots;
for (uint8 j = invbag::SLOT_BEGIN; j < slots; j++) {
uint8 slots = inst->GetItem()->BagSlots;
uint8 j;
for (j = invbag::SLOT_BEGIN; j<slots; j++) {
if (!GetItem(base_slot_id + j)) {
// Found available slot within bag
return (base_slot_id + j);
+1 -1
View File
@@ -132,7 +132,7 @@ namespace EQ
// Swap items in inventory
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = Race::Doug, uint8 class_id = Class::None, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = RACE_DOUG_0, uint8 class_id = Class::None, uint16 deity_id = deity::DeityType::DeityUnknown, uint8 level = 0);
// Remove item from inventory
bool DeleteItem(int16 slot_id, int16 quantity = 0);
+1 -1
View File
@@ -19,7 +19,7 @@
*/
#include <cstring>
#include <fmt/format.h>
#include <fmt/core.h>
#include <csignal>
#include <vector>
#include "ip_util.h"
+1 -1
View File
@@ -1273,7 +1273,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
{
int race = Race::Doug;
int race = RACE_DOUG_0;
const auto item = GetItem();
if (item) {
race = item->BaneDmgRace;
+1 -1
View File
@@ -1,6 +1,6 @@
#include "console_server.h"
#include "../strings.h"
#include <fmt/format.h>
#include <fmt/core.h>
EQ::Net::ConsoleServer::ConsoleServer(const std::string &addr, int port)
{
+4 -4
View File
@@ -4,7 +4,7 @@
#include "../eqemu_logsys.h"
#include "../servertalk.h"
#include "../rulesys.h"
#include <fmt/format.h>
#include <fmt/core.h>
EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent, std::shared_ptr<TCPConnection> connection)
{
@@ -21,7 +21,7 @@ EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent,
m_connection->OnDisconnect(std::bind(&ConsoleServerConnection::OnDisconnect, this, std::placeholders::_1));
m_connection->Start();
ClearBuffer();
auto addr = m_connection->RemoteIP();
SendLine(fmt::format("Establishing connection from: {0}:{1}", addr, m_connection->RemotePort()));
@@ -85,12 +85,12 @@ void EQ::Net::ConsoleServerConnection::QueueMessage(const std::string &msg)
}
else {
std::string cmd(m_line, m_line + m_cursor);
size_t len = m_user.length() + 2 + cmd.length();
for (size_t i = 0; i < len; ++i) {
Send("\x08");
}
if (msg.length() < cmd.length()) {
Send(msg);
size_t blank_spaces = 2 + cmd.length() - msg.length();
+1 -1
View File
@@ -5,7 +5,7 @@
#include "crc32.h"
#include "../eqemu_logsys.h"
#include <zlib.h>
#include <fmt/format.h>
#include <fmt/core.h>
#include <sstream>
EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager()
+1 -1
View File
@@ -1,7 +1,7 @@
#include "packet.h"
#include "endian.h"
#include <cctype>
#include <fmt/format.h>
#include <fmt/core.h>
void EQ::Net::Packet::PutInt8(size_t offset, int8_t value)
{
+6 -6
View File
@@ -1,7 +1,7 @@
#include "websocket_server.h"
#include "../event/event_loop.h"
#include "../event/timer.h"
#include <fmt/format.h>
#include <fmt/core.h>
#include <map>
#include <unordered_set>
#include <array>
@@ -50,7 +50,7 @@ EQ::Net::WebsocketServer::WebsocketServer(const std::string &addr, int port)
if (iter != _impl->connections.end()) {
iter->second->GetTCPConnection()->Write(data, size);
}
return websocketpp::lib::error_code();
});
@@ -76,7 +76,7 @@ EQ::Net::WebsocketServer::WebsocketServer(const std::string &addr, int port)
_impl->login_handler = [](const WebsocketServerConnection* connection, const std::string& user, const std::string& pass) {
WebsocketLoginStatus ret;
ret.account_name = "admin";
if (connection->RemoteIP() == "127.0.0.1" || connection->RemoteIP() == "::") {
ret.logged_in = true;
return ret;
@@ -125,8 +125,8 @@ Json::Value EQ::Net::WebsocketServer::HandleRequest(WebsocketServerConnection *c
void EQ::Net::WebsocketServer::SetMethodHandler(const std::string &method, MethodHandler handler, int required_status)
{
//Reserved method names
if (method == "subscribe" ||
method == "unsubscribe" ||
if (method == "subscribe" ||
method == "unsubscribe" ||
method == "login") {
return;
}
@@ -171,7 +171,7 @@ Json::Value EQ::Net::WebsocketServer::Login(WebsocketServerConnection *connectio
auto user = params[0].asString();
auto pass = params[1].asString();
auto r = _impl->login_handler(connection, user, pass);
if (r.logged_in) {
+3 -3
View File
@@ -3,7 +3,7 @@
#include "../timer.h"
#include "../util/uuid.h"
#include <sstream>
#include <fmt/format.h>
#include <fmt/core.h>
struct EQ::Net::WebsocketServerConnection::Impl {
WebsocketServer *parent;
@@ -16,7 +16,7 @@ struct EQ::Net::WebsocketServerConnection::Impl {
int status;
};
EQ::Net::WebsocketServerConnection::WebsocketServerConnection(WebsocketServer *parent,
EQ::Net::WebsocketServerConnection::WebsocketServerConnection(WebsocketServer *parent,
std::shared_ptr<TCPConnection> connection,
std::shared_ptr<websocket_connection> ws_connection)
{
@@ -34,7 +34,7 @@ EQ::Net::WebsocketServerConnection::WebsocketServerConnection(WebsocketServer *p
connection->OnDisconnect([this](EQ::Net::TCPConnection *connection) {
_impl->parent->ReleaseConnection(this);
});
connection->OnRead([this](EQ::Net::TCPConnection *c, const unsigned char *buffer, size_t buffer_size) {
_impl->ws_connection->read_all((const char*)buffer, buffer_size);
});
+4 -4
View File
@@ -3868,8 +3868,8 @@ namespace RoF
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
)
{
PacketSize += 60;
@@ -4002,8 +4002,8 @@ namespace RoF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown18
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // unknown19
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
+4 -4
View File
@@ -4007,8 +4007,8 @@ namespace RoF2
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
)
{
PacketSize += 60;
@@ -4212,8 +4212,8 @@ namespace RoF2
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // These do something with OP_WeaponEquip1
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0xffffffff); // ^
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
+6 -6
View File
@@ -2507,8 +2507,8 @@ namespace SoD
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
)
{
PacketSize -= (sizeof(structs::Texture_Struct) * EQ::textures::materialCount);
@@ -2706,8 +2706,8 @@ namespace SoD
Buffer += sizeof(structs::Spawn_Struct_Position);
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
@@ -2733,8 +2733,8 @@ namespace SoD
}
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
+6 -6
View File
@@ -2779,8 +2779,8 @@ namespace UF
}
float SpawnSize = emu->size;
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
if (!((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
)
{
PacketSize -= (sizeof(structs::Texture_Struct) * EQ::textures::materialCount);
@@ -2982,8 +2982,8 @@ namespace UF
Buffer += sizeof(structs::Spawn_Struct_Position);
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
@@ -3018,8 +3018,8 @@ namespace UF
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
}
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
if ((emu->NPC == 0) || (emu->race <= RACE_GNOME_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
)
{
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
-5
View File
@@ -27,8 +27,3 @@
// fmt
#include <fmt/format.h>
// lua
#include "lua.hpp"
#include <luabind/luabind.hpp>
#include <luabind/object.hpp>
+6 -6
View File
@@ -1,17 +1,17 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2019 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
@@ -22,7 +22,7 @@
#include <string>
#include <list>
#include <fmt/format.h>
#include <fmt/core.h>
class DBcore;
@@ -37,7 +37,7 @@ namespace EQ
static bool AddProfanity(DBcore *db, std::string profanity);
static bool RemoveProfanity(DBcore *db, std::string profanity);
static void RedactMessage(char *message);
static void RedactMessage(std::string &message);
@@ -54,7 +54,7 @@ namespace EQ
static bool load_database_entries(DBcore *db);
static bool clear_database_entries(DBcore *db);
static bool check_for_existing_entry(const std::string& profanity);
};
} /*EQEmu*/
+755 -755
View File
File diff suppressed because it is too large Load Diff
+1471 -739
View File
File diff suppressed because it is too large Load Diff
@@ -16,19 +16,12 @@
#include "../../strings.h"
#include <ctime>
class BaseBotTimersRepository {
public:
struct BotTimers {
uint32_t bot_id;
uint32_t timer_id;
uint32_t timer_value;
uint32_t recast_time;
uint8_t is_spell;
uint8_t is_disc;
uint32_t spell_id;
uint8_t is_item;
uint32_t item_id;
};
static std::string PrimaryKey()
@@ -42,12 +35,6 @@ public:
"bot_id",
"timer_id",
"timer_value",
"recast_time",
"is_spell",
"is_disc",
"spell_id",
"is_item",
"item_id",
};
}
@@ -57,12 +44,6 @@ public:
"bot_id",
"timer_id",
"timer_value",
"recast_time",
"is_spell",
"is_disc",
"spell_id",
"is_item",
"item_id",
};
}
@@ -106,12 +87,6 @@ public:
e.bot_id = 0;
e.timer_id = 0;
e.timer_value = 0;
e.recast_time = 0;
e.is_spell = 0;
e.is_disc = 0;
e.spell_id = 0;
e.is_item = 0;
e.item_id = 0;
return e;
}
@@ -137,9 +112,8 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
bot_timers_id
)
);
@@ -151,12 +125,6 @@ public:
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
return e;
}
@@ -193,12 +161,6 @@ public:
v.push_back(columns[0] + " = " + std::to_string(e.bot_id));
v.push_back(columns[1] + " = " + std::to_string(e.timer_id));
v.push_back(columns[2] + " = " + std::to_string(e.timer_value));
v.push_back(columns[3] + " = " + std::to_string(e.recast_time));
v.push_back(columns[4] + " = " + std::to_string(e.is_spell));
v.push_back(columns[5] + " = " + std::to_string(e.is_disc));
v.push_back(columns[6] + " = " + std::to_string(e.spell_id));
v.push_back(columns[7] + " = " + std::to_string(e.is_item));
v.push_back(columns[8] + " = " + std::to_string(e.item_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -223,12 +185,6 @@ public:
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.timer_id));
v.push_back(std::to_string(e.timer_value));
v.push_back(std::to_string(e.recast_time));
v.push_back(std::to_string(e.is_spell));
v.push_back(std::to_string(e.is_disc));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.is_item));
v.push_back(std::to_string(e.item_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -261,12 +217,6 @@ public:
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.timer_id));
v.push_back(std::to_string(e.timer_value));
v.push_back(std::to_string(e.recast_time));
v.push_back(std::to_string(e.is_spell));
v.push_back(std::to_string(e.is_disc));
v.push_back(std::to_string(e.spell_id));
v.push_back(std::to_string(e.is_item));
v.push_back(std::to_string(e.item_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -303,12 +253,6 @@ public:
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
all_entries.push_back(e);
}
@@ -336,12 +280,6 @@ public:
e.bot_id = static_cast<uint32_t>(strtoul(row[0], nullptr, 10));
e.timer_id = static_cast<uint32_t>(strtoul(row[1], nullptr, 10));
e.timer_value = static_cast<uint32_t>(strtoul(row[2], nullptr, 10));
e.recast_time = static_cast<uint32_t>(strtoul(row[3], nullptr, 10));
e.is_spell = static_cast<uint8_t>(strtoul(row[4], nullptr, 10));
e.is_disc = static_cast<uint8_t>(strtoul(row[5], nullptr, 10));
e.spell_id = static_cast<uint32_t>(strtoul(row[6], nullptr, 10));
e.is_item = static_cast<uint8_t>(strtoul(row[7], nullptr, 10));
e.item_id = static_cast<uint32_t>(strtoul(row[8], nullptr, 10));
all_entries.push_back(e);
}
@@ -15,6 +15,7 @@
#include "../../database.h"
#include "../../strings.h"
#include <ctime>
#include <fmt/format.h>
class BaseCharacterExpeditionLockoutsRepository {
public:
@@ -16,7 +16,6 @@
#include "../../strings.h"
#include <ctime>
class BaseNpcEmotesRepository {
public:
struct NpcEmotes {
@@ -121,9 +120,8 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE {} = {} LIMIT 1",
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
npc_emotes_id
)
);
@@ -6,7 +6,7 @@
* Any modifications to base repositories are to be made by the generator only
*
* @generator ./utils/scripts/generators/repository-generator.pl
* @docs https://docs.eqemu.io/developer/repositories
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
*/
#ifndef EQEMU_BASE_{{TABLE_NAME_UPPER}}_REPOSITORY_H
@@ -319,62 +319,6 @@ public:
return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0);
}
static std::string BaseReplace()
{
return fmt::format(
"REPLACE INTO {} ({}) ",
TableName(),
ColumnsRaw()
);
}
static int ReplaceOne(
Database& db,
const {{TABLE_NAME_STRUCT}} &e
)
{
std::vector<std::string> v;
{{INSERT_ONE_ENTRIES}}
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseReplace(),
Strings::Implode(",", v)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int ReplaceMany(
Database& db,
const std::vector<{{TABLE_NAME_STRUCT}}> &entries
)
{
std::vector<std::string> insert_chunks;
for (auto &e: entries) {
std::vector<std::string> v;
{{INSERT_MANY_ENTRIES}}
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
std::vector<std::string> v;
auto results = db.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseReplace(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
};
#endif //EQEMU_BASE_{{TABLE_NAME_UPPER}}_REPOSITORY_H
+1 -1
View File
@@ -22,7 +22,7 @@
#include "strings.h"
#include <cstdlib>
#include <cstring>
#include <fmt/format.h>
#include <fmt/core.h>
#include "../common/repositories/rule_sets_repository.h"
#include "../common/repositories/rule_values_repository.h"
-4
View File
@@ -215,7 +215,6 @@ RULE_BOOL(Character, EnableRaidEXPModifier, true, "Enable or disable the raid ex
RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the raid experience modifier based on members in raid, default is true")
RULE_BOOL(Character, LeaveCursorMoneyOnCorpse, false, "Enable or disable leaving cursor money on player corpses")
RULE_BOOL(Character, ItemExtraSkillDamageCalcAsPercent, false, "If enabled, apply Item Extra Skill Damage as Percentage-based modifiers")
RULE_BOOL(Character, UseForageCommonFood, true, "If enabled, use the common foods specified in the code.")
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -657,9 +656,6 @@ RULE_BOOL(Bots, AllowPickpocketCommand, true, "Allows the use of the bot command
RULE_BOOL(Bots, BotHealOnLevel, false, "Setting whether a bot should heal completely when leveling. Default FALSE.")
RULE_INT(Bots, AutosaveIntervalSeconds, 300, "Number of seconds after which a timer is triggered which stores the bot data. The value 0 means no periodic automatic saving.")
RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hit bot owner rather than bot.")
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
RULE_BOOL(Bots, BotsCanClickItems, true, "Enabled the ability for bots to click items they have equipped. Default TRUE")
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
RULE_CATEGORY_END()
RULE_CATEGORY(Chat)
+1 -1
View File
@@ -376,7 +376,7 @@ std::string EQ::SayLinkEngine::InjectSaylinksIfNotExist(const char *message)
void EQ::SayLinkEngine::LoadCachedSaylinks()
{
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not REGEXP '[A-Z]' and phrase not REGEXP '[0-9]'");
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not REGEXP BINARY '[A-Z]' and phrase not REGEXP '[0-9]'");
LogSaylink("Loaded [{}] saylinks into cache", saylinks.size());
g_cached_saylinks = saylinks;
}
+1 -1
View File
@@ -18,7 +18,7 @@
#include <iostream>
#include <cstring>
#include <fmt/format.h>
#include <fmt/core.h>
#if defined(_MSC_VER) && _MSC_VER >= 1800
#include <algorithm>
+1 -1
View File
@@ -34,7 +34,7 @@
*/
#include "strings.h"
#include <fmt/format.h>
#include <fmt/core.h>
#include <algorithm>
#include <cctype>
+3 -3
View File
@@ -44,7 +44,7 @@
#include <tuple>
#include <type_traits>
#include <fmt/format.h>
#include <fmt/core.h>
#ifndef _WIN32
// this doesn't appear to affect linux-based systems..need feedback for _WIN64
@@ -206,7 +206,7 @@ const std::string NUM_TO_ENGLISH_Y[] = {
"Fifty ", "Sixty ", "Seventy ", "Eighty ", "Ninety "
};
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
// _WIN32 builds require that #include<fmt/core.h> be included in whatever code file the invocation is made from (no header files)
template<typename T1, typename T2>
std::vector<std::string> join_pair(
const std::string &glue,
@@ -239,7 +239,7 @@ std::vector<std::string> join_pair(
return output;
}
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
// _WIN32 builds require that #include<fmt/core.h> be included in whatever code file the invocation is made from (no header files)
template<typename T1, typename T2, typename T3, typename T4>
std::vector<std::string> join_tuple(
const std::string &glue,
+1 -1
View File
@@ -1,6 +1,6 @@
#include <cstring>
#include "strings.h"
#include <fmt/format.h>
#include <fmt/core.h>
#include <algorithm>
#include <cctype>
#include <cinttypes>
+1 -1
View File
@@ -1,6 +1,6 @@
#include <cstring>
#include "strings.h"
#include <fmt/format.h>
#include <fmt/core.h>
#include <algorithm>
#include <cctype>
+1 -1
View File
@@ -1,7 +1,7 @@
#include "uuid.h"
#include <ios>
#include <fmt/format.h>
#include <fmt/core.h>
#ifdef _WIN32
#include <objbase.h>
+3 -3
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.38.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.36.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,9 +42,9 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9248
#define CURRENT_BINARY_DATABASE_VERSION 9247
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040
#endif
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.38.0",
"version": "22.36.0",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
-8
View File
@@ -1,8 +0,0 @@
module constantconvert
go 1.18
require (
github.com/gammazero/deque v0.2.0 // indirect
github.com/gammazero/workerpool v1.1.3 // indirect
)
-4
View File
@@ -1,4 +0,0 @@
github.com/gammazero/deque v0.2.0 h1:SkieyNB4bg2/uZZLxvya0Pq6diUlwx7m2TeT7GAIWaA=
github.com/gammazero/deque v0.2.0/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU=
github.com/gammazero/workerpool v1.1.3 h1:WixN4xzukFoN0XSeXF6puqEqFTl2mECI9S6W44HWy9Q=
github.com/gammazero/workerpool v1.1.3/go.mod h1:wPjyBLDbyKnUn2XwwyD3EEwo9dHutia9/fwNmSHWACc=
-313
View File
@@ -1,313 +0,0 @@
package main
import (
"fmt"
"github.com/gammazero/workerpool"
"io/fs"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
)
func main() {
loadDefinitions()
// get processor count
wp := workerpool.New(runtime.NumCPU())
// loop through all files in current dir that are cpp files or h files
err := filepath.WalkDir("../../", func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
return nil
}
if !strings.Contains(path, ".cpp") && !strings.Contains(path, ".h") {
return nil
}
// if file ends with ".o" skip it
if strings.HasSuffix(path, ".o") {
return nil
}
var ignoreFiles = []string{
"submodules", "/libs", "utils/", "races.h", "backward", "database_update_manifest.cpp", "zonedb.h",
}
ignore := false
for _, ignoreString := range ignoreFiles {
if strings.Contains(path, ignoreString) {
ignore = true
break
}
}
if ignore {
return nil
}
wp.Submit(func() {
// open file for reading
// get file contents
contents, err := os.ReadFile(path)
if err != nil {
log.Fatalf("impossible to read file: %s", err)
}
content := string(contents)
wroteChanges := false
var newLines []string
for _, line := range strings.Split(content, "\n") {
newLine := line
// loop through oldDefs and see if any of them are in contents
for key, value := range oldDefs {
// combine all of the above contains into a slice
// loop through slice and if any of them are in line, continue
var ignoreMatches = []string{
"#define ", "MALE", "FEMALE", "_BIT", "LANG_",
}
ignore := false
for _, ignoreString := range ignoreMatches {
if strings.Contains(newLine, ignoreString) && !strings.Contains(newLine, "NPC_") {
ignore = true
break
}
}
if ignore {
continue
}
// below we hackishly use a series of specific string contains to avoid
// making blind and wrong replacements
// but hey - at least its 100% accurate :)
if strings.Contains(line, "case "+key+":") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, " "+key+":", " "+key2+":")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "\t"+key) {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "\t"+key, "\t"+key2)
wroteChanges = true
break
}
}
}
if strings.Contains(line, key+",") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, key+",", key2+",")
wroteChanges = true
break
}
}
}
if strings.Contains(line, ", "+key) {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, ", "+key, ", "+key2)
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+" ") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+" ", "= "+key2+" ")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+")") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+")", "= "+key2+")")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+";") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+";", "= "+key2+";")
wroteChanges = true
break
}
}
}
if strings.Contains(line, "= "+key+" ||") {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, "= "+key+" ||", "= "+key2+" ||")
wroteChanges = true
break
}
}
}
// match cases where our match is on the last line and last column
// we need to be exact in the last column and not do a partial because we can
// accidentally rename say OGRE to OGRE2 mistakenly
if strings.Contains(line, key) {
columns := strings.Split(line, " ")
// get the last column
lastColumn := strings.TrimSpace(columns[len(columns)-1])
if lastColumn == key {
for key2, value2 := range newDefs {
if value == value2 {
newLine = strings.ReplaceAll(newLine, lastColumn, key2)
wroteChanges = true
break
}
}
}
}
//if strings.Contains(line, "race == "+key) {
// for key2, value2 := range newDefs {
// if value == value2 {
// newLine = strings.ReplaceAll(newLine, "race == "+key, "race == "+key2)
// wroteChanges = true
// break
// }
// }
//}
}
newLines = append(newLines, newLine)
}
// write contents back to file
if wroteChanges {
fmt.Printf("wrote changes to file [%v]\n", path)
err = os.WriteFile(path, []byte(strings.Join(newLines, "\n")), 0644)
if err != nil {
log.Fatalf("impossible to write file: %s", err)
}
}
return
})
return nil
})
if err != nil {
log.Fatalf("impossible to walk directories: %s", err)
}
wp.StopWait()
}
var newDefs = make(map[string]int)
var oldDefs = make(map[string]int)
func loadDefinitions() {
// git show master:common/races.h
cmd := exec.Command("git", "show", "master:common/races.h")
out, err := cmd.Output()
if err != nil {
println(err.Error())
return
}
// load into a string -> int map
for _, line := range strings.Split(string(out), "\n") {
if strings.Contains(line, "#define ") {
if len(strings.Split(line, " ")) <= 2 {
continue
}
// ignore
// #define MALE 0
// #define FEMALE 1
// #define NEUTER 2
if strings.Contains(line, "#define MALE") {
continue
}
if strings.Contains(line, "#define FEMALE") {
continue
}
if strings.Contains(line, "#define NEUTER") {
continue
}
// load "#define RACE_FLYING_CARPET_720 720" into map
key := strings.Split(line, " ")[1]
value := strings.Split(line, " ")[2]
value = strings.ReplaceAll(value, "//", "")
value = strings.TrimSpace(value)
//fmt.Printf("key [%v] value [%v]\n", key, value)
if !strings.HasPrefix(key, "RACE_") && !strings.HasPrefix(key, "RT_") {
continue
}
// convert value to int
intValue, err := strconv.Atoi(value)
if err != nil {
println(err.Error())
return
}
oldDefs[key] = intValue
fmt.Printf("oldDefs key [%v] value [%v]\n", key, intValue)
}
}
// cleanup/races_cpp_h
cmd = exec.Command("git", "show", "cleanup/races_cpp_h:common/races.h")
out, err = cmd.Output()
if err != nil {
println(err.Error())
return
}
// load into a string -> int map
for _, line := range strings.Split(string(out), "\n") {
if strings.Contains(line, "constexpr uint16") {
if len(strings.Split(line, " ")) <= 2 {
continue
}
// remove all extra spaces in between characters in line
line = strings.Join(strings.Fields(line), " ")
// load " constexpr uint16 Doug = 0;" into map
key := strings.Split(line, " ")[2]
value := strings.Split(line, " ")[4]
value = strings.ReplaceAll(value, "//", "")
value = strings.ReplaceAll(value, ";", "")
value = strings.TrimSpace(value)
// convert value to int
intValue, err := strconv.Atoi(value)
if err != nil {
println(err.Error())
return
}
mapKey := "Race::" + key
newDefs[mapKey] = intValue
fmt.Printf("newDefs key [%v] value [%v]\n", mapKey, value)
}
}
}
+2 -2
View File
@@ -15,8 +15,8 @@ mkdir -p build && cd build && \
-DEQEMU_BUILD_LOGIN=ON \
-DEQEMU_BUILD_LUA=ON \
-DEQEMU_BUILD_PERL=ON \
-DCMAKE_CXX_FLAGS:STRING="-O1 -g -Wno-everything" \
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g -Wno-everything" \
-DCMAKE_CXX_FLAGS:STRING="-O1 -g" \
-DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING="-O1 -g" \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-G 'Unix Makefiles' \
.. && make -j$((`nproc`-4))
+1 -1
View File
@@ -10,7 +10,7 @@ require (
require (
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
)
+2 -2
View File
@@ -10,8 +10,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
File diff suppressed because it is too large Load Diff
+1 -3
View File
@@ -78,9 +78,7 @@ ADD_EXECUTABLE(world ${world_sources} ${world_headers})
INSTALL(TARGETS world RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(world PRIVATE ../common/pch/pch.h)
ENDIF ()
TARGET_PRECOMPILE_HEADERS(world PRIVATE ../common/pch/pch.h)
ADD_DEFINITIONS(-DWORLD)
+1
View File
@@ -35,6 +35,7 @@
#include "wguild_mgr.h"
#include "../common/zone_store.h"
#include <set>
#include <fmt/format.h>
extern WebInterfaceList web_interface;
+1 -1
View File
@@ -31,7 +31,7 @@
#include "../common/md5.h"
#include "eqemu_api_world_data_service.h"
#include "../common/zone_store.h"
#include <fmt/format.h>
#include <fmt/core.h>
extern ClientList client_list;
extern ZSList zoneserver_list;
+1
View File
@@ -7,6 +7,7 @@
#include "zoneserver.h"
#include "../common/eqemu_logsys.h"
#include "../common/repositories/instance_list_repository.h"
#include <fmt/format.h>
extern ClientList client_list;
extern ZSList zoneserver_list;
+1 -1
View File
@@ -18,7 +18,7 @@
*
*/
#include <fmt/format.h>
#include <fmt/core.h>
#include "clientlist.h"
#include "cliententry.h"
#include "eqemu_api_world_data_service.h"
+1
View File
@@ -23,6 +23,7 @@
#include "../common/repositories/expeditions_repository.h"
#include "../common/repositories/expedition_lockouts_repository.h"
#include "../common/repositories/dynamic_zone_members_repository.h"
#include <fmt/format.h>
void ExpeditionDatabase::PurgeExpiredExpeditions()
{
+1 -1
View File
@@ -434,7 +434,7 @@ int main(int argc, char **argv)
tod.year,
tod.month,
tod.day,
tod.hour - 1,
tod.hour,
tod.minute
);
}
+1
View File
@@ -16,6 +16,7 @@
#include "../common/repositories/completed_shared_task_activity_state_repository.h"
#include "../common/repositories/shared_task_dynamic_zones_repository.h"
#include <ctime>
#include <fmt/format.h>
extern ClientList client_list;
extern ZSList zoneserver_list;
+1
View File
@@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/event_sub.h"
#include "web_interface.h"
#include "../common/zone_store.h"
#include <fmt/format.h>
extern uint32 numzones;
extern EQ::Random emu_random;
+38 -33
View File
@@ -204,33 +204,6 @@ SET(zone_headers
hate_list.h
heal_rotation.h
horse.h
lua_bot.h
lua_bit.h
lua_client.h
lua_corpse.h
lua_door.h
lua_encounter.h
lua_entity.h
lua_entity_list.h
lua_expedition.h
lua_general.h
lua_group.h
lua_hate_list.h
lua_inventory.h
lua_item.h
lua_iteminst.h
lua_mob.h
lua_mod.h
lua_npc.h
lua_object.h
lua_packet.h
lua_parser.h
lua_parser_events.h
lua_ptr.h
lua_raid.h
lua_spawn.h
lua_spell.h
lua_stat_bonuses.h
map.h
masterentity.h
merc.h
@@ -280,15 +253,47 @@ SET(zone_headers
zone_reload.h
zone_cli.cpp)
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
SET (lua_headers
lua_bot.h
lua_bit.h
lua_client.h
lua_corpse.h
lua_door.h
lua_encounter.h
lua_entity.h
lua_entity_list.h
lua_expedition.h
lua_general.h
lua_group.h
lua_hate_list.h
lua_inventory.h
lua_item.h
lua_iteminst.h
lua_mob.h
lua_mod.h
lua_npc.h
lua_object.h
lua_packet.h
lua_parser.h
lua_parser_events.h
lua_ptr.h
lua_raid.h
lua_spawn.h
lua_spell.h
lua_stat_bonuses.h
)
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers} ${lua_headers})
INSTALL(TARGETS zone RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/pch/pch.h)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/types.h ../common/eqemu_logsys.h ../common/eqemu_logsys_log_aliases.h ../common/features.h ../common/global_define.h)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE mob.h npc.h corpse.h doors.h bot.h entity.h client.h zone.h)
ENDIF()
IF(WIN32)
TARGET_PRECOMPILE_HEADERS(zone PRIVATE pch.h)
ENDIF(WIN32)
#TARGET_PRECOMPILE_HEADERS(zone PRIVATE ../common/types.h ../common/eqemu_logsys.h ../common/eqemu_logsys_log_aliases.h ../common/features.h ../common/global_define.h)
#TARGET_PRECOMPILE_HEADERS(zone PRIVATE mob.h npc.h corpse.h doors.h bot.h entity.h client.h zone.h)
#TARGET_PRECOMPILE_HEADERS(zone PRIVATE ${lua_headers})
ADD_DEFINITIONS(-DZONE)
+5 -5
View File
@@ -46,7 +46,7 @@ void EntityList::DescribeAggro(Client *to_who, NPC *from_who, float d, bool verb
);
bool is_engaged = from_who->IsEngaged();
bool will_aggro_npcs = from_who->GetNPCAggro();
bool will_aggro_npcs = from_who->WillAggroNPCs();
if (is_engaged) {
Mob *top = from_who->GetHateTop();
to_who->Message(
@@ -983,14 +983,14 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
float size_mod = GetSize();
float other_size_mod = other->GetSize();
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) { //For races with a fixed size
if (GetRace() == RACE_LAVA_DRAGON_49 || GetRace() == RACE_WURM_158 || GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
size_mod = 60.0f;
}
else if (size_mod < 6.0) {
size_mod = 8.0f;
}
if (other->GetRace() == Race::LavaDragon || other->GetRace() == Race::Wurm || other->GetRace() == Race::GhostDragon) { //For races with a fixed size
if (other->GetRace() == RACE_LAVA_DRAGON_49 || other->GetRace() == RACE_WURM_158 || other->GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
other_size_mod = 60.0f;
}
else if (other_size_mod < 6.0) {
@@ -1011,11 +1011,11 @@ bool Mob::CombatRange(Mob* other, float fixed_size_mod, bool aeRampage, ExtraAtt
size_mod *= size_mod * 4;
}
if (other->GetRace() == Race::VeliousDragon) // Lord Vyemm and other velious dragons
if (other->GetRace() == RACE_VELIOUS_DRAGON_184) // Lord Vyemm and other velious dragons
{
size_mod *= 1.75;
}
if (other->GetRace() == Race::DragonSkeleton) // Dracoliche in Fear. Skeletal Dragon
if (other->GetRace() == RACE_DRAGON_SKELETON_122) // Dracoliche in Fear. Skeletal Dragon
{
size_mod *= 2.25;
}
+1 -1
View File
@@ -245,7 +245,7 @@ Json::Value ApiGetNpcListDetail(EQ::Net::WebsocketServerConnection *connection,
row["swarm_owner"] = npc->GetSwarmOwner();
row["swarm_target"] = npc->GetSwarmTarget();
row["waypoint_max"] = npc->GetWaypointMax();
row["npc_aggro"] = npc->GetNPCAggro();
row["will_aggro_npcs"] = npc->WillAggroNPCs();
response.append(row);
}
+67 -67
View File
@@ -1820,7 +1820,7 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
auto emote_id = killerMob->GetEmoteID();
if (emote_id) {
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid, this);
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid);
}
killerMob->TrySpellOnKill(killed_level, spell);
@@ -2705,69 +2705,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
Corpse* corpse = nullptr;
// Parse quests even if we're killed by an NPC
if (oos) {
if (IsNPC()) {
auto emote_id = GetEmoteID();
if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid, killer_mob);
}
}
if (oos->IsNPC()) {
if (parse->HasQuestSub(oos->GetNPCTypeID(), EVENT_NPC_SLAY)) {
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
}
auto emote_id = oos->GetEmoteID();
if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
}
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell);
}
}
}
if (killer_mob && killer_mob->IsBot()) {
if (parse->BotHasQuestSub(EVENT_NPC_SLAY)) {
parse->EventBot(EVENT_NPC_SLAY, killer_mob->CastToBot(), this, "", 0);
}
killer_mob->TrySpellOnKill(killed_level, spell);
}
m_combat_record.Stop();
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse };
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
}
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (parse->HasQuestSub(ZONE_CONTROLLER_NPC_ID, EVENT_DEATH_ZONE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse, this };
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
}
if (!HasOwner() && !IsMerc() && !GetSwarmInfo() && (!is_merchant || allow_merchant_corpse) &&
((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
@@ -2799,7 +2736,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
ApplyIllusionToCorpse(illusion_spell_id, corpse);
if (killer != 0 && emoteid != 0)
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer);
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid);
if (killer != 0 && killer->IsClient()) {
corpse->AllowPlayerLoot(killer, 0);
if (killer->IsGrouped()) {
@@ -2877,6 +2814,38 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.RemoveFromXTargets(this);
}
// Parse quests even if we're killed by an NPC
if (oos) {
if (IsNPC()) {
auto emote_id = GetEmoteID();
if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid);
}
}
if (oos->IsNPC()) {
if (parse->HasQuestSub(oos->GetNPCTypeID(), EVENT_NPC_SLAY)) {
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
}
auto emote_id = oos->GetEmoteID();
if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id);
}
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell);
}
}
}
if (killer_mob && killer_mob->IsBot()) {
if (parse->BotHasQuestSub(EVENT_NPC_SLAY)) {
parse->EventBot(EVENT_NPC_SLAY, killer_mob->CastToBot(), this, "", 0);
}
killer_mob->TrySpellOnKill(killed_level, spell);
}
WipeHateList();
p_depop = true;
@@ -2885,6 +2854,37 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.UpdateFindableNPCState(this, true);
m_combat_record.Stop();
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse };
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
}
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (parse->HasQuestSub(ZONE_CONTROLLER_NPC_ID, EVENT_DEATH_ZONE)) {
const auto& export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
std::vector<std::any> args = { corpse, this };
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
}
return true;
}
@@ -4087,7 +4087,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
IsPlayerRace(GetBaseRace()) &&
RuleI(Combat, FrontalStunImmunityRaces) & GetPlayerRaceBit(GetBaseRace())
) ||
GetBaseRace() == Race::OggokCitizen
GetBaseRace() == RACE_OGGOK_CITIZEN_93
) {
is_immune_to_frontal_stun = true;
}
@@ -4107,7 +4107,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
IsPlayerRace(GetBaseRace()) &&
RuleI(Combat, FrontalStunImmunityRaces) & GetPlayerRaceBit(GetBaseRace())
) ||
GetBaseRace() == Race::OggokCitizen
GetBaseRace() == RACE_OGGOK_CITIZEN_93
)
) {
is_immune_to_frontal_stun = true;
+44 -671
View File
@@ -94,7 +94,6 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
SetPullFlag(false);
SetPullingFlag(false);
SetReturningFlag(false);
SetIsUsingItemClick(false);
m_previous_pet_order = SPO_Guard;
rest_timer.Disable();
@@ -108,8 +107,6 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
// Do this once and only in this constructor
GenerateAppearance();
GenerateBaseStats();
bot_timers.clear();
// Calculate HitPoints Last As It Uses Base Stats
current_hp = GenerateBaseHitPoints();
current_mana = GenerateBaseManaPoints();
@@ -117,6 +114,8 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm
hp_regen = CalcHPRegen();
mana_regen = CalcManaRegen();
end_regen = CalcEnduranceRegen();
for (int i = 0; i < MaxTimer; i++)
timers[i] = 0;
strcpy(name, GetCleanName());
memset(&_botInspectMessage, 0, sizeof(InspectMessage_Struct));
@@ -214,7 +213,6 @@ Bot::Bot(
SetPullFlag(false);
SetPullingFlag(false);
SetReturningFlag(false);
SetIsUsingItemClick(false);
m_previous_pet_order = SPO_Guard;
rest_timer.Disable();
@@ -240,6 +238,9 @@ Bot::Bot(
error_message.clear();
}
for (int i = 0; i < MaxTimer; i++)
timers[i] = 0;
if (GetClass() == Class::Rogue) {
m_evade_timer.Start();
}
@@ -251,10 +252,8 @@ Bot::Bot(
GenerateBaseStats();
bot_timers.clear();
if (!database.botdb.LoadTimers(this) && bot_owner) {
if (!database.botdb.LoadTimers(this) && bot_owner)
bot_owner->Message(Chat::White, "%s for '%s'", BotDatabase::fail::LoadTimers(), GetCleanName());
}
LoadAAs();
@@ -1669,7 +1668,7 @@ bool Bot::Process()
mob_close_scan_timer.GetDuration()
);
entity_list.ScanCloseMobs(close_mobs, this, IsMoving());
entity_list.ScanCloseClientMobs(close_mobs, this);
}
SpellProcess();
@@ -2681,7 +2680,7 @@ void Bot::CalcMeleeDistances(const Mob* tar, const EQ::ItemInstance* const& p_it
float other_size_mod = tar->GetSize();
// For races with a fixed size
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) {
if (GetRace() == RT_DRAGON || GetRace() == RT_WURM || GetRace() == RT_DRAGON_7) {
// size_mod = 60.0f;
}
@@ -2690,7 +2689,7 @@ void Bot::CalcMeleeDistances(const Mob* tar, const EQ::ItemInstance* const& p_it
}
// For races with a fixed size
if (tar->GetRace() == Race::LavaDragon || tar->GetRace() == Race::Wurm || tar->GetRace() == Race::GhostDragon) {
if (tar->GetRace() == RT_DRAGON || tar->GetRace() == RT_WURM || tar->GetRace() == RT_DRAGON_7) {
other_size_mod = 60.0f;
}
@@ -2902,12 +2901,12 @@ void Bot::AcquireBotTarget(Group* bot_group, Raid* raid, Client* leash_owner, fl
}
} else {
// This will keep bots on target for now..but, future updates will allow for rooting/stunning
if (auto escaping = hate_list.GetEscapingMobOnHateList(leash_owner, leash_distance)) {
if (auto escaping = hate_list.GetEscapingEntOnHateList(leash_owner, leash_distance)) {
SetTarget(escaping);
}
if (!GetTarget()) {
auto most_hate = hate_list.GetMobWithMostHateOnList(this, nullptr, true);
auto most_hate = hate_list.GetEntWithMostHateOnList(this, nullptr, true);
if (most_hate) {
SetTarget(most_hate);
}
@@ -3639,45 +3638,41 @@ uint32 Bot::SpawnedBotCount(const uint32 owner_id, uint8 class_id) {
return spawned_bot_count;
}
void Bot::LevelBotWithClient(Client* c, uint8 new_level, bool send_appearance) {
void Bot::LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp) {
// This essentially performs a '#bot update,' with appearance packets, based on the current methods.
// This should not be called outside of Client::SetEXP() due to its lack of rule checks.
// This should not be called outside of Client::SetEXP() due to it's lack of rule checks.
if (client) {
std::list<Bot*> blist = entity_list.GetBotsByBotOwnerCharacterID(client->CharacterID());
if (c) {
const auto &l = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID());
for (auto biter = blist.begin(); biter != blist.end(); ++biter) {
Bot* bot = *biter;
for (const auto &e : l) {
if (e && (e->GetLevel() != c->GetLevel())) {
int levels_change = (new_level - e->GetLevel());
if (bot && (bot->GetLevel() != client->GetLevel())) {
bot->SetPetChooser(false); // not sure what this does, but was in bot 'update' code
bot->CalcBotStats(client->GetBotOption(Client::booStatsUpdate));
if (levels_change < 0) {
parse->EventBot(EVENT_LEVEL_DOWN, e, nullptr, std::to_string(std::abs(levels_change)), 0);
} else {
parse->EventBot(EVENT_LEVEL_UP, e, nullptr, std::to_string(levels_change), 0);
if (sendlvlapp) {
bot->SendLevelAppearance();
}
e->SetPetChooser(false); // not sure what this does, but was in bot 'update' code
e->CalcBotStats(c->GetBotOption(Client::booStatsUpdate));
if (send_appearance) {
e->SendLevelAppearance();
}
// modified from Client::SetLevel()
if (!RuleB(Bots, BotHealOnLevel)) {
const int64 max_hp = e->CalcMaxHP();
if (e->GetHP() > max_hp) {
e->SetHP(max_hp);
int mhp = bot->CalcMaxHP();
if (bot->GetHP() > mhp) {
bot->SetHP(mhp);
}
} else {
e->SetHP(e->CalcMaxHP());
e->SetMana(e->CalcMaxMana());
}
else {
bot->SetHP(bot->CalcMaxHP());
bot->SetMana(bot->CalcMaxMana());
}
e->SendHPUpdate();
e->SendAppearancePacket(AT_WhoLevel, new_level, true, true); // who level change
e->AI_AddBotSpells(e->GetBotSpellID());
bot->SendHPUpdate();
bot->SendAppearancePacket(AT_WhoLevel, level, true, true); // who level change
bot->AI_AddBotSpells(bot->GetBotSpellID());
}
}
blist.clear();
}
}
@@ -7917,17 +7912,18 @@ bool Bot::UseDiscipline(uint32 spell_id, uint32 target) {
return false;
if (spell.recast_time > 0) {
if (CheckDisciplineReuseTimer(spell_id)) {
if (spells[spell_id].timer_id > 0) {
SetDisciplineReuseTimer(spell_id);
}
if (CheckDisciplineRecastTimers(this, spells[spell_id].timer_id)) {
if (spells[spell_id].timer_id > 0 && spells[spell_id].timer_id < MAX_DISCIPLINE_TIMERS)
SetDisciplineRecastTimer(spells[spell_id].timer_id, spell.recast_time);
} else {
uint32 remaining_time = (GetDisciplineReuseRemainingTime(spell_id) / 1000);
OwnerMessage(
uint32 remaining_time = (GetDisciplineRemainingTime(this, spells[spell_id].timer_id) / 1000);
GetOwner()->Message(
Chat::White,
fmt::format(
"I can use this discipline in {}.",
"{} can use this discipline in {}.",
GetCleanName(),
Strings::SecondsToTime(remaining_time)
)
).c_str()
);
return false;
}
@@ -8810,627 +8806,4 @@ void Bot::AddBotStartingItems(uint16 race_id, uint8 class_id)
}
}
void Bot::SetSpellRecastTimer(uint16 spell_id, int32 recast_delay) {
if (!IsValidSpell(spell_id)) {
OwnerMessage("Failed to set spell recast timer.");
return;
}
if (!recast_delay) {
recast_delay = CalcSpellRecastTimer(spell_id);
}
if (CheckSpellRecastTimer(spell_id)) {
BotTimer_Struct t;
t.timer_id = spells[ spell_id ].timer_id;
t.timer_value = (Timer::GetCurrentTime() + recast_delay);
t.recast_time = recast_delay;
t.is_spell = true;
t.is_disc = false;
t.spell_id = spells[ spell_id ].id;
t.is_item = false;
t.item_id = 0;
bot_timers.push_back(t);
} else {
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (
bot_timers[i].is_spell &&
(
(
spells[spell_id].timer_id != 0 &&
spells[spell_id].timer_id == bot_timers[ i ].timer_id
) ||
bot_timers[i].spell_id == spell_id
)
) {
bot_timers[i].timer_value = (Timer::GetCurrentTime() + recast_delay);
bot_timers[i].recast_time = recast_delay;
break;
}
}
}
}
}
uint32 Bot::GetSpellRecastTimer(uint16 spell_id)
{
uint32 result = 0;
if (spell_id && !IsValidSpell(spell_id)) {
OwnerMessage("Failed to get spell recast timer.");
return result;
}
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (
bot_timers[i].is_spell &&
(
!spell_id ||
(
(
spells[spell_id].timer_id != 0 &&
spells[spell_id].timer_id == bot_timers[i].timer_id
) ||
bot_timers[i].spell_id == spell_id
)
)
) {
result = bot_timers[i].timer_value;
break;
}
}
}
return result;
}
uint32 Bot::GetSpellRecastRemainingTime(uint16 spell_id)
{
uint32 result = 0;
if (GetSpellRecastTimer(spell_id) > Timer::GetCurrentTime()) {
result = (GetSpellRecastTimer(spell_id) - Timer::GetCurrentTime());
}
return result;
}
bool Bot::CheckSpellRecastTimer(uint16 spell_id)
{
ClearExpiredTimers();
if (spell_id && !IsValidSpell(spell_id)) {
OwnerMessage("Failed to check spell recast timer.");
return false;
}
if (GetSpellRecastTimer(spell_id) < Timer::GetCurrentTime()) {
return true;
}
return false;
}
void Bot::SetDisciplineReuseTimer(uint16 spell_id, int32 reuse_timer)
{
if (!IsValidSpell(spell_id)) {
OwnerMessage("Failed to set discipline reuse timer.");
return;
}
if (!reuse_timer) {
reuse_timer = CalcSpellRecastTimer(spell_id);
}
if (CheckDisciplineReuseTimer(spell_id)) {
BotTimer_Struct t;
t.timer_id = spells[ spell_id ].timer_id;
t.timer_value = (Timer::GetCurrentTime() + reuse_timer);
t.recast_time = reuse_timer;
t.is_spell = false;
t.is_disc = true;
t.spell_id = spells[ spell_id ].id;
t.is_item = false;
t.item_id = 0;
bot_timers.push_back(t);
} else {
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (
bot_timers[i].is_disc &&
(
(
spells[spell_id].timer_id != 0 &&
spells[spell_id].timer_id == bot_timers[i].timer_id
) ||
bot_timers[i].spell_id == spell_id
)
) {
bot_timers[i].timer_value = (Timer::GetCurrentTime() + reuse_timer);
bot_timers[i].recast_time = reuse_timer;
break;
}
}
}
}
}
uint32 Bot::GetDisciplineReuseTimer(uint16 spell_id)
{
uint32 result = 0;
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (
bot_timers[i].is_disc &&
(
!spell_id ||
(
(
spells[spell_id].timer_id != 0 &&
spells[spell_id].timer_id == bot_timers[i].timer_id
) ||
bot_timers[i].spell_id == spell_id
)
)
) {
result = bot_timers[i].timer_value;
break;
}
}
}
return result;
}
uint32 Bot::GetDisciplineReuseRemainingTime(uint16 spell_id) {
uint32 result = 0;
if (GetDisciplineReuseTimer(spell_id) > Timer::GetCurrentTime()) {
result = (GetDisciplineReuseTimer(spell_id) - Timer::GetCurrentTime());
}
return result;
}
bool Bot::CheckDisciplineReuseTimer(uint16 spell_id)
{
ClearExpiredTimers();
if (GetDisciplineReuseTimer(spell_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer
return true; //can cast spell
}
return false;
}
void Bot::SetItemReuseTimer(uint32 item_id, uint32 reuse_timer)
{
const auto *item = database.GetItem(item_id);
if (!item) {
OwnerMessage("Failed to set item reuse timer.");
return;
}
if (item->RecastDelay <= 0) {
return;
}
if (CheckItemReuseTimer(item_id)) {
BotTimer_Struct t;
t.timer_id = (item->RecastType == NegativeItemReuse ? item->ID : item->RecastType);
t.timer_value = (
reuse_timer != 0 ?
(Timer::GetCurrentTime() + reuse_timer) :
(Timer::GetCurrentTime() + (item->RecastDelay * 1000))
);
t.recast_time = (reuse_timer != 0 ? reuse_timer : (item->RecastDelay * 1000));
t.is_spell = false;
t.is_disc = false;
t.spell_id = 0;
t.is_item = true;
t.item_id = item->ID;
bot_timers.push_back(t);
}
else {
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (
bot_timers[i].is_item &&
(
(
item->RecastType != 0 &&
item->RecastType == bot_timers[i].timer_id
) ||
bot_timers[i].item_id == item_id
)
) {
bot_timers[i].timer_value = (
reuse_timer != 0 ?
(Timer::GetCurrentTime() + reuse_timer) :
(Timer::GetCurrentTime() + (item->RecastDelay * 1000))
);
bot_timers[i].recast_time = (
reuse_timer != 0 ?
reuse_timer :
(item->RecastDelay * 1000)
);
break;
}
}
}
}
}
uint32 Bot::GetItemReuseTimer(uint32 item_id)
{
uint32 result = 0;
const EQ::ItemData* item;
if (item_id) {
item = database.GetItem(item_id);
if (!item) {
OwnerMessage("Failed to get item reuse timer.");
return result;
}
}
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (
bot_timers[i].is_item &&
(
!item_id ||
(
(
item->RecastType != 0 &&
item->RecastType == bot_timers[i].timer_id
) ||
bot_timers[i].item_id == item_id
)
)
) {
result = bot_timers[i].timer_value;
break;
}
}
}
ClearExpiredTimers();
return result;
}
bool Bot::CheckItemReuseTimer(uint32 item_id)
{
ClearExpiredTimers();
if (GetItemReuseTimer(item_id) < Timer::GetCurrentTime()) {
return true;
}
return false;
}
uint32 Bot::GetItemReuseRemainingTime(uint32 item_id)
{
uint32 result = 0;
if (GetItemReuseTimer(item_id) > Timer::GetCurrentTime()) {
result = (GetItemReuseTimer(item_id) - Timer::GetCurrentTime());
}
return result;
}
uint32 Bot::CalcSpellRecastTimer(uint16 spell_id)
{
uint32 result = 0;
if (spells[spell_id].recast_time == 0 && spells[spell_id].recovery_time == 0) {
return result;
} else {
if (spells[spell_id].recovery_time > spells[spell_id].recast_time) {
result = spells[spell_id].recovery_time;
} else {
result = spells[spell_id].recast_time;
}
}
return result;
}
void Bot::ClearDisciplineReuseTimer(uint16 spell_id)
{
if (spell_id && !IsValidSpell(spell_id)) {
OwnerMessage(
fmt::format(
"{} is not a valid spell ID.'",
spell_id
)
);
return;
}
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (
bot_timers[i].is_disc &&
bot_timers[i].timer_value >= Timer::GetCurrentTime()
) {
if (
!spell_id ||
(
(
spells[spell_id].timer_id != 0 &&
spells[spell_id].timer_id == bot_timers[i].timer_id
) ||
bot_timers[i].spell_id == spell_id
)
) {
bot_timers[i].timer_value = 0;
}
}
}
}
ClearExpiredTimers();
}
void Bot::ClearItemReuseTimer(uint32 item_id)
{
const EQ::ItemData* item;
if (item_id) {
item = database.GetItem(item_id);
if (!item) {
OwnerMessage(
fmt::format(
"{} is not a valid item ID.",
item_id
)
);
return;
}
}
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (bot_timers[i].is_item && bot_timers[i].timer_value >= Timer::GetCurrentTime()) {
if (
!item_id ||
(
(
item->RecastType != 0 &&
item->RecastType == bot_timers[i].timer_id
) ||
bot_timers[i].item_id == item_id
)
) {
bot_timers[i].timer_value = 0;
}
}
}
}
ClearExpiredTimers();
}
void Bot::ClearSpellRecastTimer(uint16 spell_id)
{
if (spell_id && !IsValidSpell(spell_id)) {
OwnerMessage(
fmt::format(
"{} is not a valid spell ID.",
spell_id
)
);
return;
}
if (!bot_timers.empty()) {
for (int i = 0; i < bot_timers.size(); i++) {
if (bot_timers[i].is_spell && bot_timers[i].timer_value >= Timer::GetCurrentTime()) {
if (
!spell_id ||
(
(
spells[spell_id].timer_id != 0 &&
spells[spell_id].timer_id == bot_timers[i].timer_id
) ||
bot_timers[i].spell_id == spell_id
)
) {
bot_timers[i].timer_value = 0;
}
}
}
}
ClearExpiredTimers();
}
void Bot::ClearExpiredTimers()
{
if (!bot_timers.empty()) {
int current = 0;
int end = bot_timers.size();
while (current < end) {
if (bot_timers[current].timer_value < Timer::GetCurrentTime()) {
bot_timers.erase(bot_timers.begin() + current);
} else {
current++;
}
end = bot_timers.size();
}
}
}
void Bot::TryItemClick(uint16 slot_id)
{
if (!GetOwner()) {
return;
}
const auto *inst = GetClickItem(slot_id);
if (!inst) {
return;
}
const auto *item = inst->GetItem();
if (!item) {
return;
}
if (!CheckItemReuseTimer(item->ID)) {
uint32 remaining_time = (GetItemReuseRemainingTime(item->ID) / 1000);
OwnerMessage(
fmt::format(
"I can use this item in {}.",
Strings::SecondsToTime(remaining_time)
)
);
return;
}
DoItemClick(item, slot_id);
}
EQ::ItemInstance *Bot::GetClickItem(uint16 slot_id)
{
EQ::ItemInstance* inst = nullptr;
const EQ::ItemData* item = nullptr;
inst = GetBotItem(slot_id);
if (!inst || !inst->GetItem()) {
return nullptr;
}
item = inst->GetItem();
if (item->ID == MAG_EPIC_1_0 && !RuleB(Bots, CanClickMageEpicV1)) {
OwnerMessage(
fmt::format(
"{} is currently disabled for bots to click.",
item->Name
)
);
return nullptr;
}
if (item->Click.Effect <= 0) {
OwnerMessage(
fmt::format(
"{} does not have a clickable effect.",
item->Name
)
);
return nullptr;
}
if (!IsValidSpell(item->Click.Effect)) {
OwnerMessage(
fmt::format(
"{} does not have a valid clickable effect.",
item->Name
)
);
return nullptr;
}
if (item->ReqLevel > GetLevel()) {
OwnerMessage(
fmt::format(
"I am below the level requirement of {} for {}.",
item->ReqLevel,
item->Name
)
);
return nullptr;
}
if (item->Click.Level2 > GetLevel()) {
OwnerMessage(
fmt::format(
"I must be level {} to use {}.",
item->Click.Level2,
item->Name
)
);
return nullptr;
}
if (inst->GetCharges() == 0) {
OwnerMessage(
fmt::format(
"{} is out of charges.",
item->Name
)
);
return nullptr;
}
return inst;
}
void Bot::DoItemClick(const EQ::ItemData *item, uint16 slot_id)
{
bool is_casting_bard_song = false;
Mob* tar = (GetOwner()->GetTarget() ? GetOwner()->GetTarget() : this);
if (IsCasting()) {
InterruptSpell();
}
SetIsUsingItemClick(true);
BotGroupSay(
this,
fmt::format(
"Attempting to cast [{}] on {}.",
spells[item->Click.Effect].name,
tar->GetCleanName()
).c_str()
);
if (!IsCastWhileInvisibleSpell(item->Click.Effect)) {
CommonBreakInvisible();
}
if (GetClass() == Class::Bard && IsCasting() && casting_spell_slot < EQ::spells::CastingSlot::MaxGems) {
is_casting_bard_song = true;
}
if (GetClass() == Class::Bard) {
DoBardCastingFromItemClick(is_casting_bard_song, item->CastTime, item->Click.Effect, tar->GetID(), EQ::spells::CastingSlot::Item, slot_id, item->RecastType, item->RecastDelay);
} else {
if (!CastSpell(item->Click.Effect, tar->GetID(), EQ::spells::CastingSlot::Item, item->CastTime, 0, 0, slot_id)) {
OwnerMessage(
fmt::format(
"Casting failed for {}. This could be due to zone restrictions, target restrictions or other limiting factors.",
item->Name
)
);
}
}
}
uint8 Bot::spell_casting_chances[SPELL_TYPE_COUNT][Class::PLAYER_CLASS_COUNT][EQ::constants::STANCE_TYPE_COUNT][cntHSND] = { 0 };
+13 -30
View File
@@ -42,12 +42,13 @@ constexpr uint32 BOT_FOLLOW_DISTANCE_DEFAULT_MAX = 2500; // as DSq value (50 uni
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
constexpr uint32 MAG_EPIC_1_0 = 28034;
extern WorldServer worldserver;
constexpr int BotAISpellRange = 100; // TODO: Write a method that calcs what the bot's spell range is based on spell, equipment, AA, whatever and replace this
constexpr int NegativeItemReuse = -1; // Unlinked timer for items
constexpr int MaxSpellTimer = 15;
constexpr int MaxDisciplineTimer = 10;
constexpr int DisciplineReuseStart = MaxSpellTimer + 1;
constexpr int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
// nHSND negative Healer/Slower/Nuker/Doter
// pH positive Healer
@@ -221,8 +222,6 @@ public:
void SetPullFlag(bool flag = true) { m_pull_flag = flag; }
bool GetPullingFlag() const { return m_pulling_flag; }
bool GetReturningFlag() const { return m_returning_flag; }
bool GetIsUsingItemClick() { return is_using_item_click; }
void SetIsUsingItemClick(bool flag = true) { is_using_item_click = flag; }
bool UseDiscipline(uint32 spell_id, uint32 target);
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid);
uint8 GetNumberNeedingHealedInRaidGroup(uint8& need_healed, uint8 hpr, bool includePets, Raid* raid);
@@ -287,10 +286,6 @@ public:
void SetEndurance(int32 newEnd) override;
void DoEnduranceUpkeep();
void TryItemClick(uint16 slot_id);
EQ::ItemInstance* GetClickItem(uint16 slot_id);
void DoItemClick(const EQ::ItemData* inst, uint16 slot_id);
bool AI_AddBotSpells(uint32 bot_spell_id);
void AddSpellToBotList(
int16 iPriority,
@@ -413,6 +408,11 @@ public:
static Bot* GetFirstBotInGroup(Group* group);
static void ProcessClientZoneChange(Client* botOwner);
static void ProcessBotOwnerRefDelete(Mob* botOwner); // Removes a Client* reference when the Client object is destroyed
static int32 GetSpellRecastTimer(Bot *caster, int timer_index);
static bool CheckSpellRecastTimers(Bot *caster, int SpellIndex);
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
//Raid methods
static void ProcessRaidInvite(Mob* invitee, Client* invitor, bool group_invite = false);
@@ -612,23 +612,8 @@ public:
_botStance = EQ::constants::stancePassive;
}
void SetBotCasterRange(uint32 bot_caster_range) { m_bot_caster_range = bot_caster_range; }
uint32 GetSpellRecastTimer(uint16 spell_id = 0);
bool CheckSpellRecastTimer(uint16 spell_id = 0);
uint32 GetSpellRecastRemainingTime(uint16 spell_id = 0);
void SetSpellRecastTimer(uint16 spell_id, int32 recast_delay = 0);
uint32 CalcSpellRecastTimer(uint16 spell_id);
uint32 GetDisciplineReuseTimer(uint16 spell_id = 0);
bool CheckDisciplineReuseTimer(uint16 spell_id = 0);
uint32 GetDisciplineReuseRemainingTime(uint16 spell_id = 0);
void SetDisciplineReuseTimer(uint16 spell_id, int32 reuse_timer = 0);
uint32 GetItemReuseTimer(uint32 item_id = 0);
bool CheckItemReuseTimer(uint32 item_id = 0);
void SetItemReuseTimer(uint32 item_id, uint32 reuse_timer = 0);
void ClearDisciplineReuseTimer(uint16 spell_id = 0);
void ClearItemReuseTimer(uint32 item_id = 0);
void ClearSpellRecastTimer(uint16 spell_id = 0);
uint32 GetItemReuseRemainingTime(uint32 item_id = 0);
void ClearExpiredTimers();
void SetSpellRecastTimer(int timer_index, int32 recast_delay);
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;}
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
void SetBeardColor(uint8 value) { beardcolor = value; }
@@ -728,8 +713,7 @@ public:
// New accessors for BotDatabase access
bool DeleteBot();
std::vector<BotTimer_Struct> GetBotTimers() { return bot_timers; }
void SetBotTimers(std::vector<BotTimer_Struct> timers) { bot_timers = timers; }
uint32* GetTimers() { return timers; }
uint32 GetLastZoneID() const { return _lastZoneId; }
int32 GetBaseAC() const { return _baseAC; }
int32 GetBaseATK() const { return _baseATK; }
@@ -844,7 +828,6 @@ protected:
std::vector<BotSpells_Struct> AIBot_spells;
std::vector<BotSpells_Struct> AIBot_spells_enforced;
std::vector<BotTimer_Struct> bot_timers;
private:
// Class Members
@@ -878,6 +861,7 @@ private:
int32 cur_end;
int32 max_end;
int32 end_regen;
uint32 timers[MaxTimer];
Timer m_evade_timer; // can be moved to pTimers at some point
Timer m_alt_combat_hate_timer;
@@ -891,7 +875,6 @@ private:
bool m_pull_flag;
bool m_pulling_flag;
bool m_returning_flag;
bool is_using_item_click;
eStandingPetOrder m_previous_pet_order;
uint32 m_bot_caster_range;
BotCastingRoles m_CastingRoles;
+18 -355
View File
@@ -65,7 +65,7 @@
#include "dialogue_window.h"
#include "mob.h"
#include <fmt/format.h>
#include <fmt/core.h>
extern QueryServ* QServ;
extern WorldServer worldserver;
@@ -1375,7 +1375,6 @@ int bot_command_init(void)
bot_command_add("casterrange", "Controls the range casters will try to stay away from a mob (if too far, they will skip spells that are out-of-range)", AccountStatus::Player, bot_command_caster_range) ||
bot_command_add("charm", "Attempts to have a bot charm your target", AccountStatus::Player, bot_command_charm) ||
bot_command_add("circle", "Orders a Druid bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_subcommand_circle) ||
bot_command_add("clickitem", "Orders your targeted bot to click the item in the provided inventory slot.", AccountStatus::Player, bot_command_click_item) ||
bot_command_add("cure", "Orders a bot to remove any ailments", AccountStatus::Player, bot_command_cure) ||
bot_command_add("defensive", "Orders a bot to use a defensive discipline", AccountStatus::Player, bot_command_defensive) ||
bot_command_add("depart", "Orders a bot to open a magical doorway to a specified destination", AccountStatus::Player, bot_command_depart) ||
@@ -1445,7 +1444,6 @@ int bot_command_init(void)
bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", AccountStatus::Player, bot_command_summon_corpse) ||
bot_command_add("suspend", "Suspends a bot's AI processing until released", AccountStatus::Player, bot_command_suspend) ||
bot_command_add("taunt", "Toggles taunt use by a bot", AccountStatus::Player, bot_command_taunt) ||
bot_command_add("timer", "Checks or clears timers of the chosen type.", AccountStatus::GMMgmt, bot_command_timer) ||
bot_command_add("track", "Orders a capable bot to track enemies", AccountStatus::Player, bot_command_track) ||
bot_command_add("viewcombos", "Views bot race class combinations", AccountStatus::Player, bot_command_view_combos) ||
bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", AccountStatus::Player, bot_command_water_breathing)
@@ -2834,7 +2832,7 @@ void bot_command_aggressive(Client *c, const Seperator *sep)
}
}
c->Message(Chat::White, "%i of %i bots have attempted to use aggressive disciplines", success_count, candidate_count);
c->Message(Chat::White, "%i of %i bots have used aggressive disciplines", success_count, candidate_count);
}
void bot_command_apply_poison(Client *c, const Seperator *sep)
@@ -3302,7 +3300,7 @@ void bot_command_defensive(Client *c, const Seperator *sep)
auto local_entry = list_iter->SafeCastToStance();
if (helper_spell_check_fail(local_entry))
continue;
if (local_entry->stance_type != BCEnum::StT_Defensive)
if (local_entry->stance_type != BCEnum::StT_Aggressive)
continue;
for (auto bot_iter = sbl.begin(); bot_iter != sbl.end(); ) {
@@ -3334,7 +3332,7 @@ void bot_command_defensive(Client *c, const Seperator *sep)
}
}
c->Message(Chat::White, "%i of %i bots have attempted to use defensive disciplines", success_count, candidate_count);
c->Message(Chat::White, "%i of %i bots have used defensive disciplines", success_count, candidate_count);
}
void bot_command_depart(Client *c, const Seperator *sep)
@@ -3908,77 +3906,16 @@ void bot_command_invisibility(Client *c, const Seperator *sep)
void bot_command_item_use(Client* c, const Seperator* sep)
{
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: [%s empty] will display only bots that can use the item in an empty slot.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s byclass classID] - Example: [%s byclass 7] will display only bots that match the class that can use the item. Example is a Monk, use [^create help] for a list of class IDs.", sep->arg[0], sep->arg[0]);
c->Message(Chat::White, "usage: [%s casteronly] will display only caster bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s hybridonly] will display only hybrid bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s meleeonly] will display only melee bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s wiscasteronly] will display only Wisdom-based Caster bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s intcasteronly] will display only Intelligence-based Caster bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s plateonly] will display only Plate-wearing bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s chainonly] will display only Chain-wearing bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s leatheronly] will display only Leather-wearing bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: [%s clothonly] will display only Cloth-wearing bots that can use the item.", sep->arg[0]);
c->Message(Chat::White, "usage: %s ([empty])", sep->arg[0]);
return;
}
bool empty_only = false;
int8 class_mask = 0;
bool caster_only = false;
bool hybrid_only = false;
bool melee_only = false;
bool wis_caster_only = false;
bool int_caster_only = false;
bool plate_only = false;
bool chain_only = false;
bool leather_only = false;
bool cloth_only = false;
std::string arg1 = sep->arg[1];
std::string arg2 = sep->arg[2];
if (arg1.compare("empty") == 0) {
empty_only = true;
}
else if (arg1.compare("byclass") == 0) {
if (Strings::IsNumber(sep->arg[2])) {
class_mask = Strings::ToUnsignedInt(sep->arg[2]);
if (!(class_mask >= Class::Warrior && class_mask <= Class::Berserker)) {
c->Message(Chat::White, "Invalid class range, you must choose between 1 (Warrior) and 15 (Beastlord)");
return;
}
}
}
else if (arg1.compare("casteronly") == 0) {
caster_only = true;
}
else if (arg1.compare("hybridonly") == 0) {
hybrid_only = true;
}
else if (arg1.compare("meleeonly") == 0) {
melee_only = true;
}
else if (arg1.compare("wiscasteronly") == 0) {
wis_caster_only = true;
}
else if (arg1.compare("intcasteronly") == 0) {
int_caster_only = true;
}
else if (arg1.compare("plateonly") == 0) {
plate_only = true;
}
else if (arg1.compare("chainonly") == 0) {
chain_only = true;
}
else if (arg1.compare("leatheronly") == 0) {
leather_only = true;
}
else if (arg1.compare("clothonly") == 0) {
cloth_only = true;
}
else if (!arg1.empty()) {
c->Message(Chat::White, "Please choose the correct subtype. For help use %s help.", sep->arg[0]);
return;
}
const auto item_instance = c->GetInv().GetItem(EQ::invslot::slotCursor);
if (!item_instance) {
c->Message(Chat::White, "No item found on cursor!");
@@ -4011,41 +3948,11 @@ void bot_command_item_use(Client* c, const Seperator* sep)
std::list<Bot*> sbl;
MyBots::PopulateSBL_BySpawnedBots(c, sbl);
if (class_mask) {
ActionableBots::Filter_ByClasses(c, sbl, GetPlayerClassBit(class_mask));
}
for (const auto& bot_iter : sbl) {
if (!bot_iter) {
continue;
}
if (caster_only && !IsCasterClass(bot_iter->GetClass())) {
continue;
}
if (hybrid_only && !IsSpellFighterClass(bot_iter->GetClass())) {
continue;
}
if (melee_only && !IsNonSpellFighterClass(bot_iter->GetClass())) {
continue;
}
if (wis_caster_only && !IsWISCasterClass(bot_iter->GetClass())) {
continue;
}
if (int_caster_only && !IsINTCasterClass(bot_iter->GetClass())) {
continue;
}
if (plate_only && !IsPlateClass(bot_iter->GetClass())) {
continue;
}
if (chain_only && !IsChainClass(bot_iter->GetClass())) {
continue;
}
if (leather_only && !IsLeatherClass(bot_iter->GetClass())) {
continue;
}
if (cloth_only && !IsClothClass(bot_iter->GetClass())) {
continue;
}
if (((~item_data->Races) & GetPlayerRaceBit(bot_iter->GetRace())) || ((~item_data->Classes) & GetPlayerClassBit(bot_iter->GetClass()))) {
continue;
}
@@ -4090,8 +3997,7 @@ void bot_command_item_use(Client* c, const Seperator* sep)
);
bot_iter->DoAnim(29);
}
else if (!equipped_item) {
} else if (!equipped_item) {
c->Message(
Chat::Say,
fmt::format(
@@ -5288,194 +5194,6 @@ void bot_command_taunt(Client *c, const Seperator *sep)
}
}
void bot_command_timer(Client* c, const Seperator* sep)
{
if (helper_command_alias_fail(c, "bot_command_timer", sep->arg[0], "timer"))
return;
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: %s [clear | has | set] [disc | item | spell] [timer ID | item ID | spell ID | all] [optional ms for set] [actionable].", sep->arg[0]);
c->Message(Chat::White, "When setting, you can leave the value blank to use the default for the item or specify a value in ms to set the timer to.");
c->Message(Chat::White, "Returns or sets the provided timer(s) for the selected bot(s) or clears the selected timer(s) for the selected bot(s).");
return;
}
const int ab_mask = ActionableBots::ABM_Type1;
std::string arg1 = sep->arg[1];
std::string arg2 = sep->arg[2];
std::string arg3 = sep->arg[3];
int ab_arg = 4;
bool clear = false;
bool has = false;
bool set = false;
bool disc = false;
bool item = false;
bool spell = false;
uint32 timer_id = 0;
uint32 timer_value = 0;
bool all = false;
if (!arg1.compare("clear")) {
clear = true;
}
else if (!arg1.compare("has")) {
has = true;
}
else if (!arg1.compare("set")) {
set = true;
}
else {
c->Message(Chat::White, "Incorrect argument, use %s help for a list of options.", sep->arg[0]);
return;
}
if (!arg2.compare("disc")) {
disc = true;
}
else if (!arg2.compare("item")) {
item = true;
}
else if (!arg2.compare("spell")) {
spell = true;
}
else {
c->Message(Chat::White, "Incorrect timer type, use %s help for a list of options.", sep->arg[0]);
return;
}
if (sep->IsNumber(3)) {
timer_id = atoi(sep->arg[3]);
if (timer_id < 0) {
c->Message(Chat::White, "You cannot use negative numbers.");
return;
}
}
else if (!arg3.compare("all")) {
if (has || set) {
c->Message(Chat::White, "You can only use 'all' for clearing timers.");
return;
}
all = true;
}
else {
c->Message(Chat::White, "Incorrect ID option, use %s help for a list of options.", sep->arg[0]);
return;
}
if (set) {
if (sep->IsNumber(4)) {
ab_arg = 5;
timer_value = atoi(sep->arg[4]);
if (timer_value <= 0) {
c->Message(Chat::White, "You cannot use 0 or negative numbers.");
return;
}
}
}
std::string class_race_arg = sep->arg[ab_arg];
bool class_race_check = false;
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
class_race_check = true;
}
std::list<Bot*> sbl;
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
return;
}
sbl.remove(nullptr);
for (auto my_bot : sbl) {
bool found = false;
if (clear) {
c->Message(
Chat::White,
fmt::format(
"{} says, 'Clearing {} timer{}'",
my_bot->GetCleanName(),
disc ? "Discipline" : item ? "Item" : "Spell",
(all ? "s." : ".")
).c_str()
);
if (disc) {
my_bot->ClearDisciplineReuseTimer(timer_id);
}
else if (item) {
my_bot->ClearItemReuseTimer(timer_id);
}
else if (spell) {
my_bot->ClearSpellRecastTimer(timer_id);
}
}
else if (has) {
uint32 remaining_time;
std::string time_string = "";
if (disc) {
if (!my_bot->CheckDisciplineReuseTimer(timer_id)) {
remaining_time = my_bot->GetDisciplineReuseRemainingTime(timer_id) / 1000;
time_string = Strings::SecondsToTime(remaining_time);
found = true;
}
}
else if (item) {
if (!my_bot->CheckItemReuseTimer(timer_id)) {
remaining_time = my_bot->GetItemReuseRemainingTime(timer_id) / 1000;
time_string = Strings::SecondsToTime(remaining_time);
found = true;
}
}
else if (spell) {
if (!my_bot->CheckSpellRecastTimer(timer_id)) {
remaining_time = my_bot->GetSpellRecastRemainingTime(timer_id) / 1000;
time_string = Strings::SecondsToTime(remaining_time);
found = true;
}
}
c->Message(
Chat::White,
fmt::format(
"{} says, 'I {}{}{}'",
my_bot->GetCleanName(),
(!found ? " do not have that timer currently" : " have "),
(!found ? "" : time_string),
(!found ? "." : " remaining.")
).c_str()
);
}
else if (set) {
c->Message(
Chat::White,
fmt::format(
"{} says, 'Setting {} timer{} for {} to {}.'",
my_bot->GetCleanName(),
disc ? "Discipline" : item ? "Item" : "Spell",
(all ? "s" : ""),
timer_id,
timer_value ? std::to_string(timer_value) : "the default value"
).c_str()
);
if (disc) {
my_bot->ClearDisciplineReuseTimer(timer_id);
my_bot->SetDisciplineReuseTimer(timer_id, timer_value);
}
else if (item) {
my_bot->ClearItemReuseTimer(timer_id);
my_bot->SetItemReuseTimer(timer_id, timer_value);
}
else if (spell) {
my_bot->ClearSpellRecastTimer(timer_id);
my_bot->SetSpellRecastTimer(timer_id, timer_value);
}
}
}
}
void bot_command_track(Client *c, const Seperator *sep)
{
if (helper_command_alias_fail(c, "bot_command_track", sep->arg[0], "track"))
@@ -5913,11 +5631,11 @@ void bot_command_view_combos(Client *c, const Seperator *sep)
};
const uint16 race_values[17] = {
Race::Doug,
Race::Human, Race::Barbarian, Race::Erudite, Race::WoodElf,
Race::HighElf, Race::DarkElf, Race::HalfElf, Race::Dwarf,
Race::Troll, Race::Ogre, Race::Halfling, Race::Gnome,
Race::Iksar, Race::VahShir, Race::Froglok2, Race::Drakkin
RACE_DOUG_0,
RACE_HUMAN_1, RACE_BARBARIAN_2, RACE_ERUDITE_3, RACE_WOOD_ELF_4,
RACE_HIGH_ELF_5, RACE_DARK_ELF_6, RACE_HALF_ELF_7, RACE_DWARF_8,
RACE_TROLL_9, RACE_OGRE_10, RACE_HALFLING_11, RACE_GNOME_12,
RACE_IKSAR_128, RACE_VAH_SHIR_130, RACE_FROGLOK_330, RACE_DRAKKIN_522
};
if (helper_command_alias_fail(c, "bot_command_view_combos", sep->arg[0], "viewcombos")) {
@@ -6028,11 +5746,11 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep)
};
const uint16 race_values[17] = {
Race::Doug,
Race::Human, Race::Barbarian, Race::Erudite, Race::WoodElf,
Race::HighElf, Race::DarkElf, Race::HalfElf, Race::Dwarf,
Race::Troll, Race::Ogre, Race::Halfling, Race::Gnome,
Race::Iksar, Race::VahShir, Race::Froglok2, Race::Drakkin
RACE_DOUG_0,
RACE_HUMAN_1, RACE_BARBARIAN_2, RACE_ERUDITE_3, RACE_WOOD_ELF_4,
RACE_HIGH_ELF_5, RACE_DARK_ELF_6, RACE_HALF_ELF_7, RACE_DWARF_8,
RACE_TROLL_9, RACE_OGRE_10, RACE_HALFLING_11, RACE_GNOME_12,
RACE_IKSAR_128, RACE_VAH_SHIR_130, RACE_FROGLOK_330, RACE_DRAKKIN_522
};
const std::string gender_substrs[2] = {
@@ -10720,61 +10438,6 @@ void bot_command_caster_range(Client* c, const Seperator* sep)
}
}
void bot_command_click_item(Client* c, const Seperator* sep)
{
if (!RuleB(Bots, BotsCanClickItems)) {
c->Message(Chat::White, "The ability for bots to click equipped items is currently disabled.");
return;
}
if (helper_is_help_or_usage(sep->arg[1])) {
c->Message(Chat::White, "usage: <slot id> %s ([actionable: target | byname | ownergroup | ownerraid | targetgroup | namesgroup | byclass | byrace | spawned] ([actionable_name]))", sep->arg[0]);
c->Message(Chat::White, "This will cause the selected bots to click the item in the given slot ID.");
c->Message(Chat::White, "Use ^invlist to see their items along with slot IDs.");
return;
}
if (!sep->IsNumber(1)) {
c->Message(Chat::Yellow, "You must specify a slot ID. Use %s help for more information.", sep->arg[0]);
return;
}
const int ab_mask = ActionableBots::ABM_Type1;
int ab_arg = 1;
uint32 slot_id = 0;
if (sep->IsNumber(1)) {
ab_arg = 2;
slot_id = atoi(sep->arg[1]);
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
c->Message(Chat::Yellow, "You must specify a valid inventory slot from 0 to 22. Use %s help for more information", sep->arg[0]);
return;
}
}
std::string class_race_arg = sep->arg[ab_arg];
bool class_race_check = false;
if (!class_race_arg.compare("byclass") || !class_race_arg.compare("byrace")) {
class_race_check = true;
}
std::list<Bot*> sbl;
if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, !class_race_check ? sep->arg[ab_arg + 1] : nullptr, class_race_check ? atoi(sep->arg[ab_arg + 1]) : 0) == ActionableBots::ABT_None) {
return;
}
sbl.remove(nullptr);
for (auto my_bot : sbl) {
if (RuleI(Bots, BotsClickItemsMinLvl) > my_bot->GetLevel()) {
c->Message(Chat::White, "%s must be level %i to use clickable items.", my_bot->GetCleanName(), RuleI(Bots, BotsClickItemsMinLvl));
continue;
}
my_bot->TryItemClick(slot_id);
}
}
void bot_command_pickpocket(Client *c, const Seperator *sep)
{
if (helper_command_disabled(c, RuleB(Bots, AllowPickpocketCommand), "pickpocket")) {
-2
View File
@@ -554,7 +554,6 @@ void bot_command_bind_affinity(Client *c, const Seperator *sep);
void bot_command_bot(Client *c, const Seperator *sep);
void bot_command_caster_range(Client* c, const Seperator* sep);
void bot_command_charm(Client *c, const Seperator *sep);
void bot_command_click_item(Client* c, const Seperator* sep);
void bot_command_cure(Client *c, const Seperator *sep);
void bot_command_defensive(Client *c, const Seperator *sep);
void bot_command_depart(Client *c, const Seperator *sep);
@@ -596,7 +595,6 @@ void bot_command_enforce_spell_list(Client* c, const Seperator* sep);
void bot_command_summon_corpse(Client *c, const Seperator *sep);
void bot_command_suspend(Client *c, const Seperator *sep);
void bot_command_taunt(Client *c, const Seperator *sep);
void bot_command_timer(Client* c, const Seperator* sep);
void bot_command_track(Client *c, const Seperator *sep);
void bot_command_view_combos(Client *c, const Seperator *sep);
void bot_command_water_breathing(Client *c, const Seperator *sep);
+54 -77
View File
@@ -24,13 +24,12 @@
#include "../common/repositories/bot_data_repository.h"
#include "../common/repositories/bot_inventories_repository.h"
#include "../common/repositories/bot_timers_repository.h"
#include "zonedb.h"
#include "bot.h"
#include "client.h"
#include <fmt/format.h>
#include <fmt/core.h>
bool BotDatabase::LoadBotCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &bot_command_settings)
@@ -918,39 +917,45 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
if (!bot_inst)
return false;
auto timers = BotTimersRepository::GetWhere(
database,
fmt::format("bot_id = {}", bot_inst->GetBotID())
query = StringFormat(
"SELECT"
" IfNull(bt.`timer_id`, '0') As timer_id,"
" IfNull(bt.`timer_value`, '0') As timer_value,"
" IfNull(MAX(sn.`recast_time`), '0') AS MaxTimer"
" FROM `bot_timers` bt, `spells_new` sn"
" WHERE bt.`bot_id` = '%u' AND sn.`EndurTimerIndex` = ("
"SELECT case"
" WHEN timer_id > '%i' THEN timer_id - '%i'"
" ELSE timer_id END AS timer_id"
" FROM `bot_timers` WHERE `timer_id` = bt.`timer_id` AND `bot_id` = bt.`bot_id`" // double-check validity
")"
" AND sn.`classes%i` <= '%i'",
bot_inst->GetBotID(),
(DisciplineReuseStart - 1),
(DisciplineReuseStart - 1),
bot_inst->GetClass(),
bot_inst->GetLevel()
);
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
if (!results.RowCount())
return true;
std::vector<BotTimer_Struct> bot_timers;
uint32* bot_timers = bot_inst->GetTimers();
if (!bot_timers)
return false;
BotTimer_Struct t{};
t.timer_id = 0;
t.timer_value = 0;
t.recast_time = 0;
t.is_spell = false;
t.is_disc = false;
t.spell_id = 0;
t.is_item = false;
t.item_id = 0;
int timer_id = 0;
uint32 timer_value = 0;
uint32 max_value = 0;
for (auto row = results.begin(); row != results.end(); ++row) {
timer_id = Strings::ToInt(row[0]) - 1;
timer_value = Strings::ToInt(row[1]);
max_value = Strings::ToInt(row[2]);
for (auto& timer : timers) {
if (t.timer_value < (Timer::GetCurrentTime() + t.recast_time)) {
t.timer_id = timer.timer_id;
t.timer_value = timer.timer_value;
t.recast_time = timer.recast_time;
t.is_spell = timer.is_spell ? true : false;
t.is_disc = timer.is_disc ? true : false;
t.spell_id = timer.spell_id;
t.is_item = timer.is_item ? true : false;
t.item_id = timer.item_id;
bot_timers.push_back(t);
}
}
if (!bot_timers.empty()) {
bot_inst->SetBotTimers(bot_timers);
if (timer_id >= 0 && timer_id < MaxTimer && timer_value < (Timer::GetCurrentTime() + max_value))
bot_timers[timer_id] = timer_value;
}
return true;
@@ -958,56 +963,26 @@ bool BotDatabase::LoadTimers(Bot* bot_inst)
bool BotDatabase::SaveTimers(Bot* bot_inst)
{
if (!bot_inst) {
if (!bot_inst)
return false;
}
if (!DeleteTimers(bot_inst->GetBotID())) {
if (!DeleteTimers(bot_inst->GetBotID()))
return false;
}
std::vector<BotTimer_Struct> bot_timers = bot_inst->GetBotTimers();
uint32* bot_timers = bot_inst->GetTimers();
if (!bot_timers)
return false;
if (bot_timers.empty()) {
return true;
}
for (int timer_index = 0; timer_index < MaxTimer; ++timer_index) {
if (bot_timers[timer_index] <= Timer::GetCurrentTime())
continue;
std::vector<BotTimersRepository::BotTimers> timers;
if (!bot_timers.empty()) {
for (auto & bot_timer : bot_timers) {
if (bot_timer.timer_value <= Timer::GetCurrentTime()) {
continue;
}
auto t = BotTimersRepository::BotTimers{
.bot_id = bot_inst->GetBotID(),
.timer_id = bot_timer.timer_id,
.timer_value = bot_timer.timer_value,
.recast_time = bot_timer.recast_time,
.is_spell = bot_timer.is_spell ? true : false,
.is_disc = bot_timer.is_disc ? true : false,
.spell_id = bot_timer.spell_id,
.is_item = bot_timer.is_item ? true : false,
.item_id = bot_timer.item_id
};
timers.push_back(t);
}
if (timers.empty()) {
return true;
}
// delete existing
BotTimersRepository::DeleteWhere(
database,
fmt::format("bot_id = {}", bot_inst->GetBotID())
query = fmt::format(
"REPLACE INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) VALUES ('{}', '{}', '{}')",
bot_inst->GetBotID(), (timer_index + 1), bot_timers[timer_index]
);
// bulk insert current
auto success = BotTimersRepository::InsertMany(database, timers);
if (!success) {
auto results = database.QueryDatabase(query);
if (!results.Success()) {
DeleteTimers(bot_inst->GetBotID());
return false;
}
@@ -1018,11 +993,13 @@ bool BotDatabase::SaveTimers(Bot* bot_inst)
bool BotDatabase::DeleteTimers(const uint32 bot_id)
{
if (!bot_id) {
if (!bot_id)
return false;
}
BotTimersRepository::DeleteWhere(database, fmt::format("bot_id = {}", bot_id));
query = StringFormat("DELETE FROM `bot_timers` WHERE `bot_id` = '%u'", bot_id);
auto results = database.QueryDatabase(query);
if (!results.Success())
return false;
return true;
}
-11
View File
@@ -81,15 +81,4 @@ struct BotSpells_Struct {
uint8 bucket_comparison;
};
struct BotTimer_Struct {
uint32 timer_id;
uint32 timer_value;
uint32 recast_time;
bool is_spell;
bool is_disc;
uint16 spell_id;
bool is_item;
uint32 item_id;
};
#endif // BOT_STRUCTS
+111 -46
View File
@@ -108,7 +108,7 @@ bool Bot::BotCastSong(Mob* tar, uint8 botLevel) {
auto iter : botSongList) {
if (!iter.SpellId)
continue;
if (!CheckSpellRecastTimer(iter.SpellId))
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue;
@@ -142,7 +142,7 @@ bool Bot::BotCastCombatSong(Mob* tar, uint8 botLevel) {
auto iter : botSongList) {
if (!iter.SpellId)
continue;
if (!CheckSpellRecastTimer(iter.SpellId))
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue;
@@ -174,7 +174,7 @@ bool Bot::BotCastHateReduction(Mob* tar, uint8 botLevel, const BotSpell& botSpel
for (auto iter : botSongList) {
if (!iter.SpellId)
continue;
if (!CheckSpellRecastTimer(iter.SpellId))
if (!CheckSpellRecastTimers(this, iter.SpellIndex))
continue;
if (!IsSpellUsableInThisZoneType(iter.SpellId, zone->GetZoneType()))
continue;
@@ -312,7 +312,7 @@ bool Bot::BotCastSlow(Mob* tar, uint8 botLevel, uint8 botClass, BotSpell& botSpe
continue;
}
if (!CheckSpellRecastTimer(iter.SpellId)) {
if (!CheckSpellRecastTimers(this, iter.SpellIndex)) {
continue;
}
@@ -403,7 +403,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
continue;
}
if (CheckSpellRecastTimer(s.SpellId))
if (CheckSpellRecastTimers(this, s.SpellIndex))
{
if (!(!tar->IsImmuneToSpell(s.SpellId, this) && tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) {
@@ -438,7 +438,7 @@ bool Bot::BotCastDOT(Mob* tar, uint8 botLevel, const BotSpell& botSpell, const b
continue;
}
if (CheckSpellRecastTimer(s.SpellId)) {
if (CheckSpellRecastTimers(this, s.SpellIndex)) {
if (!(!tar->IsImmuneToSpell(s.SpellId, this) &&
tar->CanBuffStack(s.SpellId, botLevel, true) >= 0)) {
@@ -652,7 +652,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
}
}
if (CheckSpellRecastTimer(s.SpellId)) {
if (CheckSpellRecastTimers(this, s.SpellIndex)) {
uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore();
casted_spell = AIDoSpellCast(s.SpellIndex, tar, s.ManaCost, &TempDontBuffMeBefore);
if (TempDontBuffMeBefore != tar->DontBuffMeBefore()) {
@@ -947,7 +947,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
}
}
if (CheckSpellRecastTimer(s.SpellId))
if (CheckSpellRecastTimers(this, s.SpellIndex))
{
uint32 TempDontBuffMeBefore = tar->DontBuffMeBefore();
@@ -1306,8 +1306,10 @@ bool Bot::AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
SetMana(hasMana);
}
else {
if (CalcSpellRecastTimer(AIBot_spells[i].spellid) > 0) {
SetSpellRecastTimer(AIBot_spells[i].spellid);
AIBot_spells[i].time_cancast = Timer::GetCurrentTime() + spells[AIBot_spells[i].spellid].recast_time;
if (spells[AIBot_spells[i].spellid].timer_id > 0) {
SetSpellRecastTimer(spells[AIBot_spells[i].spellid].timer_id, spells[AIBot_spells[i].spellid].recast_time);
}
}
@@ -2042,7 +2044,7 @@ BotSpell Bot::GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType) {
continue;
}
if ((botSpellList[i].type & spellType) && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
if ((botSpellList[i].type & spellType) && CheckSpellRecastTimers(botCaster, i)) {
result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost;
@@ -2067,7 +2069,7 @@ BotSpell Bot::GetBestBotSpellForFastHeal(Bot *botCaster) {
for (auto botSpellListItr : botSpellList) {
// Assuming all the spells have been loaded into this list by level and in descending order
if (IsFastHealSpell(botSpellListItr.SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr.SpellId)) {
if (IsFastHealSpell(botSpellListItr.SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr.SpellIndex)) {
result.SpellId = botSpellListItr.SpellId;
result.SpellIndex = botSpellListItr.SpellIndex;
result.ManaCost = botSpellListItr.ManaCost;
@@ -2104,7 +2106,7 @@ BotSpell Bot::GetBestBotSpellForHealOverTime(Bot* botCaster) {
if (
botSpellList[i].spellid == botSpellListItr.SpellId &&
(botSpellList[i].type & SpellType_Heal) &&
botCaster->CheckSpellRecastTimer(botSpellListItr.SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr.SpellIndex)
) {
result.SpellId = botSpellListItr.SpellId;
result.SpellIndex = botSpellListItr.SpellIndex;
@@ -2137,7 +2139,7 @@ BotSpell Bot::GetBestBotSpellForPercentageHeal(Bot *botCaster) {
continue;
}
if (IsCompleteHealSpell(botSpellList[i].spellid) && botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
if (IsCompleteHealSpell(botSpellList[i].spellid) && CheckSpellRecastTimers(botCaster, i)) {
result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost;
@@ -2161,7 +2163,7 @@ BotSpell Bot::GetBestBotSpellForRegularSingleTargetHeal(Bot* botCaster) {
for (std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order
if (IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
if (IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
result.ManaCost = botSpellListItr->ManaCost;
@@ -2190,7 +2192,7 @@ BotSpell Bot::GetFirstBotSpellForSingleTargetHeal(Bot* botCaster) {
IsRegularSingleTargetHealSpell(botSpellListItr->SpellId) ||
IsFastHealSpell(botSpellListItr->SpellId)
) &&
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2217,7 +2219,7 @@ BotSpell Bot::GetBestBotSpellForGroupHeal(Bot* botCaster) {
// Assuming all the spells have been loaded into this list by level and in descending order
if (
IsRegularGroupHealSpell(botSpellListItr->SpellId) &&
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2255,7 +2257,7 @@ BotSpell Bot::GetBestBotSpellForGroupHealOverTime(Bot* botCaster) {
if (
botSpellList[i].spellid == botSpellListItr->SpellId &&
(botSpellList[i].type & SpellType_Heal) &&
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2285,7 +2287,7 @@ BotSpell Bot::GetBestBotSpellForGroupCompleteHeal(Bot* botCaster) {
// Assuming all the spells have been loaded into this list by level and in descending order
if (
IsGroupCompleteHealSpell(botSpellListItr->SpellId) &&
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2312,7 +2314,7 @@ BotSpell Bot::GetBestBotSpellForMez(Bot* botCaster) {
// Assuming all the spells have been loaded into this list by level and in descending order
if (
IsMesmerizeSpell(botSpellListItr->SpellId) &&
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2341,7 +2343,7 @@ BotSpell Bot::GetBestBotSpellForMagicBasedSlow(Bot* botCaster) {
if (
IsSlowSpell(botSpellListItr->SpellId) &&
spells[botSpellListItr->SpellId].resist_type == RESIST_MAGIC &&
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2369,7 +2371,7 @@ BotSpell Bot::GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster) {
if (
IsSlowSpell(botSpellListItr->SpellId) &&
spells[botSpellListItr->SpellId].resist_type == RESIST_DISEASE &&
botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)
CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)
) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2435,7 +2437,7 @@ BotSpell Bot::GetBestBotMagicianPetSpell(Bot *botCaster) {
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order
if (IsSummonPetSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
if (IsSummonPetSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
if (!strncmp(spells[botSpellListItr->SpellId].teleport_zone, petType.c_str(), petType.length())) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2544,7 +2546,7 @@ BotSpell Bot::GetBestBotSpellForNukeByTargetType(Bot* botCaster, SpellTargetType
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order
if ((IsPureNukeSpell(botSpellListItr->SpellId) || IsDamageSpell(botSpellListItr->SpellId)) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
if ((IsPureNukeSpell(botSpellListItr->SpellId) || IsDamageSpell(botSpellListItr->SpellId)) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
result.ManaCost = botSpellListItr->ManaCost;
@@ -2572,7 +2574,7 @@ BotSpell Bot::GetBestBotSpellForStunByTargetType(Bot* botCaster, SpellTargetType
for(std::list<BotSpell>::iterator botSpellListItr = botSpellList.begin(); botSpellListItr != botSpellList.end(); ++botSpellListItr)
{
// Assuming all the spells have been loaded into this list by level and in descending order
if (IsStunSpell(botSpellListItr->SpellId) && botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId))
if (IsStunSpell(botSpellListItr->SpellId) && CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex))
{
result.SpellId = botSpellListItr->SpellId;
result.SpellIndex = botSpellListItr->SpellIndex;
@@ -2612,7 +2614,7 @@ BotSpell Bot::GetBestBotWizardNukeSpellByTargetResists(Bot* botCaster, Mob* targ
// Assuming all the spells have been loaded into this list by level and in descending order
bool spellSelected = false;
if (botCaster->CheckSpellRecastTimer(botSpellListItr->SpellId)) {
if (CheckSpellRecastTimers(botCaster, botSpellListItr->SpellIndex)) {
if (selectLureNuke && (spells[botSpellListItr->SpellId].resist_difficulty < lureResisValue)) {
spellSelected = true;
}
@@ -2680,7 +2682,7 @@ BotSpell Bot::GetDebuffBotSpell(Bot* botCaster, Mob *tar) {
if (((botSpellList[i].type & SpellType_Debuff) || IsDebuffSpell(botSpellList[i].spellid))
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
&& botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
&& CheckSpellRecastTimers(botCaster, i)) {
result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost;
@@ -2733,7 +2735,7 @@ BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob *tar) {
|| (needsDiseaseResistDebuff && (IsEffectInSpell(botSpellList[i].spellid, SE_ResistDisease)) || IsEffectInSpell(botSpellList[i].spellid, SE_ResistAll)))
&& (!tar->IsImmuneToSpell(botSpellList[i].spellid, botCaster)
&& tar->CanBuffStack(botSpellList[i].spellid, botCaster->GetLevel(), true) >= 0)
&& botCaster->CheckSpellRecastTimer(botSpellList[i].spellid)) {
&& CheckSpellRecastTimers(botCaster, i)) {
result.SpellId = botSpellList[i].spellid;
result.SpellIndex = i;
result.ManaCost = botSpellList[i].manacost;
@@ -2784,31 +2786,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
for (std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) {
BotSpell selectedBotSpell = *itr;
if (IsGroupSpell(itr->SpellId) && botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
if (IsGroupSpell(itr->SpellId) && CheckSpellRecastTimers(botCaster, itr->SpellIndex)) {
if (selectedBotSpell.SpellId == 0)
continue;
if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) {
spellSelected = true;
}
else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) {
spellSelected = true;
}
else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) {
spellSelected = true;
}
else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) {
spellSelected = true;
}
else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) {
spellSelected = true;
}
if (spellSelected)
{
result.SpellId = selectedBotSpell.SpellId;
result.SpellIndex = selectedBotSpell.SpellIndex;
result.ManaCost = selectedBotSpell.ManaCost;
result.SpellId = itr->SpellId;
result.SpellIndex = itr->SpellIndex;
result.ManaCost = itr->ManaCost;
break;
}
@@ -2821,31 +2823,31 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
for(std::list<BotSpell_wPriority>::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) {
BotSpell selectedBotSpell = *itr;
if (botCaster->CheckSpellRecastTimer(selectedBotSpell.SpellId)) {
if (CheckSpellRecastTimers(botCaster, itr->SpellIndex)) {
if (selectedBotSpell.SpellId == 0)
continue;
if (isPoisoned && IsEffectInSpell(selectedBotSpell.SpellId, SE_PoisonCounter)) {
if (isPoisoned && IsEffectInSpell(itr->SpellId, SE_PoisonCounter)) {
spellSelected = true;
}
else if (isDiseased && IsEffectInSpell(selectedBotSpell.SpellId, SE_DiseaseCounter)) {
else if (isDiseased && IsEffectInSpell(itr->SpellId, SE_DiseaseCounter)) {
spellSelected = true;
}
else if (isCursed && IsEffectInSpell(selectedBotSpell.SpellId, SE_CurseCounter)) {
else if (isCursed && IsEffectInSpell(itr->SpellId, SE_CurseCounter)) {
spellSelected = true;
}
else if (isCorrupted && IsEffectInSpell(selectedBotSpell.SpellId, SE_CorruptionCounter)) {
else if (isCorrupted && IsEffectInSpell(itr->SpellId, SE_CorruptionCounter)) {
spellSelected = true;
}
else if (IsEffectInSpell(selectedBotSpell.SpellId, SE_DispelDetrimental)) {
else if (IsEffectInSpell(itr->SpellId, SE_DispelDetrimental)) {
spellSelected = true;
}
if (spellSelected)
{
result.SpellId = selectedBotSpell.SpellId;
result.SpellIndex = selectedBotSpell.SpellIndex;
result.ManaCost = selectedBotSpell.ManaCost;
result.SpellId = itr->SpellId;
result.SpellIndex = itr->SpellIndex;
result.ManaCost = itr->ManaCost;
break;
}
@@ -2857,6 +2859,69 @@ BotSpell Bot::GetBestBotSpellForCure(Bot* botCaster, Mob *tar) {
return result;
}
void Bot::SetSpellRecastTimer(int timer_index, int32 recast_delay) {
if (timer_index > 0 && timer_index <= MaxSpellTimer) {
timers[timer_index - 1] = Timer::GetCurrentTime() + recast_delay;
}
}
int32 Bot::GetSpellRecastTimer(Bot *caster, int timer_index) {
int32 result = 0;
if (caster) {
if (timer_index > 0 && timer_index <= MaxSpellTimer) {
result = caster->timers[timer_index - 1];
}
}
return result;
}
bool Bot::CheckSpellRecastTimers(Bot *caster, int SpellIndex) {
if (caster) {
if (caster->AIBot_spells[SpellIndex].time_cancast < Timer::GetCurrentTime()) { //checks spell recast
if (GetSpellRecastTimer(caster, spells[caster->AIBot_spells[SpellIndex].spellid].timer_id) < Timer::GetCurrentTime()) { //checks for spells on the same timer
return true; //can cast spell
}
}
}
return false;
}
void Bot::SetDisciplineRecastTimer(int timer_index, int32 recast_delay) {
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
timers[DisciplineReuseStart + timer_index - 1] = Timer::GetCurrentTime() + recast_delay;
}
}
int32 Bot::GetDisciplineRecastTimer(Bot *caster, int timer_index) {
int32 result = 0;
if (caster) {
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
result = caster->timers[DisciplineReuseStart + timer_index - 1];
}
}
return result;
}
uint32 Bot::GetDisciplineRemainingTime(Bot *caster, int timer_index) {
int32 result = 0;
if (caster) {
if (timer_index > 0 && timer_index <= MaxDisciplineTimer) {
if (GetDisciplineRecastTimer(caster, timer_index) > Timer::GetCurrentTime())
result = GetDisciplineRecastTimer(caster, timer_index) - Timer::GetCurrentTime();
}
}
return result;
}
bool Bot::CheckDisciplineRecastTimers(Bot *caster, int timer_index) {
if (caster) {
if (GetDisciplineRecastTimer(caster, timer_index) < Timer::GetCurrentTime()) { //checks for spells on the same timer
return true; //can cast spell
}
}
return false;
}
uint8 Bot::GetChanceToCastBySpellType(uint32 spellType)
{
uint8 spell_type_index = SPELL_TYPE_COUNT;
+101 -214
View File
@@ -69,6 +69,7 @@ extern volatile bool RunLoops;
#include "../common/events/player_events.h"
#include "../common/events/player_event_logs.h"
#include "dialogue_window.h"
#include <fmt/format.h>
extern QueryServ* QServ;
@@ -1411,163 +1412,126 @@ void Client::SetMaxHP() {
Save();
}
bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
{
if (points < 0) {
if (m_pp.ldon_points_available < (0 - points)) {
return false;
}
}
bool Client::UpdateLDoNPoints(uint32 theme_id, int points) {
bool is_loss = false;
/* make sure total stays in sync with individual buckets
m_pp.ldon_points_available = m_pp.ldon_points_guk
+m_pp.ldon_points_mir
+m_pp.ldon_points_mmc
+m_pp.ldon_points_ruj
+m_pp.ldon_points_tak; */
if(points < 0) {
if(m_pp.ldon_points_available < (0 - points))
return false;
}
switch (theme_id) {
case LDoNThemes::Unused: { // No theme, so distribute evenly across all
int split_points = (points / 5);
int guk_points = (split_points + (points % 5));
int mir_points = split_points;
int mmc_points = split_points;
int ruj_points = split_points;
int tak_points = split_points;
split_points = 0;
if (points < 0) {
if (m_pp.ldon_points_available < (0 - points)) {
if(points < 0) {
if(m_pp.ldon_points_available < (0 - points)) {
return false;
}
is_loss = true;
if (m_pp.ldon_points_guk < (0 - guk_points)) {
if(m_pp.ldon_points_guk < (0 - guk_points)) {
mir_points += (guk_points + m_pp.ldon_points_guk);
guk_points = (0 - m_pp.ldon_points_guk);
}
if (m_pp.ldon_points_mir < (0 - mir_points)) {
if(m_pp.ldon_points_mir < (0 - mir_points)) {
mmc_points += (mir_points + m_pp.ldon_points_mir);
mir_points = (0 - m_pp.ldon_points_mir);
}
if (m_pp.ldon_points_mmc < (0 - mmc_points)) {
if(m_pp.ldon_points_mmc < (0 - mmc_points)) {
ruj_points += (mmc_points + m_pp.ldon_points_mmc);
mmc_points = (0 - m_pp.ldon_points_mmc);
}
if (m_pp.ldon_points_ruj < (0 - ruj_points)) {
if(m_pp.ldon_points_ruj < (0 - ruj_points)) {
tak_points += (ruj_points + m_pp.ldon_points_ruj);
ruj_points = (0 - m_pp.ldon_points_ruj);
}
if (m_pp.ldon_points_tak < (0 - tak_points)) {
if(m_pp.ldon_points_tak < (0 - tak_points)) {
split_points = (tak_points + m_pp.ldon_points_tak);
tak_points = (0 - m_pp.ldon_points_tak);
tak_points = (0 - m_pp.ldon_points_tak);
}
}
m_pp.ldon_points_guk += guk_points;
m_pp.ldon_points_mir += mir_points;
m_pp.ldon_points_mmc += mmc_points;
m_pp.ldon_points_ruj += ruj_points;
m_pp.ldon_points_tak += tak_points;
points -= split_points;
if (split_points != 0) { // if anything left, recursively loop thru again
UpdateLDoNPoints(LDoNThemes::Unused, split_points);
UpdateLDoNPoints(0, split_points);
}
break;
}
case LDoNThemes::GUK: {
if (points < 0) {
if (m_pp.ldon_points_guk < (0 - points)) {
case LDoNThemes::GUK: {
if(points < 0) {
if(m_pp.ldon_points_guk < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_guk += points;
break;
}
case LDoNThemes::MIR: {
if (points < 0) {
if (m_pp.ldon_points_mir < (0 - points)) {
if(points < 0) {
if(m_pp.ldon_points_mir < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_mir += points;
break;
}
case LDoNThemes::MMC: {
if (points < 0) {
if (m_pp.ldon_points_mmc < (0 - points)) {
if(points < 0) {
if(m_pp.ldon_points_mmc < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_mmc += points;
break;
}
case LDoNThemes::RUJ: {
if (points < 0) {
if (m_pp.ldon_points_ruj < (0 - points)) {
if(points < 0) {
if(m_pp.ldon_points_ruj < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_ruj += points;
break;
}
case LDoNThemes::TAK: {
if (points < 0) {
if (m_pp.ldon_points_tak < (0 - points)) {
if(points < 0) {
if(m_pp.ldon_points_tak < (0 - points)) {
return false;
}
is_loss = true;
}
m_pp.ldon_points_tak += points;
break;
}
}
m_pp.ldon_points_available += points;
QuestEventID event_id = is_loss ? EVENT_LDON_POINTS_LOSS : EVENT_LDON_POINTS_GAIN;
if (parse->PlayerHasQuestSub(event_id)) {
const std::string &export_string = fmt::format(
"{} {}",
theme_id,
std::abs(points)
);
parse->EventPlayer(event_id, this, export_string, 0);
}
auto outapp = new EQApplicationPacket(OP_AdventurePointsUpdate, sizeof(AdventurePoints_Update_Struct));
auto *apus = (AdventurePoints_Update_Struct *) outapp->pBuffer;
AdventurePoints_Update_Struct* apus = (AdventurePoints_Update_Struct*)outapp->pBuffer;
apus->ldon_available_points = m_pp.ldon_points_available;
apus->ldon_guk_points = m_pp.ldon_points_guk;
apus->ldon_mirugal_points = m_pp.ldon_points_mir;
apus->ldon_guk_points = m_pp.ldon_points_guk;
apus->ldon_mirugal_points = m_pp.ldon_points_mir;
apus->ldon_mistmoore_points = m_pp.ldon_points_mmc;
apus->ldon_rujarkian_points = m_pp.ldon_points_ruj;
apus->ldon_takish_points = m_pp.ldon_points_tak;
apus->ldon_takish_points = m_pp.ldon_points_tak;
outapp->priority = 6;
QueuePacket(outapp);
safe_delete(outapp);
return true;
@@ -5727,89 +5691,26 @@ void Client::AddPVPPoints(uint32 Points)
SendPVPStats();
}
void Client::AddEbonCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentEbonCrystals += amount;
m_pp.careerEbonCrystals += amount;
void Client::AddCrystals(uint32 radiant, uint32 ebon)
{
m_pp.currentRadCrystals += radiant;
m_pp.careerRadCrystals += radiant;
m_pp.currentEbonCrystals += ebon;
m_pp.careerEbonCrystals += ebon;
SaveCurrency();
SendCrystalCounts();
MessageString(
Chat::Yellow,
YOU_RECEIVE,
fmt::format(
"{} {}",
amount,
database.CreateItemLink(RuleI(Zone, EbonCrystalItemID))
).c_str()
);
if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_GAIN)) {
const std::string &export_string = fmt::format(
"{} 0 {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_GAIN, this, export_string, 0);
// newer clients handle message client side (older clients likely used eqstr 5967 and 5968, this matches live)
if (radiant > 0)
{
MessageString(Chat::Yellow, YOU_RECEIVE, fmt::format("{} Radiant Crystals", radiant).c_str());
}
}
void Client::AddRadiantCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentRadCrystals += amount;
m_pp.careerRadCrystals += amount;
SaveCurrency();
SendCrystalCounts();
MessageString(
Chat::Yellow,
YOU_RECEIVE,
fmt::format(
"{} {}",
amount,
database.CreateItemLink(RuleI(Zone, RadiantCrystalItemID))
).c_str()
);
if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_GAIN)) {
const std::string &export_string = fmt::format(
"0 {} {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_GAIN, this, export_string, 0);
}
}
void Client::RemoveEbonCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentEbonCrystals -= amount;
SaveCurrency();
SendCrystalCounts();
if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_LOSS)) {
const std::string &export_string = fmt::format(
"{} 0 {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_LOSS, this, export_string, 0);
}
}
void Client::RemoveRadiantCrystals(uint32 amount, bool is_reclaim) {
m_pp.currentRadCrystals -= amount;
SaveCurrency();
SendCrystalCounts();
if (parse->PlayerHasQuestSub(EVENT_CRYSTAL_LOSS)) {
const std::string &export_string = fmt::format(
"0 {} {}",
amount,
is_reclaim ? 1 : 0
);
parse->EventPlayer(EVENT_CRYSTAL_LOSS, this, export_string, 0);
if (ebon > 0)
{
MessageString(Chat::Yellow, YOU_RECEIVE, fmt::format("{} Ebon Crystals", ebon).c_str());
}
}
@@ -6172,7 +6073,7 @@ void Client::CheckEmoteHail(NPC* n, const char* message)
const auto emote_id = n->GetEmoteID();
if (emote_id) {
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id, this);
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id);
}
}
@@ -6554,10 +6455,11 @@ void Client::SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount)
SendAlternateCurrencyValue(currency_id);
}
int Client::AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted)
int Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method)
{
/* 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) {
if (method == 1){
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)){
std::string event_desc = StringFormat("Added via Quest :: Cursor to Item :: alt_currency_id:%i amount:%i in zoneid:%i instid:%i", currency_id, GetZoneID(), GetInstanceID());
@@ -6565,47 +6467,32 @@ int Client::AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_sc
}
}
if (!amount) {
if(amount == 0) {
return 0;
}
if (!alternate_currency_loaded) {
if(!alternate_currency_loaded) {
alternate_currency_queued_operations.push(std::make_pair(currency_id, amount));
return 0;
}
int new_value = 0;
auto iter = alternate_currency.find(currency_id);
if (iter == alternate_currency.end()) {
if(iter == alternate_currency.end()) {
new_value = amount;
} else {
new_value = (*iter).second + amount;
}
if (new_value < 0) {
new_value = 0;
if(new_value < 0) {
alternate_currency[currency_id] = 0;
database.UpdateAltCurrencyValue(CharacterID(), currency_id, 0);
} else {
alternate_currency[currency_id] = new_value;
database.UpdateAltCurrencyValue(CharacterID(), currency_id, new_value);
}
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(
"{} {} {}",
currency_id,
std::abs(amount),
new_value
);
parse->EventPlayer(event_id, this, export_string, 0);
}
return new_value;
}
@@ -8632,8 +8519,8 @@ void Client::InitInnates()
m_pp.InnateSkills[InnateInspect] = InnateEnabled;
m_pp.InnateSkills[InnateOpen] = InnateEnabled;
if (race >= Race::Froglok2) {
if (race == Race::Skeleton2 || race == Race::Froglok2) {
if (race >= RT_FROGLOK_3) {
if (race == RT_SKELETON_2 || race == RT_FROGLOK_3) {
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
} else {
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
@@ -8641,75 +8528,75 @@ void Client::InitInnates()
}
switch (race) {
case Race::Barbarian:
case Race::HalasCitizen:
case RT_BARBARIAN:
case RT_BARBARIAN_2:
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
break;
case Race::Erudite:
case Race::EruditeCitizen:
case RT_ERUDITE:
case RT_ERUDITE_2:
m_pp.InnateSkills[InnateLore] = InnateEnabled;
break;
case Race::WoodElf:
case Race::Fayguard:
case RT_WOOD_ELF:
case RT_GUARD_3:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case Race::Gnome:
case Race::HighElf:
case Race::Felguard:
case RT_GNOME:
case RT_HIGH_ELF:
case RT_GUARD_2:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
m_pp.InnateSkills[InnateLore] = InnateEnabled;
break;
case Race::Troll:
case Race::GrobbCitizen:
case RT_TROLL:
case RT_TROLL_2:
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case Race::Dwarf:
case Race::KaladimCitizen:
case RT_DWARF:
case RT_DWARF_2:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case Race::Ogre:
case Race::OggokCitizen:
case RT_OGRE:
case RT_OGRE_2:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
m_pp.InnateSkills[InnateNoBash] = InnateEnabled;
m_pp.InnateSkills[InnateBashDoor] = InnateEnabled;
break;
case Race::Halfling:
case Race::RivervaleCitizen:
case RT_HALFLING:
case RT_HALFLING_2:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case Race::Iksar:
case RT_IKSAR:
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case Race::VahShir:
case RT_VAH_SHIR:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case Race::DarkElf:
case Race::NeriakCitizen:
case Race::ElfVampire:
case Race::FroglokGhoul:
case Race::Ghost:
case Race::Ghoul:
case Race::Skeleton:
case Race::Vampire:
case Race::Wisp:
case Race::Zombie:
case Race::Spectre:
case Race::DwarfGhost:
case Race::EruditeGhost:
case Race::DragonSkeleton:
case Race::Innoruuk:
case RT_DARK_ELF:
case RT_DARK_ELF_2:
case RT_VAMPIRE_2:
case RT_FROGLOK_2:
case RT_GHOST:
case RT_GHOUL:
case RT_SKELETON:
case RT_VAMPIRE:
case RT_WILL_O_WISP:
case RT_ZOMBIE:
case RT_SPECTRE:
case RT_GHOST_2:
case RT_GHOST_3:
case RT_DRAGON_2:
case RT_INNORUUK:
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
break;
case Race::Human:
case Race::FreeportGuard:
case Race::HumanBeggar:
case Race::HighpassCitizen:
case Race::QeynosCitizen:
case Race::Froglok2: // client does froglok weird, but this should work out fine
case RT_HUMAN:
case RT_GUARD:
case RT_BEGGAR:
case RT_HUMAN_2:
case RT_HUMAN_3:
case RT_FROGLOK_3: // client does froglok weird, but this should work out fine
break;
default:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
+2 -6
View File
@@ -611,14 +611,11 @@ public:
void SetPVPPoints(uint32 Points) { m_pp.PVPCurrentPoints = Points; }
uint32 GetPVPPoints() { return m_pp.PVPCurrentPoints; }
void AddPVPPoints(uint32 Points);
void AddEbonCrystals(uint32 amount, bool is_reclaim = false);
void AddRadiantCrystals(uint32 amount, bool is_reclaim = false);
void RemoveEbonCrystals(uint32 amount, bool is_reclaim = false);
void RemoveRadiantCrystals(uint32 amount, bool is_reclaim = false);
uint32 GetRadiantCrystals() { return m_pp.currentRadCrystals; }
void SetRadiantCrystals(uint32 value);
uint32 GetEbonCrystals() { return m_pp.currentEbonCrystals; }
void SetEbonCrystals(uint32 value);
void AddCrystals(uint32 Radiant, uint32 Ebon);
void SendCrystalCounts();
uint64 GetExperienceForKill(Mob *against);
@@ -982,7 +979,6 @@ public:
void PutLootInInventory(int16 slot_id, const EQ::ItemInstance &inst, ServerLootItem_Struct** bag_item_data = 0);
bool AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQ::invslot::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
void SummonItemIntoInventory(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool is_attuned = false);
void SummonBaggedItems(uint32 bag_item_id, const std::vector<ServerLootItem_Struct>& bag_items);
void SetStats(uint8 type,int16 set_val);
void IncStats(uint8 type,int16 increase_val);
@@ -1497,7 +1493,7 @@ public:
void ConsentCorpses(std::string consent_name, bool deny = false);
void SendAltCurrencies();
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
int AddAlternateCurrencyValue(uint32 currency_id, int amount, bool is_scripted = false);
int AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
void SendAlternateCurrencyValues();
void SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null = true);
uint32 GetAlternateCurrencyValue(uint32 currency_id) const;
+31 -27
View File
@@ -2626,7 +2626,7 @@ void Client::Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app)
parse->EventPlayer(EVENT_ALT_CURRENCY_MERCHANT_BUY, this, export_string, 0);
}
uint64 current_balance = AddAlternateCurrencyValue(alt_cur_id, -((int) cost));
uint64 current_balance = AddAlternateCurrencyValue(alt_cur_id, -((int32) cost));
int16 charges = 1;
if (item->MaxCharges != 0) {
charges = item->MaxCharges;
@@ -2701,7 +2701,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app)
}
else {
SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, 0, false, EQ::invslot::slotCursor);
AddAlternateCurrencyValue(reclaim->currency_id, -((int)reclaim->count));
AddAlternateCurrencyValue(reclaim->currency_id, -((int32)reclaim->count));
}
/* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */
if (RuleB(QueryServ, PlayerLogAlternateCurrencyTransactions)) {
@@ -5475,50 +5475,59 @@ void Client::Handle_OP_CreateObject(const EQApplicationPacket *app)
void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app)
{
VERIFY_PACKET_LENGTH(OP_CrystalCreate, app, CrystalReclaim_Struct);
auto *cr = (CrystalReclaim_Struct *) app->pBuffer;
CrystalReclaim_Struct *cr = (CrystalReclaim_Struct*)app->pBuffer;
const uint32 quantity = cr->amount;
const bool is_radiant = cr->type == CrystalReclaimTypes::Radiant;
const bool is_ebon = cr->type == CrystalReclaimTypes::Ebon;
const uint32 requestQty = cr->amount;
const bool isRadiant = cr->type == 4;
const bool isEbon = cr->type == 5;
if (!is_radiant && !is_ebon) {
// Check: Valid type requested.
if (!isRadiant && !isEbon) {
return;
}
if (quantity < 1) {
// Check: Valid quantity requested.
if (requestQty < 1) {
return;
}
// Check: Valid client state to make request.
// In this situation the client is either desynced or attempting an exploit.
const uint32 current_quantity = is_radiant ? GetRadiantCrystals() : GetEbonCrystals();
if (!current_quantity) {
const uint32 currentQty = isRadiant ? GetRadiantCrystals() : GetEbonCrystals();
if (currentQty == 0) {
return;
}
// Prevent the client from creating more than they have.
const uint32 amount = EQ::ClampUpper(quantity, current_quantity);
const uint32 item_id = is_radiant ? RuleI(Zone, RadiantCrystalItemID) : RuleI(Zone, EbonCrystalItemID);
const uint32 amount = EQ::ClampUpper(requestQty, currentQty);
const uint32 itemID = isRadiant ? RuleI(Zone, RadiantCrystalItemID) : RuleI(Zone, EbonCrystalItemID);
// Summon crystals for player.
const bool success = SummonItem(itemID, amount);
const bool success = SummonItem(item_id, amount);
if (!success) {
return;
}
if (is_ebon) {
RemoveEbonCrystals(amount, true);
} else if (is_radiant) {
RemoveRadiantCrystals(amount, true);
// Deduct crystals from client and update them.
if (isRadiant) {
m_pp.currentRadCrystals -= amount;
m_pp.careerRadCrystals -= amount;
}
else if (isEbon) {
m_pp.currentEbonCrystals -= amount;
m_pp.careerEbonCrystals -= amount;
}
SaveCurrency();
SendCrystalCounts();
}
void Client::Handle_OP_CrystalReclaim(const EQApplicationPacket *app)
{
const uint32 ebon = NukeItem(RuleI(Zone, EbonCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor);
const uint32 radiant = NukeItem(RuleI(Zone, RadiantCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor);
uint32 ebon = NukeItem(RuleI(Zone, EbonCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor);
uint32 radiant = NukeItem(RuleI(Zone, RadiantCrystalItemID), invWhereWorn | invWherePersonal | invWhereCursor);
if ((ebon + radiant) > 0) {
AddEbonCrystals(ebon, true);
AddRadiantCrystals(radiant, true);
AddCrystals(radiant, ebon);
}
}
@@ -6284,11 +6293,6 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
);
parse->EventPlayer(EVENT_ENVIRONMENTAL_DAMAGE, this, export_string, 0);
}
if (ed->dmgtype == EQ::constants::EnvironmentalDamage::Trap) {
BreakInvisibleSpells();
CancelSneakHide();
}
}
if (GetHP() <= 0) {
+1 -1
View File
@@ -1,7 +1,7 @@
#include <string.h>
#include <algorithm>
#include <thread>
#include <fmt/format.h>
#include <fmt/core.h>
#include "../common/repositories/command_subsettings_repository.h"
#ifdef _WINDOWS
+1
View File
@@ -23,6 +23,7 @@
#include "expedition.h"
#include "string_ids.h"
#include "worldserver.h"
#include <fmt/format.h>
extern WorldServer worldserver;
+3 -4
View File
@@ -523,15 +523,14 @@ int64 Mob::GetActSpellHealing(uint16 spell_id, int64 value, Mob* target, bool fr
}
}
if (extra_heal) {
if (RuleB(Spells, HOTBonusHealingSplitOverDuration)) {
if (RuleB(Spells, HOTBonusHealingSplitOverDuration)) {
if (extra_heal) {
const int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0) {
extra_heal /= duration;
value += extra_heal;
}
}
value += extra_heal;
}
value *= critical_modifier;
+10 -60
View File
@@ -186,14 +186,6 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_UNMEMORIZE_SPELL",
"EVENT_SCRIBE_SPELL",
"EVENT_UNSCRIBE_SPELL",
"EVENT_LOOT_ADDED",
"EVENT_LDON_POINTS_GAIN",
"EVENT_LDON_POINTS_LOSS",
"EVENT_ALT_CURRENCY_GAIN",
"EVENT_ALT_CURRENCY_LOSS",
"EVENT_CRYSTAL_GAIN",
"EVENT_CRYSTAL_LOSS",
// Add new events before these or Lua crashes
"EVENT_SPELL_EFFECT_BOT",
"EVENT_SPELL_EFFECT_BUFF_TIC_BOT"
@@ -1891,17 +1883,19 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
if (extra_pointers && extra_pointers->size() >= 1) {
Corpse *corpse = std::any_cast<Corpse *>(extra_pointers->at(0));
if (corpse) {
if (extra_pointers && extra_pointers->size() >= 1)
{
Corpse* corpse = std::any_cast<Corpse*>(extra_pointers->at(0));
if (corpse)
{
ExportVar(package_name.c_str(), "killed_corpse_id", corpse->GetID());
}
}
if (extra_pointers && extra_pointers->size() >= 2) {
NPC *killed = std::any_cast<NPC *>(extra_pointers->at(1));
if (killed) {
if (extra_pointers && extra_pointers->size() >= 2)
{
NPC* killed = std::any_cast<NPC*>(extra_pointers->at(1));
if (killed)
{
ExportVar(package_name.c_str(), "killed_entity_id", killed->GetID());
ExportVar(package_name.c_str(), "killed_bot_id", killed->IsBot() ? killed->CastToBot()->GetBotID() : 0);
ExportVar(package_name.c_str(), "killed_npc_id", killed->IsNPC() ? killed->GetNPCTypeID() : 0);
@@ -2247,50 +2241,6 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_LOOT_ADDED: {
if (extra_pointers && extra_pointers->size() == 1) {
auto *inst = std::any_cast<EQ::ItemInstance *>(extra_pointers->at(0));
if (inst) {
ExportVar(package_name.c_str(), "item", "QuestItem", inst);
ExportVar(package_name.c_str(), "item_id", inst->GetID());
ExportVar(package_name.c_str(), "item_name", inst->GetItem()->Name);
ExportVar(package_name.c_str(), "item_charges", inst->GetCharges());
ExportVar(package_name.c_str(), "augment_one", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN));
ExportVar(package_name.c_str(), "augment_two", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 1));
ExportVar(package_name.c_str(), "augment_three", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 2));
ExportVar(package_name.c_str(), "augment_four", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 3));
ExportVar(package_name.c_str(), "augment_five", inst->GetAugmentItemID(EQ::invaug::SOCKET_BEGIN + 4));
ExportVar(package_name.c_str(), "augment_six", inst->GetAugmentItemID(EQ::invaug::SOCKET_END));
}
}
}
case EVENT_LDON_POINTS_GAIN:
case EVENT_LDON_POINTS_LOSS: {
Seperator sep(data);
ExportVar(package_name.c_str(), "theme_id", sep.arg[0]);
ExportVar(package_name.c_str(), "points", sep.arg[1]);
break;
}
case EVENT_ALT_CURRENCY_GAIN:
case EVENT_ALT_CURRENCY_LOSS: {
Seperator sep(data);
ExportVar(package_name.c_str(), "currency_id", sep.arg[0]);
ExportVar(package_name.c_str(), "amount", sep.arg[1]);
ExportVar(package_name.c_str(), "total", sep.arg[2]);
break;
}
case EVENT_CRYSTAL_GAIN:
case EVENT_CRYSTAL_LOSS: {
Seperator sep(data);
ExportVar(package_name.c_str(), "ebon_amount", sep.arg[0]);
ExportVar(package_name.c_str(), "radiant_amount", sep.arg[1]);
ExportVar(package_name.c_str(), "is_reclaim", sep.arg[2]);
break;
}
default: {
break;
}
+2 -2
View File
@@ -4920,7 +4920,7 @@ void EntityList::ZoneWho(Client *c, Who_All_Struct *Who)
FormatMSGID = 5023; // 5023 %T1[ANONYMOUS] %2 %3 %4
uint32 PlayerClass = Class::None;
uint32 PlayerLevel = 0;
uint32 PlayerRace = Race::Doug;
uint32 PlayerRace = RACE_DOUG_0;
uint32 ZoneMSGID = 0xFFFFFFFF;
if (ClientEntry->GetAnon()==0) {
@@ -5750,7 +5750,7 @@ void EntityList::DespawnGridNodes(int32 grid_id) {
Mob *mob = m.second;
if (
mob->IsNPC() &&
mob->GetRace() == Race::Node &&
mob->GetRace() == RACE_NODE_2254 &&
mob->EntityVariableExists("grid_id") &&
Strings::ToInt(mob->GetEntityVariable("grid_id")) == grid_id)
{
-8
View File
@@ -128,14 +128,6 @@ typedef enum {
EVENT_UNMEMORIZE_SPELL,
EVENT_SCRIBE_SPELL,
EVENT_UNSCRIBE_SPELL,
EVENT_LOOT_ADDED,
EVENT_LDON_POINTS_GAIN,
EVENT_LDON_POINTS_LOSS,
EVENT_ALT_CURRENCY_GAIN,
EVENT_ALT_CURRENCY_LOSS,
EVENT_CRYSTAL_GAIN,
EVENT_CRYSTAL_LOSS,
// Add new events before these or Lua crashes
EVENT_SPELL_EFFECT_BOT,
EVENT_SPELL_EFFECT_BUFF_TIC_BOT,
+1
View File
@@ -36,6 +36,7 @@
#include "bot.h"
#include "../common/events/player_event_logs.h"
#include "worldserver.h"
#include <fmt/format.h>
extern WorldServer worldserver;
+1
View File
@@ -26,6 +26,7 @@
#include "worldserver.h"
#include "zonedb.h"
#include "../common/repositories/expedition_lockouts_repository.h"
#include <fmt/format.h>
extern WorldServer worldserver;
extern Zone* zone;
+1
View File
@@ -25,6 +25,7 @@
#include "raids.h"
#include "string_ids.h"
#include "../common/repositories/character_expedition_lockouts_repository.h"
#include <fmt/format.h>
constexpr char SystemName[] = "expedition";
+1 -1
View File
@@ -456,7 +456,7 @@ void Client::ForageItem(bool guarantee) {
}
//not an else in case theres no DB food
if (foragedfood == 0 && RuleB(Character, UseForageCommonFood)) {
if (foragedfood == 0) {
uint8 index = 0;
index = zone->random.Int(0, MAX_COMMON_FOOD_IDS-1);
foragedfood = common_food_ids[index];
+10 -2
View File
@@ -7,7 +7,10 @@ void FindEmote(Client *c, const Seperator *sep)
if (sep->IsNumber(2)) {
auto emote_id = Strings::ToUnsignedInt(sep->arg[2]);
for (auto& e : zone->npc_emote_list) {
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
auto &e = iterator.GetData();
if (emote_id == e->emoteid) {
c->Message(
Chat::White,
@@ -37,6 +40,7 @@ void FindEmote(Client *c, const Seperator *sep)
break;
}
iterator.Advance();
}
if (found_count == 50) {
@@ -66,7 +70,10 @@ void FindEmote(Client *c, const Seperator *sep)
const std::string& search_criteria = sep->argplus[2];
for (auto& e : zone->npc_emote_list) {
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
auto &e = iterator.GetData();
const std::string& current_text = Strings::ToLower(e->text);
@@ -99,6 +106,7 @@ void FindEmote(Client *c, const Seperator *sep)
break;
}
iterator.Advance();
}
if (found_count == 50) {
+2 -2
View File
@@ -5,7 +5,7 @@ void FindRace(Client *c, const Seperator *sep)
if (sep->IsNumber(2)) {
const auto race_id = static_cast<uint16>(Strings::ToUnsignedInt(sep->arg[2]));
const std::string& race_name = GetRaceIDName(race_id);
if (EQ::ValueWithin(race_id, Race::Human, Race::Pegasus3)) {
if (EQ::ValueWithin(race_id, RACE_HUMAN_1, RACE_PEGASUS_732)) {
c->Message(
Chat::White,
fmt::format(
@@ -41,7 +41,7 @@ void FindRace(Client *c, const Seperator *sep)
auto found_count = 0;
for (uint16 race_id = Race::Human; race_id <= Race::Pegasus3; race_id++) {
for (uint16 race_id = RACE_HUMAN_1; race_id <= RACE_PEGASUS_732; race_id++) {
std::string race_name = GetRaceIDName(race_id);
auto race_name_lower = Strings::ToLower(race_name);
if (!Strings::Contains(race_name_lower, search_criteria)) {
+1 -1
View File
@@ -23,7 +23,7 @@ void SetRace(Client *c, const Seperator *sep)
const uint16 race_id = Strings::ToUnsignedInt(sep->arg[2]);
if (
!EQ::ValueWithin(race_id, Race::Doug, RuleI(NPC, MaxRaceID)) &&
!EQ::ValueWithin(race_id, RACE_DOUG_0, RuleI(NPC, MaxRaceID)) &&
!EQ::ValueWithin(race_id, 2253, 2259)
) {
c->Message(
+16 -9
View File
@@ -9,11 +9,17 @@ void SetTime(Client *c, const Seperator *sep)
TimeOfDay_Struct world_time{};
zone->zone_time.GetCurrentEQTimeOfDay(time(0), &world_time);
auto time_string = fmt::format(
"{} (Timezone: {})",
Strings::ZoneTime(world_time.hour, world_time.minute),
Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr())
);
c->Message(
Chat::White,
fmt::format(
"It is currently {}.",
Strings::ZoneTime(world_time.hour - 1, world_time.minute)
time_string
).c_str()
);
@@ -21,15 +27,15 @@ void SetTime(Client *c, const Seperator *sep)
}
uint8 minutes = 0;
uint8 hours = Strings::ToUnsignedInt(sep->arg[2]);
uint8 hours = Strings::ToUnsignedInt(sep->arg[2]) + 1;
if (hours > 24) {
hours = 24;
}
uint8 real_hours = (
hours > 0 ?
hours :
(hours - 1) > 0 ?
(hours - 1) :
0
);
@@ -41,20 +47,21 @@ void SetTime(Client *c, const Seperator *sep)
}
}
c->Message(
Chat::White,
fmt::format(
"Setting world time to {}.",
Strings::ZoneTime(hours, minutes)
"Setting world time to {} (Timezone: {}).",
Strings::ZoneTime(hours, minutes),
Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr())
).c_str()
);
zone->SetTime(real_hours, minutes);
LogInfo(
"{} :: Setting world time to {}.",
"{} :: Setting world time to {} (Timezone: {})",
c->GetCleanName(),
Strings::ZoneTime(hours, minutes)
Strings::ZoneTime(hours, minutes),
Strings::ZoneTime(zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneHr())
);
}
+5 -1
View File
@@ -12,7 +12,10 @@ void ShowEmotes(Client *c, const Seperator *sep)
uint32 emote_count = 0;
const uint32 emote_id = t->GetEmoteID();
for (auto& e : zone->npc_emote_list) {
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
const auto& e = iterator.GetData();
if (emote_id == e->emoteid) {
c->Message(
Chat::White,
@@ -38,6 +41,7 @@ void ShowEmotes(Client *c, const Seperator *sep)
emote_count++;
}
iterator.Advance();
}
c->Message(
+1 -1
View File
@@ -4,7 +4,7 @@ void ShowZonePoints(Client *c, const Seperator *sep)
{
for (const auto& m : entity_list.GetMobList()) {
Mob* mob = m.second;
if (mob->IsNPC() && mob->GetRace() == Race::Node) {
if (mob->IsNPC() && mob->GetRace() == RACE_NODE_2254) {
mob->Depop();
}
}
+19 -14
View File
@@ -3,16 +3,19 @@
extern WorldServer worldserver;
#include "../corpse.h"
void command_summon(Client *c, const Seperator *sep)
{
const int arguments = sep->argnum;
int arguments = sep->argnum;
if (!arguments && !c->GetTarget()) {
c->Message(Chat::White, "Usage: #summon - Summon your target, if you have one, to your position");
c->Message(Chat::White, "Usage: #summon [Character Name] - Summon a character by name to your position");
c->Message(Chat::White, "Note: You may also summon your target if you have one.");
return;
}
Mob *t = c;
Mob* t = c;
if (arguments == 1) {
std::string character_name = sep->arg[1];
@@ -28,9 +31,9 @@ void command_summon(Client *c, const Seperator *sep)
return;
}
Client *s = entity_list.GetClientByName(character_name.c_str());
if (s) {
t = s->CastToMob();
auto search_client = entity_list.GetClientByName(character_name.c_str());
if (search_client) {
t = search_client->CastToMob();
} else {
if (!worldserver.Connected()) {
c->Message(Chat::White, "World server is currently disconnected.");
@@ -39,18 +42,15 @@ void command_summon(Client *c, const Seperator *sep)
auto pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct));
auto szp = (ServerZonePlayer_Struct *) pack->pBuffer;
strn0cpy(szp->adminname, c->GetName(), sizeof(szp->adminname));
szp->adminrank = c->Admin();
szp->ignorerestrictions = 2;
strn0cpy(szp->name, character_name.c_str(), sizeof(szp->name));
strn0cpy(szp->zone, zone->GetShortName(), sizeof(szp->zone));
szp->adminrank = c->Admin();
szp->ignorerestrictions = 2;
szp->instance_id = zone->GetInstanceID();
szp->x_pos = c->GetX();
szp->y_pos = c->GetY();
szp->z_pos = c->GetZ();
szp->x_pos = c->GetX();
szp->y_pos = c->GetY();
szp->z_pos = c->GetZ();
szp->instance_id = zone->GetInstanceID();
worldserver.SendPacket(pack);
safe_delete(pack);
return;
@@ -97,4 +97,9 @@ void command_summon(Client *c, const Seperator *sep)
}
t->GMMove(c->GetPosition());
if (t->IsNPC()) {
t->CastToNPC()->SaveGuardSpot(glm::vec4(0.0f));
}
}
+261 -130
View File
@@ -149,7 +149,7 @@ Mob* HateList::GetDamageTopOnHateList(Mob* hater)
return current;
}
Mob* HateList::GetClosestEntOnHateList(Mob *hater, bool skip_mezzed, EntityFilterType filter_type) {
Mob* HateList::GetClosestEntOnHateList(Mob *hater, bool skip_mezzed, EntityFilterType entity_type) {
Mob* close_entity = nullptr;
float close_distance = 99999.9f;
float this_distance;
@@ -163,7 +163,7 @@ Mob* HateList::GetClosestEntOnHateList(Mob *hater, bool skip_mezzed, EntityFilte
continue;
}
switch (filter_type) {
switch (entity_type) {
case EntityFilterType::Bots:
if (!e->entity_on_hatelist->IsBot()) {
continue;
@@ -344,215 +344,191 @@ int HateList::GetHateRatio(Mob *top, Mob *other)
// skip is used to ignore a certain mob on the list
// Currently used for getting 2nd on list for aggro meter
Mob *HateList::GetMobWithMostHateOnList(
Mob *center,
Mob *skip,
bool skip_mezzed,
EntityFilterType filter_type
)
Mob *HateList::GetEntWithMostHateOnList(Mob *center, Mob *skip, bool skip_mezzed)
{
if (!zone->IsLoaded()) { // hack fix for zone shutdown crashes on some servers
// hack fix for zone shutdown crashes on some servers
if (!zone->IsLoaded())
return nullptr;
}
Mob *top_hate = nullptr;
int64 hate = -1;
Mob* top_hate = nullptr;
int64 hate = -1;
if (!center) {
if (center == nullptr)
return nullptr;
}
if (RuleB(Aggro, SmartAggroList)) {
Mob *top_client_type_in_range = nullptr;
if (RuleB(Aggro, SmartAggroList)){
Mob* top_client_type_in_range = nullptr;
int64 hate_client_type_in_range = -1;
int skipped_count = 0;
int skipped_count = 0;
auto iterator = list.begin();
while (iterator != list.end()) {
struct_HateList *cur = (*iterator);
int16 aggro_mod = 0;
while (iterator != list.end())
{
struct_HateList *cur = (*iterator);
int16 aggro_mod = 0;
if (!cur) {
if (!cur){
++iterator;
continue;
}
Mob *m = cur->entity_on_hatelist;
if (!m) {
if (!cur->entity_on_hatelist){
++iterator;
continue;
}
if (m == skip) {
if (cur->entity_on_hatelist == skip) {
++iterator;
continue;
}
if (skip_mezzed && m->IsMezzed()) {
if (skip_mezzed && cur->entity_on_hatelist->IsMezzed()) {
++iterator;
continue;
}
if (
(filter_type == EntityFilterType::Bots && !m->IsBot()) ||
(filter_type == EntityFilterType::Clients && !m->IsClient()) ||
(filter_type == EntityFilterType::NPCs && !m->IsNPC())
) {
++iterator;
continue;
}
if (m->Sanctuary()) {
if (hate == -1) {
top_hate = m;
hate = 1;
if (cur->entity_on_hatelist->Sanctuary()) {
if (hate == -1)
{
top_hate = cur->entity_on_hatelist;
hate = 1;
}
++iterator;
continue;
}
if (m->DivineAura() || m->IsMezzed() || m->IsFeared()) {
if (hate == -1) {
top_hate = m;
hate = 0;
if (cur->entity_on_hatelist->DivineAura() || cur->entity_on_hatelist->IsMezzed() || cur->entity_on_hatelist->IsFeared()){
if (hate == -1)
{
top_hate = cur->entity_on_hatelist;
hate = 0;
}
++iterator;
continue;
}
int64 current_hate = cur->stored_hate_amount;
if (m->IsOfClientBot()) {
if (m->IsClient() && m->CastToClient()->IsSitting()) {
if (cur->entity_on_hatelist->IsClient() || cur->entity_on_hatelist->IsBot()){
if (cur->entity_on_hatelist->IsClient() && cur->entity_on_hatelist->CastToClient()->IsSitting()){
aggro_mod += RuleI(Aggro, SittingAggroMod);
}
if (center) {
if (center->GetTarget() == m) {
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
}
if (RuleI(Aggro, MeleeRangeAggroMod) != 0) {
if (center->CombatRange(m)) {
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if (center->CombatRange(cur->entity_on_hatelist)){
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
if (current_hate > hate_client_type_in_range || cur->is_entity_frenzy) {
if (current_hate > hate_client_type_in_range || cur->is_entity_frenzy){
hate_client_type_in_range = current_hate;
top_client_type_in_range = m;
top_client_type_in_range = cur->entity_on_hatelist;
}
}
}
}
} else {
if (center) {
if (center->GetTarget() == m) {
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
}
if (RuleI(Aggro, MeleeRangeAggroMod) != 0) {
if (center->CombatRange(m)) {
}
else{
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if (center->CombatRange(cur->entity_on_hatelist)){
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
}
}
}
}
if (m->GetMaxHP() != 0 && ((m->GetHP() * 100 / m->GetMaxHP()) < 20)) {
if (cur->entity_on_hatelist->GetMaxHP() != 0 && ((cur->entity_on_hatelist->GetHP() * 100 / cur->entity_on_hatelist->GetMaxHP()) < 20)){
aggro_mod += RuleI(Aggro, CriticallyWoundedAggroMod);
}
if (aggro_mod) {
if (aggro_mod){
current_hate += (current_hate * aggro_mod / 100);
}
if (current_hate > hate || cur->is_entity_frenzy) {
hate = current_hate;
top_hate = m;
if (current_hate > hate || cur->is_entity_frenzy){
hate = current_hate;
top_hate = cur->entity_on_hatelist;
}
++iterator;
}
if (top_client_type_in_range && top_hate) {
bool is_top_client_type = top_hate->IsClient();
if (!is_top_client_type) {
if (top_client_type_in_range != nullptr && top_hate != nullptr) {
bool isTopClientType = top_hate->IsClient();
if (!isTopClientType) {
if (top_hate->IsBot()) {
is_top_client_type = true;
isTopClientType = true;
top_client_type_in_range = top_hate;
}
}
if (!is_top_client_type) {
if (!isTopClientType) {
if (top_hate->IsMerc()) {
is_top_client_type = true;
isTopClientType = true;
top_client_type_in_range = top_hate;
}
}
if (!is_top_client_type) {
if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)) {
is_top_client_type = true;
if (!isTopClientType) {
if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)){
isTopClientType = true;
top_client_type_in_range = top_hate;
}
}
if (!is_top_client_type) {
if (!isTopClientType)
return top_client_type_in_range ? top_client_type_in_range : nullptr;
}
return top_hate ? top_hate : nullptr;
} else {
if (!top_hate && skipped_count > 0) {
}
else {
if (top_hate == nullptr && skipped_count > 0) {
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top_hate ? top_hate : nullptr;
}
} else {
auto iterator = list.begin();
int skipped_count = 0;
while (iterator != list.end()) {
}
else{
auto iterator = list.begin();
int skipped_count = 0;
while (iterator != list.end())
{
struct_HateList *cur = (*iterator);
if (cur) {
Mob *m = cur->entity_on_hatelist;
if (!m) {
if (cur->entity_on_hatelist == skip) {
++iterator;
continue;
}
if (m == skip) {
if (skip_mezzed && cur->entity_on_hatelist->IsMezzed()) {
++iterator;
continue;
}
if (skip_mezzed && m->IsMezzed()) {
++iterator;
continue;
}
if ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy) {
top_hate = m;
hate = cur->stored_hate_amount;
if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy))
{
top_hate = cur->entity_on_hatelist;
hate = cur->stored_hate_amount;
}
}
++iterator;
}
if (!top_hate && skipped_count > 0) {
if (top_hate == nullptr && skipped_count > 0) {
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top_hate ? top_hate : nullptr;
}
return nullptr;
}
Mob *HateList::GetMobWithMostHateOnList(bool skip_mezzed){
Mob *HateList::GetEntWithMostHateOnList(bool skip_mezzed){
Mob* top = nullptr;
int64 hate = -1;
@@ -563,7 +539,7 @@ Mob *HateList::GetMobWithMostHateOnList(bool skip_mezzed){
if (cur) {
LogHateDetail(
"Looping GetMobWithMostHateOnList1 [{}] cur [{}] hate [{}] calc [{}]",
"Looping GetEntWithMostHateOnList1 [{}] cur [{}] hate [{}] calc [{}]",
cur->entity_on_hatelist->GetMobDescription(),
cur->stored_hate_amount,
hate,
@@ -573,7 +549,7 @@ Mob *HateList::GetMobWithMostHateOnList(bool skip_mezzed){
if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
{
LogHateDetail(
"Looping GetMobWithMostHateOnList2 [{}]",
"Looping GetEntWithMostHateOnList2 [{}]",
cur->entity_on_hatelist->GetMobDescription()
);
@@ -589,45 +565,53 @@ Mob *HateList::GetMobWithMostHateOnList(bool skip_mezzed){
}
Mob *HateList::GetRandomMobOnHateList(EntityFilterType filter_type)
Mob *HateList::GetRandomEntOnHateList(bool skip_mezzed)
{
const auto &l = GetFilteredHateList(filter_type);
int count = list.size();
if (count <= 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
return nullptr;
if (count == 1) //No need to do all that extra work if we only have one hate entry
{
if (*list.begin() && (!skip_mezzed || !(*list.begin())->entity_on_hatelist->IsMezzed())) // Just in case tHateEntry is invalidated somehow...
return (*list.begin())->entity_on_hatelist;
int count = l.size();
if (count <= 0) { // If we don't have any entries it'll crash getting a random 0, -1 position.
return nullptr;
}
if (count == 1) { // No need to do all that extra work if we only have one hate entry
auto c = *l.begin();
if (c) {
Mob *m = c->entity_on_hatelist;
if (!m) {
return nullptr;
}
if (skip_mezzed) {
return m;
for (auto iter : list) {
if (iter->entity_on_hatelist->IsMezzed()) {
--count;
}
}
if (count <= 0) {
return nullptr;
}
}
int random = zone->random.Int(0, count - 1);
int counter = 0;
for (auto iter : list) {
if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) {
continue;
}
if (counter < random) {
++counter;
continue;
}
return nullptr;
}
auto r = l.begin();
int random_index = rand() % count;
std::advance(r, random_index);
auto e = *r;
Mob *m = e->entity_on_hatelist;
if (m) {
return m;
return iter->entity_on_hatelist;
}
return nullptr;
}
Mob *HateList::GetEscapingMobOnHateList(Mob *center, float range, bool first) {
Mob *HateList::GetEscapingEntOnHateList(Mob *center, float range, bool first) {
// function is still in design stage
if (!center)
@@ -869,6 +853,153 @@ void HateList::RemoveStaleEntries(int time_ms, float dist)
}
}
Bot* HateList::GetRandomBotOnHateList(bool skip_mezzed)
{
int count = list.size();
if (count <= 0) { //If we don't have any entries it'll crash getting a random 0, -1 position.
return nullptr;
}
if (count == 1) { //No need to do all that extra work if we only have one hate entry
if (*list.begin() && (*list.begin())->entity_on_hatelist->IsBot() && (!skip_mezzed || !(*list.begin())->entity_on_hatelist->IsMezzed())) {
return (*list.begin())->entity_on_hatelist->CastToBot();
}
return nullptr;
}
if (skip_mezzed) {
for (auto iter : list) {
if (iter->entity_on_hatelist->IsMezzed()) {
--count;
}
}
if (count <= 0) {
return nullptr;
}
}
int random = zone->random.Int(0, count - 1);
int counter = 0;
for (auto iter : list) {
if (!iter->entity_on_hatelist->IsBot()) {
continue;
}
if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) {
continue;
}
if (counter < random) {
++counter;
continue;
}
return iter->entity_on_hatelist->CastToBot();
}
return nullptr;
}
Client* HateList::GetRandomClientOnHateList(bool skip_mezzed)
{
int count = list.size();
if (count <= 0) { //If we don't have any entries it'll crash getting a random 0, -1 position.
return nullptr;
}
if (count == 1) { //No need to do all that extra work if we only have one hate entry
if (*list.begin() && (*list.begin())->entity_on_hatelist->IsClient() && (!skip_mezzed || !(*list.begin())->entity_on_hatelist->IsMezzed())) {
return (*list.begin())->entity_on_hatelist->CastToClient();
}
return nullptr;
}
if (skip_mezzed) {
for (auto iter : list) {
if (iter->entity_on_hatelist->IsMezzed()) {
--count;
}
}
if (count <= 0) {
return nullptr;
}
}
int random = zone->random.Int(0, count - 1);
int counter = 0;
for (auto iter : list) {
if (!iter->entity_on_hatelist->IsClient()) {
continue;
}
if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) {
continue;
}
if (counter < random) {
++counter;
continue;
}
return iter->entity_on_hatelist->CastToClient();
}
return nullptr;
}
NPC* HateList::GetRandomNPCOnHateList(bool skip_mezzed)
{
int count = list.size();
if (count <= 0) { //If we don't have any entries it'll crash getting a random 0, -1 position.
return nullptr;
}
if (count == 1) { //No need to do all that extra work if we only have one hate entry
if (*list.begin() && (*list.begin())->entity_on_hatelist->IsNPC() && (!skip_mezzed || !(*list.begin())->entity_on_hatelist->IsMezzed())) {
return (*list.begin())->entity_on_hatelist->CastToNPC();
}
return nullptr;
}
if (skip_mezzed) {
for (auto iter : list) {
if (iter->entity_on_hatelist->IsMezzed()) {
--count;
}
}
if (count <= 0) {
return nullptr;
}
}
int random = zone->random.Int(0, count - 1);
int counter = 0;
for (auto iter : list) {
if (!iter->entity_on_hatelist->IsNPC()) {
continue;
}
if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) {
continue;
}
if (counter < random) {
++counter;
continue;
}
return iter->entity_on_hatelist->CastToNPC();
}
return nullptr;
}
void HateList::DamageHateList(int64 damage, uint32 distance, EntityFilterType filter_type, bool is_percentage)
{
if (damage <= 0) {
+9 -5
View File
@@ -41,12 +41,16 @@ public:
HateList();
~HateList();
Mob *GetClosestEntOnHateList(Mob *hater, bool skip_mezzed = false, EntityFilterType filter_type = EntityFilterType::All);
Mob *GetClosestEntOnHateList(Mob *hater, bool skip_mezzed = false, EntityFilterType entity_type = EntityFilterType::All);
Mob *GetDamageTopOnHateList(Mob *hater); // didn't add 'skip_mezzed' due to calls being in ::Death()
Mob *GetMobWithMostHateOnList(Mob *center, Mob *skip = nullptr, bool skip_mezzed = false, EntityFilterType filter_type = EntityFilterType::All);
Mob *GetRandomMobOnHateList(EntityFilterType filter_type = EntityFilterType::All);
Mob *GetMobWithMostHateOnList(bool skip_mezzed = false);
Mob *GetEscapingMobOnHateList(Mob *center, float range = 0.0f, bool first = false);
Mob *GetEntWithMostHateOnList(Mob *center, Mob *skip = nullptr, bool skip_mezzed = false);
Mob *GetRandomEntOnHateList(bool skip_mezzed = false);
Mob *GetEntWithMostHateOnList(bool skip_mezzed = false);
Mob *GetEscapingEntOnHateList(Mob *center, float range = 0.0f, bool first = false);
Bot* GetRandomBotOnHateList(bool skip_mezzed = false);
Client *GetRandomClientOnHateList(bool skip_mezzed = false);
NPC *GetRandomNPCOnHateList(bool skip_mezzed = false);
bool IsEntOnHateList(Mob *mob);
bool IsHateListEmpty();
-50
View File
@@ -4739,53 +4739,3 @@ bool Client::IsAugmentRestricted(uint8 item_type, uint32 augment_restriction)
return false;
}
void Client::SummonItemIntoInventory(
uint32 item_id,
int16 charges,
uint32 aug1,
uint32 aug2,
uint32 aug3,
uint32 aug4,
uint32 aug5,
uint32 aug6,
bool is_attuned
)
{
auto *inst = database.CreateItem(
item_id,
charges,
aug1,
aug2,
aug3,
aug4,
aug5,
aug6,
is_attuned
);
if (!inst) {
return;
}
const bool is_arrow = inst->GetItem()->ItemType == EQ::item::ItemTypeArrow;
const int16 slot_id = m_inv.FindFreeSlot(
inst->IsClassBag(),
true,
inst->GetItem()->Size,
is_arrow
);
SummonItem(
item_id,
charges,
aug1,
aug2,
aug3,
aug4,
aug5,
aug6,
is_attuned,
slot_id
);
}
+214 -233
View File
@@ -27,37 +27,24 @@
#include "zonedb.h"
#include "global_loot_manager.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include "quest_parser_collection.h"
#ifdef _WINDOWS
#define snprintf _snprintf
#endif
// Queries the loottable: adds item & coin to the npc
void ZoneDatabase::AddLootTableToNPC(
NPC *npc,
uint32 loottable_id,
ItemList *itemlist,
uint32 *copper,
uint32 *silver,
uint32 *gold,
uint32 *plat
)
{
const bool is_global = (
copper == nullptr &&
silver == nullptr &&
gold == nullptr &&
plat == nullptr
);
if (!is_global) {
void ZoneDatabase::AddLootTableToNPC(NPC* npc, uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
const LootTable_Struct* lts = nullptr;
// global loot passes nullptr for these
bool bGlobal = copper == nullptr && silver == nullptr && gold == nullptr && plat == nullptr;
if (!bGlobal) {
*copper = 0;
*silver = 0;
*gold = 0;
*plat = 0;
}
const auto *lts = database.GetLootTable(loottable_id);
lts = database.GetLootTable(loottable_id);
if (!lts) {
return;
}
@@ -68,23 +55,19 @@ void ZoneDatabase::AddLootTableToNPC(
uint32 min_cash = lts->mincash;
uint32 max_cash = lts->maxcash;
if (min_cash > max_cash) {
const uint32 t = min_cash;
if(min_cash > max_cash) {
uint32 t = min_cash;
min_cash = max_cash;
max_cash = t;
}
uint32 cash = 0;
if (!is_global) {
if (
max_cash > 0 &&
lts->avgcoin > 0 &&
EQ::ValueWithin(lts->avgcoin, min_cash, max_cash)
) {
const float upper_chance = static_cast<float>(lts->avgcoin - min_cash) / static_cast<float>(max_cash - min_cash);
const float avg_cash_roll = static_cast<float>(zone->random.Real(0.0, 1.0));
if (!bGlobal) {
if(max_cash > 0 && lts->avgcoin > 0 && EQ::ValueWithin(lts->avgcoin, min_cash, max_cash)) {
float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash);
float avg_cash_roll = (float)zone->random.Real(0.0, 1.0);
if (avg_cash_roll < upper_chance) {
if(avg_cash_roll < upper_chance) {
cash = zone->random.Int(lts->avgcoin, max_cash);
} else {
cash = zone->random.Int(min_cash, lts->avgcoin);
@@ -94,7 +77,7 @@ void ZoneDatabase::AddLootTableToNPC(
}
}
if (cash != 0) {
if(cash != 0) {
*plat = cash / 1000;
cash -= *plat * 1000;
@@ -107,23 +90,25 @@ void ZoneDatabase::AddLootTableToNPC(
*copper = cash;
}
const uint32 global_loot_multiplier = RuleI(Zone, GlobalLootMultiplier);
uint32 global_loot_multiplier = RuleI(Zone, GlobalLootMultiplier);
for (uint32 i = 0; i < lts->NumEntries; i++) {
// Do items
for (uint32 i=0; i<lts->NumEntries; i++) {
for (uint32 k = 1; k <= (lts->Entries[i].multiplier * global_loot_multiplier); k++) {
const uint8 drop_limit = lts->Entries[i].droplimit;
const uint8 minimum_drop = lts->Entries[i].mindrop;
uint8 droplimit = lts->Entries[i].droplimit;
uint8 mindrop = lts->Entries[i].mindrop;
//LootTable Entry probability
const float probability = lts->Entries[i].probability;
float ltchance = 0.0f;
ltchance = lts->Entries[i].probability;
float drop_chance = 0.0f;
if (EQ::ValueWithin(probability, 0.0f, 100.0f)) {
drop_chance = static_cast<float>(zone->random.Real(0.0, 100.0));
if(ltchance > 0.0 && ltchance < 100.0) {
drop_chance = (float)zone->random.Real(0.0, 100.0);
}
if (probability != 0.0 && (probability == 100.0 || drop_chance <= probability)) {
AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, drop_limit, minimum_drop);
if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance <= ltchance)) {
AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop);
}
}
}
@@ -133,29 +118,31 @@ void ZoneDatabase::AddLootTableToNPC(
// maxdrops = size of the array npcd
void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item_list, uint8 droplimit, uint8 mindrop)
{
const auto *lds = GetLootDrop(lootdrop_id);
if (
!lds ||
lds->NumEntries == 0 ||
!content_service.DoesPassContentFiltering(lds->content_flags)
) {
const LootDrop_Struct *loot_drop = GetLootDrop(lootdrop_id);
if (!loot_drop) {
return;
}
if (loot_drop->NumEntries == 0) {
return;
}
if (!content_service.DoesPassContentFiltering(loot_drop->content_flags)) {
return;
}
// if this lootdrop is droplimit=0 and mindrop 0, scan list once and return
if (droplimit == 0 && mindrop == 0) {
for (uint32 i = 0; i < lds->NumEntries; ++i) {
const uint8 charges = lds->Entries[i].multiplier;
for (int j = 0; j < charges; ++j) {
if (
zone->random.Real(0.0, 100.0) <= lds->Entries[i].chance &&
npc->MeetsLootDropLevelRequirements(lds->Entries[i], true)
) {
const EQ::ItemData *database_item = GetItem(lds->Entries[i].item_id);
for (uint32 i = 0; i < loot_drop->NumEntries; ++i) {
int charges = loot_drop->Entries[i].multiplier;
for (int j = 0; j < charges; ++j) {
if (zone->random.Real(0.0, 100.0) <= loot_drop->Entries[i].chance &&
npc->MeetsLootDropLevelRequirements(loot_drop->Entries[i], true)) {
const EQ::ItemData *database_item = GetItem(loot_drop->Entries[i].item_id);
npc->AddLootDrop(
database_item,
item_list,
lds->Entries[i]
loot_drop->Entries[i]
);
}
}
@@ -163,7 +150,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
return;
}
if (lds->NumEntries > 100 && droplimit == 0) {
if (loot_drop->NumEntries > 100 && droplimit == 0) {
droplimit = 10;
}
@@ -176,17 +163,16 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
bool roll_table_chance_bypass = false;
bool active_item_list = false;
for (uint32 i = 0; i < lds->NumEntries; ++i) {
const EQ::ItemData *db_item = GetItem(lds->Entries[i].item_id);
if (db_item && npc->MeetsLootDropLevelRequirements(lds->Entries[i])) {
roll_t += lds->Entries[i].chance;
if (lds->Entries[i].chance >= 100) {
for (uint32 i = 0; i < loot_drop->NumEntries; ++i) {
const EQ::ItemData *db_item = GetItem(loot_drop->Entries[i].item_id);
if (db_item && npc->MeetsLootDropLevelRequirements(loot_drop->Entries[i])) {
roll_t += loot_drop->Entries[i].chance;
if (loot_drop->Entries[i].chance >= 100) {
roll_table_chance_bypass = true;
} else {
no_loot_prob *= (100 - lds->Entries[i].chance) / 100.0f;
}
else {
no_loot_prob *= (100 - loot_drop->Entries[i].chance) / 100.0f;
}
active_item_list = true;
}
}
@@ -205,40 +191,41 @@ void ZoneDatabase::AddLootDropToNPC(NPC *npc, uint32 lootdrop_id, ItemList *item
for (int i = 0; i < droplimit; ++i) {
if (drops < mindrop || roll_table_chance_bypass || (float) zone->random.Real(0.0, 1.0) >= no_loot_prob) {
float roll = (float) zone->random.Real(0.0, roll_t);
for (uint32 j = 0; j < lds->NumEntries; ++j) {
const auto *db_item = GetItem(lds->Entries[j].item_id);
for (uint32 j = 0; j < loot_drop->NumEntries; ++j) {
const EQ::ItemData *db_item = GetItem(loot_drop->Entries[j].item_id);
if (db_item) {
// if it doesn't meet the requirements do nothing
if (!npc->MeetsLootDropLevelRequirements(lds->Entries[j])) {
if (!npc->MeetsLootDropLevelRequirements(loot_drop->Entries[j])) {
continue;
}
if (roll < lds->Entries[j].chance) {
if (roll < loot_drop->Entries[j].chance) {
npc->AddLootDrop(
db_item,
item_list,
lds->Entries[j]
loot_drop->Entries[j]
);
drops++;
uint8 charges = lds->Entries[i].multiplier;
charges = EQ::ClampLower(charges, static_cast<uint8>(1));
int charges = (int) loot_drop->Entries[i].multiplier;
charges = EQ::ClampLower(charges, 1);
for (int k = 1; k < charges; ++k) {
float c_roll = static_cast<float>(zone->random.Real(0.0, 100.0));
if (c_roll <= lds->Entries[i].chance) {
float c_roll = (float) zone->random.Real(0.0, 100.0);
if (c_roll <= loot_drop->Entries[i].chance) {
npc->AddLootDrop(
db_item,
item_list,
lds->Entries[i]
loot_drop->Entries[i]
);
}
}
j = lds->NumEntries;
j = loot_drop->NumEntries;
break;
} else {
roll -= lds->Entries[j].chance;
}
else {
roll -= loot_drop->Entries[j].chance;
}
}
}
@@ -304,18 +291,19 @@ void NPC::AddLootDrop(
ItemList *itemlist,
LootDropEntries_Struct loot_drop,
bool wear_change,
uint32 augment_one,
uint32 augment_two,
uint32 augment_three,
uint32 augment_four,
uint32 augment_five,
uint32 augment_six
uint32 aug1,
uint32 aug2,
uint32 aug3,
uint32 aug4,
uint32 aug5,
uint32 aug6
)
{
if (!item2) {
return;
}
//make sure we are doing something...
if (!itemlist && !wear_change) {
return;
}
@@ -352,17 +340,18 @@ void NPC::AddLootDrop(
item->item_id = item2->ID;
item->charges = loot_drop.item_charges;
item->aug_1 = augment_one;
item->aug_2 = augment_two;
item->aug_3 = augment_three;
item->aug_4 = augment_four;
item->aug_5 = augment_five;
item->aug_6 = augment_six;
item->attuned = false;
item->aug_1 = aug1;
item->aug_2 = aug2;
item->aug_3 = aug3;
item->aug_4 = aug4;
item->aug_5 = aug5;
item->aug_6 = aug6;
item->attuned = 0;
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;
// unsure if required to equip, YOLO for now
if (item2->ItemType == EQ::item::ItemTypeBow) {
SetBowEquipped(true);
@@ -374,17 +363,17 @@ void NPC::AddLootDrop(
bool found = false; // track if we found an empty slot we fit into
int found_slot = INVALID_INDEX; // for multi-slot items
int foundslot = INVALID_INDEX; // for multi-slot items
auto *inst = database.CreateItem(
const auto* inst = database.CreateItem(
item2->ID,
loot_drop.item_charges,
augment_one,
augment_two,
augment_three,
augment_four,
augment_five,
augment_six
aug1,
aug2,
aug3,
aug4,
aug5,
aug6
);
if (!inst) {
@@ -392,8 +381,9 @@ void NPC::AddLootDrop(
}
if (loot_drop.equip_item > 0) {
uint8 equipment_slot = UINT8_MAX;
const EQ::ItemData *compitem = nullptr;
uint8 eslot = 0xFF;
char newid[20];
const EQ::ItemData* compitem = nullptr;
// Equip rules are as follows:
// If the item has the NoPet flag set it will not be equipped.
@@ -405,136 +395,141 @@ void NPC::AddLootDrop(
// it is an improvement.
if (!item2->NoPet) {
for (
int i = EQ::invslot::EQUIPMENT_BEGIN;
!found && i <= EQ::invslot::EQUIPMENT_END;
i++
) {
const uint32 slots = (1 << i);
for (int i = EQ::invslot::EQUIPMENT_BEGIN; !found && i <= EQ::invslot::EQUIPMENT_END; i++) {
uint32 slots = (1 << i);
if (item2->Slots & slots) {
if (equipment[i]) {
if(equipment[i])
{
compitem = database.GetItem(equipment[i]);
if (
item2->AC > compitem->AC ||
(item2->AC == compitem->AC && item2->HP > compitem->HP)
) {
if (item2->AC > compitem->AC ||
(item2->AC == compitem->AC && item2->HP > compitem->HP))
{
// item would be an upgrade
// check if we're multi-slot, if yes then we have to keep
// looking in case any of the other slots we can fit into are empty.
if (item2->Slots != slots) {
found_slot = i;
} else {
foundslot = i;
}
else {
// Unequip old item
auto *old_item = GetItem(i);
auto* olditem = GetItem(i);
old_item->equip_slot = EQ::invslot::SLOT_INVALID;
olditem->equip_slot = EQ::invslot::SLOT_INVALID;
equipment[i] = item2->ID;
found_slot = i;
found = true;
foundslot = i;
found = true;
}
}
} else {
equipment[i] = item2->ID;
found_slot = i;
found = true;
} // end if ac
}
}
}
}
else
{
equipment[i] = item2->ID;
foundslot = i;
found = true;
}
} // end if (slots)
} // end for
} // end if NoPet
// Possible slot was found but not selected. Pick it now.
if (!found && found_slot >= 0) {
equipment[found_slot] = item2->ID;
if (!found && foundslot >= 0) {
equipment[foundslot] = item2->ID;
found = true;
}
uint32 equipment_material;
if (
item2->Material <= 0 ||
(
item2->Slots & (
(1 << EQ::invslot::slotPrimary) |
(1 << EQ::invslot::slotSecondary)
)
)
) {
equipment_material = Strings::ToUnsignedInt(&item2->IDFile[2]);
} else {
equipment_material = item2->Material;
}
if (found_slot == EQ::invslot::slotPrimary) {
equipment_slot = EQ::textures::weaponPrimary;
if (item2->Damage > 0) {
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
if (!RuleB(Combat, ClassicNPCBackstab)) {
SetFacestab(true);
// @merth: IDFile size has been increased, this needs to change
uint16 emat;
if(item2->Material <= 0
|| (item2->Slots & ((1 << EQ::invslot::slotPrimary) | (1 << EQ::invslot::slotSecondary)))) {
memset(newid, 0, sizeof(newid));
for(int i=0;i<7;i++){
if (!isalpha(item2->IDFile[i])){
strn0cpy(newid, &item2->IDFile[i],6);
i=8;
}
}
if (item2->IsType2HWeapon()) {
SetTwoHanderEquipped(true);
}
} else if (
found_slot == EQ::invslot::slotSecondary &&
(
GetOwner() ||
(CanThisClassDualWield() && zone->random.Roll(NPC_DW_CHANCE)) ||
item2->Damage == 0
) &&
(
item2->IsType1HWeapon() ||
item2->ItemType == EQ::item::ItemTypeShield ||
item2->ItemType == EQ::item::ItemTypeLight
)
) {
equipment_slot = EQ::textures::weaponSecondary;
emat = Strings::ToInt(newid);
} else {
emat = item2->Material;
}
if (foundslot == EQ::invslot::slotPrimary) {
eslot = EQ::textures::weaponPrimary;
if (item2->Damage > 0) {
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
if (!RuleB(Combat, ClassicNPCBackstab))
SetFacestab(true);
}
if (item2->IsType2HWeapon())
SetTwoHanderEquipped(true);
}
else if (foundslot == EQ::invslot::slotSecondary
&& (GetOwner() != nullptr || (CanThisClassDualWield() && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) &&
(item2->IsType1HWeapon() || item2->ItemType == EQ::item::ItemTypeShield || item2->ItemType == EQ::item::ItemTypeLight))
{
eslot = EQ::textures::weaponSecondary;
if (item2->Damage > 0)
SendAddPlayerState(PlayerState::SecondaryWeaponEquipped);
}
} else if (found_slot == EQ::invslot::slotHead) {
equipment_slot = EQ::textures::armorHead;
} else if (found_slot == EQ::invslot::slotChest) {
equipment_slot = EQ::textures::armorChest;
} else if (found_slot == EQ::invslot::slotArms) {
equipment_slot = EQ::textures::armorArms;
} else if (EQ::ValueWithin(found_slot, EQ::invslot::slotWrist1, EQ::invslot::slotWrist2)) {
equipment_slot = EQ::textures::armorWrist;
} else if (found_slot == EQ::invslot::slotHands) {
equipment_slot = EQ::textures::armorHands;
} else if (found_slot == EQ::invslot::slotLegs) {
equipment_slot = EQ::textures::armorLegs;
} else if (found_slot == EQ::invslot::slotFeet) {
equipment_slot = EQ::textures::armorFeet;
}
else if (foundslot == EQ::invslot::slotHead) {
eslot = EQ::textures::armorHead;
}
else if (foundslot == EQ::invslot::slotChest) {
eslot = EQ::textures::armorChest;
}
else if (foundslot == EQ::invslot::slotArms) {
eslot = EQ::textures::armorArms;
}
else if (foundslot == EQ::invslot::slotWrist1 || foundslot == EQ::invslot::slotWrist2) {
eslot = EQ::textures::armorWrist;
}
else if (foundslot == EQ::invslot::slotHands) {
eslot = EQ::textures::armorHands;
}
else if (foundslot == EQ::invslot::slotLegs) {
eslot = EQ::textures::armorLegs;
}
else if (foundslot == EQ::invslot::slotFeet) {
eslot = EQ::textures::armorFeet;
}
if (equipment_slot != UINT8_MAX) {
if (wear_change) {
p_wear_change_struct->wear_slot_id = equipment_slot;
p_wear_change_struct->material = equipment_material;
}
}
/*
what was this about???
if (((npc->GetRace()==127) && (npc->CastToMob()->GetOwnerID()!=0)) && (item2->Slots==24576) || (item2->Slots==8192) || (item2->Slots==16384)){
npc->d_melee_texture2=Strings::ToInt(newid);
wc->wear_slot_id=8;
if (item2->Material >0)
wc->material=item2->Material;
else
wc->material=Strings::ToInt(newid);
npc->AC+=item2->AC;
npc->STR+=item2->STR;
npc->INT+=item2->INT;
}
*/
//if we found an open slot it goes in...
if(eslot != 0xFF) {
if(wear_change) {
p_wear_change_struct->wear_slot_id = eslot;
p_wear_change_struct->material = emat;
}
}
if (found) {
item->equip_slot = found_slot;
item->equip_slot = foundslot;
}
}
if (itemlist) {
if (found_slot != INVALID_INDEX) {
GetInv().PutItem(found_slot, *inst);
}
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_LOOT_ADDED)) {
std::vector<std::any> args = { inst };
parse->EventNPC(EVENT_LOOT_ADDED, this, nullptr, "", 0, &args);
if (foundslot != INVALID_INDEX) {
GetInv().PutItem(foundslot, *inst);
}
itemlist->push_back(item);
@@ -556,69 +551,55 @@ void NPC::AddLootDrop(
}
UpdateEquipmentLight();
if (UpdateActiveLight()) {
SendAppearancePacket(AT_Light, GetActiveLightType());
}
}
void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item)
void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equipitem)
{
//slot isnt needed, its determined from the item.
auto loot_drop_entry = NPC::NewLootDropEntry();
loot_drop_entry.equip_item = static_cast<uint8>(equip_item ? 1 : 0);
loot_drop_entry.equip_item = static_cast<uint8>(equipitem ? 1 : 0);
loot_drop_entry.item_charges = charges;
AddLootDrop(item, &itemlist, loot_drop_entry, true);
}
void NPC::AddItem(
uint32 item_id,
uint32 itemid,
uint16 charges,
bool equip_item,
uint32 augment_one,
uint32 augment_two,
uint32 augment_three,
uint32 augment_four,
uint32 augment_five,
uint32 augment_six
bool equipitem,
uint32 aug1,
uint32 aug2,
uint32 aug3,
uint32 aug4,
uint32 aug5,
uint32 aug6
)
{
const auto *item = database.GetItem(item_id);
if (!item) {
//slot isnt needed, its determined from the item.
const EQ::ItemData *i = database.GetItem(itemid);
if (i == nullptr) {
return;
}
auto loot_drop_entry = NPC::NewLootDropEntry();
loot_drop_entry.equip_item = static_cast<uint8>(equip_item ? 1 : 0);
loot_drop_entry.equip_item = static_cast<uint8>(equipitem ? 1 : 0);
loot_drop_entry.item_charges = charges;
AddLootDrop(
item,
&itemlist,
loot_drop_entry,
true,
augment_one,
augment_two,
augment_three,
augment_four,
augment_five,
augment_six
);
AddLootDrop(i, &itemlist, loot_drop_entry, true, aug1, aug2, aug3, aug4, aug5, aug6);
}
void NPC::AddLootTable()
{
void NPC::AddLootTable() {
if (npctype_id != 0) { // check if it's a GM spawn
database.AddLootTableToNPC(this, loottable_id, &itemlist, &copper, &silver, &gold, &platinum);
database.AddLootTableToNPC(this,loottable_id, &itemlist, &copper, &silver, &gold, &platinum);
}
}
void NPC::AddLootTable(uint32 loottable_id)
{
void NPC::AddLootTable(uint32 ldid) {
if (npctype_id != 0) { // check if it's a GM spawn
database.AddLootTableToNPC(this, loottable_id, &itemlist, &copper, &silver, &gold, &platinum);
database.AddLootTableToNPC(this,ldid, &itemlist, &copper, &silver, &gold, &platinum);
}
}
+1 -109
View File
@@ -389,96 +389,6 @@ int Lua_Bot::GetRawItemAC() {
return self->GetRawItemAC();
}
void Lua_Bot::ClearDisciplineReuseTimer() {
Lua_Safe_Call_Void();
return self->ClearDisciplineReuseTimer();
}
void Lua_Bot::ClearDisciplineReuseTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->ClearDisciplineReuseTimer(spell_id);
}
void Lua_Bot::ClearItemReuseTimer() {
Lua_Safe_Call_Void();
return self->ClearItemReuseTimer();
}
void Lua_Bot::ClearItemReuseTimer(uint32 item_id) {
Lua_Safe_Call_Void();
return self->ClearItemReuseTimer(item_id);
}
void Lua_Bot::ClearSpellRecastTimer() {
Lua_Safe_Call_Void();
return self->ClearSpellRecastTimer();
}
void Lua_Bot::ClearSpellRecastTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->ClearSpellRecastTimer(spell_id);
}
uint32 Lua_Bot::GetDisciplineReuseTimer() {
Lua_Safe_Call_Int();
return self->GetDisciplineReuseRemainingTime();
}
uint32 Lua_Bot::GetDisciplineReuseTimer(uint16 spell_id) {
Lua_Safe_Call_Int();
return self->GetDisciplineReuseRemainingTime(spell_id);
}
uint32 Lua_Bot::GetItemReuseTimer() {
Lua_Safe_Call_Int();
return self->GetItemReuseRemainingTime();
}
uint32 Lua_Bot::GetItemReuseTimer(uint32 item_id) {
Lua_Safe_Call_Int();
return self->GetItemReuseRemainingTime(item_id);
}
uint32 Lua_Bot::GetSpellRecastTimer() {
Lua_Safe_Call_Int();
return self->GetSpellRecastRemainingTime();
}
uint32 Lua_Bot::GetSpellRecastTimer(uint16 spell_id) {
Lua_Safe_Call_Int();
return self->GetSpellRecastRemainingTime(spell_id);
}
void Lua_Bot::SetDisciplineReuseTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->SetDisciplineReuseTimer(spell_id);
}
void Lua_Bot::SetDisciplineReuseTimer(uint16 spell_id, uint32 reuse_timer) {
Lua_Safe_Call_Void();
return self->SetDisciplineReuseTimer(spell_id, reuse_timer);
}
void Lua_Bot::SetItemReuseTimer(uint32 item_id) {
Lua_Safe_Call_Void();
return self->SetItemReuseTimer(item_id);
}
void Lua_Bot::SetItemReuseTimer(uint32 item_id, uint32 reuse_timer) {
Lua_Safe_Call_Void();
return self->SetItemReuseTimer(item_id, reuse_timer);
}
void Lua_Bot::SetSpellRecastTimer(uint16 spell_id) {
Lua_Safe_Call_Void();
return self->SetSpellRecastTimer(spell_id);
}
void Lua_Bot::SetSpellRecastTimer(uint16 spell_id, uint32 recast_delay) {
Lua_Safe_Call_Void();
return self->SetSpellRecastTimer(spell_id, recast_delay);
}
bool Lua_Bot::IsGrouped() {
Lua_Safe_Call_Bool();
return self->IsGrouped();
@@ -690,12 +600,6 @@ luabind::scope lua_register_bot() {
.def("ApplySpellRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::ApplySpellRaid)
.def("Camp", (void(Lua_Bot::*)(void))&Lua_Bot::Camp)
.def("Camp", (void(Lua_Bot::*)(bool))&Lua_Bot::Camp)
.def("ClearDisciplineReuseTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearDisciplineReuseTimer)
.def("ClearDisciplineReuseTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::ClearDisciplineReuseTimer)
.def("ClearItemReuseTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearItemReuseTimer)
.def("ClearItemReuseTimer", (void(Lua_Bot::*)(uint32))&Lua_Bot::ClearItemReuseTimer)
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearSpellRecastTimer)
.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("DeleteBucket", (void(Lua_Bot::*)(std::string))&Lua_Bot::DeleteBucket)
@@ -719,8 +623,6 @@ luabind::scope lua_register_bot() {
.def("GetBotID", (uint32(Lua_Bot::*)(void))&Lua_Bot::GetBotID)
.def("GetBotItem", (Lua_ItemInst(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItem)
.def("GetBotItemIDBySlot", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetBotItemIDBySlot)
.def("GetDisciplineReuseTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetDisciplineReuseTimer)
.def("GetDisciplineReuseTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetDisciplineReuseTimer)
.def("GetBucket", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucket)
.def("GetBucketExpires", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketExpires)
.def("GetBucketRemaining", (std::string(Lua_Bot::*)(std::string))&Lua_Bot::GetBucketRemaining)
@@ -731,17 +633,13 @@ luabind::scope lua_register_bot() {
.def("GetInstrumentMod", (int(Lua_Bot::*)(int))&Lua_Bot::GetInstrumentMod)
.def("GetItemAt", (Lua_ItemInst(Lua_Bot::*)(int16))&Lua_Bot::GetItemAt)
.def("GetItemIDAt", (int(Lua_Bot::*)(int16))&Lua_Bot::GetItemIDAt)
.def("GetItemReuseTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetItemReuseTimer)
.def("GetItemReuseTimer", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::GetItemReuseTimer)
.def("GetOwner", (Lua_Mob(Lua_Bot::*)(void))&Lua_Bot::GetOwner)
.def("GetRaceAbbreviation", (std::string(Lua_Bot::*)(void))&Lua_Bot::GetRaceAbbreviation)
.def("GetRawItemAC", (int(Lua_Bot::*)(void))&Lua_Bot::GetRawItemAC)
.def("GetSpellDamage", (int(Lua_Bot::*)(void))&Lua_Bot::GetSpellDamage)
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)())&Lua_Bot::GetSpellRecastTimer)
.def("GetSpellRecastTimer", (uint32(Lua_Bot::*)(uint16))&Lua_Bot::GetSpellRecastTimer)
.def("HasAugmentEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasAugmentEquippedByID)
.def("HasBotItem", (int16(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem)
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16))&Lua_Bot::HasBotSpellEntry)
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16)) & Lua_Bot::HasBotSpellEntry)
.def("HasItemEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasItemEquippedByID)
.def("IsGrouped", (bool(Lua_Bot::*)(void))&Lua_Bot::IsGrouped)
.def("IsSitting", (bool(Lua_Bot::*)(void))&Lua_Bot::IsSitting)
@@ -757,10 +655,6 @@ luabind::scope lua_register_bot() {
.def("SetBucket", (void(Lua_Bot::*)(std::string,std::string,std::string))&Lua_Bot::SetBucket)
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int))&Lua_Bot::SetExpansionBitmask)
.def("SetExpansionBitmask", (void(Lua_Bot::*)(int,bool))&Lua_Bot::SetExpansionBitmask)
.def("SetDisciplineReuseTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetDisciplineReuseTimer)
.def("SetDisciplineReuseTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetDisciplineReuseTimer)
.def("SetItemReuseTimer", (void(Lua_Bot::*)(uint32))&Lua_Bot::SetItemReuseTimer)
.def("SetItemReuseTimer", (void(Lua_Bot::*)(uint32, uint32))&Lua_Bot::SetItemReuseTimer)
.def("SetSpellDuration", (void(Lua_Bot::*)(int))&Lua_Bot::SetSpellDuration)
.def("SetSpellDuration", (void(Lua_Bot::*)(int,int))&Lua_Bot::SetSpellDuration)
.def("SetSpellDuration", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDuration)
@@ -774,8 +668,6 @@ luabind::scope lua_register_bot() {
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int))&Lua_Bot::SetSpellDurationRaid)
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool))&Lua_Bot::SetSpellDurationRaid)
.def("SetSpellDurationRaid", (void(Lua_Bot::*)(int,int,int,bool,bool))&Lua_Bot::SetSpellDurationRaid)
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::SetSpellRecastTimer)
.def("SetSpellRecastTimer", (void(Lua_Bot::*)(uint16, uint32))&Lua_Bot::SetSpellRecastTimer)
.def("SendPayload", (void(Lua_Bot::*)(int))&Lua_Bot::SendPayload)
.def("SendPayload", (void(Lua_Bot::*)(int,std::string))&Lua_Bot::SendPayload)
.def("Signal", (void(Lua_Bot::*)(int))&Lua_Bot::Signal)

Some files were not shown because too many files have changed in this diff Show More