Compare commits

...

15 Commits

Author SHA1 Message Date
Chris Miles a7e9af2d27 [Release] 22.38.0 (#3803) 2023-12-26 16:30:09 -05:00
Chris Miles 7a72d5d67e [Repositories] Add ReplaceOne and ReplaceMany (#3802) 2023-12-25 20:53:44 -05:00
regneq 25872203ff [NPC] Support for multiple emotes per type, emote variables (#3801)
* [forage rule feature] add a rule to disabled using common_food_ids from the list in forage.cpp.  currently set to enabled.

* NPC database emotes now supports basic variables. More than one variable can be used at a time.

* Format manifest

* Formatting

* Formatting

* Formatting

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2023-12-24 23:28:57 -06:00
Alex King 6396a6fbef [Cleanup] Consolidate GetHateRandom(), GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC() (#3794)
* [Cleanup] Consolidate GetHateRandomBot(), GetHateRandomClient(), and GetHateRandomNPC()

# Notes
- These were separate methods and duplicated a lot of code, consolidated into the singular method using the `EntityFilterType`.

* Simplify random logic. Use filtered hate list.

* D

* D
2023-12-24 23:28:47 -06:00
Chris Miles 6db0a5c3f0 [Database] Fix issue with saylinks query in MySQL 8.0+ (#3800) 2023-12-24 09:43:31 -06:00
Chris Miles 4fa9e1d66f [Code Cleanup] Race constants refactor (#3782)
* [Code Cleanup] Race constants refactor

* Update races.h
2023-12-22 21:34:55 -06:00
JJ 556af8c5e9 [Database] Update faction mods with Live data (#3799)
Optional update to bring database up-to-date with Live data which includes Froglok and Drakkin data which was previously missing.
Raw data can be found in the Live client at Resources\Faction\FactionAssociations.txt
See discussion at #3678
2023-12-22 21:34:35 -06:00
Alex King f3ef8a0993 [Quest API] Add SummonItemIntoInventory() to Perl/Lua (#3797)
* [Quest API] Add SummonItemIntoInventory() to Perl/Lua

# Perl
- Add `$client->SummonItemIntoInventory(item_data)`.

## Example
```pl
sub EVENT_SAY {
	if ($text=~/#a/i) {
		my %item_data = (
			"item_id" => 32557,
			"charges" => 1
		);
		$client->SummonItemIntoInventory(\%item_data);
	}
}
```

# Lua
- Add `client:SummonItemIntoInventory(item_data)`.

## Example
```lua
function event_say(e)
	if e.message:find("#a") then
		local item_data = {
			"item_id" = 32557,
			"charges" = 1
		}
		e.self:SummonItemIntoInventory(item_data)
	end
end
```

* Update effects.cpp
2023-12-22 02:45:40 -06:00
regneq 267c280db8 [forage rule feature] add a rule to disabled using common_food_ids from the list in forage.cpp. currently set to enabled. (#3796) 2023-12-22 02:43:17 -06:00
Alex King e06c7d7735 [Quest API] Add GetHateTopBot(), GetHateTopClient(), and GetHateTopNPC() to Perl/Lua (#3793)
# Perl
- Add `$mob->GetHateTopBot()`.
- Add `$mob->GetHateTopClient()`.
- Add `$mob->GetHateTopNPC()`.

# Lua
- Add `mob:GetHateTopBot()`.
- Add `mob:GetHateTopClient()`.
- Add `mob:GetHateTopNPC()`.
2023-12-22 02:41:32 -06:00
nytmyr 028ebc3a0c [Bots] Remove unnecessary error on SetItemReuse (#3795)
This error is not necessary as it can be triggered when clicked spells have secondary effects that run through the same spell checks for clicked items but aren't actually clicked by the item. Spells that trigger other spell effects and some Bard scaling songs could trigger this after the initial click.
2023-12-20 10:01:54 -05:00
Alex King b3bd44cd76 [Bug Fix] Fix can_riposte parameter in DoMeleeSkillAttackDmg (#3792)
# Note
- `can_riposte` logic was reverse, setting to `true` caused the attack to not be able to be riposted, the opposite of the intended functionality.
2023-12-18 22:27:58 -05:00
Alex King 75a627a3a2 [Bug Fix] Disable Hide/Improved Hide on Trap damage (#3791)
# Notes
- Further fixes an issue where traps don't drop hide/invisible.
2023-12-18 22:24:03 -05:00
dependabot[bot] 0194aedc92 Bump golang.org/x/crypto in /utils/scripts/build/should-release (#3790)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-18 18:10:48 -06:00
Alex King 5cc87cbda7 [Bug Fix] Fix Bard Invisibility Songs breaking every 4 ticks (#3783)
# Notes
- Fixes #2361.
2023-12-18 18:10:28 -06:00
61 changed files with 12409 additions and 2869 deletions
+39
View File
@@ -1,3 +1,42 @@
## [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
@@ -5133,6 +5133,16 @@ 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`;
)"
}
+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_NERIAK_CITIZEN_77) {
if (r2 == Race::NeriakCitizen) {
return true;
}
break;
case BARBARIAN:
if (r2 == RACE_HALAS_CITIZEN_90) {
if (r2 == Race::HalasCitizen) {
return true;
}
}
+19 -18
View File
@@ -801,34 +801,35 @@ 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)
{
// Check basic inventory
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
continue;
const int16 last_bag_slot = RuleI(World, ExpansionSettings) & EQ::expansions::bitHoT ? EQ::invslot::slotGeneral10 : EQ::invslot::slotGeneral8;
if (!GetItem(i))
// Found available slot in personal inventory
return i;
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) { // Check basic inventory
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
continue;
}
if (!GetItem(i)) {
return i; // Found available slot in personal inventory
}
}
if (!for_bag) {
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
for (int16 i = invslot::GENERAL_BEGIN; i <= last_bag_slot; i++) {
if ((((uint64) 1 << i) & m_lookup->PossessionsBitmask) == 0) {
continue;
}
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)
{
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) {
continue;
}
int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
const int16 base_slot_id = InventoryProfile::CalcSlotId(i, invbag::SLOT_BEGIN);
uint8 slots = inst->GetItem()->BagSlots;
uint8 j;
for (j = invbag::SLOT_BEGIN; j<slots; j++) {
const uint8 slots = inst->GetItem()->BagSlots;
for (uint8 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_0, 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, 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
@@ -1273,7 +1273,7 @@ int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
{
int race = RACE_DOUG_0;
int race = Race::Doug;
const auto item = GetItem();
if (item) {
race = item->BaneDmgRace;
+4 -4
View File
@@ -3868,8 +3868,8 @@ namespace RoF
}
float SpawnSize = emu->size;
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))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
for (k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
@@ -2733,8 +2733,8 @@ namespace SoD
}
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)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522))
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
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_12) || (emu->race == RACE_IKSAR_128) ||
(emu->race == RACE_VAH_SHIR_130) || (emu->race == RACE_FROGLOK_330) || (emu->race == RACE_DRAKKIN_522)
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
)
{
structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer;
+755 -755
View File
File diff suppressed because it is too large Load Diff
+739 -1471
View File
File diff suppressed because it is too large Load Diff
@@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseNpcEmotesRepository {
public:
struct NpcEmotes {
@@ -120,8 +121,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} 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://eqemu.gitbook.io/server/in-development/developer-area/repositories
* @docs https://docs.eqemu.io/developer/repositories
*/
#ifndef EQEMU_BASE_{{TABLE_NAME_UPPER}}_REPOSITORY_H
@@ -319,6 +319,62 @@ 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
View File
@@ -215,6 +215,7 @@ 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)
+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 BINARY '[A-Z]' and phrase not REGEXP '[0-9]'");
auto saylinks = SaylinkRepository::GetWhere(database, "phrase not REGEXP '[A-Z]' and phrase not REGEXP '[0-9]'");
LogSaylink("Loaded [{}] saylinks into cache", saylinks.size());
g_cached_saylinks = saylinks;
}
+2 -2
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.37.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.38.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9247
#define CURRENT_BINARY_DATABASE_VERSION 9248
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9041
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.37.0",
"version": "22.38.0",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
+8
View File
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,4 @@
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
@@ -0,0 +1,313 @@
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)
}
}
}
+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.14.0 // indirect
golang.org/x/crypto v0.17.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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
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/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
+4 -4
View File
@@ -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_LAVA_DRAGON_49 || GetRace() == RACE_WURM_158 || GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) { //For races with a fixed size
size_mod = 60.0f;
}
else if (size_mod < 6.0) {
size_mod = 8.0f;
}
if (other->GetRace() == RACE_LAVA_DRAGON_49 || other->GetRace() == RACE_WURM_158 || other->GetRace() == RACE_GHOST_DRAGON_196) { //For races with a fixed size
if (other->GetRace() == Race::LavaDragon || other->GetRace() == Race::Wurm || other->GetRace() == Race::GhostDragon) { //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_VELIOUS_DRAGON_184) // Lord Vyemm and other velious dragons
if (other->GetRace() == Race::VeliousDragon) // Lord Vyemm and other velious dragons
{
size_mod *= 1.75;
}
if (other->GetRace() == RACE_DRAGON_SKELETON_122) // Dracoliche in Fear. Skeletal Dragon
if (other->GetRace() == Race::DragonSkeleton) // Dracoliche in Fear. Skeletal Dragon
{
size_mod *= 2.25;
}
+6 -6
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);
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid, this);
}
killerMob->TrySpellOnKill(killed_level, spell);
@@ -2710,7 +2710,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
if (IsNPC()) {
auto emote_id = GetEmoteID();
if (emote_id) {
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid);
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid, killer_mob);
}
}
@@ -2721,7 +2721,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
auto emote_id = oos->GetEmoteID();
if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id);
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
}
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell);
@@ -2799,7 +2799,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);
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer);
if (killer != 0 && killer->IsClient()) {
corpse->AllowPlayerLoot(killer, 0);
if (killer->IsGrouped()) {
@@ -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_OGGOK_CITIZEN_93
GetBaseRace() == Race::OggokCitizen
) {
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_OGGOK_CITIZEN_93
GetBaseRace() == Race::OggokCitizen
)
) {
is_immune_to_frontal_stun = true;
+4 -4
View File
@@ -2681,7 +2681,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() == RT_DRAGON || GetRace() == RT_WURM || GetRace() == RT_DRAGON_7) {
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) {
// size_mod = 60.0f;
}
@@ -2690,7 +2690,7 @@ void Bot::CalcMeleeDistances(const Mob* tar, const EQ::ItemInstance* const& p_it
}
// For races with a fixed size
if (tar->GetRace() == RT_DRAGON || tar->GetRace() == RT_WURM || tar->GetRace() == RT_DRAGON_7) {
if (tar->GetRace() == Race::LavaDragon || tar->GetRace() == Race::Wurm || tar->GetRace() == Race::GhostDragon) {
other_size_mod = 60.0f;
}
@@ -2902,12 +2902,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.GetEscapingEntOnHateList(leash_owner, leash_distance)) {
if (auto escaping = hate_list.GetEscapingMobOnHateList(leash_owner, leash_distance)) {
SetTarget(escaping);
}
if (!GetTarget()) {
auto most_hate = hate_list.GetEntWithMostHateOnList(this, nullptr, true);
auto most_hate = hate_list.GetMobWithMostHateOnList(this, nullptr, true);
if (most_hate) {
SetTarget(most_hate);
}
+10 -10
View File
@@ -5913,11 +5913,11 @@ void bot_command_view_combos(Client *c, const Seperator *sep)
};
const uint16 race_values[17] = {
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
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
};
if (helper_command_alias_fail(c, "bot_command_view_combos", sep->arg[0], "viewcombos")) {
@@ -6028,11 +6028,11 @@ void bot_subcommand_bot_create(Client *c, const Seperator *sep)
};
const uint16 race_values[17] = {
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
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
};
const std::string gender_substrs[2] = {
+43 -43
View File
@@ -6172,7 +6172,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);
n->DoNPCEmote(EQ::constants::EmoteEventTypes::Hailed, emote_id, this);
}
}
@@ -8632,8 +8632,8 @@ void Client::InitInnates()
m_pp.InnateSkills[InnateInspect] = InnateEnabled;
m_pp.InnateSkills[InnateOpen] = InnateEnabled;
if (race >= RT_FROGLOK_3) {
if (race == RT_SKELETON_2 || race == RT_FROGLOK_3) {
if (race >= Race::Froglok2) {
if (race == Race::Skeleton2 || race == Race::Froglok2) {
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
} else {
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
@@ -8641,75 +8641,75 @@ void Client::InitInnates()
}
switch (race) {
case RT_BARBARIAN:
case RT_BARBARIAN_2:
case Race::Barbarian:
case Race::HalasCitizen:
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
break;
case RT_ERUDITE:
case RT_ERUDITE_2:
case Race::Erudite:
case Race::EruditeCitizen:
m_pp.InnateSkills[InnateLore] = InnateEnabled;
break;
case RT_WOOD_ELF:
case RT_GUARD_3:
case Race::WoodElf:
case Race::Fayguard:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_GNOME:
case RT_HIGH_ELF:
case RT_GUARD_2:
case Race::Gnome:
case Race::HighElf:
case Race::Felguard:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
m_pp.InnateSkills[InnateLore] = InnateEnabled;
break;
case RT_TROLL:
case RT_TROLL_2:
case Race::Troll:
case Race::GrobbCitizen:
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_DWARF:
case RT_DWARF_2:
case Race::Dwarf:
case Race::KaladimCitizen:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_OGRE:
case RT_OGRE_2:
case Race::Ogre:
case Race::OggokCitizen:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
m_pp.InnateSkills[InnateSlam] = InnateEnabled;
m_pp.InnateSkills[InnateNoBash] = InnateEnabled;
m_pp.InnateSkills[InnateBashDoor] = InnateEnabled;
break;
case RT_HALFLING:
case RT_HALFLING_2:
case Race::Halfling:
case Race::RivervaleCitizen:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_IKSAR:
case Race::Iksar:
m_pp.InnateSkills[InnateRegen] = InnateEnabled;
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
case RT_VAH_SHIR:
case Race::VahShir:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
break;
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:
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:
m_pp.InnateSkills[InnateUltraVision] = InnateEnabled;
break;
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
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
break;
default:
m_pp.InnateSkills[InnateInfravision] = InnateEnabled;
+1
View File
@@ -982,6 +982,7 @@ 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);
+1
View File
@@ -6287,6 +6287,7 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
if (ed->dmgtype == EQ::constants::EnvironmentalDamage::Trap) {
BreakInvisibleSpells();
CancelSneakHide();
}
}
+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_0;
uint32 PlayerRace = Race::Doug;
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_2254 &&
mob->GetRace() == Race::Node &&
mob->EntityVariableExists("grid_id") &&
Strings::ToInt(mob->GetEntityVariable("grid_id")) == grid_id)
{
+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) {
if (foragedfood == 0 && RuleB(Character, UseForageCommonFood)) {
uint8 index = 0;
index = zone->random.Int(0, MAX_COMMON_FOOD_IDS-1);
foragedfood = common_food_ids[index];
+2 -10
View File
@@ -7,10 +7,7 @@ void FindEmote(Client *c, const Seperator *sep)
if (sep->IsNumber(2)) {
auto emote_id = Strings::ToUnsignedInt(sep->arg[2]);
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
auto &e = iterator.GetData();
for (auto& e : zone->npc_emote_list) {
if (emote_id == e->emoteid) {
c->Message(
Chat::White,
@@ -40,7 +37,6 @@ void FindEmote(Client *c, const Seperator *sep)
break;
}
iterator.Advance();
}
if (found_count == 50) {
@@ -70,10 +66,7 @@ void FindEmote(Client *c, const Seperator *sep)
const std::string& search_criteria = sep->argplus[2];
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
auto &e = iterator.GetData();
for (auto& e : zone->npc_emote_list) {
const std::string& current_text = Strings::ToLower(e->text);
@@ -106,7 +99,6 @@ 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_1, RACE_PEGASUS_732)) {
if (EQ::ValueWithin(race_id, Race::Human, Race::Pegasus3)) {
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_1; race_id <= RACE_PEGASUS_732; race_id++) {
for (uint16 race_id = Race::Human; race_id <= Race::Pegasus3; 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_0, RuleI(NPC, MaxRaceID)) &&
!EQ::ValueWithin(race_id, Race::Doug, RuleI(NPC, MaxRaceID)) &&
!EQ::ValueWithin(race_id, 2253, 2259)
) {
c->Message(
+1 -5
View File
@@ -12,10 +12,7 @@ void ShowEmotes(Client *c, const Seperator *sep)
uint32 emote_count = 0;
const uint32 emote_id = t->GetEmoteID();
LinkedListIterator<NPC_Emote_Struct *> iterator(zone->NPCEmoteList);
iterator.Reset();
while (iterator.MoreElements()) {
const auto& e = iterator.GetData();
for (auto& e : zone->npc_emote_list) {
if (emote_id == e->emoteid) {
c->Message(
Chat::White,
@@ -41,7 +38,6 @@ 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_2254) {
if (mob->IsNPC() && mob->GetRace() == Race::Node) {
mob->Depop();
}
}
+126 -257
View File
@@ -149,7 +149,7 @@ Mob* HateList::GetDamageTopOnHateList(Mob* hater)
return current;
}
Mob* HateList::GetClosestEntOnHateList(Mob *hater, bool skip_mezzed, EntityFilterType entity_type) {
Mob* HateList::GetClosestEntOnHateList(Mob *hater, bool skip_mezzed, EntityFilterType filter_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 (entity_type) {
switch (filter_type) {
case EntityFilterType::Bots:
if (!e->entity_on_hatelist->IsBot()) {
continue;
@@ -344,191 +344,215 @@ 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::GetEntWithMostHateOnList(Mob *center, Mob *skip, bool skip_mezzed)
Mob *HateList::GetMobWithMostHateOnList(
Mob *center,
Mob *skip,
bool skip_mezzed,
EntityFilterType filter_type
)
{
// hack fix for zone shutdown crashes on some servers
if (!zone->IsLoaded())
if (!zone->IsLoaded()) { // hack fix for zone shutdown crashes on some servers
return nullptr;
}
Mob* top_hate = nullptr;
int64 hate = -1;
Mob *top_hate = nullptr;
int64 hate = -1;
if (center == nullptr)
if (!center) {
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;
}
if (!cur->entity_on_hatelist){
Mob *m = cur->entity_on_hatelist;
if (!m) {
++iterator;
continue;
}
if (cur->entity_on_hatelist == skip) {
if (m == skip) {
++iterator;
continue;
}
if (skip_mezzed && cur->entity_on_hatelist->IsMezzed()) {
if (skip_mezzed && m->IsMezzed()) {
++iterator;
continue;
}
if (cur->entity_on_hatelist->Sanctuary()) {
if (hate == -1)
{
top_hate = cur->entity_on_hatelist;
hate = 1;
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;
}
++iterator;
continue;
}
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;
if (m->DivineAura() || m->IsMezzed() || m->IsFeared()) {
if (hate == -1) {
top_hate = m;
hate = 0;
}
++iterator;
continue;
}
int64 current_hate = cur->stored_hate_amount;
if (cur->entity_on_hatelist->IsClient() || cur->entity_on_hatelist->IsBot()){
if (cur->entity_on_hatelist->IsClient() && cur->entity_on_hatelist->CastToClient()->IsSitting()){
if (m->IsOfClientBot()) {
if (m->IsClient() && m->CastToClient()->IsSitting()) {
aggro_mod += RuleI(Aggro, SittingAggroMod);
}
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
if (center) {
if (center->GetTarget() == m) {
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if (center->CombatRange(cur->entity_on_hatelist)){
}
if (RuleI(Aggro, MeleeRangeAggroMod) != 0) {
if (center->CombatRange(m)) {
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 = cur->entity_on_hatelist;
top_client_type_in_range = m;
}
}
}
}
}
else{
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
} else {
if (center) {
if (center->GetTarget() == m) {
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if (center->CombatRange(cur->entity_on_hatelist)){
}
if (RuleI(Aggro, MeleeRangeAggroMod) != 0) {
if (center->CombatRange(m)) {
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
}
}
}
}
if (cur->entity_on_hatelist->GetMaxHP() != 0 && ((cur->entity_on_hatelist->GetHP() * 100 / cur->entity_on_hatelist->GetMaxHP()) < 20)){
if (m->GetMaxHP() != 0 && ((m->GetHP() * 100 / m->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 = cur->entity_on_hatelist;
if (current_hate > hate || cur->is_entity_frenzy) {
hate = current_hate;
top_hate = m;
}
++iterator;
}
if (top_client_type_in_range != nullptr && top_hate != nullptr) {
bool isTopClientType = top_hate->IsClient();
if (!isTopClientType) {
if (top_client_type_in_range && top_hate) {
bool is_top_client_type = top_hate->IsClient();
if (!is_top_client_type) {
if (top_hate->IsBot()) {
isTopClientType = true;
is_top_client_type = true;
top_client_type_in_range = top_hate;
}
}
if (!isTopClientType) {
if (!is_top_client_type) {
if (top_hate->IsMerc()) {
isTopClientType = true;
is_top_client_type = true;
top_client_type_in_range = top_hate;
}
}
if (!isTopClientType) {
if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)){
isTopClientType = true;
if (!is_top_client_type) {
if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)) {
is_top_client_type = true;
top_client_type_in_range = top_hate;
}
}
if (!isTopClientType)
if (!is_top_client_type) {
return top_client_type_in_range ? top_client_type_in_range : nullptr;
}
return top_hate ? top_hate : nullptr;
}
else {
if (top_hate == nullptr && skipped_count > 0) {
} else {
if (!top_hate && 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) {
if (cur->entity_on_hatelist == skip) {
Mob *m = cur->entity_on_hatelist;
if (!m) {
++iterator;
continue;
}
if (skip_mezzed && cur->entity_on_hatelist->IsMezzed()) {
if (m == skip) {
++iterator;
continue;
}
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;
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;
}
}
++iterator;
}
if (top_hate == nullptr && skipped_count > 0) {
if (!top_hate && skipped_count > 0) {
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top_hate ? top_hate : nullptr;
}
return nullptr;
}
Mob *HateList::GetEntWithMostHateOnList(bool skip_mezzed){
Mob *HateList::GetMobWithMostHateOnList(bool skip_mezzed){
Mob* top = nullptr;
int64 hate = -1;
@@ -539,7 +563,7 @@ Mob *HateList::GetEntWithMostHateOnList(bool skip_mezzed){
if (cur) {
LogHateDetail(
"Looping GetEntWithMostHateOnList1 [{}] cur [{}] hate [{}] calc [{}]",
"Looping GetMobWithMostHateOnList1 [{}] cur [{}] hate [{}] calc [{}]",
cur->entity_on_hatelist->GetMobDescription(),
cur->stored_hate_amount,
hate,
@@ -549,7 +573,7 @@ Mob *HateList::GetEntWithMostHateOnList(bool skip_mezzed){
if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
{
LogHateDetail(
"Looping GetEntWithMostHateOnList2 [{}]",
"Looping GetMobWithMostHateOnList2 [{}]",
cur->entity_on_hatelist->GetMobDescription()
);
@@ -565,53 +589,45 @@ Mob *HateList::GetEntWithMostHateOnList(bool skip_mezzed){
}
Mob *HateList::GetRandomEntOnHateList(bool skip_mezzed)
Mob *HateList::GetRandomMobOnHateList(EntityFilterType 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;
const auto &l = GetFilteredHateList(filter_type);
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 (skip_mezzed) {
for (auto iter : list) {
if (iter->entity_on_hatelist->IsMezzed()) {
--count;
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;
}
return m;
}
if (count <= 0) {
return nullptr;
}
return nullptr;
}
int random = zone->random.Int(0, count - 1);
int counter = 0;
auto r = l.begin();
int random_index = rand() % count;
for (auto iter : list) {
std::advance(r, random_index);
if (skip_mezzed && iter->entity_on_hatelist->IsMezzed()) {
continue;
}
if (counter < random) {
auto e = *r;
++counter;
continue;
}
return iter->entity_on_hatelist;
Mob *m = e->entity_on_hatelist;
if (m) {
return m;
}
return nullptr;
}
Mob *HateList::GetEscapingEntOnHateList(Mob *center, float range, bool first) {
Mob *HateList::GetEscapingMobOnHateList(Mob *center, float range, bool first) {
// function is still in design stage
if (!center)
@@ -853,153 +869,6 @@ 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) {
+5 -9
View File
@@ -41,16 +41,12 @@ public:
HateList();
~HateList();
Mob *GetClosestEntOnHateList(Mob *hater, bool skip_mezzed = false, EntityFilterType entity_type = EntityFilterType::All);
Mob *GetClosestEntOnHateList(Mob *hater, bool skip_mezzed = false, EntityFilterType filter_type = EntityFilterType::All);
Mob *GetDamageTopOnHateList(Mob *hater); // didn't add 'skip_mezzed' due to calls being in ::Death()
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);
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);
bool IsEntOnHateList(Mob *mob);
bool IsHateListEmpty();
+50
View File
@@ -4739,3 +4739,53 @@ 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
);
}
+30
View File
@@ -3217,6 +3217,35 @@ void Lua_Client::RemoveRadiantCrystals(uint32 amount)
self->RemoveRadiantCrystals(amount);
}
void Lua_Client::SummonItemIntoInventory(luabind::object item_table) {
Lua_Safe_Call_Void();
if (luabind::type(item_table) != LUA_TTABLE) {
return;
}
const uint32 item_id = luabind::object_cast<uint32>(item_table["item_id"]);
const int16 charges = luabind::object_cast<uint32>(item_table["charges"]);
const uint32 augment_one = luabind::type(item_table["augment_one"]) != LUA_TNIL ? luabind::object_cast<uint32>(item_table["augment_one"]) : 0;
const uint32 augment_two = luabind::type(item_table["augment_two"]) != LUA_TNIL ? luabind::object_cast<uint32>(item_table["augment_two"]) : 0;
const uint32 augment_three = luabind::type(item_table["augment_three"]) != LUA_TNIL ? luabind::object_cast<uint32>(item_table["augment_three"]) : 0;
const uint32 augment_four = luabind::type(item_table["augment_four"]) != LUA_TNIL ? luabind::object_cast<uint32>(item_table["augment_four"]) : 0;
const uint32 augment_five = luabind::type(item_table["augment_five"]) != LUA_TNIL ? luabind::object_cast<uint32>(item_table["augment_five"]) : 0;
const uint32 augment_six = luabind::type(item_table["augment_six"]) != LUA_TNIL ? luabind::object_cast<uint32>(item_table["augment_six"]) : 0;
const bool attuned = luabind::type(item_table["attuned"]) != LUA_TNIL ? luabind::object_cast<bool>(item_table["attuned"]) : false;
self->SummonItemIntoInventory(
item_id,
charges,
augment_one,
augment_two,
augment_three,
augment_four,
augment_five,
augment_six,
attuned
);
}
luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>())
@@ -3723,6 +3752,7 @@ luabind::scope lua_register_client() {
.def("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,uint32,uint32,uint32,uint32))&Lua_Client::SummonItem)
.def("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,uint32,uint32,uint32,uint32,bool))&Lua_Client::SummonItem)
.def("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,uint32,uint32,uint32,uint32,bool,int))&Lua_Client::SummonItem)
.def("SummonItemIntoInventory", (void(Lua_Client::*)(luabind::adl::object))&Lua_Client::SummonItemIntoInventory)
.def("TGB", (bool(Lua_Client::*)(void))&Lua_Client::TGB)
.def("TakeMoneyFromPP", (bool(Lua_Client::*)(uint64))&Lua_Client::TakeMoneyFromPP)
.def("TakeMoneyFromPP", (bool(Lua_Client::*)(uint64,bool))&Lua_Client::TakeMoneyFromPP)
+1
View File
@@ -486,6 +486,7 @@ public:
void AddRadiantCrystals(uint32 amount);
void RemoveEbonCrystals(uint32 amount);
void RemoveRadiantCrystals(uint32 amount);
void SummonItemIntoInventory(luabind::object item_table);
void ApplySpell(int spell_id);
void ApplySpell(int spell_id, int duration);
+18
View File
@@ -1015,6 +1015,21 @@ Lua_Mob Lua_Mob::GetHateTop() {
return Lua_Mob(self->GetHateTop());
}
Lua_Bot Lua_Mob::GetHateTopBot() {
Lua_Safe_Call_Class(Lua_Bot);
return Lua_Bot(self->GetHateTopBot());
}
Lua_Client Lua_Mob::GetHateTopClient() {
Lua_Safe_Call_Class(Lua_Client);
return Lua_Client(self->GetHateTopClient());
}
Lua_NPC Lua_Mob::GetHateTopNPC() {
Lua_Safe_Call_Class(Lua_NPC);
return Lua_NPC(self->GetHateTopNPC());
}
Lua_Mob Lua_Mob::GetHateDamageTop(Lua_Mob other) {
Lua_Safe_Call_Class(Lua_Mob);
return Lua_Mob(self->GetHateDamageTop(other));
@@ -3456,6 +3471,9 @@ luabind::scope lua_register_mob() {
.def("GetHateRandomClient", (Lua_Client(Lua_Mob::*)(void))&Lua_Mob::GetHateRandomClient)
.def("GetHateRandomNPC", (Lua_NPC(Lua_Mob::*)(void))&Lua_Mob::GetHateRandomNPC)
.def("GetHateTop", (Lua_Mob(Lua_Mob::*)(void))&Lua_Mob::GetHateTop)
.def("GetHateTopBot", (Lua_Bot(Lua_Mob::*)(void))&Lua_Mob::GetHateTopBot)
.def("GetHateTopClient", (Lua_Client(Lua_Mob::*)(void))&Lua_Mob::GetHateTopClient)
.def("GetHateTopNPC", (Lua_NPC(Lua_Mob::*)(void))&Lua_Mob::GetHateTopNPC)
.def("GetHeading", &Lua_Mob::GetHeading)
.def("GetHelmTexture", &Lua_Mob::GetHelmTexture)
.def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel)
+3
View File
@@ -225,6 +225,9 @@ public:
Lua_HateList GetHateListByDistance();
Lua_HateList GetHateListByDistance(uint32 distance);
Lua_Mob GetHateTop();
Lua_Bot GetHateTopBot();
Lua_Client GetHateTopClient();
Lua_NPC GetHateTopNPC();
Lua_Mob GetHateDamageTop(Lua_Mob other);
Lua_Mob GetHateRandom();
Lua_Bot GetHateRandomBot();
+2 -2
View File
@@ -3933,14 +3933,14 @@ float Merc::GetMaxMeleeRangeToTarget(Mob* target) {
float size_mod = GetSize();
float other_size_mod = target->GetSize();
if (GetRace() == RACE_LAVA_DRAGON_49 || GetRace() == RACE_WURM_158 || GetRace() == RACE_GHOST_DRAGON_196) //For races with a fixed size
if (GetRace() == Race::LavaDragon || GetRace() == Race::Wurm || GetRace() == Race::GhostDragon) //For races with a fixed size
{
size_mod = 60.0f;
} else if (size_mod < 6.0) {
size_mod = 8.0f;
}
if (target->GetRace() == RACE_LAVA_DRAGON_49 || target->GetRace() == RACE_WURM_158 || target->GetRace() == RACE_GHOST_DRAGON_196) //For races with a fixed size
if (target->GetRace() == Race::LavaDragon || target->GetRace() == Race::Wurm || target->GetRace() == Race::GhostDragon) //For races with a fixed size
{
other_size_mod = 60.0f;
} else if (other_size_mod < 6.0) {
+96 -96
View File
@@ -2867,7 +2867,7 @@ void Mob::ShowStats(Client* c)
);
// Drakkin Features
if (t->GetRace() == RACE_DRAKKIN_522) {
if (t->GetRace() == Race::Drakkin) {
c->Message(
Chat::White,
fmt::format(
@@ -3526,7 +3526,7 @@ void Mob::GMMove(const glm::vec4 &position, bool save_guard_spot) {
void Mob::SendIllusionPacket(const AppearanceStruct& a)
{
uint16 new_race = (
a.race_id != RACE_DOUG_0 ?
a.race_id != Race::Doug ?
a.race_id :
(use_model ? use_model : GetBaseRace())
);
@@ -3558,7 +3558,7 @@ void Mob::SendIllusionPacket(const AppearanceStruct& a)
uint32 new_drakkin_tattoo = a.drakkin_tattoo == UINT32_MAX ? GetDrakkinTattoo() : a.drakkin_tattoo;
// Reset features to Base from the Player Profile
if (IsClient() && a.race_id == RACE_DOUG_0) {
if (IsClient() && a.race_id == Race::Doug) {
new_beard = CastToClient()->GetBaseBeard();
new_beard_color = CastToClient()->GetBaseBeardColor();
new_drakkin_details = CastToClient()->GetBaseDetails();
@@ -3918,48 +3918,48 @@ uint16 Mob::GetFactionRace() {
uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) {
if (
IsPlayerRace(in_race) ||
in_race == RACE_BROWNIE_15 ||
in_race == RACE_KERRAN_23 ||
in_race == RACE_LION_50 ||
in_race == RACE_DRACNID_57 ||
in_race == RACE_ZOMBIE_70 ||
in_race == RACE_QEYNOS_CITIZEN_71 ||
in_race == RACE_RIVERVALE_CITIZEN_81 ||
in_race == RACE_HALAS_CITIZEN_90 ||
in_race == RACE_GROBB_CITIZEN_92 ||
in_race == RACE_OGGOK_CITIZEN_93 ||
in_race == RACE_KALADIM_CITIZEN_94 ||
in_race == RACE_ELF_VAMPIRE_98 ||
in_race == RACE_FELGUARD_106 ||
in_race == RACE_FAYGUARD_112 ||
in_race == RACE_ERUDITE_GHOST_118 ||
in_race == RACE_IKSAR_CITIZEN_139 ||
in_race == RACE_SHADE_224 ||
in_race == RACE_TROLL_CREW_MEMBER_331 ||
in_race == RACE_PIRATE_DECKHAND_332 ||
in_race == RACE_GNOME_PIRATE_338 ||
in_race == RACE_DARK_ELF_PIRATE_339 ||
in_race == RACE_OGRE_PIRATE_340 ||
in_race == RACE_HUMAN_PIRATE_341 ||
in_race == RACE_ERUDITE_PIRATE_342 ||
in_race == RACE_UNDEAD_PIRATE_344 ||
in_race == RACE_KNIGHT_OF_HATE_351 ||
in_race == RACE_WARLOCK_OF_HATE_352 ||
in_race == RACE_UNDEAD_VAMPIRE_359 ||
in_race == RACE_VAMPIRE_360 ||
in_race == RACE_SAND_ELF_364 ||
in_race == RACE_TAELOSIAN_NATIVE_385 ||
in_race == RACE_TAELOSIAN_EVOKER_386 ||
in_race == RACE_DRACHNID_461 ||
in_race == RACE_ZOMBIE_471 ||
in_race == RACE_ELDDAR_489 ||
in_race == RACE_VAMPIRE_497 ||
in_race == RACE_KERRAN_562 ||
in_race == RACE_BROWNIE_568 ||
in_race == RACE_HUMAN_566 ||
in_race == RACE_ELVEN_GHOST_587 ||
in_race == RACE_HUMAN_GHOST_588 ||
in_race == RACE_COLDAIN_645
in_race == Race::Brownie ||
in_race == Race::Kerran ||
in_race == Race::Lion ||
in_race == Race::Drachnid ||
in_race == Race::Zombie ||
in_race == Race::QeynosCitizen ||
in_race == Race::RivervaleCitizen ||
in_race == Race::HalasCitizen ||
in_race == Race::GrobbCitizen ||
in_race == Race::OggokCitizen ||
in_race == Race::KaladimCitizen ||
in_race == Race::ElfVampire ||
in_race == Race::Felguard ||
in_race == Race::Fayguard ||
in_race == Race::EruditeGhost ||
in_race == Race::IksarCitizen ||
in_race == Race::Shade ||
in_race == Race::TrollCrewMember ||
in_race == Race::PirateDeckhand ||
in_race == Race::GnomePirate ||
in_race == Race::DarkElfPirate ||
in_race == Race::OgrePirate ||
in_race == Race::HumanPirate ||
in_race == Race::EruditePirate ||
in_race == Race::TrollZombie ||
in_race == Race::KnightOfHate ||
in_race == Race::ArcanistOfHate ||
in_race == Race::UndeadVampire ||
in_race == Race::Vampire3 ||
in_race == Race::SandElf ||
in_race == Race::Nihil ||
in_race == Race::Trusik ||
in_race == Race::Drachnid2 ||
in_race == Race::Zombie2 ||
in_race == Race::Elddar ||
in_race == Race::Vampire4 ||
in_race == Race::Kerran2 ||
in_race == Race::Brownie2 ||
in_race == Race::Human2 ||
in_race == Race::ElvenGhost ||
in_race == Race::HumanGhost ||
in_race == Race::Coldain2
) {
if (in_gender >= 2) { // Male default for PC Races
return 0;
@@ -3967,33 +3967,33 @@ uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) {
return in_gender;
}
} else if (
in_race == RACE_FREEPORT_GUARD_44 ||
in_race == RACE_MIMIC_52 ||
in_race == RACE_HUMAN_BEGGAR_55 ||
in_race == RACE_VAMPIRE_65 ||
in_race == RACE_HIGHPASS_CITIZEN_67 ||
in_race == RACE_NERIAK_CITIZEN_77 ||
in_race == RACE_ERUDITE_CITIZEN_78 ||
in_race == RACE_CLOCKWORK_GNOME_88 ||
in_race == RACE_DWARF_GHOST_117 ||
in_race == RACE_SPECTRAL_IKSAR_147 ||
in_race == RACE_INVISIBLE_MAN_127 ||
in_race == RACE_VAMPYRE_208 ||
in_race == RACE_RECUSO_237 ||
in_race == RACE_BROKEN_SKULL_PIRATE_333 ||
in_race == RACE_INVISIBLE_MAN_OF_ZOMM_600 ||
in_race == RACE_OGRE_NPC_MALE_624 ||
in_race == RACE_BEEFEATER_667 ||
in_race == RACE_ERUDITE_678
in_race == Race::FreeportGuard ||
in_race == Race::Mimic ||
in_race == Race::HumanBeggar ||
in_race == Race::Vampire ||
in_race == Race::HighpassCitizen ||
in_race == Race::NeriakCitizen ||
in_race == Race::EruditeCitizen ||
in_race == Race::ClockworkGnome ||
in_race == Race::DwarfGhost ||
in_race == Race::IksarSpirit ||
in_race == Race::InvisibleMan ||
in_race == Race::Vampire2 ||
in_race == Race::Recuso ||
in_race == Race::BrokenSkullPirate ||
in_race == Race::InvisibleManOfZomm ||
in_race == Race::Ogre2 ||
in_race == Race::RoyalGuard ||
in_race == Race::Erudite2
) { // Male only races
return 0;
} else if (
in_race == RACE_FAIRY_25 ||
in_race == RACE_PIXIE_56 ||
in_race == RACE_BANSHEE_487 ||
in_race == RACE_BANSHEE_488 ||
in_race == RACE_AYONAE_RO_498 ||
in_race == RACE_SULLON_ZEK_499
in_race == Race::Fairy ||
in_race == Race::Pixie ||
in_race == Race::Banshee2 ||
in_race == Race::Banshee3 ||
in_race == Race::AyonaeRo ||
in_race == Race::SullonZek
) { // Female only races
return 1;
} else { // Neutral default for NPC Races
@@ -4883,7 +4883,7 @@ bool Mob::RemoveFromHateList(Mob* mob)
}
if(GetTarget() == mob)
{
SetTarget(hate_list.GetEntWithMostHateOnList(this));
SetTarget(hate_list.GetMobWithMostHateOnList(this));
}
return bFound;
@@ -6867,22 +6867,22 @@ void Mob::RemoveAllNimbusEffects()
bool Mob::IsBoat() const {
return (
race == RACE_SHIP_72 ||
race == RACE_LAUNCH_73 ||
race == RACE_GHOST_SHIP_114 ||
race == RACE_SHIP_404 ||
race == RACE_MERCHANT_SHIP_550 ||
race == RACE_PIRATE_SHIP_551 ||
race == RACE_GHOST_SHIP_552 ||
race == RACE_BOAT_533
race == Race::Ship ||
race == Race::Launch ||
race == Race::GhostShip ||
race == Race::DiscordShip ||
race == Race::MerchantShip ||
race == Race::PirateShip ||
race == Race::GhostShip2 ||
race == Race::Boat2
);
}
bool Mob::IsControllableBoat() const {
return (
race == RACE_BOAT_141 ||
race == RACE_ROWBOAT_502
race == Race::Boat ||
race == Race::Rowboat
);
}
@@ -8218,37 +8218,37 @@ int Mob::DispatchZoneControllerEvent(
std::string Mob::GetRacePlural()
{
switch (GetBaseRace()) {
case RACE_HUMAN_1:
case Race::Human:
return "Humans";
case RACE_BARBARIAN_2:
case Race::Barbarian:
return "Barbarians";
case RACE_ERUDITE_3:
case Race::Erudite:
return "Erudites";
case RACE_WOOD_ELF_4:
case Race::WoodElf:
return "Wood Elves";
case RACE_HIGH_ELF_5:
case Race::HighElf:
return "High Elves";
case RACE_DARK_ELF_6:
case Race::DarkElf:
return "Dark Elves";
case RACE_HALF_ELF_7:
case Race::HalfElf:
return "Half Elves";
case RACE_DWARF_8:
case Race::Dwarf:
return "Dwarves";
case RACE_TROLL_9:
case Race::Troll:
return "Trolls";
case RACE_OGRE_10:
case Race::Ogre:
return "Ogres";
case RACE_HALFLING_11:
case Race::Halfling:
return "Halflings";
case RACE_GNOME_12:
case Race::Gnome:
return "Gnomes";
case RACE_IKSAR_128:
case Race::Iksar:
return "Iksar";
case RACE_VAH_SHIR_130:
case Race::VahShir:
return "Vah Shir";
case RACE_FROGLOK_330:
case Race::Froglok2:
return "Frogloks";
case RACE_DRAKKIN_522:
case Race::Drakkin:
return "Drakkin";
default:
return "Races";
+12 -9
View File
@@ -83,7 +83,7 @@ struct AppearanceStruct {
uint8 hair = UINT8_MAX;
uint8 hair_color = UINT8_MAX;
uint8 helmet_texture = UINT8_MAX;
uint16 race_id = RACE_DOUG_0;
uint16 race_id = Race::Doug;
bool send_effects = true;
float size = -1.0f;
Client *target = nullptr;
@@ -748,14 +748,17 @@ public:
int64 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHateAmount(tmob,is_dam);}
int64 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHateAmount(tmob, true);}
int GetHateRatio(Mob *first, Mob *with) { return hate_list.GetHateRatio(first, with); }
Mob* GetHateTop() { return hate_list.GetEntWithMostHateOnList(this);}
Mob* GetSecondaryHate(Mob *skip) { return hate_list.GetEntWithMostHateOnList(this, skip); }
Mob* GetHateTop() { return hate_list.GetMobWithMostHateOnList(this);}
Bot* GetHateTopBot() { return hate_list.GetMobWithMostHateOnList(this, nullptr, false, EntityFilterType::Bots)->CastToBot();}
Client* GetHateTopClient() { return hate_list.GetMobWithMostHateOnList(this, nullptr, false, EntityFilterType::Clients)->CastToClient();}
NPC* GetHateTopNPC() { return hate_list.GetMobWithMostHateOnList(this, nullptr, false, EntityFilterType::NPCs)->CastToNPC();}
Mob* GetSecondaryHate(Mob *skip) { return hate_list.GetMobWithMostHateOnList(this, skip); }
Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTopOnHateList(other);}
Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();}
Client* GetHateRandomClient() { return hate_list.GetRandomClientOnHateList(); }
NPC* GetHateRandomNPC() { return hate_list.GetRandomNPCOnHateList(); }
Bot* GetHateRandomBot() { return hate_list.GetRandomBotOnHateList(); }
Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();}
Mob* GetHateRandom() { return hate_list.GetRandomMobOnHateList(); }
Bot* GetHateRandomBot() { return hate_list.GetRandomMobOnHateList(EntityFilterType::Bots)->CastToBot(); }
Client* GetHateRandomClient() { return hate_list.GetRandomMobOnHateList(EntityFilterType::Clients)->CastToClient(); }
NPC* GetHateRandomNPC() { return hate_list.GetRandomMobOnHateList(EntityFilterType::NPCs)->CastToNPC(); }
Mob* GetHateMost() { return hate_list.GetMobWithMostHateOnList();}
Mob* GetHateClosest(bool skip_mezzed = false) { return hate_list.GetClosestEntOnHateList(this, skip_mezzed); }
Bot* GetHateClosestBot(bool skip_mezzed = false) { return hate_list.GetClosestEntOnHateList(this, skip_mezzed, EntityFilterType::Bots)->CastToBot(); }
Client* GetHateClosestClient(bool skip_mezzed = false) { return hate_list.GetClosestEntOnHateList(this, skip_mezzed, EntityFilterType::Clients)->CastToClient(); }
@@ -1121,7 +1124,7 @@ public:
void DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int base_damage, int min_damage = 0, int32 hate_override = -1, int ReuseTime = 10);
void DoThrowingAttackDmg(Mob* other, const EQ::ItemInstance* RangeWeapon = nullptr, const EQ::ItemData* AmmoItem = nullptr, int32 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, int AmmoSlot = 0, float speed = 4.0f, bool DisableProcs = false);
void DoMeleeSkillAttackDmg(Mob* other, int32 weapon_damage, EQ::skills::SkillType skillinuse, int16 chance_mod = 0, int16 focus = 0, bool CanRiposte = false, int ReuseTime = 0);
void DoMeleeSkillAttackDmg(Mob* other, int32 weapon_damage, EQ::skills::SkillType skillinuse, int16 chance_mod = 0, int16 focus = 0, bool can_riposte = false, int ReuseTime = 0);
void DoArcheryAttackDmg(Mob* other, const EQ::ItemInstance* RangeWeapon = nullptr, const EQ::ItemInstance* Ammo = nullptr, int32 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, uint32 ammo_id = 0, const EQ::ItemData *AmmoItem = nullptr, int AmmoSlot = 0, float speed = 4.0f, bool DisableProcs = false);
bool TryProjectileAttack(Mob* other, const EQ::ItemData *item, EQ::skills::SkillType skillInUse, uint64 weapon_dmg, const EQ::ItemInstance* RangeWeapon, const EQ::ItemInstance* Ammo, int AmmoSlot, float speed, bool DisableProcs = false);
void ProjectileAttack();
+4 -4
View File
@@ -769,7 +769,7 @@ void Client::AI_Process()
{
if(AI_target_check_timer->Check())
{
SetTarget(hate_list.GetEntWithMostHateOnList(this));
SetTarget(hate_list.GetMobWithMostHateOnList(this));
}
}
@@ -1073,12 +1073,12 @@ void Mob::AI_Process() {
if (IsFocused()) {
if (!target) {
SetTarget(hate_list.GetEntWithMostHateOnList(this));
SetTarget(hate_list.GetMobWithMostHateOnList(this));
}
}
else {
if (!ImprovedTaunt())
SetTarget(hate_list.GetEntWithMostHateOnList(this));
SetTarget(hate_list.GetMobWithMostHateOnList(this));
}
}
@@ -1800,7 +1800,7 @@ void Mob::AI_Event_Engaged(Mob *attacker, bool yell_for_help)
auto emote_id = GetEmoteID();
if (emote_id) {
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid);
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid, attacker);
}
std::string mob_name = GetCleanName();
+69 -39
View File
@@ -155,10 +155,10 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
// lava dragon is a fixed size model and should always use its default
// otherwise pathing issues
if (race == RACE_LAVA_DRAGON_49) {
if (race == Race::LavaDragon) {
size = 5;
}
if (race == RACE_WURM_158) {
if (race == Race::Wurm) {
size = 15;
}
@@ -1058,7 +1058,7 @@ bool NPC::Process()
NPCAssistCap() < RuleI(Combat, NPCAssistCap)) {
// Some cases like flash of light used for aggro haven't set target
if (!GetTarget()) {
SetTarget(hate_list.GetEntWithMostHateOnList(this));
SetTarget(hate_list.GetMobWithMostHateOnList(this));
}
AIYellForHelp(this, GetTarget());
if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled())
@@ -3046,42 +3046,72 @@ void NPC::SendPayload(int payload_id, std::string payload_value)
}
NPC_Emote_Struct* NPC::GetNPCEmote(uint32 emoteid, uint8 event_) {
LinkedListIterator<NPC_Emote_Struct*> iterator(zone->NPCEmoteList);
iterator.Reset();
while(iterator.MoreElements())
{
NPC_Emote_Struct* nes = iterator.GetData();
std::vector<NPC_Emote_Struct *> emotes;
for (auto &e: zone->npc_emote_list) {
NPC_Emote_Struct *nes = e;
if (emoteid == nes->emoteid && event_ == nes->event_) {
return nes;
emotes.push_back(e);
}
iterator.Advance();
}
return nullptr;
if (emotes.empty()) {
return nullptr;
}
else if (emotes.size() == 1) {
return emotes[0];
}
int index = zone->random.Roll0(emotes.size());
return emotes[index];
}
void NPC::DoNPCEmote(uint8 event_, uint32 emoteid)
void NPC::DoNPCEmote(uint8 event_, uint32 emoteid, Mob* target)
{
if (emoteid == 0)
{
if (emoteid == 0) {
return;
}
NPC_Emote_Struct* nes = GetNPCEmote(emoteid,event_);
if(nes == nullptr)
{
NPC_Emote_Struct *nes = GetNPCEmote(emoteid, event_);
if (nes == nullptr) {
return;
}
if(emoteid == nes->emoteid)
{
if(nes->type == 1)
Emote("%s",nes->text);
else if(nes->type == 2)
Shout("%s",nes->text);
else if(nes->type == 3)
entity_list.MessageCloseString(this, true, 200, 10, GENERIC_STRING, nes->text);
else
Say("%s",nes->text);
std::string processed = nes->text;
Strings::FindReplace(processed, "$mname", GetCleanName());
Strings::FindReplace(processed, "$mracep", GetRacePlural() = GetClass());
Strings::FindReplace(processed, "$mrace", GetPlayerRaceName(GetRace()));
Strings::FindReplace(processed, "$mclass", GetClassIDName(GetClass()));
if (target) {
Strings::FindReplace(processed, "$name", target->GetCleanName());
Strings::FindReplace(processed, "$racep", GetRacePlural() = target->GetClass());
Strings::FindReplace(processed, "$race", GetPlayerRaceName(target->GetRace()));
Strings::FindReplace(processed, "$class", GetClassIDName(target->GetClass()));
}
else {
Strings::FindReplace(processed, "$name", "foe");
Strings::FindReplace(processed, "$race", "race");
Strings::FindReplace(processed, "$racep", "races");
Strings::FindReplace(processed, "$class", "class");
}
if (emoteid == nes->emoteid) {
if (event_ == EQ::constants::EmoteEventTypes::Hailed && target) {
DoQuestPause(target);
}
if (nes->type == 1) {
Emote("%s", processed.c_str());
}
else if (nes->type == 2) {
Shout("%s", processed.c_str());
}
else if (nes->type == 3) {
entity_list.MessageCloseString(this, true, 200, 10, GENERIC_STRING, processed.c_str());
}
else {
Say("%s", processed.c_str());
}
}
}
@@ -3691,25 +3721,25 @@ void NPC::ScaleNPC(uint8 npc_level, bool always_scale, bool override_special_abi
bool NPC::IsGuard()
{
switch (GetRace()) {
case RT_GUARD:
case Race::FreeportGuard:
if (GetTexture() == 1 || GetTexture() == 2)
return true;
break;
case RT_IKSAR_2:
case Race::IksarCitizen:
if (GetTexture() == 1)
return true;
break;
case RT_GUARD_2:
case RT_GUARD_3:
case RT_GUARD_4:
case RT_HUMAN_3:
case RT_HALFLING_2:
case RT_ERUDITE_2:
case RT_BARBARIAN_2:
case RT_DARK_ELF_2:
case RT_TROLL_2:
case Race::Felguard:
case Race::Fayguard:
case Race::VahShirGuard:
case Race::QeynosCitizen:
case Race::RivervaleCitizen:
case Race::EruditeCitizen:
case Race::HalasCitizen:
case Race::NeriakCitizen:
case Race::GrobbCitizen:
case OGGOK_CITIZEN:
case RT_DWARF_2:
case Race::KaladimCitizen:
return true;
default:
break;
+1 -1
View File
@@ -476,7 +476,7 @@ public:
const uint32 GetAltCurrencyType() const { return NPCTypedata->alt_currency_type; }
NPC_Emote_Struct* GetNPCEmote(uint32 emoteid, uint8 event_);
void DoNPCEmote(uint8 event_, uint32 emoteid);
void DoNPCEmote(uint8 event_, uint32 emoteid, Mob* target = nullptr);
bool CanTalk();
void DoQuestPause(Mob *other);
+31
View File
@@ -3028,6 +3028,36 @@ void Perl_Client_RemoveRadiantCrystals(Client* self, uint32 amount)
self->RemoveRadiantCrystals(amount);
}
void Perl_Client_SummonItemIntoInventory(Client* self, perl::reference table_ref)
{
perl::hash table = table_ref;
if (!table.exists("item_id") || !table.exists("charges")) {
return;
}
const uint32 item_id = table["item_id"];
const int16 charges = table["charges"];
const uint32 augment_one = table.exists("augment_one") ? table["augment_one"] : 0;
const uint32 augment_two = table.exists("augment_two") ? table["augment_two"] : 0;
const uint32 augment_three = table.exists("augment_three") ? table["augment_three"] : 0;
const uint32 augment_four = table.exists("augment_four") ? table["augment_four"] : 0;
const uint32 augment_five = table.exists("augment_five") ? table["augment_five"] : 0;
const uint32 augment_six = table.exists("augment_six") ? table["augment_six"] : 0;
const bool attuned = table.exists("attuned") ? table["attuned"] : false;
self->SummonItemIntoInventory(
item_id,
charges,
augment_one,
augment_two,
augment_three,
augment_four,
augment_five,
augment_six,
attuned
);
}
void perl_register_client()
{
perl::interpreter perl(PERL_GET_THX);
@@ -3535,6 +3565,7 @@ void perl_register_client()
package.add("SummonItem", (void(*)(Client*, uint32, int16, bool, uint32, uint32, uint32, uint32))&Perl_Client_SummonItem);
package.add("SummonItem", (void(*)(Client*, uint32, int16, bool, uint32, uint32, uint32, uint32, uint32))&Perl_Client_SummonItem);
package.add("SummonItem", (void(*)(Client*, uint32, int16, bool, uint32, uint32, uint32, uint32, uint32, uint16))&Perl_Client_SummonItem);
package.add("SummonItemIntoInventory", &Perl_Client_SummonItemIntoInventory);
package.add("TGB", &Perl_Client_TGB);
package.add("TakeMoneyFromPP", (bool(*)(Client*, uint64_t))&Perl_Client_TakeMoneyFromPP);
package.add("TakeMoneyFromPP", (bool(*)(Client*, uint64_t, bool))&Perl_Client_TakeMoneyFromPP);
+18
View File
@@ -1344,6 +1344,21 @@ Mob* Perl_Mob_GetHateTop(Mob* self) // @categories Hate and Aggro
return self->GetHateTop();
}
Bot* Perl_Mob_GetHateTopBot(Mob* self) // @categories Hate and Aggro
{
return self->GetHateTopBot();
}
Client* Perl_Mob_GetHateTopClient(Mob* self) // @categories Hate and Aggro
{
return self->GetHateTopClient();
}
NPC* Perl_Mob_GetHateTopNPC(Mob* self) // @categories Hate and Aggro
{
return self->GetHateTopNPC();
}
Mob* Perl_Mob_GetHateDamageTop(Mob* self, Mob* other) // @categories Hate and Aggro
{
return self->GetHateDamageTop(other);
@@ -3581,6 +3596,9 @@ void perl_register_mob()
package.add("GetHateRandomClient", &Perl_Mob_GetHateRandomClient);
package.add("GetHateRandomNPC", &Perl_Mob_GetHateRandomNPC);
package.add("GetHateTop", &Perl_Mob_GetHateTop);
package.add("GetHateTopBot", &Perl_Mob_GetHateTopBot);
package.add("GetHateTopClient", &Perl_Mob_GetHateTopClient);
package.add("GetHateTopNPC", &Perl_Mob_GetHateTopNPC);
package.add("GetHeading", &Perl_Mob_GetHeading);
package.add("GetHelmTexture", &Perl_Mob_GetHelmTexture);
package.add("GetHerosForgeModel", &Perl_Mob_GetHerosForgeModel);
+1 -1
View File
@@ -71,7 +71,7 @@ Petition::Petition(uint32 id)
{
petid = id;
charclass = Class::None;
charrace = RACE_DOUG_0;
charrace = Race::Doug;
charlevel = 0;
checkouts = 0;
unavailables = 0;
+8 -9
View File
@@ -2385,7 +2385,7 @@ int Mob::TryAssassinate(Mob *defender, EQ::skills::SkillType skillInUse)
}
void Mob::DoMeleeSkillAttackDmg(Mob *other, int32 weapon_damage, EQ::skills::SkillType skillinuse, int16 chance_mod,
int16 focus, bool CanRiposte, int ReuseTime)
int16 focus, bool can_riposte, int ReuseTime)
{
if (!CanDoSpecialAttack(other)) {
return;
@@ -2425,15 +2425,14 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, int32 weapon_damage, EQ::skills::Ski
}
DamageHitInfo my_hit {};
my_hit.base_damage = weapon_damage;
my_hit.min_damage = 0;
my_hit.damage_done = 1;
my_hit.skill = skillinuse;
my_hit.offense = offense(my_hit.skill);
my_hit.tohit = GetTotalToHit(my_hit.skill, chance_mod);
// slot range exclude ripe etc ...
my_hit.hand = CanRiposte ? EQ::invslot::slotRange : EQ::invslot::slotPrimary;
my_hit.base_damage = weapon_damage;
my_hit.min_damage = 0;
my_hit.damage_done = 1;
my_hit.skill = skillinuse;
my_hit.offense = offense(my_hit.skill);
my_hit.tohit = GetTotalToHit(my_hit.skill, chance_mod);
my_hit.hand = can_riposte ? EQ::invslot::slotPrimary : EQ::invslot::slotRange;
if (IsNPC()) {
my_hit.min_damage = CastToNPC()->GetMinDamage();
+16 -16
View File
@@ -7430,42 +7430,42 @@ bool Mob::PassCastRestriction(int value)
case IS_BIXIE:
case IS_BIXIE2:
if ((GetRace() == RT_BIXIE) ||(GetRace() == RT_BIXIE_2))
if ((GetRace() == Race::Bixie) ||(GetRace() == Race::Bixie2))
return true;
break;
case IS_HARPY:
if ((GetRace() == RT_HARPY) ||(GetRace() == RT_HARPY_2))
if ((GetRace() == Race::Harpy) ||(GetRace() == Race::Harpy2))
return true;
break;
case IS_GNOLL:
if ((GetRace() == RT_GNOLL) || (GetRace() == RT_GNOLL_2) || (GetRace() == RT_GNOLL_3))
if ((GetRace() == Race::Gnoll) || (GetRace() == Race::Gnoll2) || (GetRace() == Race::Gnoll3))
return true;
break;
case IS_SPORALI:
if ((GetRace() == RT_SPORALI) ||(GetRace() == RT_FUNGUSMAN))
if ((GetRace() == Race::Sporali) ||(GetRace() == Race::Fungusman))
return true;
break;
case IS_KOBOLD:
if ((GetRace() == RT_KOBOLD) ||(GetRace() == RT_KOBOLD_2))
if ((GetRace() == Race::Kobold) ||(GetRace() == Race::Kobold2))
return true;
break;
case IS_FROSTCRYPT_SHADE:
if (GetRace() == RT_GIANT_SHADE)
if (GetRace() == Race::GiantShade)
return true;
break;
case IS_DRAKKIN:
if (GetRace() == RT_DRAKKIN)
if (GetRace() == Race::Drakkin)
return true;
break;
case IS_UNDEAD_OR_VALDEHOLM_GIANT:
if (GetBodyType() == BT_Undead || GetRace() == RT_GIANT_12 || GetRace() == RT_GIANT_13)
if (GetBodyType() == BT_Undead || GetRace() == Race::Giant2 || GetRace() == Race::Giant3)
return true;
break;
@@ -7496,7 +7496,7 @@ bool Mob::PassCastRestriction(int value)
break;
case IS_FAE_OR_PIXIE:
if ((GetRace() == RT_PIXIE) || (GetRace() == RT_FAY_DRAKE))
if ((GetRace() == Race::Pixie) || (GetRace() == Race::FayDrake))
return true;
break;
@@ -7511,12 +7511,12 @@ bool Mob::PassCastRestriction(int value)
break;
case IS_CLOCKWORK_AND_HP_LESS_THAN_45_PCT:
if ((GetRace() == RT_GNOMEWORK || GetRace() == RACE_CLOCKWORK_GNOME_88) && (GetHPRatio() < 45))
if ((GetRace() == Race::Gnomework || GetRace() == Race::ClockworkGnome) && (GetHPRatio() < 45))
return true;
break;
case IS_WISP_AND_HP_LESS_THAN_10_PCT:
if ((GetRace() == RT_WILL_O_WISP) && (GetHPRatio() < 10))
if ((GetRace() == Race::Wisp) && (GetHPRatio() < 10))
return true;
break;
@@ -7889,12 +7889,12 @@ bool Mob::PassCastRestriction(int value)
break;
case IS_TREANT:
if (GetRace() == RT_TREANT || GetRace() == RT_TREANT_2 || GetRace() == RT_TREANT_3)
if (GetRace() == Race::Treant || GetRace() == Race::Treant2 || GetRace() == Race::Treant3)
return true;
break;
case IS_SCARECROW:
if (GetRace() == RT_SCARECROW || GetRace() == RT_SCARECROW_2)
if (GetRace() == Race::Scarecrow || GetRace() == Race::Scarecrow2)
return true;
break;
@@ -10263,7 +10263,7 @@ void Mob::ApplySpellEffectIllusion(int32 spell_id, Mob *caster, int buffslot, in
gender_id
);
if (base != RACE_ELEMENTAL_75 && base != RACE_DRAKKIN_522) {
if (base != Race::Elemental && base != Race::Drakkin) {
if (max > 0) {
if (limit == 0) {
SendIllusionPacket(
@@ -10303,7 +10303,7 @@ void Mob::ApplySpellEffectIllusion(int32 spell_id, Mob *caster, int buffslot, in
}
);
}
} else if (base == RACE_ELEMENTAL_75){
} else if (base == Race::Elemental){
SendIllusionPacket(
AppearanceStruct{
.gender_id = static_cast<uint8>(gender_id),
@@ -10311,7 +10311,7 @@ void Mob::ApplySpellEffectIllusion(int32 spell_id, Mob *caster, int buffslot, in
.texture = static_cast<uint8>(limit),
}
);
} else if (base == RACE_DRAKKIN_522) {
} else if (base == Race::Drakkin) {
FaceChange_Struct f{
.haircolor = GetHairColor(),
.beardcolor = GetBeardColor(),
+1 -4
View File
@@ -2765,9 +2765,6 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
CastToBot()->SetItemReuseTimer(item->ID);
CastToBot()->SetIsUsingItemClick(false);
}
else {
GetOwner()->Message(Chat::Red, "%s says, 'Failed to set item reuse timer for %s.", GetCleanName());
}
}
if (IsNPC()) {
@@ -3885,7 +3882,7 @@ bool Mob::SpellOnTarget(
// Prevent double invising, which made you uninvised
// Not sure if all 3 should be stacking
//This is not live like behavior (~Kayen confirmed 2/2/22)
if (!RuleB(Spells, AllowDoubleInvis)) {
if (!RuleB(Spells, AllowDoubleInvis) && !IsActiveBardSong(spell_id)) {
if (IsEffectInSpell(spell_id, SE_Invisibility)) {
if (spelltar->invisible) {
spelltar->MessageString(Chat::SpellFailure, ALREADY_INVIS, GetCleanName());
+46 -46
View File
@@ -880,118 +880,118 @@ float Mob::GetZOffset() const {
float offset = 3.125f;
switch (GetModel()) {
case RACE_BASILISK_436:
case Race::Basilisk:
offset = 0.577f;
break;
case RACE_DRAKE_430:
case Race::Drake2:
offset = 0.5f;
break;
case RACE_DRAKE_432:
case Race::Drake3:
offset = 1.9f;
break;
case RACE_DRAGON_435:
case Race::Dragon:
offset = 0.93f;
break;
case RACE_LAVA_SPIDER_450:
case Race::LavaSpider:
offset = 0.938f;
break;
case RACE_ALLIGATOR_479:
case Race::Alligator2:
offset = 0.8f;
break;
case RACE_LAVA_SPIDER_QUEEN_451:
case Race::LavaSpiderQueen:
offset = 0.816f;
break;
case RACE_DRAGON_437:
case Race::Dragon2:
offset = 0.527f;
break;
case RACE_PUMA_439:
case Race::Puma2:
offset = 1.536f;
break;
case RACE_RAT_415:
case Race::Rat:
offset = 1.0f;
break;
case RACE_DRAGON_438:
case RACE_DRAGON_452:
case Race::Dragon3:
case Race::Dragon4:
offset = 0.776f;
break;
case RACE_SPIDER_QUEEN_441:
case Race::SpiderQueen:
offset = 0.816f;
break;
case RACE_SPIDER_440:
case Race::Spider:
offset = 0.938f;
break;
case RACE_IMP_46:
case RACE_SNAKE_468:
case RACE_CORATHUS_459:
case Race::Imp:
case Race::Snake:
case Race::Corathus:
offset = 1.0f;
break;
case RACE_DRACHNID_COCOON_462:
case Race::DrachnidCocoon:
offset = 1.5f;
break;
case RACE_DRAGON_530:
case Race::Dragon5:
offset = 1.2f;
break;
case RACE_GOO_549:
case RACE_GOO_548:
case Race::Goo4:
case Race::Goo3:
offset = 0.5f;
break;
case RACE_GOO_547:
case Race::Goo2:
offset = 0.5f;
break;
case RACE_DRACOLICH_604:
case Race::Dracolich:
offset = 1.2f;
break;
case RACE_TELMIRA_653:
case Race::Telmira:
offset = 5.9f;
break;
case RACE_MORELL_THULE_658:
case Race::MorellThule:
offset = 4.0f;
break;
case RACE_ARMOR_OF_MARR_323:
case RACE_AMYGDALAN_663:
case Race::AnimatedArmor:
case Race::Amygdalan:
offset = 5.0f;
break;
case RACE_SPECTRAL_IKSAR_147:
case RACE_SANDMAN_664:
case Race::IksarSpirit:
case Race::Sandman:
offset = 4.0f;
break;
case RACE_LAVA_DRAGON_49:
case RACE_ALARAN_SENTRY_STONE_703:
case Race::LavaDragon:
case Race::AlaranSentryStone:
offset = 9.0f;
break;
case RACE_RABBIT_668:
case Race::Rabbit:
offset = 5.0f;
break;
case RACE_WURM_158:
case RACE_BLIND_DREAMER_669:
case Race::Wurm:
case Race::BlindDreamer:
offset = 7.0f;
break;
case RACE_SIREN_187:
case RACE_HALAS_CITIZEN_90:
case RACE_OTTERMAN_190:
case Race::Siren:
case Race::HalasCitizen:
case Race::Othmir:
offset = .5f;
break;
case RACE_COLDAIN_183:
case Race::Coldain:
offset = .6f;
break;
case RACE_WEREWOLF_14:
case Race::Werewolf:
offset = 1.2f;
break;
case RACE_DWARF_8:
case Race::Dwarf:
offset = .7f;
break;
case RACE_HORSE_216:
case Race::Horse:
offset = 1.4f;
break;
case RACE_ENCHANTED_ARMOR_175:
case RACE_TIGER_63:
case Race::EnchantedArmor:
case Race::Tiger:
offset = 1.75f;
break;
case RACE_STATUE_OF_RALLOS_ZEK_66:
case Race::StatueOfRallosZek:
offset = 1.0f;
break;
case RACE_GORAL_687:
case RACE_SELYRAH_686:
case Race::Goral:
case Race::Selyrah:
offset = 2.0f;
break;
default:
+1 -1
View File
@@ -2015,7 +2015,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
{
if (zone && zone->IsLoaded()) {
zone->SendReloadMessage("NPC Emotes");
zone->LoadNPCEmotes(&zone->NPCEmoteList);
zone->LoadNPCEmotes(&zone->npc_emote_list);
}
break;
}
+7 -7
View File
@@ -1056,7 +1056,7 @@ Zone::~Zone() {
safe_delete_array(short_name);
safe_delete_array(long_name);
safe_delete(Weather_Timer);
NPCEmoteList.Clear();
npc_emote_list.clear();
zone_point_list.Clear();
entity_list.Clear();
ClearBlockedSpells();
@@ -1152,7 +1152,7 @@ bool Zone::Init(bool is_static) {
LoadLDoNTrapEntries();
LoadVeteranRewards();
LoadAlternateCurrencies();
LoadNPCEmotes(&NPCEmoteList);
LoadNPCEmotes(&npc_emote_list);
LoadAlternateAdvancement();
@@ -1233,8 +1233,8 @@ void Zone::ReloadStaticData() {
LoadVeteranRewards();
LoadAlternateCurrencies();
NPCEmoteList.Clear();
LoadNPCEmotes(&NPCEmoteList);
npc_emote_list.clear();
LoadNPCEmotes(&npc_emote_list);
//load the zone config file.
if (!LoadZoneCFG(GetShortName(), GetInstanceVersion())) { // try loading the zone name...
@@ -2548,10 +2548,10 @@ void Zone::DoAdventureActions()
}
void Zone::LoadNPCEmotes(LinkedList<NPC_Emote_Struct*>* NPCEmoteList)
void Zone::LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* NPCEmoteList)
{
NPCEmoteList->Clear();
NPCEmoteList->clear();
const std::string query = "SELECT emoteid, event_, type, text FROM npc_emotes";
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
@@ -2565,7 +2565,7 @@ void Zone::LoadNPCEmotes(LinkedList<NPC_Emote_Struct*>* NPCEmoteList)
nes->event_ = Strings::ToInt(row[1]);
nes->type = Strings::ToInt(row[2]);
strn0cpy(nes->text, row[3], sizeof(nes->text));
NPCEmoteList->Insert(nes);
NPCEmoteList->push_back(nes);
}
LogInfo("Loaded [{}] npc emotes", Strings::Commify(results.RowCount()));
+2 -2
View File
@@ -185,7 +185,7 @@ public:
DynamicZone *GetDynamicZone();
IPathfinder *pathing;
LinkedList<NPC_Emote_Struct *> NPCEmoteList;
std::vector<NPC_Emote_Struct *> npc_emote_list;
LinkedList<Spawn2 *> spawn2_list;
LinkedList<ZonePoint *> zone_point_list;
std::vector<ZonePointsRepository::ZonePoints> virtual_zone_point_list;
@@ -282,7 +282,7 @@ public:
void LoadMercSpells();
void LoadMercTemplates();
void LoadNewMerchantData(uint32 merchantid);
void LoadNPCEmotes(LinkedList<NPC_Emote_Struct *> *NPCEmoteList);
void LoadNPCEmotes(std::vector<NPC_Emote_Struct *> *NPCEmoteList);
void LoadTempMerchantData();
void LoadTickItems();
void LoadVeteranRewards();