Compare commits

..

39 Commits

Author SHA1 Message Date
regneq caae34ac5e fixed client lua summonitem.
export npc:CanTalk to lua.
added QuestSlot.
Added a condition for questslot in summonitem function.
2024-04-05 18:01:48 -07:00
regneq 56c7db4cbf [MultiQuest] Add functions to Loot. Import to Lua_NPC. 2024-04-05 12:08:01 -07:00
KayenEQ 043eeced6f [Bug Fix] Client not updating HP bar when an HP Buff with a Heal is applied. (#4237)
* [Bug Fix] HP Bar not updating when applying HP Buff with a heal.

Bug: When an HP buff with a heal effect is applied for first time, the heal portion of the effect heals the client and updates HPs currently server side, but client side the HP bar does not register it as a heal thus you display as less than full HP. However due to server thinking your healed, you are unable to correct it by healing.

Solution: You need to resend the HP update after buff completed and action packet resent.

* add SE_MaxHPChange to fix

would result in same bug
2024-04-02 01:13:29 -05:00
KayenEQ e9a0c79301 [Bug Fix] SPA214 SE_MaxHPChange calculation errors corrected. (#4238)
* [Bug Fix] HP Bar not updating when applying HP Buff with a heal.

Bug: When an HP buff with a heal effect is applied for first time, the heal portion of the effect heals the client and updates HPs currently server side, but client side the HP bar does not register it as a heal thus you display as less than full HP. However due to server thinking your healed, you are unable to correct it by healing.

Solution: You need to resend the HP update after buff completed and action packet resent.

* add SE_MaxHPChange to fix

would result in same bug

* [Bug Fix] SPA214 Percent HP change calculation fix

Fix how spell and item bonuses using SPA 214 are calculated. Will now be calculated consistent with client.

* [Bug Fix] SPA214 SE_MaxHPChange calculation errors corrected.

removed code from other PR
2024-04-02 01:12:55 -05:00
Alex King dc48c45421 [Bug Fix] Fix Bot Creation Issue (#4235)
# Notes
- Creating bots was failing because were checking for `false` on `Database::CheckUsedName()` in `BotDatabase::QueryNameAvailability`.
- `Database::CheckUsedName()` is now `Database::IsNameUsed()` and checks for both bots and character name usages.
- We were checking for `false` which was always happening when there were no entries for the supplied name, meaning we were never allowed to create a bot.
2024-04-02 01:12:08 -05:00
Chris Miles d7a8fb8691 [Fix] Fix manifest for skill caps schema type (#4231) 2024-04-02 01:08:19 -05:00
Chris Miles 3a5381d38a [Crash] Check mob pointer before trying to remove it (#4230) 2024-04-01 18:09:57 -04:00
Alex King e64f03fcc0 [Bug Fix] Fix Lua Crash with Spell Blocked Event (#4236) 2024-04-01 18:06:39 -04:00
Alex King d77966797e [Quest API] Add Spell Blocked Event to Perl/Lua (#4217)
* [Spells] Add Unblockable Spell Table and Spell Blocked Event

- Add `EVENT_SPELL_BLOCKED`, exports `$blocking_spell_id`, `$cast_spell_id`, `$blocking_spell`, and `$cast_spell`.

- Add `event_spell_blocked`, exports `e.blocking_spell_id`, `e.cast_spell_id`, `e.blocking_spell`, and `e.cast_spell`.

- Adds `spells_unblockable` table with a `spell_id` and `is_unblockable` column.
- This table will need to be populated based on known spells that should be unblockable.

- This event will allow operators to perform events when spells are blocked.

* Cleanup

* Cleanup

* Update spells.cpp

* Remove unused repositories.

* Finalize

* Update lua_parser_events.cpp
2024-03-31 22:58:30 -05:00
Akkadius 048aad437b Update pull_request_template.md 2024-03-31 22:55:27 -05:00
hg b2d9de8d96 [Quests] Avoid Player and Bot quests in unloaded zone (#4232)
If a mob has a target when a zone is shutdown it will crash while trying
to dispatch EVENT_TARGET_CHANGE when the Mob destructor cleans up hatelists
if a quest interface isn't loaded for the type (in this case no bot scripts):

 	zone.exe!fmt::v10::format<std::string const &,char const *>(fmt::v10::basic_format_string<char,std::string const &,char const *> fmt={...}, const std::string & <args_0>={...}, const char * && <args_1>=0x0000000000000000) Line 2835	C++
>	zone.exe!QuestParserCollection::GetQIByBotQuest(std::string & filename={...}) Line 1138	C++
 	zone.exe!QuestParserCollection::BotHasQuestSubLocal(QuestEventID event_id=EVENT_TARGET_CHANGE) Line 353	C++
 	zone.exe!QuestParserCollection::BotHasQuestSub(QuestEventID event_id=EVENT_TARGET_CHANGE) Line 389	C++
 	zone.exe!Mob::SetTarget(Mob * mob=0x0000000000000000) Line 5431	C++
 	zone.exe!NPC::SetTarget(Mob * mob=0x0000000000000000) Line 575	C++
 	zone.exe!Mob::RemoveFromHateList(Mob * mob=0x000001bfbdc66040) Line 4894	C++
 	zone.exe!EntityList::RemoveFromTargets(Mob * mob=0x000001bfbdc66040, bool RemoveFromXTargets=true) Line 1530	C++
 	zone.exe!Mob::~Mob() Line 547	C++
 	zone.exe!NPC::~NPC() Line 537	C++
 	zone.exe!NPC::`scalar deleting destructor'(unsigned int)	C++
 	zone.exe!EntityList::RemoveAllMobs() Line 2678	C++
 	zone.exe!EntityList::Clear() Line 3090	C++
 	zone.exe!Zone::~Zone() Line 1103	C++
 	zone.exe!Zone::`scalar deleting destructor'(unsigned int)	C++
 	zone.exe!Zone::Shutdown(bool quiet=false) Line 928	C++

This is caused by the Zone destructor deleting short_name before calling
entity_list.Clear(). With an unloaded quest interface BotHasQuestSubLocal
calls GetQIByBotQuest which gets a null zone->GetShortName() and crashes
while formatting strings.

The immediate regressing commit for this crash is because a check for
zone->IsLoaded() was removed in 74f1eac4 with others that were removed
to fix a regression by #4025. GetQIByBotQuest and GetQIByPlayerQuest
always had this check and should have remained for them.

This restores the zone->IsLoaded() checks for GetQIByBotQuest/PlayerQuest.
The other functions cannot have that check added until the other issues
mentioned in #4149 are addressed.
2024-03-31 22:49:13 -05:00
Fryguy 42bfa4bb2e [Bug Fix] Shared Tasks - charid is now character_id (#4233)
## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)

# Checklist:

- [x] I have performed a self-review of my code. Ensuring variables, functions and methods are named in a human-readable way, comments are added only where naming of variables, functions and methods can't give enough context.
- [x] I have tested my changes
- [x] I own the changes of my code take responsibilities for the potential issues that occur
2024-03-31 22:41:15 -05:00
Chris Miles 72ce7c8e91 Update pull_request_template.md 2024-03-31 15:52:54 -05:00
Chris Miles e306c86875 Create pull_request_template.md 2024-03-31 15:48:33 -05:00
Alex King 3ae7979a67 [Bug Fix] Fix Issue With Bot Raid Aggro (#4222)
# Notes
- Bots were reportedly being bypassed by NPCs due to not taking into consideration their raid group's damage.
- Must have been missed when bot raids were implemented.
2024-03-31 11:56:12 -05:00
Xackery b638795f9b [Feature] Add LuaMod functions for CommonDamage and HealDamage (#4227)
* Add LuaMod functions for CommonDamage and HealDamage

* Remove extra bracket
2024-03-31 11:30:16 -04:00
KayenEQ 9e3bf91374 [Spells] Implemented SPA 463 SE_SHIELD_TARGET (#4224)
SPA 463 SE_SHIELD_TARGET

Live description: "Shields your target, taking a percentage of their damage".

Only example spell on live is an NPC who uses it during a raid event "Laurion's Song" expansion. SPA 54492 'Guardian Stance' Described as 100% Melee Shielding

Example of mechanic. Base value = 70. Caster puts buff on target. Each melee hit Buff Target takes 70% less damage, Buff Caster receives 30% of the melee damage.
Added mechanic to cause buff to fade if target or caster are separated by a distance greater than the casting range of the spell. This allows similar mechanics to the /shield ability, without a range removal mechanic it would be too easy to abuse if put on a player spell. *can not confirm live does this currently

Can not be cast on self.
2024-03-30 13:34:03 -04:00
KayenEQ cd89926435 [Feature] Additive Spell Focus from Worn slot with Limit Checks (#4208)
* [Feature] Additive Spell Focus from Worn slot with limits

New rule (UseAdditiveFocusFromWornSlotWithLimits) allows you place to focus effects in worn slots which will apply the focus additively and perform normal limit checks on those focus. This differs from regular focus behavior that only takes highest value.

This is a new version of an old rule "UseAdditiveFocusFromWornSlot"
which allowed similar behavior but ignored focus limits. Thus hindering its full potential for itemization.

* Update spell_effects.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-03-30 13:23:02 -04:00
Xackery e19f72f021 [Feature] Add RegisterBug LuaMod (#4209)
* Add RegisterBug LuaMod

* Add missing header

* Add missing header to lua_mod

* Fix RegisterBug ignore_default

* Fix ignore_default

* Fix formatting
2024-03-30 11:45:37 -04:00
JJ df1dc5d1e4 [Cleanup] Avoid unnecessary copies in database functions (#4220)
Since `auto` doesn't deduce references, these will most likely create copies having unintended results.
2024-03-29 07:45:41 -04:00
Alex King e11286164f [Bug Fix] Fix Luabind Double Class Register (#4219)
* [Bug Fix] Fix Luabind Double Class Register

# Notes
- These two methods were registering to the same class as another method, causing an error seen by @neckkola and others.

# Error
```
zone: /home/eqemu/source_jas/libs/luabind/src/class_registry.cpp:151: void luabind::detail::class_registry::add_class(const luabind::type_id&, luabind::detail::class_rep*): Assertion `(m_classes.find(info) == m_classes.end()) && "you are trying to register a class twice"' failed.
```

* Update lua_general.cpp
2024-03-28 20:05:55 -04:00
JJ b946b800fb [Cleanup] Reference type in GetRaidLeaderName (#4218)
Minor cleanup from #4054
2024-03-28 19:15:16 -04:00
Alex King ab8ac81df6 [Bug Fix] Fix Group Leadership (#4214)
* [Bug Fix] Fix Group Leadership

# Notes
- We were not sending anything to `group_leaders` table if we did not already have an existing row.

# Video

* Update database.cpp
2024-03-28 15:33:49 -05:00
Alex King 109940fc0c [Quest API] Add Class/Deity/Race Methods to Perl/Lua (#4215)
# Perl
- Add `$client->GetDeityBitmask()`.
- Add `quest::get_class_bitmask(class_id)`.
- Add `quest::get_deity_bitmask(deity_id)`.
- Add `quest::get_race_bitmask(race_id)`.

# Lua
- Add `client:GetDeityBitmask()`.
- Add `eq.get_class_bitmask(class_id)`.
- Add `eq.get_deity_bitmask(deity_id)`.
- Add `eq.get_race_bitmask(race_id)`.

# Notes
- Allows operators to get the class/deity/race bitmask of a class/deity/race by ID.
- Allows operators to get a client's deity bitmask.
2024-03-28 15:32:02 -05:00
Fryguy a87496b0cf [Lua] Add Zone and Language Constants (#4211)
* [LUA] Add Zone and Language Constants

This will add Zone:

```lua
if eq.get_zone_id() == Zone.Qeynos then
   foo()
end
```

It will also add Language:

```lua
if e.language == Language.ElderElvish and e.other:GetLanguageSkill(Language.ElderElvish) >= 100 then
   e.self:Say("You know my language!", Language.ElderElvish);
end
```

These changes should help avoid magic numbers in quests and aide in readability without the need for -- comments to clarify.

* Adjust to lower case
2024-03-28 13:16:41 -04:00
Alex King f905ee70e4 [Bug Fix] Fix Auto Login Issue (#4213)
* [Bug Fix] Fix Auto Login Issue

# Notes
- We were setting `live_name` value regardless of if we were zoning, causing us to automatically log in to the last character we'd logged in to before.

* Remove &
2024-03-28 09:48:17 -04:00
JJ 52417023f8 [Cleanup] Remove unnecessary reference types (#4212)
Minor clean up from #4054 and #4181
2024-03-27 22:17:21 -04:00
KayenEQ 20d9417628 [Spells] SPA148 Stacking Fix (#4206)
Update to SPA148 which acts to block spells buffs that are of lesser value than the current buff for specific effect slots. This effected was preventing detrimental debuffs from being applied that were using same effect slot. This bug affected a very small amount of spell interactions and was fixed on live in 2018.  Example being Vishmitars Corruption (6642) being blocked by SteelOak Skin (5352)

 I confirmed the behavior on live myself. The detrimental buff  if in conflict should now be applied instead of blocked.
2024-03-27 14:39:40 -04:00
Xackery 4692799677 [Bug Fix] Fix event_consider any_cast error (#4210) 2024-03-27 14:31:38 -04:00
Chris Miles cf7f0f4321 [Skill Caps] Further improvements (#4205) 2024-03-24 13:04:26 -04:00
Chris Miles 823a5956de [Hotfix] Fix crash in SendEnterWorld (#4204) 2024-03-23 23:28:29 -05:00
JJ 6a8bd3c5d6 [Bug Fix] Fix fishing chances (#4203)
Fix regression from #4008 where the item count wasn't being incremented
Move the zone table chance to a rule
General cleanup of some initializers and variable types
2024-03-23 23:32:07 -04:00
Alex King 523ba30d81 [Repositories] Convert database.cpp to Repositories (#4054)
* [Repositories] Convert database.cpp to Repositories

- Convert all database.cpp methods to repositories where possible.

* Final push.

* Cleanup

* Cleanup

* Update database.h

* Fix crash

* Update database.cpp
2024-03-23 19:30:56 -05:00
Alex King d7ea290b6b [Skill Caps] Remove from shared memory and simplify (#4069)
* [Skill Caps] Remove from shared memory and simplify

- Removes Skill Caps loading from shared memory and puts it into zone.
- Adds `id` column to `skill_caps`.
- Remove primary keys and use `id` as primary key.
- Add unique index using `skill_id`, `class_id`, `level`, and `cap`.
- Renames `class` to `class_id` in `skill_caps` table.
- Renames `skillID` to `skill_id` in `skill_caps` table.
- Regenerates Skill Caps repository.
- Adds `#reload skill_caps` to reload skill caps in real time.

* Update groups.cpp

* Update groups.cpp
2024-03-23 18:52:40 -05:00
Alex King 036309ebec [Hot Fix] Hot Fix for Group::AddToGroup Hot Fix (#4202)
# Notes
- Typo in previous.
2024-03-23 18:51:43 -05:00
Alex King b400700d81 [Hot Fix] Fix Group::AddToGroup (#4201)
# Notes
- We were not using `r` values at any point.
2024-03-23 18:49:15 -05:00
Alex King 21cec87ac4 [Bug Fix] Fix Bot/Character ID Overlap in Groups (#4093)
* [Bug Fix] Fix Bot/Character ID Overlap in Groups

- Attempt to fix bot/character ID overlap in groups keeping bots with the same unique identifier as players from not spawning on zone.
- Adds `bot_id` to `group_id` to differentiate bots from characters and hopefully alleviate this issue.

* Update base_group_id_repository.h

* Final push
2024-03-23 17:55:03 -05:00
Alex King abdec39cdd [Quest API] Add Archetype Methods to Perl/Lua (#4181)
* [Quest API] Add Archetype Methods to Perl/Lua

- Add `$mob->GetArchetypeName()`.
- Add `$mob->IsIntelligenceCasterClass()`.
- Add `$mob->IsPureMeleeClass()`.
- Add `$mob->IsWisdomCasterClass()`.

- Add `mob:GetArchetypeName()`.
- Add `mob:IsIntelligenceCasterClass()`.
- Add `mob:IsPureMeleeClass()`.
- Add `mob:IsWisdomCasterClass()`.

- Allows operators to use mob archetypes to perform different operations.
- Add a namespace for archetypes instead of constants.
- Utilize `IsIntelligenceCasterClass()`, `IsPureMeleeClass()`, and `IsWisdomCasterClass()` where necessary.
-

* Update mob.cpp
2024-03-23 14:37:35 -05:00
Fryguy d2372de982 [Bug Fix] Radiant/Ebon Crystals should only extract to 1000 (#4195)
* [Bug] Radiant/Ebon Crystals should only extract to 1000

Creating a stack larger than 1000 can cause potential dupe issues further down the stream if other tasks are performed on the stack.

* Use stacksize instead

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
2024-03-23 12:56:59 -05:00
110 changed files with 4544 additions and 2949 deletions
+42 -45
View File
@@ -29,6 +29,8 @@
#include "../../common/content/world_content_service.h"
#include "../../common/zone_store.h"
#include "../../common/path_manager.h"
#include "../../common/repositories/skill_caps_repository.h"
#include "../../common/file.h"
EQEmuLogSys LogSys;
WorldContentService content_service;
@@ -164,81 +166,76 @@ void ExportSpells(SharedDatabase *db)
fclose(f);
}
bool SkillUsable(SharedDatabase *db, int skill_id, int class_id)
bool SkillUsable(SharedDatabase* db, int skill_id, int class_id)
{
bool res = false;
std::string query = StringFormat(
"SELECT max(cap) FROM skill_caps WHERE class=%d AND skillID=%d",
class_id, skill_id
const auto& l = SkillCapsRepository::GetWhere(
*db,
fmt::format(
"`class_id` = {} AND `skill_id` = {} ORDER BY `cap` DESC LIMIT 1",
class_id,
skill_id
)
);
auto results = db->QueryDatabase(query);
if (!results.Success()) {
return false;
}
if (results.RowCount() == 0) {
return false;
}
auto row = results.begin();
if (row[0] && Strings::ToInt(row[0]) > 0) {
return true;
}
return false;
return !l.empty();
}
int GetSkill(SharedDatabase *db, int skill_id, int class_id, int level)
uint32 GetSkill(SharedDatabase* db, int skill_id, int class_id, int level)
{
std::string query = StringFormat(
"SELECT cap FROM skill_caps WHERE class=%d AND skillID=%d AND level=%d",
class_id, skill_id, level
const auto& l = SkillCapsRepository::GetWhere(
*db,
fmt::format(
"`class_id` = {} AND `skill_id` = {} AND `level` = {}",
class_id,
skill_id,
level
)
);
auto results = db->QueryDatabase(query);
if (!results.Success()) {
if (l.empty()) {
return 0;
}
if (results.RowCount() == 0) {
return 0;
}
auto e = l.front();
auto row = results.begin();
return Strings::ToInt(row[0]);
return e.cap;
}
void ExportSkillCaps(SharedDatabase *db)
void ExportSkillCaps(SharedDatabase* db)
{
LogInfo("Exporting Skill Caps");
std::string file = fmt::format("{}/export/SkillCaps.txt", path.GetServerPath());
FILE *f = fopen(file.c_str(), "w");
if (!f) {
std::ofstream file(fmt::format("{}/export/SkillCaps.txt", path.GetServerPath()));
if (!file || !file.is_open()) {
LogError("Unable to open export/SkillCaps.txt to write, skipping.");
return;
}
for (int cl = 1; cl <= 16; ++cl) {
for (int skill = 0; skill <= 77; ++skill) {
if (SkillUsable(db, skill, cl)) {
int previous_cap = 0;
for (int level = 1; level <= 100; ++level) {
int cap = GetSkill(db, skill, cl, level);
const uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) {
if (SkillUsable(db, skill_id, class_id)) {
uint32 previous_cap = 0;
for (uint8 level = 1; level <= skill_cap_max_level; level++) {
uint32 cap = GetSkill(db, skill_id, class_id, level);
if (cap < previous_cap) {
cap = previous_cap;
}
fprintf(f, "%d^%d^%d^%d^0\n", cl, skill, level, cap);
file << fmt::format("{}^{}^{}^{}^0", class_id, skill_id, level, cap) << std::endl;
previous_cap = cap;
}
}
}
}
fclose(f);
file.close();
}
void ExportBaseData(SharedDatabase *db)
+11 -9
View File
@@ -83,6 +83,7 @@ SET(common_sources
shared_tasks.cpp
shareddb.cpp
skills.cpp
skill_caps.cpp
spdat.cpp
strings.cpp
struct_strategy.cpp
@@ -492,7 +493,7 @@ SET(repositories
repositories/zone_repository.h
repositories/zone_points_repository.h
)
)
SET(common_headers
additive_lagged_fibonacci_engine.h
@@ -592,7 +593,7 @@ SET(common_headers
ptimer.h
queue.h
races.h
raid.h
raid.h
random.h
rdtsc.h
rulesys.h
@@ -606,6 +607,7 @@ SET(common_headers
shared_tasks.h
shareddb.h
skills.h
skill_caps.h
spdat.h
strings.h
struct_strategy.h
@@ -681,13 +683,13 @@ SOURCE_GROUP(Event FILES
event/event_loop.h
event/timer.h
event/task.h
)
)
SOURCE_GROUP(Json FILES
json/json.h
json/jsoncpp.cpp
json/json-forwards.h
)
)
SOURCE_GROUP(Net FILES
net/console_server.cpp
@@ -724,7 +726,7 @@ SOURCE_GROUP(Net FILES
net/websocket_server.h
net/websocket_server_connection.cpp
net/websocket_server_connection.h
)
)
SOURCE_GROUP(Patches FILES
patches/patches.h
@@ -768,12 +770,12 @@ SOURCE_GROUP(Patches FILES
patches/titanium_limits.cpp
patches/uf.cpp
patches/uf_limits.cpp
)
)
SOURCE_GROUP(StackWalker FILES
StackWalker/StackWalker.h
StackWalker/StackWalker.cpp
)
)
SOURCE_GROUP(Util FILES
util/memory_stream.h
@@ -781,7 +783,7 @@ SOURCE_GROUP(Util FILES
util/directory.h
util/uuid.cpp
util/uuid.h
)
)
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker)
@@ -794,6 +796,6 @@ ENDIF (UNIX)
IF (WIN32 AND EQEMU_BUILD_PCH)
TARGET_PRECOMPILE_HEADERS(common PRIVATE pch/pch.h)
ENDIF()
ENDIF ()
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+995 -1287
View File
File diff suppressed because it is too large Load Diff
+144 -140
View File
@@ -18,8 +18,8 @@
#ifndef EQEMU_DATABASE_H
#define EQEMU_DATABASE_H
#define AUTHENTICATION_TIMEOUT 60
#define INVALID_ID 0xFFFFFFFF
#define AUTHENTICATION_TIMEOUT 60
#define INVALID_ID 0xFFFFFFFF
#include "global_define.h"
#include "eqemu_logsys.h"
@@ -38,8 +38,7 @@
class MySQLRequestResult;
class Client;
namespace EQ
{
namespace EQ {
class InventoryProfile;
}
@@ -52,10 +51,11 @@ struct npcDecayTimes_Struct {
struct VarCache_Struct {
std::map<std::string, std::string> m_cache;
uint32 last_update;
uint32 last_update;
VarCache_Struct() : last_update(0) { }
void Add(const std::string &key, const std::string &value) { m_cache[key] = value; }
const std::string *Get(const std::string &key) {
void Add(const std::string& key, const std::string& value) { m_cache[key] = value; }
const std::string* Get(const std::string& key)
{
auto it = m_cache.find(key);
return (it != m_cache.end() ? &it->second : nullptr);
}
@@ -76,37 +76,33 @@ class PTimerList;
#define SQL(...) #__VA_ARGS__
class LogSettings;
class Database : public DBcore {
public:
Database();
Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port, std::string connection_label = "default");
Database(
const std::string& host,
const std::string& user,
const std::string& password,
const std::string& database,
uint32 port
);
bool Connect(
const std::string& host,
const std::string& user,
const std::string& password,
const std::string& database,
uint32 port,
std::string connection_label = "default"
);
~Database();
/* Character Creation */
bool CreateCharacter(
uint32 account_id,
char *name,
uint16 gender,
uint16 race,
uint16 class_,
uint8 str,
uint8 sta,
uint8 cha,
uint8 dex,
uint8 int_,
uint8 agi,
uint8 wis,
uint8 face
);
bool DeleteCharacter(char *character_name);
bool MoveCharacterToZone(const char *charname, uint32 zone_id);
bool DeleteCharacter(const std::string& name);
bool MoveCharacterToZone(const std::string& name, uint32 zone_id);
bool MoveCharacterToZone(uint32 character_id, uint32 zone_id);
bool ReserveName(uint32 account_id, char *name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct *pp);
bool UpdateName(const char *oldname, const char *newname);
bool ReserveName(uint32 account_id, const std::string& name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool UpdateName(const std::string& old_name, const std::string& new_name);
bool CopyCharacter(
const std::string& source_character_name,
const std::string& destination_character_name,
@@ -114,163 +110,171 @@ public:
);
/* General Information Queries */
bool AddBannedIP(const std::string& banned_ip, const std::string& notes); //Add IP address to the banned_ips table.
bool AddToNameFilter(const std::string& name);
bool CheckBannedIPs(const std::string& login_ip); //Check incoming connection against banned IP table.
bool CheckGMIPs(const std::string& login_ip, uint32 account_id);
bool CheckNameFilter(const std::string& name, bool surname = false);
bool IsNameUsed(const std::string& name);
bool AddBannedIP(std::string banned_ip, std::string notes); //Add IP address to the banned_ips table.
bool AddToNameFilter(std::string name);
bool CheckBannedIPs(std::string login_ip); //Check incoming connection against banned IP table.
bool CheckGMIPs(std::string login_ip, uint32 account_id);
bool CheckNameFilter(std::string name, bool surname = false);
bool CheckUsedName(std::string name);
uint32 GetAccountIDByChar(const std::string& name, uint32* character_id = 0);
uint32 GetAccountIDByChar(uint32 character_id);
uint32 GetAccountIDByName(const std::string& account_name, const std::string& loginserver, int16* status = 0, uint32* lsid = 0);
uint32 GetCharacterID(const std::string& name);
uint32 GetGuildIDByCharID(uint32 character_id);
uint32 GetGroupIDByCharID(uint32 character_id);
uint32 GetRaidIDByCharID(uint32 character_id);
uint32 GetAccountIDByChar(const char* charname, uint32* oCharID = 0);
uint32 GetAccountIDByChar(uint32 char_id);
uint32 GetAccountIDByName(std::string account_name, std::string loginserver, int16* status = 0, uint32* lsid = 0);
uint32 GetCharacterID(const std::string& name);
uint32 GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id);
uint32 GetGuildIDByCharID(uint32 char_id);
uint32 GetGroupIDByCharID(uint32 char_id);
uint32 GetRaidIDByCharID(uint32 char_id);
void GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID = 0);
void GetCharName(uint32 char_id, char* name);
std::string GetCharNameByID(uint32 char_id);
std::string GetNPCNameByID(uint32 npc_id);
std::string GetCleanNPCNameByID(uint32 npc_id);
void LoginIP(uint32 account_id, std::string login_ip);
const std::string GetAccountName(uint32 account_id, uint32* lsaccount_id = 0);
const std::string GetCharName(uint32 character_id);
const std::string GetCharNameByID(uint32 character_id);
const std::string GetNPCNameByID(uint32 npc_id);
const std::string GetCleanNPCNameByID(uint32 npc_id);
void LoginIP(uint32 account_id, const std::string& login_ip);
/* Instancing */
bool AddClientToInstance(uint16 instance_id, uint32 character_id);
bool CheckInstanceByCharID(uint16 instance_id, uint32 character_id);
bool CheckInstanceExists(uint16 instance_id);
bool CheckInstanceExpired(uint16 instance_id);
bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
bool GetUnusedInstanceID(uint16 &instance_id);
bool GetUnusedInstanceID(uint16& instance_id);
bool IsGlobalInstance(uint16 instance_id);
bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
bool RemoveClientsFromInstance(uint16 instance_id);
bool VerifyInstanceAlive(uint16 instance_id, uint32 character_id);
bool VerifyZoneInstance(uint32 zone_id, uint16 instance_id);
uint16 GetInstanceID(uint32 zone, uint32 charid, int16 version);
uint16 GetInstanceID(uint32 zone, uint32 character_id, int16 version);
std::vector<uint16> GetInstanceIDs(uint32 zone_id, uint32 character_id);
uint8_t GetInstanceVersion(uint16 instance_id);
uint32 GetTimeRemainingInstance(uint16 instance_id, bool &is_perma);
uint32 GetTimeRemainingInstance(uint16 instance_id, bool& is_perma);
uint32 GetInstanceZoneID(uint16 instance_id);
void AssignGroupToInstance(uint32 gid, uint32 instance_id);
void AssignRaidToInstance(uint32 rid, uint32 instance_id);
void AssignGroupToInstance(uint32 group_id, uint32 instance_id);
void AssignRaidToInstance(uint32 raid_id, uint32 instance_id);
void DeleteInstance(uint16 instance_id);
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 charid, uint32 group_id);
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 charid, uint32 raid_id);
void GetCharactersInInstance(uint16 instance_id, std::list<uint32> &character_ids);
void FlagInstanceByGroupLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 group_id);
void FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 character_id, uint32 raid_id);
void GetCharactersInInstance(uint16 instance_id, std::list<uint32>& character_ids);
void PurgeExpiredInstances();
void SetInstanceDuration(uint16 instance_id, uint32 new_duration);
void CleanupInstanceCorpses();
/* Adventure related. */
void UpdateAdventureStatsEntry(uint32 char_id, uint8 theme, bool win = false, bool remove = false);
bool GetAdventureStats(uint32 char_id, AdventureStats_Struct *as);
void UpdateAdventureStatsEntry(uint32 character_id, uint8 theme_id, bool is_win = false, bool is_remove = false);
bool GetAdventureStats(uint32 character_id, AdventureStats_Struct* as);
/* Account Related */
const std::string GetLiveChar(uint32 account_id);
bool SetAccountStatus(const std::string& account_name, int16 status);
bool SetLocalPassword(uint32 account_id, const std::string& password);
bool UpdateLiveChar(const std::string& name, uint32 account_id);
int16 CheckStatus(uint32 account_id);
void SetAccountCRCField(uint32 account_id, const std::string& field_name, uint64 checksum);
uint32 CheckLogin(const std::string& name, const std::string& password, const std::string& loginserver, int16* status = 0);
uint32 CreateAccount(
const std::string& name,
const std::string& password,
int16 status,
const std::string& loginserver,
uint32 lsaccount_id
);
uint32 GetAccountIDFromLSID(
const std::string& in_loginserver_id,
uint32 in_loginserver_account_id,
char* in_account_name = 0,
int16* in_status = 0
);
bool DeleteAccount(const char *name, const char* loginserver);
bool GetLiveChar(uint32 account_id, char* cname);
bool SetAccountStatus(const char* name, int16 status);
bool SetAccountStatus(const std::string& account_name, int16 status);
bool SetLocalPassword(uint32 accid, const char* password);
bool UpdateLiveChar(char* charname, uint32 account_id);
uint8 GetAgreementFlag(uint32 account_id);
void SetAgreementFlag(uint32 account_id);
int16 CheckStatus(uint32 account_id);
int GetIPExemption(const std::string& account_ip);
void SetIPExemption(const std::string& account_ip, int exemption_amount);
void SetAccountCRCField(uint32 account_id, std::string field_name, uint64 checksum);
uint32 CheckLogin(const char* name, const char* password, const char *loginserver, int16* oStatus = 0);
uint32 CreateAccount(const char* name, const char* password, int16 status, const char* loginserver, uint32 lsaccount_id);
uint32 GetAccountIDFromLSID(const std::string& in_loginserver_id, uint32 in_loginserver_account_id, char* in_account_name = 0, int16* in_status = 0);
uint8 GetAgreementFlag(uint32 account_id);
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
void SetAgreementFlag(uint32 account_id);
int GetIPExemption(std::string account_ip);
void SetIPExemption(std::string account_ip, int exemption_amount);
int GetInstanceID(uint32 char_id, uint32 zone_id);
int GetInstanceID(uint32 character_id, uint32 zone_id);
/* Groups */
std::string GetGroupLeaderForLogin(std::string character_name);
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
std::string GetGroupLeaderForLogin(const std::string& character_name);
char* GetGroupLeadershipInfo(
uint32 group_id,
char* leaderbuf,
char* maintank = nullptr,
char* assist = nullptr,
char* puller = nullptr,
char* marknpc = nullptr,
char* mentoree = nullptr,
int* mentor_percent = nullptr,
GroupLeadershipAA_Struct* GLAA = nullptr
);
std::string GetGroupLeaderName(uint32 group_id);
uint32 GetGroupID(const char* name);
void ClearGroup(uint32 gid = 0);
void ClearGroupLeader(uint32 gid = 0);
void SetGroupID(const char* name, uint32 id, uint32 charid, uint32 ismerc = false);
void SetGroupLeaderName(uint32 gid, const char* name);
uint32 GetGroupID(const std::string& name);
void ClearGroup(uint32 group_id = 0);
void ClearGroupLeader(uint32 group_id = 0);
void SetGroupLeaderName(uint32 group_id, const std::string& name);
/* Raids */
const std::string GetRaidLeaderName(uint32 raid_id);
uint32 GetRaidID(const std::string& name);
void ClearRaid(uint32 raid_id = 0);
void ClearRaidDetails(uint32 raid_id = 0);
void ClearRaidLeader(uint32 group_id = std::numeric_limits<uint32>::max(), uint32 raid_id = 0);
void GetGroupLeadershipInfo(
uint32 group_id,
uint32 raid_id,
char* maintank = nullptr,
char* assist = nullptr,
char* puller = nullptr,
char* marknpc = nullptr,
char* mentoree = nullptr,
int* mentor_percent = nullptr,
GroupLeadershipAA_Struct* GLAA = nullptr
);
void GetRaidLeadershipInfo(
uint32 raid_id,
char* maintank = nullptr,
char* assist = nullptr,
char* puller = nullptr,
char* marknpc = nullptr,
RaidLeadershipAA_Struct* RLAA = nullptr
);
void SetRaidGroupLeaderInfo(uint32 group_id, uint32 raid_id);
const char *GetRaidLeaderName(uint32 rid);
uint32 GetRaidID(const char* name);
void ClearRaid(uint32 rid = 0);
void ClearRaidDetails(uint32 rid = 0);
void ClearRaidLeader(uint32 gid = 0xFFFFFFFF, uint32 rid = 0);
void GetGroupLeadershipInfo(uint32 gid, uint32 rid, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
void GetRaidLeadershipInfo(uint32 rid, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, RaidLeadershipAA_Struct* RLAA = nullptr);
void SetRaidGroupLeaderInfo(uint32 gid, uint32 rid);
void PurgeAllDeletedDataBuckets();
void PurgeAllDeletedDataBuckets();
/* Database Variables */
bool GetVariable(const std::string& name, std::string& value);
bool SetVariable(const std::string& name, const std::string& value);
bool LoadVariables();
bool GetVariable(std::string varname, std::string &varvalue);
bool SetVariable(const std::string& varname, const std::string &varvalue);
bool LoadVariables();
uint8 GetPEQZone(uint32 zone_id, uint32 version);
uint32 GetServerType();
void AddReport(const std::string& who, const std::string& against, const std::string& lines);
struct TimeOfDay_Struct LoadTime(time_t& realtime);
bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year);
void ClearMerchantTemp();
void ClearPTimers(uint32 character_id);
void SetFirstLogon(uint32 character_id, uint8 first_logon);
void SetLFG(uint32 character_id, bool is_lfg);
void SetLFP(uint32 character_id, bool is_lfp);
void SetLoginFlags(uint32 character_id, bool is_lfp, bool is_lfg, uint8 first_logon);
/* General Queries */
int64 CountInvSnapshots();
void ClearInvSnapshots(bool from_now = false);
bool GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0);
bool LoadPTimers(uint32 charid, PTimerList &into);
uint8 GetPEQZone(uint32 zone_id, uint32 version);
uint8 GetMinStatus(uint32 zone_id, uint32 instance_version);
uint8 GetRaceSkill(uint8 skillid, uint8 in_race);
uint8 GetServerType();
uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level);
void AddReport(std::string who, std::string against, std::string lines);
struct TimeOfDay_Struct LoadTime(time_t &realtime);
bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year);
void ClearMerchantTemp();
void ClearPTimers(uint32 charid);
void SetFirstLogon(uint32 CharID, uint8 firstlogon);
void SetLFG(uint32 CharID, bool LFG);
void SetLFP(uint32 CharID, bool LFP);
void SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon);
int CountInvSnapshots();
void ClearInvSnapshots(bool from_now = false);
void SourceDatabaseTableFromUrl(std::string table_name, std::string url);
void SourceSqlFromUrl(std::string url);
void SourceDatabaseTableFromUrl(const std::string& table_name, const std::string& url);
void SourceSqlFromUrl(const std::string& url);
private:
Mutex Mvarcache;
Mutex Mvarcache;
VarCache_Struct varcache;
/* Groups, utility methods. */
void ClearAllGroupLeaders();
void ClearAllGroups();
void ClearAllGroupLeaders();
void ClearAllGroups();
/* Raid, utility methods. */
void ClearAllRaids();
@@ -5433,6 +5433,42 @@ ADD PRIMARY KEY (`id`);
ALTER TABLE `rule_values`
MODIFY COLUMN `rule_value` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL AFTER `rule_name`;
)"
},
ManifestEntry{
.version = 9267,
.description = "2024_02_18_group_id_bot_id.sql",
.check = "SHOW COLUMNS FROM `group_id` LIKE 'bot_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `group_id`
CHANGE COLUMN `groupid` `group_id` int(11) UNSIGNED NOT NULL DEFAULT 0 FIRST,
CHANGE COLUMN `charid` `character_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `group_id`,
CHANGE COLUMN `ismerc` `merc_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `name`,
ADD COLUMN `bot_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `character_id`,
MODIFY COLUMN `name` varchar(64) NOT NULL DEFAULT '' AFTER `character_id`,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`group_id`, `character_id`, `bot_id`, `merc_id`) USING BTREE;
ALTER TABLE `group_id`
MODIFY COLUMN `character_id` int(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `name`;
)"
},
ManifestEntry{
.version = 9268,
.description = "2024_03_23_skill_caps.sql",
.check = "SHOW COLUMNS FROM `skill_caps` LIKE 'skill_id'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `skill_caps`
CHANGE COLUMN `skillID` `skill_id` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 FIRST,
CHANGE COLUMN `class` `class_id` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `skill_id`,
ADD COLUMN `id` int(3) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`id`) USING BTREE,
ADD INDEX `level_skill_cap`(`skill_id`, `class_id`, `level`, `cap`);
)",
.content_schema_update = true,
}
// -- template; copy/paste this when you need to create a new entry
// ManifestEntry{
+10 -5
View File
@@ -421,20 +421,25 @@ void Database::AssignGroupToInstance(uint32 group_id, uint32 instance_id)
auto zone_id = GetInstanceZoneID(instance_id);
auto version = GetInstanceVersion(instance_id);
auto l = GroupIdRepository::GetWhere(
const auto& l = GroupIdRepository::GetWhere(
*this,
fmt::format(
"groupid = {}",
"`group_id` = {}",
group_id
)
);
if (l.empty()) {
return;
}
for (const auto& e : l) {
if (!GetInstanceID(zone_id, e.charid, version)) {
AddClientToInstance(instance_id, e.charid);
if (!e.character_id) {
continue;
}
if (!GetInstanceID(zone_id, e.character_id, version)) {
AddClientToInstance(instance_id, e.character_id);
}
}
}
@@ -504,7 +509,7 @@ void Database::FlagInstanceByRaidLeader(uint32 zone_id, int16 version, uint32 ch
return;
}
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id));
auto raid_leader_id = GetCharacterID(GetRaidLeaderName(raid_id).c_str());
auto raid_leader_instance_id = GetInstanceID(zone_id, raid_leader_id, version);
if (!raid_leader_instance_id) {
+2
View File
@@ -89,6 +89,8 @@ namespace EQ
using RoF2::invslot::SLOT_INVALID;
using RoF2::invslot::SLOT_BEGIN;
using RoF2::invslot::SLOT_QUEST;
using Titanium::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
const int16 SLOT_AUGMENT_GENERIC_RETURN = 1001; // clients don't appear to use this method... (internal inventory return value)
+5
View File
@@ -130,6 +130,11 @@ enum CrystalReclaimTypes
Radiant = 4,
};
namespace ItemStackSizeConstraint {
constexpr int16 Minimum = 1;
constexpr int16 Maximum = 1000;
}
///////////////////////////////////////////////////////////////////////////////
+5
View File
@@ -82,6 +82,10 @@ Zone extensions and features
#define QUEST_GLOBAL_DIRECTORY "global"
#endif
// Number of quest items a Quest NPC can hold
#define MAX_NPC_QUEST_INVENTORY 24
//the min ratio at which a mob's speed is reduced
#define FLEE_HP_MINSPEED 22
//number of tics to try to run straight away before looking again
@@ -111,6 +115,7 @@ Zone extensions and features
#define SKILL_MAX_LEVEL 75
/*
Zone Numerical configuration
+2
View File
@@ -25,6 +25,8 @@ struct LootItem {
uint16 trivial_max_level;
uint16 npc_min_level;
uint16 npc_max_level;
uint8 quest;
uint8 pet;
};
typedef std::list<LootItem*> LootItems;
+2
View File
@@ -165,6 +165,8 @@ namespace RoF2
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 SLOT_QUEST = 9999;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
+2
View File
@@ -162,6 +162,8 @@ namespace RoF
const int16 SLOT_INVALID = IINVALID;
const int16 SLOT_BEGIN = INULL;
const int16 SLOT_QUEST = 9999;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
+2
View File
@@ -152,6 +152,8 @@ namespace SoD
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_QUEST = 9999;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
+2
View File
@@ -152,6 +152,8 @@ namespace SoF
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_QUEST = 9999;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
+2
View File
@@ -151,6 +151,8 @@ namespace Titanium
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_QUEST = 9999;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
+2
View File
@@ -152,6 +152,8 @@ namespace UF
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
const int16 SLOT_QUEST = 9999;
const int16 POSSESSIONS_BEGIN = slotCharm;
const int16 POSSESSIONS_END = slotCursor;
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
+1 -1
View File
@@ -1379,7 +1379,7 @@ uint32 GetPlayerRaceValue(uint16 race_id) {
}
}
uint32 GetPlayerRaceBit(uint16 race_id) {
uint16 GetPlayerRaceBit(uint16 race_id) {
switch (race_id) {
case HUMAN:
return PLAYER_RACE_HUMAN_BIT;
+1 -1
View File
@@ -124,7 +124,7 @@ bool IsPlayerRace(uint16 race_id);
const std::string GetPlayerRaceAbbreviation(uint16 race_id);
uint32 GetPlayerRaceValue(uint16 race_id);
uint32 GetPlayerRaceBit(uint16 race_id);
uint16 GetPlayerRaceBit(uint16 race_id);
uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value);
uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit);
+44
View File
@@ -44,7 +44,51 @@ public:
*/
// Custom extended repository methods here
static int16 GetAccountStatus(Database& db, const uint32 account_id)
{
auto results = db.QueryDatabase(
fmt::format(
"SELECT `status`, TIMESTAMPDIFF(SECOND, NOW(), `suspendeduntil`) FROM `{}` WHERE `{}` = {}",
TableName(),
PrimaryKey(),
account_id
)
);
if (!results.Success() || !results.RowCount()) {
return 0;
}
auto row = results.begin();
int16 status = static_cast<int16>(Strings::ToInt(row[0]));
int date_diff = 0;
if (row[1]) {
date_diff = Strings::ToInt(row[1]);
}
if (date_diff > 0) {
status = -1;
}
return status;
}
static bool UpdatePassword(Database& db, const uint32 account_id, const std::string& password)
{
auto results = db.QueryDatabase(
fmt::format(
"UPDATE `{}` SET `password` = MD5('{}') WHERE `{}` = {}",
TableName(),
password,
PrimaryKey(),
account_id
)
);
return results.Success();
}
};
#endif //EQEMU_ACCOUNT_REPOSITORY_H
@@ -44,7 +44,65 @@ public:
*/
// Custom extended repository methods here
static void UpdateAdventureStatsEntry(Database& db, uint32 character_id, uint8 theme_id, bool is_win, bool is_remove)
{
std::string field;
switch (theme_id) {
case LDoNThemes::GUK: {
field = "guk_";
break;
}
case LDoNThemes::MIR: {
field = "mir_";
break;
}
case LDoNThemes::MMC: {
field = "mmc_";
break;
}
case LDoNThemes::RUJ: {
field = "ruj_";
break;
}
case LDoNThemes::TAK: {
field = "tak_";
break;
}
}
field += is_win ? "wins" : "losses";
auto e = FindOne(db, character_id);
if (!e.player_id && !is_remove) {
const std::string& query = fmt::format(
"INSERT INTO `{}` SET `{}` = 1, `{}` = {}",
TableName(),
field,
PrimaryKey(),
character_id
);
db.QueryDatabase(query);
return;
}
const std::string& field_operation = is_remove ? "-" : "+";
const std::string& query = fmt::format(
"UPDATE `{}` SET `{}` = {} {} 1 WHERE `{}` = {}",
TableName(),
field,
field,
field_operation,
PrimaryKey(),
character_id
);
db.QueryDatabase(query);
}
};
#endif //EQEMU_ADVENTURE_STATS_REPOSITORY_H
@@ -22,7 +22,7 @@ public:
int32_t accid;
std::string ip;
int32_t count;
std::string lastused;
time_t lastused;
};
static std::string PrimaryKey()
@@ -46,7 +46,7 @@ public:
"accid",
"ip",
"count",
"lastused",
"UNIX_TIMESTAMP(lastused)",
};
}
@@ -130,7 +130,7 @@ public:
e.accid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.ip = row[1] ? row[1] : "";
e.count = row[2] ? static_cast<int32_t>(atoi(row[2])) : 1;
e.lastused = row[3] ? row[3] : std::time(nullptr);
e.lastused = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
return e;
}
@@ -167,7 +167,7 @@ public:
v.push_back(columns[0] + " = " + std::to_string(e.accid));
v.push_back(columns[1] + " = '" + Strings::Escape(e.ip) + "'");
v.push_back(columns[2] + " = " + std::to_string(e.count));
v.push_back(columns[3] + " = '" + Strings::Escape(e.lastused) + "'");
v.push_back(columns[3] + " = FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -192,7 +192,7 @@ public:
v.push_back(std::to_string(e.accid));
v.push_back("'" + Strings::Escape(e.ip) + "'");
v.push_back(std::to_string(e.count));
v.push_back("'" + Strings::Escape(e.lastused) + "'");
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -225,7 +225,7 @@ public:
v.push_back(std::to_string(e.accid));
v.push_back("'" + Strings::Escape(e.ip) + "'");
v.push_back(std::to_string(e.count));
v.push_back("'" + Strings::Escape(e.lastused) + "'");
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -262,7 +262,7 @@ public:
e.accid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.ip = row[1] ? row[1] : "";
e.count = row[2] ? static_cast<int32_t>(atoi(row[2])) : 1;
e.lastused = row[3] ? row[3] : std::time(nullptr);
e.lastused = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -290,7 +290,7 @@ public:
e.accid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.ip = row[1] ? row[1] : "";
e.count = row[2] ? static_cast<int32_t>(atoi(row[2])) : 1;
e.lastused = row[3] ? row[3] : std::time(nullptr);
e.lastused = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -368,7 +368,7 @@ public:
v.push_back(std::to_string(e.accid));
v.push_back("'" + Strings::Escape(e.ip) + "'");
v.push_back(std::to_string(e.count));
v.push_back("'" + Strings::Escape(e.lastused) + "'");
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -394,7 +394,7 @@ public:
v.push_back(std::to_string(e.accid));
v.push_back("'" + Strings::Escape(e.ip) + "'");
v.push_back(std::to_string(e.count));
v.push_back("'" + Strings::Escape(e.lastused) + "'");
v.push_back("FROM_UNIXTIME(" + (e.lastused > 0 ? std::to_string(e.lastused) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -19,34 +19,37 @@
class BaseGroupIdRepository {
public:
struct GroupId {
int32_t groupid;
int32_t charid;
uint32_t group_id;
std::string name;
int8_t ismerc;
uint32_t character_id;
uint32_t bot_id;
uint32_t merc_id;
};
static std::string PrimaryKey()
{
return std::string("groupid");
return std::string("group_id");
}
static std::vector<std::string> Columns()
{
return {
"groupid",
"charid",
"group_id",
"name",
"ismerc",
"character_id",
"bot_id",
"merc_id",
};
}
static std::vector<std::string> SelectColumns()
{
return {
"groupid",
"charid",
"group_id",
"name",
"ismerc",
"character_id",
"bot_id",
"merc_id",
};
}
@@ -87,10 +90,11 @@ public:
{
GroupId e{};
e.groupid = 0;
e.charid = 0;
e.name = "";
e.ismerc = 0;
e.group_id = 0;
e.name = "";
e.character_id = 0;
e.bot_id = 0;
e.merc_id = 0;
return e;
}
@@ -101,7 +105,7 @@ public:
)
{
for (auto &group_id : group_ids) {
if (group_id.groupid == group_id_id) {
if (group_id.group_id == group_id_id) {
return group_id;
}
}
@@ -127,10 +131,11 @@ public:
if (results.RowCount() == 1) {
GroupId e{};
e.groupid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.charid = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.name = row[2] ? row[2] : "";
e.ismerc = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
e.group_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.name = row[1] ? row[1] : "";
e.character_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.bot_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.merc_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
return e;
}
@@ -164,10 +169,11 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.groupid));
v.push_back(columns[1] + " = " + std::to_string(e.charid));
v.push_back(columns[2] + " = '" + Strings::Escape(e.name) + "'");
v.push_back(columns[3] + " = " + std::to_string(e.ismerc));
v.push_back(columns[0] + " = " + std::to_string(e.group_id));
v.push_back(columns[1] + " = '" + Strings::Escape(e.name) + "'");
v.push_back(columns[2] + " = " + std::to_string(e.character_id));
v.push_back(columns[3] + " = " + std::to_string(e.bot_id));
v.push_back(columns[4] + " = " + std::to_string(e.merc_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -175,7 +181,7 @@ public:
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.groupid
e.group_id
)
);
@@ -189,10 +195,11 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.groupid));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.group_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back(std::to_string(e.ismerc));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.merc_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -203,7 +210,7 @@ public:
);
if (results.Success()) {
e.groupid = results.LastInsertedID();
e.group_id = results.LastInsertedID();
return e;
}
@@ -222,10 +229,11 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.groupid));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.group_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back(std::to_string(e.ismerc));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.merc_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -259,10 +267,11 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
GroupId e{};
e.groupid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.charid = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.name = row[2] ? row[2] : "";
e.ismerc = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
e.group_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.name = row[1] ? row[1] : "";
e.character_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.bot_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.merc_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -287,10 +296,11 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
GroupId e{};
e.groupid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.charid = row[1] ? static_cast<int32_t>(atoi(row[1])) : 0;
e.name = row[2] ? row[2] : "";
e.ismerc = row[3] ? static_cast<int8_t>(atoi(row[3])) : 0;
e.group_id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.name = row[1] ? row[1] : "";
e.character_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
e.bot_id = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.merc_id = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -365,10 +375,11 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.groupid));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.group_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back(std::to_string(e.ismerc));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.merc_id));
auto results = db.QueryDatabase(
fmt::format(
@@ -391,10 +402,11 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.groupid));
v.push_back(std::to_string(e.charid));
v.push_back(std::to_string(e.group_id));
v.push_back("'" + Strings::Escape(e.name) + "'");
v.push_back(std::to_string(e.ismerc));
v.push_back(std::to_string(e.character_id));
v.push_back(std::to_string(e.bot_id));
v.push_back(std::to_string(e.merc_id));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -105,7 +105,7 @@ public:
e.gid = 0;
e.leadername = "";
e.marknpc = "";
e.leadershipaa = 0;
e.leadershipaa = "";
e.maintank = "";
e.assist = "";
e.puller = "";
@@ -150,7 +150,7 @@ public:
e.gid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.leadername = row[1] ? row[1] : "";
e.marknpc = row[2] ? row[2] : "";
e.leadershipaa = row[3] ? row[3] : 0;
e.leadershipaa = row[3] ? row[3] : "";
e.maintank = row[4] ? row[4] : "";
e.assist = row[5] ? row[5] : "";
e.puller = row[6] ? row[6] : "";
@@ -302,7 +302,7 @@ public:
e.gid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.leadername = row[1] ? row[1] : "";
e.marknpc = row[2] ? row[2] : "";
e.leadershipaa = row[3] ? row[3] : 0;
e.leadershipaa = row[3] ? row[3] : "";
e.maintank = row[4] ? row[4] : "";
e.assist = row[5] ? row[5] : "";
e.puller = row[6] ? row[6] : "";
@@ -335,7 +335,7 @@ public:
e.gid = row[0] ? static_cast<int32_t>(atoi(row[0])) : 0;
e.leadername = row[1] ? row[1] : "";
e.marknpc = row[2] ? row[2] : "";
e.leadershipaa = row[3] ? row[3] : 0;
e.leadershipaa = row[3] ? row[3] : "";
e.maintank = row[4] ? row[4] : "";
e.assist = row[5] ? row[5] : "";
e.puller = row[6] ? row[6] : "";
@@ -19,8 +19,9 @@
class BaseSkillCapsRepository {
public:
struct SkillCaps {
uint8_t skillID;
uint8_t class_;
uint32_t id;
uint8_t skill_id;
uint8_t class_id;
uint8_t level;
uint32_t cap;
uint8_t class_;
@@ -28,14 +29,15 @@ public:
static std::string PrimaryKey()
{
return std::string("skillID");
return std::string("id");
}
static std::vector<std::string> Columns()
{
return {
"skillID",
"`class`",
"id",
"skill_id",
"class_id",
"level",
"cap",
"class_",
@@ -45,8 +47,9 @@ public:
static std::vector<std::string> SelectColumns()
{
return {
"skillID",
"`class`",
"id",
"skill_id",
"class_id",
"level",
"cap",
"class_",
@@ -90,11 +93,12 @@ public:
{
SkillCaps e{};
e.skillID = 0;
e.class_ = 0;
e.level = 0;
e.cap = 0;
e.class_ = 0;
e.id = 0;
e.skill_id = 0;
e.class_id = 0;
e.level = 0;
e.cap = 0;
e.class_ = 0;
return e;
}
@@ -105,7 +109,7 @@ public:
)
{
for (auto &skill_caps : skill_capss) {
if (skill_caps.skillID == skill_caps_id) {
if (skill_caps.id == skill_caps_id) {
return skill_caps;
}
}
@@ -131,11 +135,12 @@ public:
if (results.RowCount() == 1) {
SkillCaps e{};
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
return e;
}
@@ -169,11 +174,11 @@ public:
auto columns = Columns();
v.push_back(columns[0] + " = " + std::to_string(e.skillID));
v.push_back(columns[1] + " = " + std::to_string(e.class_));
v.push_back(columns[2] + " = " + std::to_string(e.level));
v.push_back(columns[3] + " = " + std::to_string(e.cap));
v.push_back(columns[4] + " = " + std::to_string(e.class_));
v.push_back(columns[1] + " = " + std::to_string(e.skill_id));
v.push_back(columns[2] + " = " + std::to_string(e.class_id));
v.push_back(columns[3] + " = " + std::to_string(e.level));
v.push_back(columns[4] + " = " + std::to_string(e.cap));
v.push_back(columns[5] + " = " + std::to_string(e.class_));
auto results = db.QueryDatabase(
fmt::format(
@@ -181,7 +186,7 @@ public:
TableName(),
Strings::Implode(", ", v),
PrimaryKey(),
e.skillID
e.id
)
);
@@ -195,8 +200,9 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.skillID));
v.push_back(std::to_string(e.class_));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.skill_id));
v.push_back(std::to_string(e.class_id));
v.push_back(std::to_string(e.level));
v.push_back(std::to_string(e.cap));
v.push_back(std::to_string(e.class_));
@@ -210,7 +216,7 @@ public:
);
if (results.Success()) {
e.skillID = results.LastInsertedID();
e.id = results.LastInsertedID();
return e;
}
@@ -229,8 +235,9 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.skillID));
v.push_back(std::to_string(e.class_));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.skill_id));
v.push_back(std::to_string(e.class_id));
v.push_back(std::to_string(e.level));
v.push_back(std::to_string(e.cap));
v.push_back(std::to_string(e.class_));
@@ -267,11 +274,12 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
SkillCaps e{};
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -296,11 +304,12 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
SkillCaps e{};
e.skillID = row[0] ? static_cast<uint8_t>(strtoul(row[0], nullptr, 10)) : 0;
e.class_ = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
e.level = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.cap = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
e.class_ = row[4] ? static_cast<uint8_t>(strtoul(row[4], nullptr, 10)) : 0;
e.id = row[0] ? static_cast<uint32_t>(strtoul(row[0], nullptr, 10)) : 0;
e.skill_id = row[1] ? static_cast<uint8_t>(strtoul(row[1], nullptr, 10)) : 0;
e.class_id = row[2] ? static_cast<uint8_t>(strtoul(row[2], nullptr, 10)) : 0;
e.level = row[3] ? static_cast<uint8_t>(strtoul(row[3], nullptr, 10)) : 0;
e.cap = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
e.class_ = row[5] ? static_cast<uint8_t>(strtoul(row[5], nullptr, 10)) : 0;
all_entries.push_back(e);
}
@@ -375,8 +384,9 @@ public:
{
std::vector<std::string> v;
v.push_back(std::to_string(e.skillID));
v.push_back(std::to_string(e.class_));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.skill_id));
v.push_back(std::to_string(e.class_id));
v.push_back(std::to_string(e.level));
v.push_back(std::to_string(e.cap));
v.push_back(std::to_string(e.class_));
@@ -402,8 +412,9 @@ public:
for (auto &e: entries) {
std::vector<std::string> v;
v.push_back(std::to_string(e.skillID));
v.push_back(std::to_string(e.class_));
v.push_back(std::to_string(e.id));
v.push_back(std::to_string(e.skill_id));
v.push_back(std::to_string(e.class_id));
v.push_back(std::to_string(e.level));
v.push_back(std::to_string(e.cap));
v.push_back(std::to_string(e.class_));
@@ -23,7 +23,7 @@ public:
std::string varname;
std::string value;
std::string information;
std::string ts;
time_t ts;
};
static std::string PrimaryKey()
@@ -49,7 +49,7 @@ public:
"varname",
"value",
"information",
"ts",
"UNIX_TIMESTAMP(ts)",
};
}
@@ -135,7 +135,7 @@ public:
e.varname = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.information = row[3] ? row[3] : "";
e.ts = row[4] ? row[4] : std::time(nullptr);
e.ts = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
return e;
}
@@ -172,7 +172,7 @@ public:
v.push_back(columns[1] + " = '" + Strings::Escape(e.varname) + "'");
v.push_back(columns[2] + " = '" + Strings::Escape(e.value) + "'");
v.push_back(columns[3] + " = '" + Strings::Escape(e.information) + "'");
v.push_back(columns[4] + " = '" + Strings::Escape(e.ts) + "'");
v.push_back(columns[4] + " = FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -198,7 +198,7 @@ public:
v.push_back("'" + Strings::Escape(e.varname) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back("'" + Strings::Escape(e.information) + "'");
v.push_back("'" + Strings::Escape(e.ts) + "'");
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -232,7 +232,7 @@ public:
v.push_back("'" + Strings::Escape(e.varname) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back("'" + Strings::Escape(e.information) + "'");
v.push_back("'" + Strings::Escape(e.ts) + "'");
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
@@ -270,7 +270,7 @@ public:
e.varname = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.information = row[3] ? row[3] : "";
e.ts = row[4] ? row[4] : std::time(nullptr);
e.ts = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -299,7 +299,7 @@ public:
e.varname = row[1] ? row[1] : "";
e.value = row[2] ? row[2] : "";
e.information = row[3] ? row[3] : "";
e.ts = row[4] ? row[4] : std::time(nullptr);
e.ts = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
all_entries.push_back(e);
}
@@ -378,7 +378,7 @@ public:
v.push_back("'" + Strings::Escape(e.varname) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back("'" + Strings::Escape(e.information) + "'");
v.push_back("'" + Strings::Escape(e.ts) + "'");
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
auto results = db.QueryDatabase(
fmt::format(
@@ -405,7 +405,7 @@ public:
v.push_back("'" + Strings::Escape(e.varname) + "'");
v.push_back("'" + Strings::Escape(e.value) + "'");
v.push_back("'" + Strings::Escape(e.information) + "'");
v.push_back("'" + Strings::Escape(e.ts) + "'");
v.push_back("FROM_UNIXTIME(" + (e.ts > 0 ? std::to_string(e.ts) : "null") + ")");
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
}
+9 -1
View File
@@ -44,7 +44,15 @@ public:
*/
// Custom extended repository methods here
static void ClearAllGroups(Database& db)
{
db.QueryDatabase(
fmt::format(
"DELETE FROM `{}`",
TableName()
)
);
}
};
#endif //EQEMU_GROUP_ID_REPOSITORY_H
@@ -44,7 +44,15 @@ public:
*/
// Custom extended repository methods here
static void ClearAllGroupLeaders(Database& db)
{
db.QueryDatabase(
fmt::format(
"DELETE FROM `{}`",
TableName()
)
);
}
};
#endif //EQEMU_GROUP_LEADERS_REPOSITORY_H
@@ -191,4 +191,5 @@ public:
return UpdateOne(db, m);
}
};
#endif //EQEMU_GUILD_MEMBERS_REPOSITORY_H
@@ -44,7 +44,30 @@ public:
*/
// Custom extended repository methods here
static int64 CountInventorySnapshots(Database& db)
{
const std::string& query = "SELECT COUNT(*) FROM (SELECT * FROM `inventory_snapshots` a GROUP BY `charid`, `time_index`) b";
auto results = db.QueryDatabase(query);
if (!results.Success() || !results.RowCount()) {
return -1;
}
auto row = results.begin();
const int64 count = Strings::ToBigInt(row[0]);
if (count > std::numeric_limits<int>::max()) {
return -2;
}
if (count < 0) {
return -3;
}
return count;
}
};
#endif //EQEMU_INVENTORY_SNAPSHOTS_REPOSITORY_H
@@ -66,6 +66,16 @@ public:
return results.Success() ? results.RowsAffected() : 0;
}
static void ClearAllRaidDetails(Database& db)
{
db.QueryDatabase(
fmt::format(
"DELETE FROM `{}`",
TableName()
)
);
}
};
#endif //EQEMU_RAID_DETAILS_REPOSITORY_H
@@ -1,297 +0,0 @@
#ifndef EQEMU_RAID_LEADERS_REPOSITORY_H
#define EQEMU_RAID_LEADERS_REPOSITORY_H
#include "../database.h"
#include "../strings.h"
class RaidLeadersRepository {
public:
struct RaidLeaders {
int gid;
int rid;
std::string marknpc;
std::string maintank;
std::string assist;
std::string puller;
std::string leadershipaa;
std::string mentoree;
int mentor_percent;
};
static std::string PrimaryKey()
{
return std::string("");
}
static std::vector<std::string> Columns()
{
return {
"gid",
"rid",
"marknpc",
"maintank",
"assist",
"puller",
"leadershipaa",
"mentoree",
"mentor_percent",
};
}
static std::string ColumnsRaw()
{
return std::string(Strings::Implode(", ", Columns()));
}
static std::string InsertColumnsRaw()
{
std::vector<std::string> insert_columns;
for (auto &column : Columns()) {
if (column == PrimaryKey()) {
continue;
}
insert_columns.push_back(column);
}
return std::string(Strings::Implode(", ", insert_columns));
}
static std::string TableName()
{
return std::string("raid_leaders");
}
static std::string BaseSelect()
{
return fmt::format(
"SELECT {} FROM {}",
ColumnsRaw(),
TableName()
);
}
static std::string BaseInsert()
{
return fmt::format(
"INSERT INTO {} ({}) ",
TableName(),
InsertColumnsRaw()
);
}
static RaidLeaders NewEntity()
{
RaidLeaders entry{};
entry.gid = 0;
entry.rid = 0;
entry.marknpc = "";
entry.maintank = "";
entry.assist = "";
entry.puller = "";
entry.leadershipaa = 0;
entry.mentoree = "";
entry.mentor_percent = 0;
return entry;
}
static RaidLeaders GetRaidLeadersEntry(
const std::vector<RaidLeaders> &raid_leaderss,
int raid_leaders_id
)
{
for (auto &raid_leaders : raid_leaderss) {
if (raid_leaders. == raid_leaders_id) {
return raid_leaders;
}
}
return NewEntity();
}
static RaidLeaders FindOne(
int raid_leaders_id
)
{
auto results = database.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
BaseSelect(),
raid_leaders_id
)
);
auto row = results.begin();
if (results.RowCount() == 1) {
RaidLeaders entry{};
entry.gid = atoi(row[0]);
entry.rid = atoi(row[1]);
entry.marknpc = row[2];
entry.maintank = row[3];
entry.assist = row[4];
entry.puller = row[5];
entry.leadershipaa = row[6];
entry.mentoree = row[7];
entry.mentor_percent = atoi(row[8]);
return entry;
}
return NewEntity();
}
static int DeleteOne(
int raid_leaders_id
)
{
auto results = database.QueryDatabase(
fmt::format(
"DELETE FROM {} WHERE {} = {}",
TableName(),
PrimaryKey(),
raid_leaders_id
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static int UpdateOne(
RaidLeaders raid_leaders_entry
)
{
std::vector<std::string> update_values;
auto columns = Columns();
update_values.push_back(columns[0] + " = " + std::to_string(raid_leaders_entry.gid));
update_values.push_back(columns[1] + " = " + std::to_string(raid_leaders_entry.rid));
update_values.push_back(columns[2] + " = '" + Strings::Escape(raid_leaders_entry.marknpc) + "'");
update_values.push_back(columns[3] + " = '" + Strings::Escape(raid_leaders_entry.maintank) + "'");
update_values.push_back(columns[4] + " = '" + Strings::Escape(raid_leaders_entry.assist) + "'");
update_values.push_back(columns[5] + " = '" + Strings::Escape(raid_leaders_entry.puller) + "'");
update_values.push_back(columns[6] + " = '" + Strings::Escape(raid_leaders_entry.leadershipaa) + "'");
update_values.push_back(columns[7] + " = '" + Strings::Escape(raid_leaders_entry.mentoree) + "'");
update_values.push_back(columns[8] + " = " + std::to_string(raid_leaders_entry.mentor_percent));
auto results = database.QueryDatabase(
fmt::format(
"UPDATE {} SET {} WHERE {} = {}",
TableName(),
Strings::Implode(", ", update_values),
PrimaryKey(),
raid_leaders_entry.
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static RaidLeaders InsertOne(
RaidLeaders raid_leaders_entry
)
{
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(raid_leaders_entry.gid));
insert_values.push_back(std::to_string(raid_leaders_entry.rid));
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.marknpc) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.maintank) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.assist) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.puller) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.leadershipaa) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.mentoree) + "'");
insert_values.push_back(std::to_string(raid_leaders_entry.mentor_percent));
auto results = database.QueryDatabase(
fmt::format(
"{} VALUES ({})",
BaseInsert(),
Strings::Implode(",", insert_values)
)
);
if (results.Success()) {
raid_leaders_entry.id = results.LastInsertedID();
return raid_leaders_entry;
}
raid_leaders_entry = InstanceListRepository::NewEntity();
return raid_leaders_entry;
}
static int InsertMany(
std::vector<RaidLeaders> raid_leaders_entries
)
{
std::vector<std::string> insert_chunks;
for (auto &raid_leaders_entry: raid_leaders_entries) {
std::vector<std::string> insert_values;
insert_values.push_back(std::to_string(raid_leaders_entry.gid));
insert_values.push_back(std::to_string(raid_leaders_entry.rid));
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.marknpc) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.maintank) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.assist) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.puller) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.leadershipaa) + "'");
insert_values.push_back("'" + Strings::Escape(raid_leaders_entry.mentoree) + "'");
insert_values.push_back(std::to_string(raid_leaders_entry.mentor_percent));
insert_chunks.push_back("(" + Strings::Implode(",", insert_values) + ")");
}
std::vector<std::string> insert_values;
auto results = database.QueryDatabase(
fmt::format(
"{} VALUES {}",
BaseInsert(),
Strings::Implode(",", insert_chunks)
)
);
return (results.Success() ? results.RowsAffected() : 0);
}
static std::vector<RaidLeaders> All()
{
std::vector<RaidLeaders> all_entries;
auto results = database.QueryDatabase(
fmt::format(
"{}",
BaseSelect()
)
);
all_entries.reserve(results.RowCount());
for (auto row = results.begin(); row != results.end(); ++row) {
RaidLeaders entry{};
entry.gid = atoi(row[0]);
entry.rid = atoi(row[1]);
entry.marknpc = row[2];
entry.maintank = row[3];
entry.assist = row[4];
entry.puller = row[5];
entry.leadershipaa = row[6];
entry.mentoree = row[7];
entry.mentor_percent = atoi(row[8]);
all_entries.push_back(entry);
}
return all_entries;
}
};
#endif //EQEMU_RAID_LEADERS_REPOSITORY_H
+11 -1
View File
@@ -60,7 +60,7 @@ public:
);
return results.Success() ? results.RowsAffected() : 0;
}
static int UpdateRaidAssister(
Database& db,
int32_t raid_id,
@@ -98,5 +98,15 @@ public:
return results.Success() ? results.RowsAffected() : 0;
}
static void ClearAllRaids(Database& db)
{
db.QueryDatabase(
fmt::format(
"DELETE FROM `{}`",
TableName()
)
);
}
};
#endif //EQEMU_RAID_MEMBERS_REPOSITORY_H
+3 -1
View File
@@ -355,6 +355,7 @@ RULE_INT(Zone, GlobalLootMultiplier, 1, "Sets Global Loot drop multiplier for da
RULE_BOOL(Zone, KillProcessOnDynamicShutdown, true, "When process has booted a zone and has hit its zone shut down timer, it will hard kill the process to free memory back to the OS")
RULE_INT(Zone, SpawnEventMin, 3, "When strict is set in spawn_events, specifies the max EQ minutes into the trigger hour a spawn_event will fire. Going below 3 may cause the spawn_event to not fire.")
RULE_INT(Zone, ForageChance, 25, "Chance of foraging from zone table vs global table")
RULE_INT(Zone, FishingChance, 399, "Chance of fishing from zone table vs global table")
RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross zone spells (cast/remove) to affect bots")
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
@@ -450,7 +451,8 @@ RULE_BOOL(Spells, Jun182014HundredHandsRevamp, false, "This should be true for i
RULE_BOOL(Spells, SwarmPetTargetLock, false, "Use old method of swarm pets target locking till target dies then despawning")
RULE_BOOL(Spells, NPC_UseFocusFromSpells, true, "Allow NPC to use most spell derived focus effects")
RULE_BOOL(Spells, NPC_UseFocusFromItems, false, "Allow NPC to use most item derived focus effects")
RULE_BOOL(Spells, UseAdditiveFocusFromWornSlot, false, "Allows an additive focus effect to be calculated from worn slot")
RULE_BOOL(Spells, UseAdditiveFocusFromWornSlot, false, "Allows an additive focus effect to be calculated from worn slot. Does not apply limits checks. Can only have one additive focus rule be true.")
RULE_BOOL(Spells, UseAdditiveFocusFromWornSlotWithLimits, false, "Allows an additive focus effect to be calculated from worn slot. Applies normal limit checks. Can only have one additive focus rule be true.")
RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false, "Ignore Leadership Alternate Abilities level if true")
RULE_BOOL(Spells, FlatItemExtraSpellAmt, false, "Allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc")
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false, "Ignore the 5 level spread on applying SpellDmg")
+1
View File
@@ -273,6 +273,7 @@
#define ServerOP_ReloadFactions 0x4126
#define ServerOP_ReloadLoot 0x4127
#define ServerOP_ReloadBaseData 0x4128
#define ServerOP_ReloadSkillCaps 0x4129
#define ServerOP_CZDialogueWindow 0x4500
#define ServerOP_CZLDoNUpdate 0x4501
+1 -1
View File
@@ -60,7 +60,7 @@ SharedTaskRequest SharedTask::GetRequestCharacters(Database &db, uint32_t reques
request.group_type = SharedTaskRequestGroupType::Group;
auto characters = CharacterDataRepository::GetWhere(
db, fmt::format(
"id IN (select charid from group_id where groupid = (select groupid from group_id where charid = {}))",
"id IN (select character_id from group_id where group_id = (select group_id from group_id where character_id = {}))",
requested_character_id
)
);
+4 -134
View File
@@ -45,6 +45,7 @@
#include "repositories/loottable_repository.h"
#include "repositories/character_item_recast_repository.h"
#include "repositories/character_corpses_repository.h"
#include "repositories/skill_caps_repository.h"
namespace ItemField
{
@@ -793,8 +794,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQ::InventoryProfile *inv)
}
if (cv_conflict) {
char char_name[64] = "";
GetCharName(char_id, char_name);
const std::string& char_name = GetCharName(char_id);
LogError("ClientVersion/Expansion conflict during inventory load at zone entry for [{}] (charid: [{}], inver: [{}], gmi: [{}])",
char_name,
char_id,
@@ -1626,136 +1626,6 @@ bool SharedDatabase::GetCommandSubSettings(std::vector<CommandSubsettingsReposit
return true;
}
bool SharedDatabase::LoadSkillCaps(const std::string &prefix) {
skill_caps_mmf.reset(nullptr);
try {
const auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("skill_caps");
mutex.Lock();
std::string file_name = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("skill_caps"));
LogInfo("Loading [{}]", file_name);
skill_caps_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name);
LogInfo("Loaded skill caps via shared memory");
mutex.Unlock();
} catch(std::exception &ex) {
LogError("Error loading skill caps: {}", ex.what());
return false;
}
return true;
}
void SharedDatabase::LoadSkillCaps(void *data) {
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
const uint32 level_count = HARD_LEVEL_CAP + 1;
uint16 *skill_caps_table = static_cast<uint16*>(data);
const std::string query = "SELECT skillID, class, level, cap FROM skill_caps ORDER BY skillID, class, level";
auto results = QueryDatabase(query);
if (!results.Success()) {
LogError("Error loading skill caps from database: {}", results.ErrorMessage().c_str());
return;
}
for(auto& row = results.begin(); row != results.end(); ++row) {
const uint8 skillID = Strings::ToUnsignedInt(row[0]);
const uint8 class_ = Strings::ToUnsignedInt(row[1]) - 1;
const uint8 level = Strings::ToUnsignedInt(row[2]);
const uint16 cap = Strings::ToUnsignedInt(row[3]);
if(skillID >= skill_count || class_ >= class_count || level >= level_count)
continue;
const uint32 index = (((class_ * skill_count) + skillID) * level_count) + level;
skill_caps_table[index] = cap;
}
}
uint16 SharedDatabase::GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const
{
if(!skill_caps_mmf) {
return 0;
}
if(Class_ == 0)
return 0;
int SkillMaxLevel = RuleI(Character, SkillCapMaxLevel);
if(SkillMaxLevel < 1) {
SkillMaxLevel = RuleI(Character, MaxLevel);
}
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
const uint32 level_count = HARD_LEVEL_CAP + 1;
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
return 0;
}
if(Level > static_cast<uint8>(SkillMaxLevel)){
Level = static_cast<uint8>(SkillMaxLevel);
}
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count) + Level;
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
return skill_caps_table[index];
}
uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const
{
if(!skill_caps_mmf) {
return 0;
}
if(Class_ == 0)
return 0;
int SkillMaxLevel = RuleI(Character, SkillCapMaxLevel);
if (SkillMaxLevel < 1) {
SkillMaxLevel = RuleI(Character, MaxLevel);
}
const uint32 class_count = Class::PLAYER_CLASS_COUNT;
const uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
const uint32 level_count = HARD_LEVEL_CAP + 1;
if(Class_ > class_count || static_cast<uint32>(Skill) > skill_count || Level > level_count) {
return 0;
}
uint8 ret = 0;
if(Level > static_cast<uint8>(SkillMaxLevel)) {
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count);
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
for(uint8 x = 0; x < Level; x++){
if(skill_caps_table[index + x]){
ret = x;
break;
}
}
}
else
{
const uint32 index = ((((Class_ - 1) * skill_count) + Skill) * level_count);
const uint16 *skill_caps_table = static_cast<uint16*>(skill_caps_mmf->Get());
for(int x = 0; x < SkillMaxLevel; x++){
if(skill_caps_table[index + x]){
ret = x;
break;
}
}
}
if(ret > GetSkillCap(Class_, Skill, Level))
ret = static_cast<uint8>(GetSkillCap(Class_, Skill, Level));
return ret;
}
void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID) {
const std::string query = StringFormat("SELECT `spellid`, `type` FROM `damageshieldtypes` WHERE `spellid` > 0 "
"AND `spellid` <= %i", iMaxSpellID);
@@ -1984,9 +1854,9 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].min_range = Strings::ToFloat(row[231]);
sp[tempid].no_remove = Strings::ToBool(row[232]);
sp[tempid].damage_shield_type = 0;
}
}
LoadDamageShieldTypes(sp, max_spells);
LoadDamageShieldTypes(sp, max_spells);
}
void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message) {
-8
View File
@@ -160,14 +160,6 @@ public:
uint32 GetSharedItemsCount() { return m_shared_items_count; }
uint32 GetItemsCount();
/**
* skills
*/
void LoadSkillCaps(void *data);
bool LoadSkillCaps(const std::string &prefix);
uint16 GetSkillCap(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const;
uint8 GetTrainLevel(uint8 Class_, EQ::skills::SkillType Skill, uint8 Level) const;
/**
* spells
*/
+91
View File
@@ -0,0 +1,91 @@
#include "skill_caps.h"
SkillCaps *SkillCaps::SetContentDatabase(Database *db)
{
m_content_database = db;
return this;
}
SkillCapsRepository::SkillCaps SkillCaps::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
{
if (!IsPlayerClass(class_id)) {
return SkillCapsRepository::NewEntity();
}
for (const auto &e: m_skill_caps) {
if (
e.class_id == class_id &&
e.level == level &&
static_cast<EQ::skills::SkillType>(e.skill_id) == skill_id
) {
return e;
}
}
return SkillCapsRepository::NewEntity();
}
uint8 SkillCaps::GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
{
if (
!IsPlayerClass(class_id) ||
class_id > Class::PLAYER_CLASS_COUNT ||
static_cast<uint32>(skill_id) > (EQ::skills::HIGHEST_SKILL + 1)
) {
return 0;
}
const uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
for (const auto &e: m_skill_caps) {
for (uint8 current_level = 1; current_level <= max_level; current_level++) {
if (
e.class_id == class_id &&
static_cast<EQ::skills::SkillType>(e.skill_id) == skill_id &&
e.level == current_level
) {
return current_level;
}
}
}
return 0;
}
void SkillCaps::LoadSkillCaps()
{
const auto &l = SkillCapsRepository::All(*m_content_database);
m_skill_caps.reserve(l.size());
for (const auto &e: l) {
if (
e.level < 1 ||
!IsPlayerClass(e.class_id) ||
static_cast<EQ::skills::SkillType>(e.skill_id) >= EQ::skills::SkillCount
) {
continue;
}
m_skill_caps.emplace_back(e);
}
LogInfo(
"Loaded [{}] Skill Cap Entr{}",
l.size(),
l.size() != 1 ? "ies" : "y"
);
}
void SkillCaps::ReloadSkillCaps()
{
ClearSkillCaps();
LoadSkillCaps();
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef CODE_SKILL_CAPS_H
#define CODE_SKILL_CAPS_H
#include "repositories/skill_caps_repository.h"
#include "types.h"
#include "classes.h"
#include "skills.h"
class SkillCaps {
public:
inline void ClearSkillCaps() { m_skill_caps.clear(); }
SkillCapsRepository::SkillCaps GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
uint8 GetTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
void LoadSkillCaps();
void ReloadSkillCaps();
SkillCaps *SetContentDatabase(Database *db);
private:
Database *m_content_database{};
std::vector<SkillCapsRepository::SkillCaps> m_skill_caps = {};
};
extern SkillCaps skill_caps;
#endif //CODE_SKILL_CAPS_H
+1 -1
View File
@@ -18,10 +18,10 @@
*/
#include "skills.h"
#include "classes.h"
#include <string.h>
bool EQ::skills::IsTradeskill(SkillType skill)
{
switch (skill) {
-1
View File
@@ -26,7 +26,6 @@
#include <map>
#include <vector>
namespace EQ
{
namespace skills {
+1 -1
View File
@@ -1257,7 +1257,7 @@ typedef enum {
#define SE_Ff_Override_NotFocusable 460 // implemented, @Fc, Allow spell to be focused event if flagged with 'not_focusable' in spell table, base: 1
#define SE_ImprovedDamage2 461 // implemented, @Fc, On Caster, spell damage mod pct, base: min pct, limit: max pct
#define SE_FcDamageAmt2 462 // implemented, @Fc, On Caster, spell damage mod flat amt, base: amt
//#define SE_Shield_Target 463 //
#define SE_Shield_Target 463 // implemented, Base1 % damage shielded on target
#define SE_PC_Pet_Rampage 464 // implemented - Base1 % chance to do rampage for base2 % of damage each melee round
#define SE_PC_Pet_AE_Rampage 465 // implemented - Base1 % chance to do AE rampage for base2 % of damage each melee round
#define SE_PC_Pet_Flurry_Chance 466 // implemented - Base1 % chance to do flurry from double attack hit.
+1 -1
View File
@@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9266
#define CURRENT_BINARY_DATABASE_VERSION 9268
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9043
#endif
+28
View File
@@ -0,0 +1,28 @@
# Description
Please include a summary of the changes and the related issue (Why is this change necessary). Please also include relevant motivation and context. List any dependencies that are required for this change.
Fixes # (issue)
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
# Testing
Attach images and describe testing done to validate functionality.
Clients tested:
# Checklist
- [ ] I have tested my changes
- [ ] I have performed a self-review of my code. Ensuring variables, functions and methods are named in a human-readable way, comments are added only where naming of variables, functions and methods can't give enough context.
- [ ] I have made corresponding changes to the documentation (if applicable, if not delete this line)
- [ ] I own the changes of my code and take responsibility for the potential issues that occur
- [ ] If my changes make database schema changes, I have tested the changes on a local database (attach image). Updated version.h CURRENT_BINARY_DATABASE_VERSION to the new version. (Delete this if not applicable)
-2
View File
@@ -4,13 +4,11 @@ SET(shared_memory_sources
items.cpp
main.cpp
spells.cpp
skill_caps.cpp
)
SET(shared_memory_headers
items.h
spells.h
skill_caps.h
)
ADD_EXECUTABLE(shared_memory ${shared_memory_sources} ${shared_memory_headers})
+1 -17
View File
@@ -28,7 +28,6 @@
#include "../common/eqemu_exception.h"
#include "../common/strings.h"
#include "items.h"
#include "skill_caps.h"
#include "spells.h"
#include "../common/content/world_content_service.h"
#include "../common/zone_store.h"
@@ -183,7 +182,6 @@ int main(int argc, char **argv)
bool load_all = true;
bool load_items = false;
bool load_loot = false;
bool load_skill_caps = false;
bool load_spells = false;
if (argc > 1) {
@@ -197,11 +195,7 @@ int main(int argc, char **argv)
break;
case 's':
if (strcasecmp("skill_caps", argv[i]) == 0) {
load_skill_caps = true;
load_all = false;
}
else if (strcasecmp("spells", argv[i]) == 0) {
if (strcasecmp("spells", argv[i]) == 0) {
load_spells = true;
load_all = false;
}
@@ -236,16 +230,6 @@ int main(int argc, char **argv)
}
}
if (load_all || load_skill_caps) {
LogInfo("Loading skill caps");
try {
LoadSkillCaps(&content_db, hotfix_name);
} catch (std::exception &ex) {
LogError("{}", ex.what());
return 1;
}
}
if (load_all || load_spells) {
LogInfo("Loading spells");
try {
-45
View File
@@ -1,45 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "skill_caps.h"
#include "../common/global_define.h"
#include "../common/shareddb.h"
#include "../common/ipc_mutex.h"
#include "../common/memory_mapped_file.h"
#include "../common/eqemu_exception.h"
#include "../common/classes.h"
#include "../common/features.h"
void LoadSkillCaps(SharedDatabase *database, const std::string &prefix) {
EQ::IPCMutex mutex("skill_caps");
mutex.Lock();
uint32 class_count = Class::PLAYER_CLASS_COUNT;
uint32 skill_count = EQ::skills::HIGHEST_SKILL + 1;
uint32 level_count = HARD_LEVEL_CAP + 1;
uint32 size = (class_count * skill_count * level_count * sizeof(uint16));
auto Config = EQEmuConfig::get();
std::string file_name = Config->SharedMemDir + prefix + std::string("skill_caps");
EQ::MemoryMappedFile mmf(file_name, size);
mmf.ZeroFile();
void *ptr = mmf.Get();
database->LoadSkillCaps(ptr);
mutex.Unlock();
}
-29
View File
@@ -1,29 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EQEMU_SHARED_MEMORY_SKILL_CAPS_H
#define __EQEMU_SHARED_MEMORY_SKILL_CAPS_H
#include <string>
#include "../common/eqemu_config.h"
class SharedDatabase;
void LoadSkillCaps(SharedDatabase *database, const std::string &prefix);
#endif
@@ -280,7 +280,7 @@ foreach my $table_to_generate (@tables) {
# column names (string)
$column_names_quoted .= sprintf("\t\t\t\"%s\",\n", format_column_name_for_mysql($column_name));
if ($data_type =~ /datetime/) {
if ($data_type =~ /datetime|timestamp/) {
$select_column_names_quoted .= sprintf("\t\t\t\"UNIX_TIMESTAMP(%s)\",\n", format_column_name_for_mysql($column_name));
}
else {
@@ -293,7 +293,7 @@ foreach my $table_to_generate (@tables) {
if ($data_type =~ /int|float|double|decimal/) {
$query_value = sprintf('" + std::to_string(e.%s));', $column_name_formatted);
}
elsif ($data_type =~ /datetime/) {
elsif ($data_type =~ /datetime|timestamp/) {
$query_value = sprintf('FROM_UNIXTIME(" + (e.%s > 0 ? std::to_string(e.%s) : "null") + ")");', $column_name_formatted, $column_name_formatted);
}
@@ -309,7 +309,7 @@ foreach my $table_to_generate (@tables) {
if ($data_type =~ /int|float|double|decimal/) {
$value = sprintf('std::to_string(e.%s)', $column_name_formatted);
}
elsif ($data_type =~ /datetime/) {
elsif ($data_type =~ /datetime|timestamp/) {
$value = sprintf('"FROM_UNIXTIME(" + (e.%s > 0 ? std::to_string(e.%s) : "null") + ")"', $column_name_formatted, $column_name_formatted);
}
@@ -332,7 +332,7 @@ foreach my $table_to_generate (@tables) {
$all_entries .= sprintf("\t\t\te.%-${longest_column_length}s = row[%s] ? strtoll(row[%s], nullptr, 10) : %s;\n", $column_name_formatted, $index, $index, $default_value);
$find_one_entries .= sprintf("\t\t\te.%-${longest_column_length}s = row[%s] ? strtoll(row[%s], nullptr, 10) : %s;\n", $column_name_formatted, $index, $index, $default_value);
}
elsif ($data_type =~ /datetime/) {
elsif ($data_type =~ /datetime|timestamp/) {
$all_entries .= sprintf("\t\t\te.%-${longest_column_length}s = strtoll(row[%s] ? row[%s] : \"-1\", nullptr, 10);\n", $column_name_formatted, $index, $index);
$find_one_entries .= sprintf("\t\t\te.%-${longest_column_length}s = strtoll(row[%s] ? row[%s] : \"-1\", nullptr, 10);\n", $column_name_formatted, $index, $index);
}
@@ -591,7 +591,7 @@ sub translate_mysql_data_type_to_c
elsif ($mysql_data_type =~ /double/) {
$struct_data_type = 'double';
}
elsif ($mysql_data_type =~ /datetime/) {
elsif ($mysql_data_type =~ /datetime|timestamp/) {
$struct_data_type = 'time_t';
}
+40 -12
View File
@@ -53,6 +53,9 @@
#include "../common/repositories/inventory_repository.h"
#include "../common/events/player_event_logs.h"
#include "../common/content/world_content_service.h"
#include "../common/repositories/group_id_repository.h"
#include "../common/repositories/character_data_repository.h"
#include "../common/skill_caps.h"
#include <iostream>
#include <iomanip>
@@ -190,9 +193,10 @@ bool Client::CanTradeFVNoDropItem()
void Client::SendEnterWorld(std::string name)
{
char char_name[64] = { 0 };
if (is_player_zoning && database.GetLiveChar(GetAccountID(), char_name)) {
if(database.GetAccountIDByChar(char_name) != GetAccountID()) {
std::string live_name {};
if (is_player_zoning) {
live_name = database.GetLiveChar(GetAccountID());
if(database.GetAccountIDByChar(live_name) != GetAccountID()) {
eqs->Close();
return;
} else {
@@ -200,8 +204,8 @@ void Client::SendEnterWorld(std::string name)
}
}
auto outapp = new EQApplicationPacket(OP_EnterWorld, strlen(char_name) + 1);
memcpy(outapp->pBuffer,char_name,strlen(char_name)+1);
auto outapp = new EQApplicationPacket(OP_EnterWorld, live_name.length() + 1);
memcpy(outapp->pBuffer, live_name.c_str(), live_name.length() + 1);
QueuePacket(outapp);
safe_delete(outapp);
}
@@ -764,9 +768,15 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
auto ew = (EnterWorld_Struct *) app->pBuffer;
strn0cpy(char_name, ew->name, sizeof(char_name));
uint32 temporary_account_id = 0;
charid = database.GetCharacterInfo(char_name, &temporary_account_id, &zone_id, &instance_id);
if (!charid) {
const auto& l = CharacterDataRepository::GetWhere(
database,
fmt::format(
"`name` = '{}' LIMIT 1",
Strings::Escape(char_name)
)
);
if (l.empty()) {
LogInfo("Could not get CharInfo for [{}]", char_name);
eqs->Close();
return true;
@@ -784,13 +794,24 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
instance_id = r.instance.id;
}
const auto& e = l.front();
// Make sure this account owns this character
if (temporary_account_id != account_id) {
LogInfo("Account [{}] does not own the character named [{}] from account [{}]", account_id, char_name, temporary_account_id);
if (e.account_id != account_id) {
LogInfo(
"Account [{}] does not own the character named [{}] from account [{}]",
account_id,
char_name,
e.account_id
);
eqs->Close();
return true;
}
charid = e.id;
zone_id = e.zone_id;
instance_id = e.zone_instance;
// This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above)
// (This is a literal translation of the original process..I don't see why it can't be changed to a single-target query over account iteration)
if (!is_player_zoning) {
@@ -881,7 +902,14 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
}
if(!is_player_zoning) {
database.SetGroupID(char_name, 0, charid);
GroupIdRepository::DeleteWhere(
database,
fmt::format(
"`character_id` = {} AND `name` = '{}'",
charid,
Strings::Escape(char_name)
)
);
database.SetLoginFlags(charid, false, false, 1);
} else {
auto group_id = database.GetGroupID(char_name);
@@ -2107,7 +2135,7 @@ void Client::SetClassStartingSkills(PlayerProfile_Struct *pp)
i == EQ::skills::SkillAlcoholTolerance || i == EQ::skills::SkillBindWound)
continue;
pp->skills[i] = content_db.GetSkillCap(pp->class_, (EQ::skills::SkillType)i, 1);
pp->skills[i] = skill_caps.GetSkillCap(pp->class_, (EQ::skills::SkillType)i, 1).cap;
}
}
+1 -1
View File
@@ -344,7 +344,7 @@ bool ClientListEntry::CheckAuth(uint32 loginserver_account_id, const char *key_p
paccountid = database.CreateAccount(
loginserver_account_name,
0,
std::string(),
default_account_status,
source_loginserver,
LSID()
+1 -2
View File
@@ -57,8 +57,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string &username, const
return ret;
}
char account_name[64];
database.GetAccountName(ret.account_id, account_name);
const std::string& account_name = database.GetAccountName(ret.account_id);
ret.account_name = account_name;
ret.status = database.CheckStatus(ret.account_id);
+1
View File
@@ -156,6 +156,7 @@ std::vector<Reload> reload_types = {
Reload{.command = "opcodes", .opcode = ServerOP_ReloadOpcodes, .desc = "Opcodes"},
Reload{.command = "perl_export", .opcode = ServerOP_ReloadPerlExportSettings, .desc = "Perl Event Export Settings"},
Reload{.command = "rules", .opcode = ServerOP_ReloadRules, .desc = "Rules"},
Reload{.command = "skill_caps", .opcode = ServerOP_ReloadSkillCaps, .desc = "Skill Caps"},
Reload{.command = "static", .opcode = ServerOP_ReloadStaticZoneData, .desc = "Static Zone Data"},
Reload{.command = "tasks", .opcode = ServerOP_ReloadTasks, .desc = "Tasks"},
Reload{.command = "titles", .opcode = ServerOP_ReloadTitles, .desc = "Titles"},
+4 -1
View File
@@ -86,8 +86,9 @@
#include "world_boot.h"
#include "../common/path_manager.h"
#include "../common/events/player_event_logs.h"
#include "../common/skill_caps.h"
SkillCaps skill_caps;
ZoneStore zone_store;
ClientList client_list;
GroupLFPList LFPGroupList;
@@ -193,6 +194,8 @@ int main(int argc, char **argv)
->SetExpansionContext()
->ReloadContentFlags();
skill_caps.SetContentDatabase(&content_db)->LoadSkillCaps();
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
server_connection = std::make_unique<EQ::Net::ServertalkServer>();
-4
View File
@@ -292,10 +292,6 @@ bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv)
LogError("Error: Could not load item data. But ignoring");
}
if (!content_db.LoadSkillCaps(std::string(hotfix_name))) {
LogError("Error: Could not load skill cap data. But ignoring");
}
guild_mgr.LoadGuilds();
guild_mgr.LoadTributes();
+6 -5
View File
@@ -49,6 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/patches/patches.h"
#include "../zone/data_bucket.h"
#include "../common/repositories/guild_tributes_repository.h"
#include "../common/skill_caps.h"
extern ClientList client_list;
extern GroupLFPList LFPGroupList;
@@ -1436,6 +1437,11 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_ReloadSkillCaps: {
zoneserver_list.SendPacket(pack);
skill_caps.ReloadSkillCaps();
break;
}
case ServerOP_ReloadRules: {
zoneserver_list.SendPacket(pack);
RuleManager::Instance()->LoadRules(&database, "default", true);
@@ -1496,11 +1502,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
LogInfo("Error: Could not load item data. But ignoring");
}
LogInfo("Loading skill caps");
if (!content_db.LoadSkillCaps(hotfix_name)) {
LogInfo("Error: Could not load skill cap data. But ignoring");
}
zoneserver_list.SendPacket(pack);
break;
}
+1 -3
View File
@@ -57,9 +57,7 @@ EQ::Net::WebsocketLoginStatus CheckLogin(
return ret;
}
char account_name[64];
database.GetAccountName(static_cast<uint32>(ret.account_id), account_name);
ret.account_name = account_name;
ret.account_name = database.GetAccountName(static_cast<uint32>(ret.account_id));
ret.logged_in = true;
ret.status = database.CheckStatus(ret.account_id);
return ret;
+97 -4
View File
@@ -2816,6 +2816,9 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.RemoveFromAutoXTargets(this);
// Here we create the corpse.
DeleteInvalidQuestLoot();
corpse = new Corpse(
this,
&m_loot_items,
@@ -3964,6 +3967,18 @@ bool Mob::CheckDoubleAttack()
}
void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks special) {
#ifdef LUA_EQEMU
int64 lua_ret = 0;
bool ignore_default = false;
lua_ret = LuaParser::Instance()->CommonDamage(this, attacker, damage, spell_id, static_cast<int>(skill_used), avoidable, buffslot, iBuffTic, static_cast<int>(special), ignore_default);
if (lua_ret != 0) {
damage = lua_ret;
}
if (ignore_default) {
//return lua_ret;
}
#endif
// This method is called with skill_used=ABJURE for Damage Shield damage.
bool FromDamageShield = (skill_used == EQ::skills::SkillAbjuration);
bool ignore_invul = false;
@@ -4691,6 +4706,19 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
void Mob::HealDamage(uint64 amount, Mob* caster, uint16 spell_id)
{
#ifdef LUA_EQEMU
uint64 lua_ret = 0;
bool ignore_default = false;
lua_ret = LuaParser::Instance()->HealDamage(this, caster, amount, spell_id, ignore_default);
if (lua_ret != 0) {
amount = lua_ret;
}
if (ignore_default) {
//return lua_ret;
}
#endif
int64 maxhp = GetMaxHP();
int64 curhp = GetHP();
uint64 acthealed = 0;
@@ -6285,9 +6313,24 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + defender->GetPositionalDmgTakenAmt(this);
if (defender->GetShielderID()) {
DoShieldDamageOnShielder(defender, hit.damage_done, hit.skill);
hit.damage_done -= hit.damage_done * defender->GetShieldTargetMitigation() / 100; //Default shielded takes 50 pct damage
if (defender->GetShielderID() || defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT]) {
bool use_shield_ability = true;
//If defender is being shielded by an ability AND has a shield spell effect buff use highest mitigation value.
if ((defender->GetShieldTargetMitigation() && defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT]) &&
(defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] >= defender->GetShieldTargetMitigation())){
bool use_shield_ability = false;
}
//use targeted /shield ability values
if (defender->GetShielderID() && use_shield_ability) {
DoShieldDamageOnShielder(defender, hit.damage_done, hit.skill);
hit.damage_done -= hit.damage_done * defender->GetShieldTargetMitigation() / 100; //Default shielded takes 50 pct damage
}
//use spell effect SPA 463 values
else if (defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT]){
DoShieldDamageOnShielderSpellEffect(defender, hit.damage_done, hit.skill);
hit.damage_done -= hit.damage_done * defender->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] / 100;
}
}
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
@@ -6330,7 +6373,57 @@ void Mob::DoShieldDamageOnShielder(Mob *shield_target, int64 hit_damage_done, EQ
hit_damage_done -= hit_damage_done * mitigation / 100;
shielder->Damage(this, hit_damage_done, SPELL_UNKNOWN, skillInUse, true, -1, false, m_specialattacks);
shielder->CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
}
void Mob::DoShieldDamageOnShielderSpellEffect(Mob* shield_target, int64 hit_damage_done, EQ::skills::SkillType skillInUse)
{
if (!shield_target) {
return;
}
/*
SPA 463 SE_SHIELD_TARGET
Live description: "Shields your target, taking a percentage of their damage".
Only example spell on live is an NPC who uses it during a raid event "Laurion's Song" expansion. SPA 54492 'Guardian Stance' Described as 100% Melee Shielding
Example of mechanic. Base value = 70. Caster puts buff on target. Each melee hit Buff Target takes 70% less damage, Buff Caster receives 30% of the melee damage.
Added mechanic to cause buff to fade if target or caster are seperated by a distance greater than the casting range of the spell. This allows similiar mechanics
to the /shield ability, without a range removal mechanic it would be too easy to abuse if put on a player spell. *can not confirm live does this currently
Can not be cast on self.
*/
if (shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT])
{
if (shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] >= 0)
{
Mob *shielder = entity_list.GetMob(shield_target->buffs[shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]].casterid);
if (!shielder) {
shield_target->BuffFadeBySlot(shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]);
return;
}
int shield_spell_id = shield_target->buffs[shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]].spellid;
if (!IsValidSpell(shield_spell_id)) {
return;
}
float max_range = spells[shield_spell_id].range;
if (spells[shield_spell_id].aoe_range > max_range) {
max_range = spells[shield_spell_id].aoe_range;
}
max_range += 5.0f; //small buffer in case casted at exactly max range.
if (shield_target->CalculateDistance(shielder->GetX(), shielder->GetY(), shielder->GetZ()) > max_range) {
shield_target->BuffFadeBySlot(shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT]);
return;
}
int mitigation = 100 - shield_target->spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT];
hit_damage_done -= hit_damage_done * mitigation / 100;
shielder->Damage(this, hit_damage_done, SPELL_UNKNOWN, skillInUse, true, -1, false, m_specialattacks);
}
}
}
void Mob::CommonBreakInvisibleFromCombat()
+24 -1
View File
@@ -2090,7 +2090,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
if (focus)
{
if (WornType){
if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) {
if (RuleB(Spells, UseAdditiveFocusFromWornSlotWithLimits)) {
new_bonus->FocusEffectsWornWithLimits[focus] = spells[spell_id].effect_id[i];
}
else if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) {
new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base_value[i];
}
}
@@ -3298,6 +3301,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break;
}
case SE_Shield_Target:
{
if (new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] < effect_value) {
new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] = effect_value;
new_bonus->ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] = buffslot;
}
break;
}
case SE_TriggerMeleeThreshold:
new_bonus->TriggerMeleeThreshold = true;
break;
@@ -4989,6 +5001,7 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
case SE_MaxHPChange:
if (negate_spellbonus) { spellbonuses.MaxHPChange = effect_value; }
if (negate_aabonus) { aabonuses.MaxHPChange = effect_value; }
if (negate_aabonus) { aabonuses.MaxHP = effect_value; }
if (negate_itembonus) { itembonuses.MaxHPChange = effect_value; }
break;
@@ -5916,6 +5929,7 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
if (negate_itembonus) { itembonuses.SkillProcSuccess[e] = effect_value; }
if (negate_aabonus) { aabonuses.SkillProcSuccess[e] = effect_value; }
}
break;
}
case SE_SkillProcAttempt: {
@@ -5925,6 +5939,15 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
if (negate_itembonus) { itembonuses.SkillProc[e] = effect_value; }
if (negate_aabonus) { aabonuses.SkillProc[e] = effect_value; }
}
break;
}
case SE_Shield_Target: {
if (negate_spellbonus) {
spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_MITIGATION_PERCENT] = effect_value;
spellbonuses.ShieldTargetSpa[SBIndex::SHIELD_TARGET_BUFFSLOT] = effect_value;
}
break;
}
}
}
+122 -107
View File
@@ -27,6 +27,7 @@
#include "../common/repositories/bot_starting_items_repository.h"
#include "../common/data_verification.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include "../common/skill_caps.h"
// This constructor is used during the bot create command
Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm::vec4(), Ground, false), rest_timer(1), ping_timer(1) {
@@ -1171,7 +1172,7 @@ uint16 Bot::GetPrimarySkillValue() {
}
uint16 Bot::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const {
return(content_db.GetSkillCap(class_, skillid, level));
return skill_caps.GetSkillCap(class_, skillid, level).cap;
}
uint32 Bot::GetTotalATK() {
@@ -2287,7 +2288,7 @@ bool Bot::TryMeditate() {
if (!IsMoving() && !spellend_timer.Enabled()) {
if (GetTarget() && AI_EngagedCastCheck()) {
BotMeditate(false);
} else if (GetArchetype() == ARCHETYPE_CASTER) {
} else if (GetArchetype() == Archetype::Caster) {
BotMeditate(true);
}
@@ -2755,7 +2756,7 @@ Mob* Bot::GetBotTarget(Client* bot_owner)
}
}
if (GetArchetype() == ARCHETYPE_CASTER) {
if (GetArchetype() == Archetype::Caster) {
BotMeditate(true);
}
}
@@ -3343,7 +3344,7 @@ void Bot::LoadAndSpawnAllZonedBots(Client* bot_owner) {
}
if (bot_spawn_limit >= 0 && spawned_bots_count >= bot_spawn_limit) {
database.SetGroupID(b->GetCleanName(), 0, b->GetBotID());
Group::RemoveFromGroup(b);
g->UpdatePlayer(bot_owner);
continue;
}
@@ -3355,7 +3356,7 @@ void Bot::LoadAndSpawnAllZonedBots(Client* bot_owner) {
bot_spawn_limit_class >= 0 &&
spawned_bot_count_class >= bot_spawn_limit_class
) {
database.SetGroupID(b->GetCleanName(), 0, b->GetBotID());
Group::RemoveFromGroup(b);
g->UpdatePlayer(bot_owner);
continue;
}
@@ -3375,7 +3376,7 @@ void Bot::LoadAndSpawnAllZonedBots(Client* bot_owner) {
}
if (!bot_owner->HasGroup()) {
database.SetGroupID(b->GetCleanName(), 0, b->GetBotID());
Group::RemoveFromGroup(b);
}
}
}
@@ -3632,7 +3633,7 @@ bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) {
bot->SetFollowID(0);
if (group->DelMember(bot)) {
group->DelMemberOOZ(bot->GetName());
database.SetGroupID(bot->GetCleanName(), 0, bot->GetBotID());
Group::RemoveFromGroup(bot);
if (group->GroupCount() < 2) {
group->DisbandGroup();
}
@@ -3646,7 +3647,7 @@ bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) {
group->members[i]->SetFollowID(0);
}
group->DisbandGroup();
database.SetGroupID(bot->GetCleanName(), 0, bot->GetBotID());
Group::RemoveFromGroup(bot);
}
Result = true;
}
@@ -5189,31 +5190,26 @@ void Bot::ProcessBotOwnerRefDelete(Mob* botOwner) {
}
}
int64 Bot::CalcMaxMana() {
switch(GetCasterClass()) {
case 'I':
max_mana = (GenerateBaseManaPoints() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
max_mana += itembonuses.heroic_max_mana;
case 'W': {
max_mana = (GenerateBaseManaPoints() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
max_mana += itembonuses.heroic_max_mana;
break;
}
case 'N': {
max_mana = 0;
break;
}
default: {
LogDebug("Invalid Class [{}] in CalcMaxMana", GetCasterClass());
max_mana = 0;
break;
}
int64 Bot::CalcMaxMana()
{
if (IsIntelligenceCasterClass() || IsWisdomCasterClass()) {
max_mana = (
GenerateBaseManaPoints() +
itembonuses.Mana +
spellbonuses.Mana +
aabonuses.Mana +
GroupLeadershipAAManaEnhancement()
);
max_mana += itembonuses.heroic_max_mana;
} else {
max_mana = 0;
}
if (current_mana > max_mana)
if (current_mana > max_mana) {
current_mana = max_mana;
else if (max_mana < 0)
} else if (max_mana < 0) {
max_mana = 0;
}
return max_mana;
}
@@ -5528,87 +5524,107 @@ bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, EQ::spells::CastingSlot
return Result;
}
int32 Bot::GenerateBaseManaPoints() {
int32 bot_mana = 0;
int32 WisInt = 0;
int32 Bot::GenerateBaseManaPoints()
{
int32 bot_mana = 0;
int32 WisInt = 0;
int32 MindLesserFactor, MindFactor;
int wisint_mana = 0;
int base_mana = 0;
int ConvertedWisInt = 0;
switch(GetCasterClass()) {
case 'I':
WisInt = INT;
if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
if (WisInt > 100) {
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
if (WisInt > 201)
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
}
else
ConvertedWisInt = WisInt;
int wisint_mana = 0;
int base_mana = 0;
int ConvertedWisInt = 0;
if (GetLevel() < 41) {
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
base_mana = (GetLevel() * 15);
} else if (GetLevel() < 81) {
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
base_mana = (600 + ((GetLevel() - 40) * 30));
} else {
wisint_mana = (9 * ConvertedWisInt);
base_mana = (1800 + ((GetLevel() - 80) * 18));
if (IsIntelligenceCasterClass()) {
WisInt = INT;
if (
GetOwner() &&
GetOwner()->CastToClient() &&
GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD &&
RuleB(Character, SoDClientUseSoDHPManaEnd)
) {
if (WisInt > 100) {
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
if (WisInt > 201) {
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
}
bot_mana = (base_mana + wisint_mana);
} else {
if (((WisInt - 199) / 2) > 0)
MindLesserFactor = ((WisInt - 199) / 2);
else
MindLesserFactor = 0;
MindFactor = WisInt - MindLesserFactor;
if (WisInt > 100)
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
else
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
ConvertedWisInt = WisInt;
}
break;
case 'W':
WisInt = WIS;
if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
if (WisInt > 100) {
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
if (WisInt > 201)
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
} else
ConvertedWisInt = WisInt;
if (GetLevel() < 41) {
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
base_mana = (GetLevel() * 15);
} else if (GetLevel() < 81) {
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
base_mana = (600 + ((GetLevel() - 40) * 30));
} else {
wisint_mana = (9 * ConvertedWisInt);
base_mana = (1800 + ((GetLevel() - 80) * 18));
}
bot_mana = (base_mana + wisint_mana);
if (GetLevel() < 41) {
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
base_mana = (GetLevel() * 15);
} else if (GetLevel() < 81) {
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
base_mana = (600 + ((GetLevel() - 40) * 30));
} else {
if (((WisInt - 199) / 2) > 0)
MindLesserFactor = ((WisInt - 199) / 2);
else
MindLesserFactor = 0;
MindFactor = (WisInt - MindLesserFactor);
if (WisInt > 100)
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
else
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
wisint_mana = (9 * ConvertedWisInt);
base_mana = (1800 + ((GetLevel() - 80) * 18));
}
break;
default:
bot_mana = 0;
break;
bot_mana = (base_mana + wisint_mana);
} else {
if (((WisInt - 199) / 2) > 0) {
MindLesserFactor = ((WisInt - 199) / 2);
} else {
MindLesserFactor = 0;
}
MindFactor = WisInt - MindLesserFactor;
if (WisInt > 100) {
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
} else {
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
}
}
} else if (IsWisdomCasterClass()) {
WisInt = WIS;
if (
GetOwner() &&
GetOwner()->CastToClient() &&
GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD &&
RuleB(Character, SoDClientUseSoDHPManaEnd)
) {
if (WisInt > 100) {
ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
if (WisInt > 201) {
ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
}
} else {
ConvertedWisInt = WisInt;
}
if (GetLevel() < 41) {
wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000);
base_mana = (GetLevel() * 15);
} else if (GetLevel() < 81) {
wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100));
base_mana = (600 + ((GetLevel() - 40) * 30));
} else {
wisint_mana = (9 * ConvertedWisInt);
base_mana = (1800 + ((GetLevel() - 80) * 18));
}
bot_mana = (base_mana + wisint_mana);
} else {
if (((WisInt - 199) / 2) > 0) {
MindLesserFactor = ((WisInt - 199) / 2);
} else {
MindLesserFactor = 0;
}
MindFactor = (WisInt - MindLesserFactor);
if (WisInt > 100) {
bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
} else {
bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
}
}
} else {
bot_mana = 0;
}
max_mana = bot_mana;
return bot_mana;
}
@@ -6219,11 +6235,10 @@ int64 Bot::CalcMaxHP() {
uint32 nd = 10000;
bot_hp += (GenerateBaseHitPoints() + itembonuses.HP);
bot_hp += itembonuses.heroic_max_hp;
nd += aabonuses.MaxHP;
nd += aabonuses.MaxHP + spellbonuses.MaxHPChange + itembonuses.MaxHPChange;
bot_hp = ((float)bot_hp * (float)nd / (float)10000);
bot_hp += (spellbonuses.HP + aabonuses.HP);
bot_hp += GroupLeadershipAAHealthEnhancement();
bot_hp += (bot_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f));
max_hp = bot_hp;
if (current_hp > max_hp)
current_hp = max_hp;
@@ -6585,14 +6600,14 @@ void Bot::ProcessBotGroupInvite(Client* c, std::string const& botName) {
entity_list.AddGroup(g);
database.SetGroupLeaderName(g->GetID(), c->GetName());
g->SaveGroupLeaderAA();
database.SetGroupID(c->GetName(), g->GetID(), c->CharacterID());
database.SetGroupID(invitedBot->GetCleanName(), g->GetID(), invitedBot->GetBotID());
g->AddToGroup(c);
g->AddToGroup(invitedBot);
} else {
delete g;
}
} else {
if (AddBotToGroup(invitedBot, c->GetGroup())) {
database.SetGroupID(invitedBot->GetCleanName(), c->GetGroup()->GetID(), invitedBot->GetBotID());
c->GetGroup()->AddToGroup(invitedBot);
}
}
} else if (invitedBot->HasGroup()) {
@@ -6743,7 +6758,7 @@ void Bot::CalcBotStats(bool showtext) {
SetLevel(GetBotOwner()->GetLevel());
for (int sindex = 0; sindex <= EQ::skills::HIGHEST_SKILL; ++sindex) {
skills[sindex] = content_db.GetSkillCap(GetClass(), (EQ::skills::SkillType)sindex, GetLevel());
skills[sindex] = skill_caps.GetSkillCap(GetClass(), (EQ::skills::SkillType)sindex, GetLevel()).cap;
}
taunt_timer.Start(1000);
+3 -31
View File
@@ -184,35 +184,11 @@ bool BotDatabase::QueryNameAvailablity(const std::string& bot_name, bool& availa
if (
bot_name.empty() ||
bot_name.size() > 60 ||
!database.CheckUsedName(bot_name)
database.IsNameUsed(bot_name)
) {
return false;
}
const auto& bot_data = BotDataRepository::GetWhere(
database,
fmt::format(
"`name` LIKE '{}' LIMIT 1",
bot_name
)
);
if (!bot_data.empty()) {
return false;
}
const auto& character_data = CharacterDataRepository::GetWhere(
database,
fmt::format(
"`name` LIKE '{}' LIMIT 1",
bot_name
)
);
if (!character_data.empty()) {
return false;
}
available_flag = true;
return true;
@@ -1922,18 +1898,14 @@ bool BotDatabase::LoadGroupedBotsByGroupID(const uint32 owner_id, const uint32 g
const auto& l = GroupIdRepository::GetWhere(
database,
fmt::format(
"`groupid` = {} AND `name` IN (SELECT `name` FROM `bot_data` WHERE `owner_id` = {})",
"`group_id` = {} AND `bot_id` != 0 AND `name` IN (SELECT `name` FROM `bot_data` WHERE `owner_id` = {})",
group_id,
owner_id
)
);
if (l.empty()) {
return true;
}
for (const auto& e : l) {
group_list.push_back(e.charid);
group_list.emplace_back(e.bot_id);
}
return true;
+1 -1
View File
@@ -98,7 +98,7 @@ void Raid::HandleBotGroupDisband(uint32 owner, uint32 gid)
auto r_group_members = GetRaidGroupMembers(GetGroup(b->GetName()));
auto g = new Group(b);
entity_list.AddGroup(g);
database.SetGroupID(b->GetCleanName(), g->GetID(), b->GetBotID());
g->AddToGroup(b);
database.SetGroupLeaderName(g->GetID(), b->GetName());
for (auto m: r_group_members) {
+4 -4
View File
@@ -591,7 +591,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
//Only check archetype if spell is not a group spell
//Hybrids get all buffs
switch (tar->GetArchetype()) {
case ARCHETYPE_CASTER:
case Archetype::Caster:
//TODO: probably more caster specific spell effects in here
if (
(
@@ -606,7 +606,7 @@ bool Bot::BotCastCombatBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
continue;
}
break;
case ARCHETYPE_MELEE:
case Archetype::Melee:
if (
(
IsEffectInSpell(s.SpellId, SE_IncreaseSpellHaste) ||
@@ -899,7 +899,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
switch (tar->GetArchetype())
{
case ARCHETYPE_CASTER:
case Archetype::Caster:
//TODO: probably more caster specific spell effects in here
if (IsEffectInSpell(s.SpellId, SE_AttackSpeed) || IsEffectInSpell(s.SpellId, SE_ATK) ||
IsEffectInSpell(s.SpellId, SE_STR) || IsEffectInSpell(s.SpellId, SE_ReverseDS))
@@ -907,7 +907,7 @@ bool Bot::BotCastBuff(Mob* tar, uint8 botLevel, uint8 botClass) {
continue;
}
break;
case ARCHETYPE_MELEE:
case Archetype::Melee:
if (IsEffectInSpell(s.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(s.SpellId, SE_ManaPool) ||
IsEffectInSpell(s.SpellId, SE_CastingLevel) || IsEffectInSpell(s.SpellId, SE_ManaRegen_v2) ||
IsEffectInSpell(s.SpellId, SE_CurrentMana))
+65 -27
View File
@@ -57,6 +57,7 @@ extern volatile bool RunLoops;
#include "queryserv.h"
#include "mob_movement_manager.h"
#include "cheat_manager.h"
#include "lua_parser.h"
#include "../common/repositories/character_alternate_abilities_repository.h"
#include "../common/repositories/account_flags_repository.h"
@@ -73,6 +74,7 @@ extern volatile bool RunLoops;
#include "../common/events/player_event_logs.h"
#include "dialogue_window.h"
#include "../common/zone_store.h"
#include "../common/skill_caps.h"
extern QueryServ* QServ;
@@ -2226,8 +2228,8 @@ void Client::ChangeLastName(std::string last_name) {
bool Client::ChangeFirstName(const char* in_firstname, const char* gmname)
{
// check duplicate name
bool usedname = database.CheckUsedName((const char*) in_firstname);
if (!usedname) {
bool used_name = database.IsNameUsed((const char*) in_firstname);
if (used_name) {
return false;
}
@@ -2756,31 +2758,48 @@ void Client::CheckLanguageSkillIncrease(uint8 language_id, uint8 teacher_skill)
}
}
bool Client::HasSkill(EQ::skills::SkillType skill_id) const {
return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id));
}
bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const {
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skill_id == EQ::skills::Skill1HPiercing)
skill_id = EQ::skills::Skill2HPiercing;
return(content_db.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0);
//if you don't have it by max level, then odds are you never will?
}
uint16 Client::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const {
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
skillid = EQ::skills::Skill2HPiercing;
return(content_db.GetSkillCap(class_, skillid, level));
}
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_)
bool Client::HasSkill(EQ::skills::SkillType skill_id) const
{
if (ClientVersion() < EQ::versions::ClientVersion::RoF2 && class_ == Class::Berserker && skillid == EQ::skills::Skill1HPiercing)
skillid = EQ::skills::Skill2HPiercing;
return GetSkill(skill_id) > 0 && CanHaveSkill(skill_id);
}
return(content_db.GetTrainLevel(class_, skillid, RuleI(Character, MaxLevel)));
bool Client::CanHaveSkill(EQ::skills::SkillType skill_id) const
{
if (
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
class_ == Class::Berserker &&
skill_id == EQ::skills::Skill1HPiercing
) {
skill_id = EQ::skills::Skill2HPiercing;
}
return skill_caps.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)).cap > 0;
}
uint16 Client::MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const
{
if (
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
class_id == Class::Berserker &&
skill_id == EQ::skills::Skill1HPiercing
) {
skill_id = EQ::skills::Skill2HPiercing;
}
return skill_caps.GetSkillCap(class_id, skill_id, level).cap;
}
uint8 Client::SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id)
{
if (
ClientVersion() < EQ::versions::ClientVersion::RoF2 &&
class_id == Class::Berserker &&
skill_id == EQ::skills::Skill1HPiercing
) {
skill_id = EQ::skills::Skill2HPiercing;
}
return skill_caps.GetTrainLevel(class_id, skill_id, RuleI(Character, MaxLevel));
}
uint16 Client::GetMaxSkillAfterSpecializationRules(EQ::skills::SkillType skillid, uint16 maxSkill)
@@ -4442,7 +4461,7 @@ bool Client::GroupFollow(Client* inviter) {
}
//now we have a group id, can set inviter's id
database.SetGroupID(inviter->GetName(), group->GetID(), inviter->CharacterID(), false);
group->AddToGroup(inviter);
database.SetGroupLeaderName(group->GetID(), inviter->GetName());
group->UpdateGroupAAs();
@@ -9226,6 +9245,7 @@ void Client::ShowDevToolsMenu()
menu_reload_six += " | " + Saylink::Silent("#reload quest", "Quests");
menu_reload_seven += Saylink::Silent("#reload rules", "Rules");
menu_reload_seven += " | " + Saylink::Silent("#reload skill_caps", "Skill Caps");
menu_reload_seven += " | " + Saylink::Silent("#reload static", "Static Zone Data");
menu_reload_seven += " | " + Saylink::Silent("#reload tasks", "Tasks");
@@ -11353,6 +11373,16 @@ void Client::SendReloadCommandMessages() {
).c_str()
);
auto skill_caps_link = Saylink::Silent("#reload skill_caps");
Message(
Chat::White,
fmt::format(
"Usage: {} - Reloads Skill Caps globally",
skill_caps_link
).c_str()
);
auto static_link = Saylink::Silent("#reload static");
Message(
@@ -11618,6 +11648,14 @@ void Client::RegisterBug(BugReport_Struct* r) {
b.bug_report = r->bug_report;
b.system_info = r->system_info;
#ifdef LUA_EQEMU
bool ignore_default = false;
LuaParser::Instance()->RegisterBug(this, b, ignore_default);
if (ignore_default) {
return;
}
#endif
auto n = BugReportsRepository::InsertOne(database, b);
if (!n.id) {
Message(Chat::White, "Failed to created your bug report."); // Client sends success message
@@ -11767,7 +11805,7 @@ void Client::MaxSkills()
auto current_skill_value = (
EQ::skills::IsSpecializedSkill(s.first) ?
MAX_SPECIALIZED_SKILL :
content_db.GetSkillCap(GetClass(), s.first, GetLevel())
skill_caps.GetSkillCap(GetClass(), s.first, GetLevel()).cap
);
if (GetSkill(s.first) < current_skill_value) {
+3 -3
View File
@@ -815,9 +815,9 @@ public:
void SetHoTT(uint32 mobid);
void ShowSkillsWindow();
uint16 MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const;
inline uint16 MaxSkill(EQ::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
uint8 SkillTrainLevel(EQ::skills::SkillType skillid, uint16 class_);
uint16 MaxSkill(EQ::skills::SkillType skill_id, uint8 class_id, uint8 level) const;
inline uint16 MaxSkill(EQ::skills::SkillType skill_id) const { return MaxSkill(skill_id, GetClass(), GetLevel()); }
uint8 SkillTrainLevel(EQ::skills::SkillType skill_id, uint8 class_id);
void MaxSkills();
void SendTradeskillSearchResults(const std::string &query, unsigned long objtype, unsigned long someid);
+86 -93
View File
@@ -322,11 +322,12 @@ int64 Client::CalcMaxHP()
//but the actual effect sent on live causes the client
//to apply it to (basehp + itemhp).. I will oblige to the client's whims over
//the aa description
nd += aabonuses.MaxHP; //Natural Durability, Physical Enhancement, Planar Durability
nd += aabonuses.MaxHP + spellbonuses.MaxHPChange + itembonuses.MaxHPChange; //Natural Durability, Physical Enhancement, Planar Durability (MaxHP and MaxHPChange are SPA214)
max_hp = (float)max_hp * (float)nd / (float)10000; //this is to fix the HP-above-495k issue
max_hp += spellbonuses.HP + aabonuses.HP;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
if (current_hp > max_hp) {
current_hp = max_hp;
}
@@ -523,28 +524,26 @@ int32 Client::GetRawItemAC()
int64 Client::CalcMaxMana()
{
switch (GetCasterClass()) {
case 'I':
case 'W': {
max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
break;
}
case 'N': {
max_mana = 0;
break;
}
default: {
LogSpells("Invalid Class [{}] in CalcMaxMana", GetCasterClass());
max_mana = 0;
break;
}
if (IsIntelligenceCasterClass() || IsWisdomCasterClass()) {
max_mana = (
CalcBaseMana() +
itembonuses.Mana +
spellbonuses.Mana +
aabonuses.Mana +
GroupLeadershipAAManaEnhancement()
);
} else {
max_mana = 0;
}
if (max_mana < 0) {
max_mana = 0;
}
if (current_mana > max_mana) {
current_mana = max_mana;
}
int mana_perc_cap = spellbonuses.ManaPercCap[SBIndex::RESOURCE_PERCENT_CAP];
if (mana_perc_cap) {
int curMana_cap = (max_mana * mana_perc_cap) / 100;
@@ -552,96 +551,90 @@ int64 Client::CalcMaxMana()
current_mana = curMana_cap;
}
}
LogSpells("for [{}] returning [{}]", GetName(), max_mana);
return max_mana;
}
int64 Client::CalcBaseMana()
{
int ConvertedWisInt = 0;
int MindLesserFactor, MindFactor;
int WisInt = 0;
int64 base_mana = 0;
int wisint_mana = 0;
int64 max_m = 0;
switch (GetCasterClass()) {
case 'I':
WisInt = GetINT();
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
ConvertedWisInt = WisInt;
int over200 = WisInt;
if (WisInt > 100) {
if (WisInt > 200) {
over200 = (WisInt - 200) / -2 + WisInt;
}
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
}
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
if (base_data.level == GetLevel()) {
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
int ConvertedWisInt = 0;
int MindLesserFactor, MindFactor;
int WisInt = 0;
int64 base_mana = 0;
int wisint_mana = 0;
int64 max_m = 0;
if (IsIntelligenceCasterClass()) {
WisInt = GetINT();
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
ConvertedWisInt = WisInt;
int over200 = WisInt;
if (WisInt > 100) {
if (WisInt > 200) {
over200 = (WisInt - 200) / -2 + WisInt;
}
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
}
else {
if ((( WisInt - 199 ) / 2) > 0) {
MindLesserFactor = ( WisInt - 199 ) / 2;
}
else {
MindLesserFactor = 0;
}
MindFactor = WisInt - MindLesserFactor;
if (WisInt > 100) {
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
}
else {
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
}
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
if (base_data.level == GetLevel()) {
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
}
break;
case 'W':
WisInt = GetWIS();
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
ConvertedWisInt = WisInt;
int over200 = WisInt;
if (WisInt > 100) {
if (WisInt > 200) {
over200 = (WisInt - 200) / -2 + WisInt;
}
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
}
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
if (base_data.level == GetLevel()) {
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
}
} else {
if (((WisInt - 199) / 2) > 0) {
MindLesserFactor = (WisInt - 199) / 2;
} else {
MindLesserFactor = 0;
}
else {
if ((( WisInt - 199 ) / 2) > 0) {
MindLesserFactor = ( WisInt - 199 ) / 2;
}
else {
MindLesserFactor = 0;
}
MindFactor = WisInt - MindLesserFactor;
if (WisInt > 100) {
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
}
else {
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
}
MindFactor = WisInt - MindLesserFactor;
if (WisInt > 100) {
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
} else {
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
}
break;
case 'N': {
max_m = 0;
break;
}
} else if (IsWisdomCasterClass()) {
WisInt = GetWIS();
if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {
ConvertedWisInt = WisInt;
int over200 = WisInt;
if (WisInt > 100) {
if (WisInt > 200) {
over200 = (WisInt - 200) / -2 + WisInt;
}
ConvertedWisInt = (3 * over200 - 300) / 2 + over200;
}
default: {
LogDebug("Invalid Class [{}] in CalcMaxMana", GetCasterClass());
max_m = 0;
break;
auto base_data = zone->GetBaseData(GetLevel(), GetClass());
if (base_data.level == GetLevel()) {
max_m = base_data.mana + (ConvertedWisInt * base_data.mana_fac) + itembonuses.heroic_max_mana;
}
} else {
if (((WisInt - 199) / 2) > 0) {
MindLesserFactor = (WisInt - 199) / 2;
} else {
MindLesserFactor = 0;
}
MindFactor = WisInt - MindLesserFactor;
if (WisInt > 100) {
max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
} else {
max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
}
}
} else {
max_m = 0;
}
#if EQDEBUG >= 11
LogDebug("Client::CalcBaseMana() called for [{}] - returning [{}]", GetName(), max_m);
#endif
return max_m;
}
+18 -6
View File
@@ -1530,8 +1530,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
}
} //else, somebody from our group is already here...
if (!group)
database.SetGroupID(GetName(), 0, CharacterID(), false); //cannot re-establish group, kill it
if (!group) { //cannot re-establish group, kill it
Group::RemoveFromGroup(this);
}
}
else { //no group id
@@ -5596,9 +5597,20 @@ void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app)
}
// Prevent the client from creating more than they have.
const uint32 amount = EQ::ClampUpper(quantity, current_quantity);
uint32 amount = EQ::ClampUpper(quantity, current_quantity);
const uint32 item_id = is_radiant ? RuleI(Zone, RadiantCrystalItemID) : RuleI(Zone, EbonCrystalItemID);
const auto item = database.GetItem(item_id);
// Prevent pulling more than max stack size or 1,000 (if stackable), whichever is lesser
const uint32 max_reclaim_amount = EQ::Clamp(
item && item->Stackable ? item->StackSize : ItemStackSizeConstraint::Minimum,
ItemStackSizeConstraint::Minimum,
ItemStackSizeConstraint::Maximum
);
if (amount > max_reclaim_amount) {
amount = max_reclaim_amount;
}
const bool success = SummonItem(item_id, amount);
if (!success) {
return;
@@ -6863,7 +6875,7 @@ void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
Client *c = entity_list.GetClientByName(gmn->oldname);
LogInfo("GM([{}]) changeing players name. Old:[{}] New:[{}]", GetName(), gmn->oldname, gmn->newname);
const bool used_name = database.CheckUsedName(gmn->newname);
const bool used_name = database.IsNameUsed(gmn->newname);
if (!c) {
Message(Chat::Red, fmt::format("{} not found for name change. Operation failed!", gmn->oldname).c_str());
return;
@@ -6874,7 +6886,7 @@ void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
return;
}
if (!used_name) {
if (used_name) {
Message(Chat::Red, fmt::format("{} is already in use. Operation failed!", gmn->newname).c_str());
return;
}
@@ -7178,7 +7190,7 @@ void Client::Handle_OP_GroupCancelInvite(const EQApplicationPacket *app)
if (!GetMerc())
{
database.SetGroupID(GetName(), 0, CharacterID(), false);
Group::RemoveFromGroup(this);
}
return;
}
+12 -6
View File
@@ -19,9 +19,11 @@
#define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from
#define SEE_POSITION 0.5f //ratio of GetSize() where NPCs try to see for LOS
#define ARCHETYPE_HYBRID 1
#define ARCHETYPE_CASTER 2
#define ARCHETYPE_MELEE 3
namespace Archetype {
constexpr uint8 Hybrid = 1;
constexpr uint8 Caster = 2;
constexpr uint8 Melee = 3;
};
#define CON_GREEN 2
#define CON_LIGHTBLUE 18
@@ -285,7 +287,7 @@ struct StatBonuses {
int32 AC;
int64 HP;
int64 HPRegen;
int64 MaxHP;
int64 MaxHP; //same bonus as MaxHPChange when applied to spells and item bonuses
int64 ManaRegen;
int64 EnduranceRegen;
int64 Mana;
@@ -411,7 +413,7 @@ struct StatBonuses {
int32 MeleeLifetap; //i
int32 Vampirism; //i
int32 HealRate; // Spell effect that influences effectiveness of heals
int32 MaxHPChange; // Spell Effect
int32 MaxHPChange; // percent change in hit points (aabonuses use variable MaxHP)
int16 SkillDmgTaken[EQ::skills::HIGHEST_SKILL + 2]; // All Skills + -1
int32 HealAmt; // Item Effect
int32 SpellDmg; // Item Effect
@@ -443,7 +445,8 @@ struct StatBonuses {
int32 SongRange; // increases range of beneficial bard songs
uint32 HPToManaConvert; // Uses HP to cast spells at specific conversion
int32 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot
int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot, limits do not apply
int32 FocusEffectsWornWithLimits[HIGHEST_FOCUS + 1];// Optional to allow focus effects to be applied additively from worn slot, limits apply
bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses)
int32 SkillDamageAmount2[EQ::skills::HIGHEST_SKILL + 2]; // Adds skill specific damage
uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit
@@ -509,6 +512,7 @@ struct StatBonuses {
uint8 invisibility; // invisibility level
uint8 invisibility_verse_undead; // IVU level
uint8 invisibility_verse_animal; // IVA level
int32 ShieldTargetSpa[2]; // [0] base = % mitigation amount, [1] buff slot
// AAs
int32 TrapCircumvention; // reduce chance to trigger a trap.
@@ -654,6 +658,8 @@ namespace SBIndex {
constexpr uint16 COMBAT_PROC_SPELL_ID = 1; // SPA
constexpr uint16 COMBAT_PROC_RATE_MOD = 2; // SPA
constexpr uint16 COMBAT_PROC_REUSE_TIMER = 3; // SPA
constexpr uint16 SHIELD_TARGET_MITIGATION_PERCENT = 0; // SPA 463
constexpr uint16 SHIELD_TARGET_BUFFSLOT = 1; // SPA 463
};
+20
View File
@@ -202,6 +202,7 @@ const char* QuestEventSubroutines[_LargestEventID] = {
"EVENT_ENTITY_VARIABLE_SET",
"EVENT_ENTITY_VARIABLE_UPDATE",
"EVENT_AA_LOSS",
"EVENT_SPELL_BLOCKED",
// Add new events before these or Lua crashes
"EVENT_SPELL_EFFECT_BOT",
@@ -1937,6 +1938,25 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_SPELL_BLOCKED: {
Seperator sep(data);
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[1]);
ExportVar(package_name.c_str(), "blocking_spell_id", blocking_spell_id);
ExportVar(package_name.c_str(), "cast_spell_id", cast_spell_id);
if (IsValidSpell(blocking_spell_id)) {
ExportVar(package_name.c_str(), "blocking_spell", "Spell", (void*) &spells[blocking_spell_id]);
}
if (IsValidSpell(cast_spell_id)) {
ExportVar(package_name.c_str(), "cast_spell", "Spell", (void*) &spells[cast_spell_id]);
}
break;
}
//tradeskill events
case EVENT_COMBINE_SUCCESS:
case EVENT_COMBINE_FAILURE: {
+19 -3
View File
@@ -1579,9 +1579,7 @@ std::string Perl__GetCharactersInInstance(uint16 instance_id)
char_id_string = fmt::format("{} player(s) in instance: ", character_ids.size());
auto iter = character_ids.begin();
while (iter != character_ids.end()) {
char char_name[64];
database.GetCharName(*iter, char_name);
char_id_string += char_name;
char_id_string += database.GetCharName(*iter);
char_id_string += "(";
char_id_string += itoa(*iter);
char_id_string += ")";
@@ -5842,6 +5840,21 @@ std::string Perl__silent_saylink(std::string text, std::string link_name)
return Saylink::Silent(text, link_name);
}
uint16 Perl__get_class_bitmask(uint8 class_id)
{
return GetPlayerClassBit(class_id);
}
uint32 Perl__get_deity_bitmask(uint16 deity_id)
{
return static_cast<uint32>(EQ::deity::GetDeityBitmask(static_cast<EQ::deity::DeityType>(deity_id)));
}
uint16 Perl__get_race_bitmask(uint16 race_id)
{
return GetPlayerRaceBit(race_id);
}
void perl_register_quest()
{
perl::interpreter perl(PERL_GET_THX);
@@ -6488,9 +6501,11 @@ void perl_register_quest()
package.add("getconsiderlevelname", &Perl__getconsiderlevelname);
package.add("gethexcolorcode", &Perl__gethexcolorcode);
package.add("getcurrencyid", &Perl__getcurrencyid);
package.add("get_class_bitmask", &Perl__get_class_bitmask);
package.add("get_data", &Perl__get_data);
package.add("get_data_expires", &Perl__get_data_expires);
package.add("get_data_remaining", &Perl__get_data_remaining);
package.add("get_deity_bitmask", &Perl__get_deity_bitmask);
package.add("get_dz_task_id", &Perl__get_dz_task_id);
package.add("getexpmodifierbycharid", (double(*)(uint32, uint32))&Perl__getexpmodifierbycharid);
package.add("getexpmodifierbycharid", (double(*)(uint32, uint32, int16))&Perl__getexpmodifierbycharid);
@@ -6523,6 +6538,7 @@ void perl_register_quest()
package.add("getgroupidbycharid", &Perl__getgroupidbycharid);
package.add("getinventoryslotname", &Perl__getinventoryslotname);
package.add("getraididbycharid", &Perl__getraididbycharid);
package.add("get_race_bitmask", &Perl__get_race_bitmask);
package.add("get_recipe_component_item_ids", &Perl__GetRecipeComponentItemIDs);
package.add("get_recipe_container_item_ids", &Perl__GetRecipeContainerItemIDs);
package.add("get_recipe_fail_item_ids", &Perl__GetRecipeFailItemIDs);
+7
View File
@@ -2675,6 +2675,10 @@ void EntityList::RemoveAllMobs()
{
auto it = mob_list.begin();
while (it != mob_list.end()) {
if (!it->second) {
++it;
continue;
}
safe_delete(it->second);
free_ids.push(it->first);
it = mob_list.erase(it);
@@ -2812,6 +2816,9 @@ bool EntityList::RemoveMob(uint16 delete_id)
auto it = mob_list.find(delete_id);
if (it != mob_list.end()) {
if (!it->second) {
return false;
}
if (npc_list.count(delete_id)) {
entity_list.RemoveNPC(delete_id);
}
+1
View File
@@ -143,6 +143,7 @@ typedef enum {
EVENT_ENTITY_VARIABLE_SET,
EVENT_ENTITY_VARIABLE_UPDATE,
EVENT_AA_LOSS,
EVENT_SPELL_BLOCKED,
// Add new events before these or Lua crashes
EVENT_SPELL_EFFECT_BOT,
+32 -37
View File
@@ -44,17 +44,14 @@ extern WorldServer worldserver;
struct NPCType;
//max number of items which can be in the foraging table
//for a given zone.
#define FORAGE_ITEM_LIMIT 50
//max number of items which can be in the foraging
// and fishing tables for a given zone.
constexpr uint8 FORAGE_ITEM_LIMIT = 50;
constexpr uint8 FISHING_ITEM_LIMIT = 50;
uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
{
uint32 forage_items[FORAGE_ITEM_LIMIT];
for (uint16 slot_id = 0; slot_id < FORAGE_ITEM_LIMIT; slot_id++) {
forage_items[slot_id] = 0;
}
uint32 forage_items[FORAGE_ITEM_LIMIT] = {};
const auto& l = ForageRepository::GetWhere(
*this,
@@ -77,7 +74,7 @@ uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
l.size() != 1 ? "s" : ""
);
int forage_chances[FORAGE_ITEM_LIMIT];
int forage_chances[FORAGE_ITEM_LIMIT] = {};
int current_chance = 0;
uint32 item_id = 0;
@@ -118,13 +115,8 @@ uint32 ZoneDatabase::LoadForage(uint32 zone_id, uint8 skill_level)
uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_id, uint8 &npc_chance)
{
uint32 fishing_items[50];
int fishing_chances[50];
for (uint16 slot_id = 0; slot_id < 50; slot_id++) {
fishing_items[slot_id] = 0;
fishing_chances[slot_id] = 0;
}
uint32 fishing_items[FISHING_ITEM_LIMIT] = {};
int fishing_chances[FISHING_ITEM_LIMIT] = {};
const auto& l = FishingRepository::GetWhere(
*this,
@@ -146,15 +138,15 @@ uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_
l.size() != 1 ? "s" : ""
);
uint32 npc_ids[50];
uint32 npc_chances[50];
uint32 npc_ids[FISHING_ITEM_LIMIT] = {};
uint32 npc_chances[FISHING_ITEM_LIMIT] = {};
int current_chance = 0;
uint32 item_id = 0;
uint8 count = 0;
for (const auto &e: l) {
if (count >= 50) {
if (count >= FISHING_ITEM_LIMIT) {
break;
}
@@ -164,6 +156,8 @@ uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_
npc_chances[count] = e.npc_chance;
current_chance = fishing_chances[count];
count++;
}
npc_id = 0;
@@ -175,7 +169,7 @@ uint32 ZoneDatabase::LoadFishing(uint32 zone_id, uint8 skill_level, uint32 &npc_
const int roll = zone->random.Int(1, current_chance);
for (uint16 i = 0; i < count; i++) {
for (uint8 i = 0; i < count; i++) {
if (roll > fishing_chances[i]) {
continue;
}
@@ -269,32 +263,33 @@ void Client::GoFish(bool guarantee, bool use_bait)
fishing_timer.Disable();
//we're doing this a second time (1st in Client::Handle_OP_Fishing) to make sure that, between when we started fishing & now, we're still able to fish (in case we move, change equip, etc)
if (!CanFish()) //if we can't fish here, we don't need to bother with the rest
if (!CanFish()) { //if we can't fish here, we don't need to bother with the rest
return;
}
//multiple entries yeilds higher probability of dropping...
uint32 common_fish_ids[MAX_COMMON_FISH_IDS] = {
1038, // Tattered Cloth Sandals
1038, // Tattered Cloth Sandals
1038, // Tattered Cloth Sandals
1038, // Tattered Cloth Sandals
1038, // Tattered Cloth Sandals
1038, // Tattered Cloth Sandals
13019, // Fresh Fish
13076, // Fish Scales
13076, // Fish Scales
7007, // Rusty Dagger
7007, // Rusty Dagger
7007 // Rusty Dagger
7007, // Rusty Dagger
7007, // Rusty Dagger
7007 // Rusty Dagger
};
//success formula is not researched at all
int fishing_skill = GetSkill(EQ::skills::SkillFishing); //will take into account skill bonuses on pole & bait
uint16 fishing_skill = GetSkill(EQ::skills::SkillFishing); //will take into account skill bonuses on pole & bait
//make sure we still have a fishing pole on:
int32 bslot = m_inv.HasItemByUse(EQ::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal);
int16 bslot = m_inv.HasItemByUse(EQ::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal);
const EQ::ItemInstance* Bait = nullptr;
if (bslot != INVALID_INDEX)
if (bslot != INVALID_INDEX) {
Bait = m_inv.GetItem(bslot);
}
//if the bait isnt equipped, need to add its skill bonus
if (bslot >= EQ::invslot::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == EQ::skills::SkillFishing) {
@@ -309,8 +304,8 @@ void Client::GoFish(bool guarantee, bool use_bait)
if (guarantee || zone->random.Int(0,175) < fishing_skill) {
uint32 food_id = 0;
//25% chance to fish an item.
if (zone->random.Int(0, 399) <= fishing_skill ) {
//chance to fish a zone item.
if (zone->random.Int(0, RuleI(Zone, FishingChance)) <= fishing_skill ) {
uint32 npc_id = 0;
uint8 npc_chance = 0;
food_id = content_db.LoadFishing(m_pp.zone_id, fishing_skill, npc_id, npc_chance);
@@ -348,7 +343,7 @@ void Client::GoFish(bool guarantee, bool use_bait)
DeleteItemInInventory(bslot, 1, true); //do we need client update?
}
if(food_id == 0) {
if (food_id == 0) {
int index = zone->random.Int(0, MAX_COMMON_FISH_IDS-1);
food_id = (RuleB(Character, UseNoJunkFishing) ? 13019 : common_fish_ids[index]);
}
@@ -449,9 +444,9 @@ void Client::ForageItem(bool guarantee) {
13419, // Vegetables
13048, // Rabbit Meat
13047, // Roots
13044, // Pod Of Water
14905, // mushroom
13106 // Fishing Grubs
13044, // Pod of Water
14905, // Mushroom
13106 // Fishing Grubs
};
// these may need to be fine tuned, I am just guessing here
+1 -1
View File
@@ -53,7 +53,7 @@ void command_movechar(Client *c, const Seperator *sep)
return;
}
const bool moved = database.MoveCharacterToZone(character_name.c_str(), zone_id);
const bool moved = database.MoveCharacterToZone(character_name, zone_id);
std::string moved_string = moved ? "Succeeded" : "Failed";
c->Message(
Chat::White,
+5
View File
@@ -34,6 +34,7 @@ void command_reload(Client *c, const Seperator *sep)
bool is_perl_export = !strcasecmp(sep->arg[1], "perl_export");
bool is_quest = !strcasecmp(sep->arg[1], "quest") || (is_rq_alias);
bool is_rules = !strcasecmp(sep->arg[1], "rules");
bool is_skill_caps = !strcasecmp(sep->arg[1], "skill_caps");
bool is_static = !strcasecmp(sep->arg[1], "static");
bool is_tasks = !strcasecmp(sep->arg[1], "tasks");
bool is_titles = !strcasecmp(sep->arg[1], "titles");
@@ -66,6 +67,7 @@ void command_reload(Client *c, const Seperator *sep)
!is_perl_export &&
!is_quest &&
!is_rules &&
!is_skill_caps &&
!is_static &&
!is_tasks &&
!is_titles &&
@@ -161,6 +163,9 @@ void command_reload(Client *c, const Seperator *sep)
} else if (is_rules) {
c->Message(Chat::White, "Attempting to reload Rules globally.");
pack = new ServerPacket(ServerOP_ReloadRules, 0);
} else if (is_skill_caps) {
c->Message(Chat::White, "Attempting to reload Skill Caps globally.");
pack = new ServerPacket(ServerOP_ReloadSkillCaps, 0);
} else if (is_static) {
c->Message(Chat::White, "Attempting to reload Static Zone Data globally.");
pack = new ServerPacket(ServerOP_ReloadStaticZoneData, 0);
+176 -126
View File
@@ -203,155 +203,141 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
}
}
bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 CharacterID, bool ismerc)
bool Group::AddMember(Mob* new_member, std::string new_member_name, uint32 character_id, bool is_merc)
{
bool InZone = true;
bool in_zone = true;
// This method should either be passed a Mob*, if the new member is in this zone, or a nullptr Mob*
// and the name and CharacterID of the new member, if they are out of zone.
if(!newmember && !NewMemberName)
{
// and the name and character_id of the new member, if they are out of zone.
if (!new_member && new_member_name.empty()) {
return false;
}
if(GroupCount() >= MAX_GROUP_MEMBERS) //Sanity check for merging groups together.
{
if (GroupCount() >= MAX_GROUP_MEMBERS) { //Sanity check for merging groups together.
return false;
}
if(!newmember)
{
InZone = false;
}
else
{
NewMemberName = newmember->GetCleanName();
if (!new_member) {
in_zone = false;
} else {
new_member_name = new_member->GetCleanName();
if(newmember->IsClient())
{
CharacterID = newmember->CastToClient()->CharacterID();
if (new_member->IsClient()) {
character_id = new_member->CastToClient()->CharacterID();
}
if(newmember->IsMerc())
{
Client* owner = newmember->CastToMerc()->GetMercenaryOwner();
if(owner)
{
CharacterID = owner->CastToClient()->CharacterID();
if (new_member->IsMerc()) {
Client* o = new_member->CastToMerc()->GetMercenaryOwner();
if (o) {
character_id = o->CastToClient()->CharacterID();
}
ismerc = true;
is_merc = true;
}
}
// See if they are already in the group
uint32 i = 0;
for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
{
if (!strcasecmp(membername[i], NewMemberName))
{
for (const auto& m : membername) {
if (Strings::EqualFold(m, new_member_name)) {
return false;
}
}
// Put them in the group
for (i = 0; i < MAX_GROUP_MEMBERS; ++i)
{
if (membername[i][0] == '\0')
{
if(InZone)
{
members[i] = newmember;
for (int slot_id = 0; slot_id < MAX_GROUP_MEMBERS; ++slot_id) {
if (membername[slot_id][0] == '\0') {
if (in_zone) {
members[slot_id] = new_member;
}
strcpy(membername[i], NewMemberName);
MemberRoles[i] = 0;
strcpy(membername[slot_id], new_member_name.c_str());
MemberRoles[slot_id] = 0;
break;
}
}
// Is this even possible based on the above loops? Remove?
if (i == MAX_GROUP_MEMBERS)
{
return false;
}
int x=1;
int x = 1;
//build the template join packet
auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer;
strcpy(gj->membername, NewMemberName);
gj->action = groupActJoin;
auto gj = (GroupJoin_Struct*) outapp->pBuffer;
strcpy(gj->membername, new_member_name.c_str());
gj->action = groupActJoin;
gj->leader_aas = LeaderAbilities;
for (i = 0;i < MAX_GROUP_MEMBERS; i++)
{
if (members[i] != nullptr && members[i] != newmember)
{
for (int slot_id = 0; slot_id < MAX_GROUP_MEMBERS; slot_id++) {
if (members[slot_id] && members[slot_id] != new_member) {
//fill in group join & send it
strcpy(gj->yourname, members[i]->GetCleanName());
if(members[i]->IsClient())
{
members[i]->CastToClient()->QueuePacket(outapp);
strcpy(gj->yourname, members[slot_id]->GetCleanName());
if (members[slot_id]->IsClient()) {
members[slot_id]->CastToClient()->QueuePacket(outapp);
//put new member into existing group members' list(s)
strcpy(members[i]->CastToClient()->GetPP().groupMembers[GroupCount()-1], NewMemberName);
strcpy(
members[slot_id]->CastToClient()->GetPP().groupMembers[GroupCount() - 1],
new_member_name.c_str()
);
}
//put existing group member(s) into the new member's list
if(InZone && newmember && newmember->IsClient())
{
if(IsLeader(members[i]))
{
strcpy(newmember->CastToClient()->GetPP().groupMembers[0], members[i]->GetCleanName());
}
else
{
strcpy(newmember->CastToClient()->GetPP().groupMembers[x], members[i]->GetCleanName());
if (in_zone && new_member && new_member->IsClient()) {
if (IsLeader(members[slot_id])) {
strcpy(new_member->CastToClient()->GetPP().groupMembers[0], members[slot_id]->GetCleanName());
} else {
strcpy(new_member->CastToClient()->GetPP().groupMembers[x], members[slot_id]->GetCleanName());
++x;
}
}
}
}
if(InZone && newmember)
{
if (in_zone && new_member) {
//put new member in his own list.
newmember->SetGrouped(true);
new_member->SetGrouped(true);
if(newmember->IsClient())
{
strcpy(newmember->CastToClient()->GetPP().groupMembers[x], NewMemberName);
newmember->CastToClient()->Save();
database.SetGroupID(NewMemberName, GetID(), newmember->CastToClient()->CharacterID(), false);
SendMarkedNPCsToMember(newmember->CastToClient());
if (new_member->IsClient()) {
strcpy(new_member->CastToClient()->GetPP().groupMembers[x], new_member_name.c_str());
NotifyMainTank(newmember->CastToClient(), 1);
NotifyMainAssist(newmember->CastToClient(), 1);
NotifyPuller(newmember->CastToClient(), 1);
new_member->CastToClient()->Save();
AddToGroup(new_member);
SendMarkedNPCsToMember(new_member->CastToClient());
NotifyMainTank(new_member->CastToClient(), 1);
NotifyMainAssist(new_member->CastToClient(), 1);
NotifyPuller(new_member->CastToClient(), 1);
}
if(newmember->IsMerc())
{
Client* owner = newmember->CastToMerc()->GetMercenaryOwner();
if(owner)
{
database.SetGroupID(NewMemberName, GetID(), owner->CharacterID(), true);
if (new_member->IsMerc()) {
Client* o = new_member->CastToMerc()->GetMercenaryOwner();
if (o) {
AddToGroup(new_member);
}
}
Group* group = newmember->CastToClient()->GetGroup();
if (group) {
group->SendHPManaEndPacketsTo(newmember);
group->SendHPPacketsFrom(newmember);
Group* g = new_member->CastToClient()->GetGroup();
if (g) {
g->SendHPManaEndPacketsTo(new_member);
g->SendHPPacketsFrom(new_member);
}
}
else
{
database.SetGroupID(NewMemberName, GetID(), CharacterID, ismerc);
} else {
AddToGroup(
AddToGroupRequest{
.mob = nullptr,
.member_name = new_member_name,
.character_id = character_id,
}
);
}
if (newmember && newmember->IsClient())
newmember->CastToClient()->JoinGroupXTargets(this);
if (new_member && new_member->IsClient()) {
new_member->CastToClient()->JoinGroupXTargets(this);
}
safe_delete(outapp);
@@ -362,20 +348,18 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
return true;
}
void Group::AddMember(const char *NewMemberName)
void Group::AddMember(const std::string& new_member_name)
{
// This method should be called when both the new member and the group leader are in a different zone to this one.
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i)
if(!strcasecmp(membername[i], NewMemberName))
{
for (const auto& m : membername) {
if (Strings::EqualFold(m, new_member_name)) {
return;
}
}
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i)
{
if (membername[i][0] == '\0')
{
strcpy(membername[i], NewMemberName);
for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
if (membername[i][0] == '\0') {
strcpy(membername[i], new_member_name.c_str());
MemberRoles[i] = 0;
break;
}
@@ -752,7 +736,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
if(oldmember->IsClient())
{
database.SetGroupID(oldmember->GetCleanName(), 0, oldmember->CastToClient()->CharacterID(), false);
RemoveFromGroup(oldmember);
}
if(oldmember->IsMerc())
@@ -760,7 +744,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender)
Client* owner = oldmember->CastToMerc()->GetMercenaryOwner();
if(owner)
{
database.SetGroupID(oldmember->GetCleanName(), 0, owner->CharacterID(), true);
RemoveFromGroup(oldmember);
}
}
@@ -943,7 +927,7 @@ void Group::DisbandGroup(bool joinraid) {
}
strcpy(gu->yourname, members[i]->GetCleanName());
database.SetGroupID(members[i]->GetCleanName(), 0, members[i]->CastToClient()->CharacterID(), false);
RemoveFromGroup(members[i]);
members[i]->CastToClient()->QueuePacket(outapp);
SendMarkedNPCsToMember(members[i]->CastToClient(), true);
if (!joinraid)
@@ -955,7 +939,7 @@ void Group::DisbandGroup(bool joinraid) {
Client* owner = members[i]->CastToMerc()->GetMercenaryOwner();
if(owner)
{
database.SetGroupID(members[i]->GetCleanName(), 0, owner->CharacterID(), true);
RemoveFromGroup(members[i]);
}
}
@@ -1148,31 +1132,30 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float
bool Group::LearnMembers() {
auto rows = GroupIdRepository::GetWhere(
const auto& l = GroupIdRepository::GetWhere(
database,
fmt::format(
"groupid = {}",
"`group_id` = {}",
GetID()
)
);
if (rows.empty()) {
if (l.empty()) {
LogError(
"Error getting group members for group [{}]",
GetID()
);
}
for(int i = 0; i < MAX_GROUP_MEMBERS; ++i)
{
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
members[i] = nullptr;
memset(membername[i],0,64);
memset(membername[i], 0, 64);
MemberRoles[i] = 0;
}
int memberIndex = 0;
for (const auto& member : rows) {
if (memberIndex >= MAX_GROUP_MEMBERS) {
int member_index = 0;
for (const auto& e : l) {
if (member_index >= MAX_GROUP_MEMBERS) {
LogError(
"Too many members in group [{}]",
GetID()
@@ -1180,14 +1163,15 @@ bool Group::LearnMembers() {
break;
}
if (member.name.empty()) {
members[memberIndex] = nullptr;
membername[memberIndex][0] = '\0';
if (e.name.empty()) {
members[member_index] = nullptr;
membername[member_index][0] = '\0';
} else {
members[memberIndex] = nullptr;
strn0cpy(membername[memberIndex], member.name.c_str(), 64);
members[member_index] = nullptr;
strn0cpy(membername[member_index], e.name.c_str(), 64);
}
++memberIndex;
++member_index;
}
VerifyGroup();
@@ -1264,10 +1248,10 @@ void Client::LeaveGroup() {
else
{
//force things a little
database.SetGroupID(GetCleanName(), 0, CharacterID(), false);
if (GetMerc())
{
database.SetGroupID(GetMerc()->GetCleanName(), 0, CharacterID(), true);
Group::RemoveFromGroup(this);
if (GetMerc()) {
Group::RemoveFromGroup(GetMerc());
}
}
@@ -2514,3 +2498,69 @@ bool Group::IsLeader(const char* name) {
std::string Group::GetLeaderName() {
return database.GetGroupLeaderName(GetID());
}
void Group::RemoveFromGroup(Mob* m)
{
uint32 bot_id = 0;
uint32 character_id = 0;
uint32 merc_id = 0;
if (m->IsBot()) {
bot_id = m->CastToBot()->GetBotID();
} else if (m->IsClient()) {
character_id = m->CastToClient()->CharacterID();
} else if (m->IsMerc()) {
merc_id = m->CastToMerc()->GetMercenaryID();
}
GroupIdRepository::DeleteWhere(
database,
fmt::format(
"`character_id` = {} AND `bot_id` = {} AND `merc_id` = {}",
character_id,
bot_id,
merc_id
)
);
}
void Group::AddToGroup(Mob* m)
{
AddToGroup(
AddToGroupRequest{
.mob = m
}
);
}
// Handles database-side, should eventually be consolidated to handle memory-based group stuff as well
void Group::AddToGroup(AddToGroupRequest r)
{
uint32 bot_id = 0;
uint32 character_id = r.character_id;
uint32 merc_id = 0;
std::string name = r.member_name;
if (r.mob) {
if (r.mob->IsBot()) {
bot_id = r.mob->CastToBot()->GetBotID();
} else if (r.mob->IsClient()) {
character_id = r.mob->CastToClient()->CharacterID();
} else if (r.mob->IsMerc()) {
merc_id = r.mob->CastToMerc()->GetMercenaryID();
}
name = r.mob->GetCleanName();
}
GroupIdRepository::ReplaceOne(
database,
GroupIdRepository::GroupId{
.group_id = GetID(),
.name = name,
.character_id = character_id,
.bot_id = bot_id,
.merc_id = merc_id
}
);
}
+12 -2
View File
@@ -52,8 +52,15 @@ public:
Group(uint32 gid);
~Group();
bool AddMember(Mob* newmember, const char* NewMemberName = nullptr, uint32 CharacterID = 0, bool ismerc = false);
void AddMember(const char* NewMemberName);
struct AddToGroupRequest {
Mob* mob = nullptr;
// Only used cross-zone, otherwise use Mob* mob
std::string member_name = std::string();
uint32 character_id = 0;
};
bool AddMember(Mob* new_member, std::string new_member_name = std::string(), uint32 character_id = 0, bool is_merc = false);
void AddMember(const std::string& new_member_name);
void SendUpdate(uint32 type,Mob* member);
void SendLeadershipAAUpdate();
void SendWorldGroup(uint32 zone_id,Mob* zoningmember);
@@ -145,6 +152,9 @@ public:
void SetDirtyAutoHaters();
inline XTargetAutoHaters *GetXTargetAutoMgr() { return &m_autohatermgr; }
void JoinRaidXTarget(Raid *raid, bool first = false);
void AddToGroup(AddToGroupRequest r);
void AddToGroup(Mob* m);
static void RemoveFromGroup(Mob* m);
void SetGroupMentor(int percent, char *name);
void ClearGroupMentor();
+32 -30
View File
@@ -108,46 +108,48 @@ void HateList::SetHateAmountOnEnt(Mob* other, int64 in_hate, uint64 in_damage)
Mob* HateList::GetDamageTopOnHateList(Mob* hater)
{
Mob* current = nullptr;
Group* grp = nullptr;
Raid* r = nullptr;
uint64 dmg_amt = 0;
Mob* c = nullptr;
Mob* m = nullptr;
Group* g = nullptr;
Raid* r = nullptr;
auto iterator = list.begin();
while (iterator != list.end())
{
grp = nullptr;
uint64 damage = 0;
for (const auto& e : list) {
c = e->entity_on_hatelist;
if (!c) {
continue;
}
g = nullptr;
r = nullptr;
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient()){
r = entity_list.GetRaidByClient((*iterator)->entity_on_hatelist->CastToClient());
if (c->IsBot()) {
r = entity_list.GetRaidByBot(c->CastToBot());
} else if (c->IsClient()) {
r = entity_list.GetRaidByClient(c->CastToClient());
}
grp = entity_list.GetGroupByMob((*iterator)->entity_on_hatelist);
g = entity_list.GetGroupByMob(c);
if ((*iterator)->entity_on_hatelist && r){
if (r->GetTotalRaidDamage(hater) >= dmg_amt)
{
current = (*iterator)->entity_on_hatelist;
dmg_amt = r->GetTotalRaidDamage(hater);
if (r) {
if (r->GetTotalRaidDamage(hater) >= damage) {
m = c;
damage = r->GetTotalRaidDamage(hater);
}
}
else if ((*iterator)->entity_on_hatelist != nullptr && grp != nullptr)
{
if (grp->GetTotalGroupDamage(hater) >= dmg_amt)
{
current = (*iterator)->entity_on_hatelist;
dmg_amt = grp->GetTotalGroupDamage(hater);
} else if (g) {
if (g->GetTotalGroupDamage(hater) >= damage) {
m = c;
damage = g->GetTotalGroupDamage(hater);
}
} else if (static_cast<uint64>(e->hatelist_damage) >= damage) {
m = c;
damage = static_cast<uint64>(e->hatelist_damage);
}
else if ((*iterator)->entity_on_hatelist != nullptr && (uint64)(*iterator)->hatelist_damage >= dmg_amt)
{
current = (*iterator)->entity_on_hatelist;
dmg_amt = (*iterator)->hatelist_damage;
}
++iterator;
}
return current;
return m;
}
Mob* HateList::GetClosestEntOnHateList(Mob *hater, bool skip_mezzed, EntityFilterType filter_type) {
+29 -1
View File
@@ -601,7 +601,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
inst->SetOrnamentHeroModel(ornament_hero_model);
// check to see if item is usable in requested slot
if (enforce_usable && (to_slot >= EQ::invslot::EQUIPMENT_BEGIN && to_slot <= EQ::invslot::EQUIPMENT_END)) {
if (enforce_usable && to_slot != EQ::invslot::SLOT_QUEST && (to_slot >= EQ::invslot::EQUIPMENT_BEGIN && to_slot <= EQ::invslot::EQUIPMENT_END)) {
uint32 slottest = to_slot;
if(!(slots & ((uint32)1 << slottest))) {
Message(
@@ -648,6 +648,34 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
RecordPlayerEventLog(PlayerEvent::ITEM_CREATION, e);
}
//We're coming from a quest method.
if (to_slot == EQ::invslot::SLOT_QUEST) {
bool stacking = TryStacking(inst);
if (stacking) {
safe_delete(inst);
return true;
}
else {
bool bag = false;
if (inst->IsClassBag()) {
bag = true;
}
to_slot = m_inv.FindFreeSlot(bag, true, item->Size);
//make sure we are not completely full...
if (to_slot == EQ::invslot::slotCursor || to_slot == INVALID_INDEX) {
if (inst->GetItem()->NoDrop == 0) {
//If it's no drop, force it to the cursor. This carries the risk of deletion if the player already has this item on their cursor
// or if the cursor queue is full. But in this situation, we have little other recourse.
PushItemOnCursor(*inst);
LogInventory("{} has a full inventory and {} is a no drop item. Forcing to cursor", GetName(), inst->GetItem()->Name);
safe_delete(inst);
}
}
}
}
// put item into inventory
if (to_slot == EQ::invslot::slotCursor) {
+378 -3
View File
@@ -285,6 +285,8 @@ void NPC::AddLootDrop(
const EQ::ItemData *item2,
LootdropEntriesRepository::LootdropEntries loot_drop,
bool wear_change,
bool quest,
bool pet,
uint32 augment_one,
uint32 augment_two,
uint32 augment_three,
@@ -297,6 +299,10 @@ void NPC::AddLootDrop(
return;
}
if (CountQuestItems() >= MAX_NPC_QUEST_INVENTORY) {
return;
}
auto item = new LootItem;
if (LogSys.log_settings[Logs::Loot].is_category_enabled == 1) {
@@ -318,6 +324,10 @@ void NPC::AddLootDrop(
);
}
if (quest || pet) {
LogLoot("Adding {} to npc: {}. Wearchange: {} Multiquest: {} Pet: {}", item2->Name, GetName(), wear_change, quest, pet);
}
EQApplicationPacket *outapp = nullptr;
WearChange_Struct *p_wear_change_struct = nullptr;
if (wear_change) {
@@ -339,6 +349,8 @@ void NPC::AddLootDrop(
item->trivial_min_level = loot_drop.trivial_min_level;
item->trivial_max_level = loot_drop.trivial_max_level;
item->equip_slot = EQ::invslot::SLOT_INVALID;
item->quest = quest;
item->pet = pet;
// unsure if required to equip, YOLO for now
if (item2->ItemType == EQ::item::ItemTypeBow) {
@@ -349,6 +361,11 @@ void NPC::AddLootDrop(
SetArrowEquipped(true);
}
if (pet && quest) {
LogLoot("Error: Item {} is being added to {} as both a pet and a quest.", item2->Name, GetName());
item->pet = 0;
}
bool found = false; // track if we found an empty slot we fit into
int found_slot = INVALID_INDEX; // for multi-slot items
@@ -541,20 +558,21 @@ void NPC::AddLootDrop(
safe_delete(inst);
}
void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item)
void NPC::AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item, bool quest)
{
auto l = LootdropEntriesRepository::NewNpcEntity();
l.equip_item = static_cast<uint8>(equip_item ? 1 : 0);
l.item_charges = charges;
AddLootDrop(item, l, true);
AddLootDrop(item, l, equip_item, quest);
}
void NPC::AddItem(
uint32 item_id,
uint16 charges,
bool equip_item,
bool quest,
uint32 augment_one,
uint32 augment_two,
uint32 augment_three,
@@ -576,7 +594,8 @@ void NPC::AddItem(
AddLootDrop(
item,
l,
true,
equip_item,
quest,
augment_one,
augment_two,
augment_three,
@@ -695,6 +714,50 @@ LootItem *NPC::GetItem(int slot_id)
return (nullptr);
}
LootItem *NPC::GetItemByItemID(int16 item_id)
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *item = *cur;
if (item->item_id == item_id) {
return item;
}
}
return(nullptr);
}
void NPC::RemoveItem(LootItem *item_data, uint8 quantity) {
if (!item_data) {
return;
}
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *item = *cur;
if (item != item_data) { continue; }
if (!item) {
return;
}
if (item->charges <= quantity) {
m_loot_items.erase(cur);
UpdateEquipmentLight();
if (UpdateActiveLight()) { SendAppearancePacket(AppearanceType::Light, GetActiveLightType()); }
}
else {
item->charges -= quantity;
}
return;
}
}
void NPC::RemoveItem(uint32 item_id, uint16 quantity, uint16 slot)
{
LootItems::iterator cur, end;
@@ -941,3 +1004,315 @@ void NPC::RemoveLootCash()
m_loot_gold = 0;
m_loot_platinum = 0;
}
bool NPC::HasQuestLootItem(int16 itemid)
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *quest_item = *cur;
if (quest_item && quest_item->quest == 1 && quest_item->item_id == itemid) {
return true;
}
}
return false;
}
bool NPC::HasQuestLoot()
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *quest_loot = *cur;
if (quest_loot && quest_loot->quest == 1) {
return true;
}
}
return false;
}
bool NPC::RemoveQuestLootItems(int16 itemid)
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *quest_item = *cur;
if (quest_item && quest_item->quest == 1) {
if (itemid == 0 || itemid == quest_item->item_id) {
RemoveItem(quest_item);
return true;
}
}
}
return false;
}
bool NPC::HasRequiredQuestLoot(int16 itemid1, int16 itemid2, int16 itemid3, int16 itemid4)
{
if (itemid2 == 0 && itemid3 == 0 && itemid4 == 0) {
return true;
}
uint8 item2count = 0, item3count = 0, item4count = 0, item1npc = 0, item2npc = 0, item3npc = 0, item4npc = 0;
uint8 item1count = 1;
if (itemid2 > 0) {
item2count = 1;
}
if (itemid3 > 0) {
item3count = 1;
}
if (itemid4 > 0) {
item4count = 1;
}
if (itemid1 == itemid2 && itemid2 > 0) {
item2count = item1count;
++item1count;
++item2count;
}
if (itemid1 == itemid3 && itemid3 > 0) {
item3count = item1count;
++item1count;
++item3count;
}
if (itemid1 == itemid4 && itemid4 > 0) {
item4count = item1count;
++item1count;
++item4count;
}
if (itemid2 == itemid3 && itemid2 > 0 && itemid3 > 0) {
item3count = item2count;
++item2count;
++item3count;
}
if (itemid2 == itemid4 && itemid2 > 0 && itemid4 > 0) {
item4count = item2count;
++item2count;
++item4count;
}
if (itemid3 == itemid4 && itemid3 > 0 && itemid4 > 0) {
item4count = item3count;
++item3count;
++item4count;
}
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *sitem = *cur;
if (sitem && sitem->quest == 1) {
if (sitem->item_id == itemid1) {
++item1npc;
}
if (sitem->item_id == itemid2 && itemid2 > 0) {
++item2npc;
}
if (sitem->item_id == itemid3 && itemid3 > 0) {
++item3npc;
}
if (sitem->item_id == itemid4 && itemid4 > 0) {
++item4npc;
}
}
}
if (item1npc < item1count) {
return false;
}
if (itemid2 > 0 && item2npc < item2count) {
return false;
}
if (itemid3 > 0 && item3npc < item3count) {
return false;
}
if (itemid4 > 0 && item4npc < item4count) {
return false;
}
return true;
}
void NPC::CleanQuestLootItems()
{
//Removes nodrop or multiple quest loot items from a NPC before sending the corpse items to the client.
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
uint8 count = 0;
for (; cur != end; ++cur) {
LootItem *quest_item = *cur;
if (quest_item && (quest_item->quest == 1 || quest_item->pet == 1)) {
uint8 count = CountQuestItem(quest_item->item_id);
if (count > 1 && quest_item->pet != 1) {
RemoveItem(quest_item);
return;
}
else {
const EQ::ItemData *item = database.GetItem(quest_item->item_id);
if (item && item->NoDrop == 0) {
RemoveItem(quest_item);
return;
}
}
}
}
}
uint8 NPC::CountQuestItem(uint16 itemid)
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
uint8 count = 0;
for (; cur != end; ++cur) {
LootItem *quest_item = *cur;
if (quest_item && quest_item->item_id == itemid) {
++count;
}
}
return count;
}
uint8 NPC::CountQuestItems()
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
uint8 count = 0;
for (; cur != end; ++cur) {
LootItem *quest_item = *cur;
if (quest_item && quest_item->quest == 1) {
++count;
}
}
return count;
}
bool NPC::AddQuestLoot(int16 itemid, int8 charges) {
auto l = LootdropEntriesRepository::NewNpcEntity();
const EQ::ItemData *item = database.GetItem(itemid);
if (item) {
l.item_charges = charges;
l.equip_item = 0;
AddLootDrop(item, l, false, false, true);
LogLoot("Adding item {} to the NPC's loot marked as quest.", itemid);
if (itemid > 0 && HasPetLootItem(itemid)) {
LogLoot("Deleting quest item {} from NPC's pet loot.", itemid);
RemovePetLootItems(itemid);
}
}
else
return false;
return true;
}
void NPC::DeleteQuestLoot(int16 itemid1, int16 itemid2, int16 itemid3, int16 itemid4)
{
int16 items = m_loot_items.size();
for (int i = 0; i < items; ++i) {
if (itemid1 == 0) {
if (!RemoveQuestLootItems(itemid1))
break;
}
else {
if (itemid1 != 0) {
RemoveQuestLootItems(itemid1);
}
if (itemid2 != 0) {
RemoveQuestLootItems(itemid2);
}
if (itemid3 != 0) {
RemoveQuestLootItems(itemid3);
}
if (itemid4 != 0) {
RemoveQuestLootItems(itemid4);
}
}
}
}
void NPC::DeleteInvalidQuestLoot()
{
int16 items = m_loot_items.size();
for (int i = 0; i < items; ++i) {
CleanQuestLootItems();
}
}
bool NPC::AddPetLoot(int16 itemid, int8 charges, bool fromquest) {
auto l = LootdropEntriesRepository::NewNpcEntity();
const EQ::ItemData *item = database.GetItem(itemid);
bool IsCharmedPet = IsPet() && IsCharmed();
if (!item) {
return false;
}
bool valid = (item->NoDrop != 0 && ( !IsCharmedPet || (IsCharmedPet && CountQuestItem(item->ID) == 0)));
if (!fromquest || valid) {
if (item) {
l.item_charges = charges;
AddLootDrop(item, l, true, true, false, true);
LogLoot("Adding item {} to the NPC's loot marked as pet.", itemid);
return true;
}
}
else {
LogLoot("Item {} is a duplicate or no drop. Deleting...", itemid);
return false;
}
return false;
}
bool NPC::HasPetLootItem(int16 itemid)
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *quest_item = *cur;
if (quest_item && quest_item->pet == 1 && quest_item->item_id == itemid) {
return true;
}
}
return false;
}
bool NPC::RemovePetLootItems(int16 itemid)
{
LootItems::iterator cur, end;
cur = m_loot_items.begin();
end = m_loot_items.end();
for (; cur != end; ++cur) {
LootItem *quest_item = *cur;
if (quest_item && quest_item->pet == 1) {
if (itemid == 0 || itemid == quest_item->item_id) {
RemoveItem(quest_item);
return true;
}
}
}
return false;
}
+22 -10
View File
@@ -150,12 +150,17 @@ void Lua_Client::SetBaseGender(int v) {
self->SetBaseGender(v);
}
int Lua_Client::GetClassBitmask() {
uint16 Lua_Client::GetClassBitmask() {
Lua_Safe_Call_Int();
return GetPlayerClassBit(self->GetClass());
}
int Lua_Client::GetRaceBitmask() {
uint32 Lua_Client::GetDeityBitmask() {
Lua_Safe_Call_Int();
return static_cast<uint32>(EQ::deity::GetDeityBitmask(static_cast<EQ::deity::DeityType>(GetDeity())));
}
uint16 Lua_Client::GetRaceBitmask() {
Lua_Safe_Call_Int();
return GetPlayerRaceBit(self->GetBaseRace());
}
@@ -950,14 +955,19 @@ void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5);
}
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned) {
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6) {
Lua_Safe_Call_Void();
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5, 0, attuned);
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5, aug6);
}
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, int to_slot) {
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6, bool attuned) {
Lua_Safe_Call_Void();
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5, 0, attuned, to_slot);
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5, aug6, 0, attuned);
}
void Lua_Client::SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6, bool attuned, int to_slot) {
Lua_Safe_Call_Void();
self->SummonItem(item_id, charges, aug1, aug2, aug3, aug4, aug5, aug6, 0, attuned, to_slot);
}
void Lua_Client::SetStats(int type, int value) {
@@ -3507,13 +3517,14 @@ luabind::scope lua_register_client() {
.def("GetCarriedPlatinum", (uint32(Lua_Client::*)(void))&Lua_Client::GetCarriedPlatinum)
.def("GetCharacterFactionLevel", (int(Lua_Client::*)(int))&Lua_Client::GetCharacterFactionLevel)
.def("GetClassAbbreviation", (std::string(Lua_Client::*)(void))&Lua_Client::GetClassAbbreviation)
.def("GetClassBitmask", (int(Lua_Client::*)(void))&Lua_Client::GetClassBitmask)
.def("GetClassBitmask", (uint16(Lua_Client::*)(void))&Lua_Client::GetClassBitmask)
.def("GetClientMaxLevel", (int(Lua_Client::*)(void))&Lua_Client::GetClientMaxLevel)
.def("GetClientVersion", (int(Lua_Client::*)(void))&Lua_Client::GetClientVersion)
.def("GetClientVersionBit", (uint32(Lua_Client::*)(void))&Lua_Client::GetClientVersionBit)
.def("GetCorpseCount", (int64(Lua_Client::*)(void))&Lua_Client::GetCorpseCount)
.def("GetCorpseID", (int(Lua_Client::*)(int))&Lua_Client::GetCorpseID)
.def("GetCorpseItemAt", (int(Lua_Client::*)(int,int))&Lua_Client::GetCorpseItemAt)
.def("GetDeityBitmask", (uint32(Lua_Client::*)(void))&Lua_Client::GetDeityBitmask)
.def("GetDiscSlotBySpellID", (int(Lua_Client::*)(int32))&Lua_Client::GetDiscSlotBySpellID)
.def("GetDisciplineTimer", (uint32(Lua_Client::*)(uint32))&Lua_Client::GetDisciplineTimer)
.def("GetDuelTarget", (int(Lua_Client::*)(void))&Lua_Client::GetDuelTarget)
@@ -3571,7 +3582,7 @@ luabind::scope lua_register_client() {
.def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(void))&Lua_Client::GetNextAvailableSpellBookSlot)
.def("GetPVP", (bool(Lua_Client::*)(void))&Lua_Client::GetPVP)
.def("GetPVPPoints", (uint32(Lua_Client::*)(void))&Lua_Client::GetPVPPoints)
.def("GetRaceBitmask", (int(Lua_Client::*)(void))&Lua_Client::GetRaceBitmask)
.def("GetRaceBitmask", (uint16(Lua_Client::*)(void))&Lua_Client::GetRaceBitmask)
.def("GetRadiantCrystals", (uint32(Lua_Client::*)(void))&Lua_Client::GetRadiantCrystals)
.def("GetRaid", (Lua_Raid(Lua_Client::*)(void))&Lua_Client::GetRaid)
.def("GetRaidOrGroupOrSelf", (luabind::object(Lua_Client::*)(lua_State*))&Lua_Client::GetRaidOrGroupOrSelf)
@@ -3857,8 +3868,9 @@ luabind::scope lua_register_client() {
.def("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,uint32,uint32))&Lua_Client::SummonItem)
.def("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,uint32,uint32,uint32))&Lua_Client::SummonItem)
.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("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,uint32,uint32,uint32,uint32,uint32))&Lua_Client::SummonItem)
.def("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,uint32,uint32,uint32,uint32,uint32,bool))&Lua_Client::SummonItem)
.def("SummonItem", (void(Lua_Client::*)(uint32,int,uint32,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)
+6 -4
View File
@@ -57,8 +57,9 @@ public:
void SetBaseClass(int v);
void SetBaseRace(int v);
void SetBaseGender(int v);
int GetClassBitmask();
int GetRaceBitmask();
uint16 GetClassBitmask();
uint32 GetDeityBitmask();
uint16 GetRaceBitmask();
int GetBaseFace();
int GetLanguageSkill(int skill_id);
int GetLDoNPointsTheme(int theme);
@@ -250,9 +251,10 @@ public:
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3);
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4);
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5);
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5,
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6);
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6,
bool attuned);
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5,
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6,
bool attuned, int to_slot);
void SummonBaggedItems(uint32 bag_item_id, luabind::adl::object bag_items_table);
void SetStats(int type, int value);
+541
View File
@@ -41,6 +41,8 @@ struct MessageTypes { };
struct Rule { };
struct Journal_SpeakMode { };
struct Journal_Mode { };
struct ZoneIDs { };
struct LanguageIDs { };
struct lua_registered_event {
std::string encounter_name;
@@ -5474,6 +5476,18 @@ std::string lua_silent_say_link(std::string text, std::string link_name) {
return Saylink::Silent(text, link_name);
}
uint16 lua_get_class_bitmask(uint8 class_id) {
return GetPlayerClassBit(class_id);
}
uint32 lua_get_deity_bitmask(uint16 deity_id) {
return static_cast<uint32>(EQ::deity::GetDeityBitmask(static_cast<EQ::deity::DeityType>(deity_id)));
}
uint16 lua_get_race_bitmask(uint16 race_id) {
return GetPlayerRaceBit(race_id);
}
#define LuaCreateNPCParse(name, c_type, default_value) do { \
cur = table[#name]; \
if(luabind::type(cur) != LUA_TNIL) { \
@@ -6270,6 +6284,9 @@ luabind::scope lua_register_general() {
luabind::def("get_bot_race_by_id", &lua_get_bot_race_by_id),
luabind::def("silent_say_link", (std::string(*)(std::string))&lua_silent_say_link),
luabind::def("silent_say_link", (std::string(*)(std::string,std::string))&lua_silent_say_link),
luabind::def("get_class_bitmask", &lua_get_class_bitmask),
luabind::def("get_deity_bitmask", &lua_get_deity_bitmask),
luabind::def("get_race_bitmask", &lua_get_race_bitmask),
/*
Cross Zone
*/
@@ -7233,6 +7250,530 @@ luabind::scope lua_register_message_types() {
)];
}
luabind::scope lua_register_zone_types() {
return luabind::class_<ZoneIDs>("Zone")
.enum_("constants")
[(
luabind::value("qeynos", Zones::QEYNOS),
luabind::value("qeynos2", Zones::QEYNOS2),
luabind::value("qrg", Zones::QRG),
luabind::value("qeytoqrg", Zones::QEYTOQRG),
luabind::value("highpass", Zones::HIGHPASS),
luabind::value("highkeep", Zones::HIGHKEEP),
luabind::value("freportn", Zones::FREPORTN),
luabind::value("freportw", Zones::FREPORTW),
luabind::value("freporte", Zones::FREPORTE),
luabind::value("runnyeye", Zones::RUNNYEYE),
luabind::value("qey2hh1", Zones::QEY2HH1),
luabind::value("northkarana", Zones::NORTHKARANA),
luabind::value("southkarana", Zones::SOUTHKARANA),
luabind::value("eastkarana", Zones::EASTKARANA),
luabind::value("beholder", Zones::BEHOLDER),
luabind::value("blackburrow", Zones::BLACKBURROW),
luabind::value("paw", Zones::PAW),
luabind::value("rivervale", Zones::RIVERVALE),
luabind::value("kithicor", Zones::KITHICOR),
luabind::value("commons", Zones::COMMONS),
luabind::value("ecommons", Zones::ECOMMONS),
luabind::value("erudnint", Zones::ERUDNINT),
luabind::value("erudnext", Zones::ERUDNEXT),
luabind::value("nektulos", Zones::NEKTULOS),
luabind::value("cshome", Zones::CSHOME),
luabind::value("lavastorm", Zones::LAVASTORM),
luabind::value("nektropos", Zones::NEKTROPOS),
luabind::value("halas", Zones::HALAS),
luabind::value("everfrost", Zones::EVERFROST),
luabind::value("soldunga", Zones::SOLDUNGA),
luabind::value("soldungb", Zones::SOLDUNGB),
luabind::value("misty", Zones::MISTY),
luabind::value("nro", Zones::NRO),
luabind::value("sro", Zones::SRO),
luabind::value("befallen", Zones::BEFALLEN),
luabind::value("oasis", Zones::OASIS),
luabind::value("tox", Zones::TOX),
luabind::value("hole", Zones::HOLE),
luabind::value("neriaka", Zones::NERIAKA),
luabind::value("neriakb", Zones::NERIAKB),
luabind::value("neriakc", Zones::NERIAKC),
luabind::value("neriakd", Zones::NERIAKD),
luabind::value("najena", Zones::NAJENA),
luabind::value("qcat", Zones::QCAT),
luabind::value("innothule", Zones::INNOTHULE),
luabind::value("feerrott", Zones::FEERROTT),
luabind::value("cazicthule", Zones::CAZICTHULE),
luabind::value("oggok", Zones::OGGOK),
luabind::value("rathemtn", Zones::RATHEMTN),
luabind::value("lakerathe", Zones::LAKERATHE),
luabind::value("grobb", Zones::GROBB),
luabind::value("aviak", Zones::AVIAK),
luabind::value("gfaydark", Zones::GFAYDARK),
luabind::value("akanon", Zones::AKANON),
luabind::value("steamfont", Zones::STEAMFONT),
luabind::value("lfaydark", Zones::LFAYDARK),
luabind::value("crushbone", Zones::CRUSHBONE),
luabind::value("mistmoore", Zones::MISTMOORE),
luabind::value("kaladima", Zones::KALADIMA),
luabind::value("felwithea", Zones::FELWITHEA),
luabind::value("felwitheb", Zones::FELWITHEB),
luabind::value("unrest", Zones::UNREST),
luabind::value("kedge", Zones::KEDGE),
luabind::value("guktop", Zones::GUKTOP),
luabind::value("gukbottom", Zones::GUKBOTTOM),
luabind::value("kaladimb", Zones::KALADIMB),
luabind::value("butcher", Zones::BUTCHER),
luabind::value("oot", Zones::OOT),
luabind::value("cauldron", Zones::CAULDRON),
luabind::value("airplane", Zones::AIRPLANE),
luabind::value("fearplane", Zones::FEARPLANE),
luabind::value("permafrost", Zones::PERMAFROST),
luabind::value("kerraridge", Zones::KERRARIDGE),
luabind::value("paineel", Zones::PAINEEL),
luabind::value("hateplane", Zones::HATEPLANE),
luabind::value("arena", Zones::ARENA),
luabind::value("fieldofbone", Zones::FIELDOFBONE),
luabind::value("warslikswood", Zones::WARSLIKSWOOD),
luabind::value("soltemple", Zones::SOLTEMPLE),
luabind::value("droga", Zones::DROGA),
luabind::value("cabwest", Zones::CABWEST),
luabind::value("swampofnohope", Zones::SWAMPOFNOHOPE),
luabind::value("firiona", Zones::FIRIONA),
luabind::value("lakeofillomen", Zones::LAKEOFILLOMEN),
luabind::value("dreadlands", Zones::DREADLANDS),
luabind::value("burningwood", Zones::BURNINGWOOD),
luabind::value("kaesora", Zones::KAESORA),
luabind::value("sebilis", Zones::SEBILIS),
luabind::value("citymist", Zones::CITYMIST),
luabind::value("skyfire", Zones::SKYFIRE),
luabind::value("frontiermtns", Zones::FRONTIERMTNS),
luabind::value("overthere", Zones::OVERTHERE),
luabind::value("emeraldjungle", Zones::EMERALDJUNGLE),
luabind::value("trakanon", Zones::TRAKANON),
luabind::value("timorous", Zones::TIMOROUS),
luabind::value("kurn", Zones::KURN),
luabind::value("erudsxing", Zones::ERUDSXING),
luabind::value("stonebrunt", Zones::STONEBRUNT),
luabind::value("warrens", Zones::WARRENS),
luabind::value("karnor", Zones::KARNOR),
luabind::value("chardok", Zones::CHARDOK),
luabind::value("dalnir", Zones::DALNIR),
luabind::value("charasis", Zones::CHARASIS),
luabind::value("cabeast", Zones::CABEAST),
luabind::value("nurga", Zones::NURGA),
luabind::value("veeshan", Zones::VEESHAN),
luabind::value("veksar", Zones::VEKSAR),
luabind::value("iceclad", Zones::ICECLAD),
luabind::value("frozenshadow", Zones::FROZENSHADOW),
luabind::value("velketor", Zones::VELKETOR),
luabind::value("kael", Zones::KAEL),
luabind::value("skyshrine", Zones::SKYSHRINE),
luabind::value("thurgadina", Zones::THURGADINA),
luabind::value("eastwastes", Zones::EASTWASTES),
luabind::value("cobaltscar", Zones::COBALTSCAR),
luabind::value("greatdivide", Zones::GREATDIVIDE),
luabind::value("wakening", Zones::WAKENING),
luabind::value("westwastes", Zones::WESTWASTES),
luabind::value("crystal", Zones::CRYSTAL),
luabind::value("necropolis", Zones::NECROPOLIS),
luabind::value("templeveeshan", Zones::TEMPLEVEESHAN),
luabind::value("sirens", Zones::SIRENS),
luabind::value("mischiefplane", Zones::MISCHIEFPLANE),
luabind::value("growthplane", Zones::GROWTHPLANE),
luabind::value("sleeper", Zones::SLEEPER),
luabind::value("thurgadinb", Zones::THURGADINB),
luabind::value("erudsxing2", Zones::ERUDSXING2),
luabind::value("shadowhaven", Zones::SHADOWHAVEN),
luabind::value("bazaar", Zones::BAZAAR),
luabind::value("nexus", Zones::NEXUS),
luabind::value("echo_", Zones::ECHO_),
luabind::value("acrylia", Zones::ACRYLIA),
luabind::value("sharvahl", Zones::SHARVAHL),
luabind::value("paludal", Zones::PALUDAL),
luabind::value("fungusgrove", Zones::FUNGUSGROVE),
luabind::value("vexthal", Zones::VEXTHAL),
luabind::value("sseru", Zones::SSERU),
luabind::value("katta", Zones::KATTA),
luabind::value("netherbian", Zones::NETHERBIAN),
luabind::value("ssratemple", Zones::SSRATEMPLE),
luabind::value("griegsend", Zones::GRIEGSEND),
luabind::value("thedeep", Zones::THEDEEP),
luabind::value("shadeweaver", Zones::SHADEWEAVER),
luabind::value("hollowshade", Zones::HOLLOWSHADE),
luabind::value("grimling", Zones::GRIMLING),
luabind::value("mseru", Zones::MSERU),
luabind::value("letalis", Zones::LETALIS),
luabind::value("twilight", Zones::TWILIGHT),
luabind::value("thegrey", Zones::THEGREY),
luabind::value("tenebrous", Zones::TENEBROUS),
luabind::value("maiden", Zones::MAIDEN),
luabind::value("dawnshroud", Zones::DAWNSHROUD),
luabind::value("scarlet", Zones::SCARLET),
luabind::value("umbral", Zones::UMBRAL),
luabind::value("akheva", Zones::AKHEVA),
luabind::value("arena2", Zones::ARENA2),
luabind::value("jaggedpine", Zones::JAGGEDPINE),
luabind::value("nedaria", Zones::NEDARIA),
luabind::value("tutorial", Zones::TUTORIAL),
luabind::value("load", Zones::LOAD),
luabind::value("load2", Zones::LOAD2),
luabind::value("hateplaneb", Zones::HATEPLANEB),
luabind::value("shadowrest", Zones::SHADOWREST),
luabind::value("tutoriala", Zones::TUTORIALA),
luabind::value("tutorialb", Zones::TUTORIALB),
luabind::value("clz", Zones::CLZ),
luabind::value("codecay", Zones::CODECAY),
luabind::value("pojustice", Zones::POJUSTICE),
luabind::value("poknowledge", Zones::POKNOWLEDGE),
luabind::value("potranquility", Zones::POTRANQUILITY),
luabind::value("ponightmare", Zones::PONIGHTMARE),
luabind::value("podisease", Zones::PODISEASE),
luabind::value("poinnovation", Zones::POINNOVATION),
luabind::value("potorment", Zones::POTORMENT),
luabind::value("povalor", Zones::POVALOR),
luabind::value("bothunder", Zones::BOTHUNDER),
luabind::value("postorms", Zones::POSTORMS),
luabind::value("hohonora", Zones::HOHONORA),
luabind::value("solrotower", Zones::SOLROTOWER),
luabind::value("powar", Zones::POWAR),
luabind::value("potactics", Zones::POTACTICS),
luabind::value("poair", Zones::POAIR),
luabind::value("powater", Zones::POWATER),
luabind::value("pofire", Zones::POFIRE),
luabind::value("poeartha", Zones::POEARTHA),
luabind::value("potimea", Zones::POTIMEA),
luabind::value("hohonorb", Zones::HOHONORB),
luabind::value("nightmareb", Zones::NIGHTMAREB),
luabind::value("poearthb", Zones::POEARTHB),
luabind::value("potimeb", Zones::POTIMEB),
luabind::value("gunthak", Zones::GUNTHAK),
luabind::value("dulak", Zones::DULAK),
luabind::value("torgiran", Zones::TORGIRAN),
luabind::value("nadox", Zones::NADOX),
luabind::value("hatesfury", Zones::HATESFURY),
luabind::value("guka", Zones::GUKA),
luabind::value("ruja", Zones::RUJA),
luabind::value("taka", Zones::TAKA),
luabind::value("mira", Zones::MIRA),
luabind::value("mmca", Zones::MMCA),
luabind::value("gukb", Zones::GUKB),
luabind::value("rujb", Zones::RUJB),
luabind::value("takb", Zones::TAKB),
luabind::value("mirb", Zones::MIRB),
luabind::value("mmcb", Zones::MMCB),
luabind::value("gukc", Zones::GUKC),
luabind::value("rujc", Zones::RUJC),
luabind::value("takc", Zones::TAKC),
luabind::value("mirc", Zones::MIRC),
luabind::value("mmcc", Zones::MMCC),
luabind::value("gukd", Zones::GUKD),
luabind::value("rujd", Zones::RUJD),
luabind::value("takd", Zones::TAKD),
luabind::value("mird", Zones::MIRD),
luabind::value("mmcd", Zones::MMCD),
luabind::value("guke", Zones::GUKE),
luabind::value("ruje", Zones::RUJE),
luabind::value("take", Zones::TAKE),
luabind::value("mire", Zones::MIRE),
luabind::value("mmce", Zones::MMCE),
luabind::value("gukf", Zones::GUKF),
luabind::value("rujf", Zones::RUJF),
luabind::value("takf", Zones::TAKF),
luabind::value("mirf", Zones::MIRF),
luabind::value("mmcf", Zones::MMCF),
luabind::value("gukg", Zones::GUKG),
luabind::value("rujg", Zones::RUJG),
luabind::value("takg", Zones::TAKG),
luabind::value("mirg", Zones::MIRG),
luabind::value("mmcg", Zones::MMCG),
luabind::value("gukh", Zones::GUKH),
luabind::value("rujh", Zones::RUJH),
luabind::value("takh", Zones::TAKH),
luabind::value("mirh", Zones::MIRH),
luabind::value("mmch", Zones::MMCH),
luabind::value("ruji", Zones::RUJI),
luabind::value("taki", Zones::TAKI),
luabind::value("miri", Zones::MIRI),
luabind::value("mmci", Zones::MMCI),
luabind::value("rujj", Zones::RUJJ),
luabind::value("takj", Zones::TAKJ),
luabind::value("mirj", Zones::MIRJ),
luabind::value("mmcj", Zones::MMCJ),
luabind::value("chardokb", Zones::CHARDOKB),
luabind::value("soldungc", Zones::SOLDUNGC),
luabind::value("abysmal", Zones::ABYSMAL),
luabind::value("natimbi", Zones::NATIMBI),
luabind::value("qinimi", Zones::QINIMI),
luabind::value("riwwi", Zones::RIWWI),
luabind::value("barindu", Zones::BARINDU),
luabind::value("ferubi", Zones::FERUBI),
luabind::value("snpool", Zones::SNPOOL),
luabind::value("snlair", Zones::SNLAIR),
luabind::value("snplant", Zones::SNPLANT),
luabind::value("sncrematory", Zones::SNCREMATORY),
luabind::value("tipt", Zones::TIPT),
luabind::value("vxed", Zones::VXED),
luabind::value("yxtta", Zones::YXTTA),
luabind::value("uqua", Zones::UQUA),
luabind::value("kodtaz", Zones::KODTAZ),
luabind::value("ikkinz", Zones::IKKINZ),
luabind::value("qvic", Zones::QVIC),
luabind::value("inktuta", Zones::INKTUTA),
luabind::value("txevu", Zones::TXEVU),
luabind::value("tacvi", Zones::TACVI),
luabind::value("qvicb", Zones::QVICB),
luabind::value("wallofslaughter", Zones::WALLOFSLAUGHTER),
luabind::value("bloodfields", Zones::BLOODFIELDS),
luabind::value("draniksscar", Zones::DRANIKSSCAR),
luabind::value("causeway", Zones::CAUSEWAY),
luabind::value("chambersa", Zones::CHAMBERSA),
luabind::value("chambersb", Zones::CHAMBERSB),
luabind::value("chambersc", Zones::CHAMBERSC),
luabind::value("chambersd", Zones::CHAMBERSD),
luabind::value("chamberse", Zones::CHAMBERSE),
luabind::value("chambersf", Zones::CHAMBERSF),
luabind::value("provinggrounds", Zones::PROVINGGROUNDS),
luabind::value("anguish", Zones::ANGUISH),
luabind::value("dranikhollowsa", Zones::DRANIKHOLLOWSA),
luabind::value("dranikhollowsb", Zones::DRANIKHOLLOWSB),
luabind::value("dranikhollowsc", Zones::DRANIKHOLLOWSC),
luabind::value("dranikcatacombsa", Zones::DRANIKCATACOMBSA),
luabind::value("dranikcatacombsb", Zones::DRANIKCATACOMBSB),
luabind::value("dranikcatacombsc", Zones::DRANIKCATACOMBSC),
luabind::value("draniksewersa", Zones::DRANIKSEWERSA),
luabind::value("draniksewersb", Zones::DRANIKSEWERSB),
luabind::value("draniksewersc", Zones::DRANIKSEWERSC),
luabind::value("riftseekers", Zones::RIFTSEEKERS),
luabind::value("harbingers", Zones::HARBINGERS),
luabind::value("dranik", Zones::DRANIK),
luabind::value("broodlands", Zones::BROODLANDS),
luabind::value("stillmoona", Zones::STILLMOONA),
luabind::value("stillmoonb", Zones::STILLMOONB),
luabind::value("thundercrest", Zones::THUNDERCREST),
luabind::value("delvea", Zones::DELVEA),
luabind::value("delveb", Zones::DELVEB),
luabind::value("thenest", Zones::THENEST),
luabind::value("guildlobby", Zones::GUILDLOBBY),
luabind::value("guildhall", Zones::GUILDHALL),
luabind::value("barter", Zones::BARTER),
luabind::value("illsalin", Zones::ILLSALIN),
luabind::value("illsalina", Zones::ILLSALINA),
luabind::value("illsalinb", Zones::ILLSALINB),
luabind::value("illsalinc", Zones::ILLSALINC),
luabind::value("dreadspire", Zones::DREADSPIRE),
luabind::value("drachnidhive", Zones::DRACHNIDHIVE),
luabind::value("drachnidhivea", Zones::DRACHNIDHIVEA),
luabind::value("drachnidhiveb", Zones::DRACHNIDHIVEB),
luabind::value("drachnidhivec", Zones::DRACHNIDHIVEC),
luabind::value("westkorlach", Zones::WESTKORLACH),
luabind::value("westkorlacha", Zones::WESTKORLACHA),
luabind::value("westkorlachb", Zones::WESTKORLACHB),
luabind::value("westkorlachc", Zones::WESTKORLACHC),
luabind::value("eastkorlach", Zones::EASTKORLACH),
luabind::value("eastkorlacha", Zones::EASTKORLACHA),
luabind::value("shadowspine", Zones::SHADOWSPINE),
luabind::value("corathus", Zones::CORATHUS),
luabind::value("corathusa", Zones::CORATHUSA),
luabind::value("corathusb", Zones::CORATHUSB),
luabind::value("nektulosa", Zones::NEKTULOSA),
luabind::value("arcstone", Zones::ARCSTONE),
luabind::value("relic", Zones::RELIC),
luabind::value("skylance", Zones::SKYLANCE),
luabind::value("devastation", Zones::DEVASTATION),
luabind::value("devastationa", Zones::DEVASTATIONA),
luabind::value("rage", Zones::RAGE),
luabind::value("ragea", Zones::RAGEA),
luabind::value("takishruins", Zones::TAKISHRUINS),
luabind::value("takishruinsa", Zones::TAKISHRUINSA),
luabind::value("elddar", Zones::ELDDAR),
luabind::value("elddara", Zones::ELDDARA),
luabind::value("theater", Zones::THEATER),
luabind::value("theatera", Zones::THEATERA),
luabind::value("freeporteast", Zones::FREEPORTEAST),
luabind::value("freeportwest", Zones::FREEPORTWEST),
luabind::value("freeportsewers", Zones::FREEPORTSEWERS),
luabind::value("freeportacademy", Zones::FREEPORTACADEMY),
luabind::value("freeporttemple", Zones::FREEPORTTEMPLE),
luabind::value("freeportmilitia", Zones::FREEPORTMILITIA),
luabind::value("freeportarena", Zones::FREEPORTARENA),
luabind::value("freeportcityhall", Zones::FREEPORTCITYHALL),
luabind::value("freeporttheater", Zones::FREEPORTTHEATER),
luabind::value("freeporthall", Zones::FREEPORTHALL),
luabind::value("northro", Zones::NORTHRO),
luabind::value("southro", Zones::SOUTHRO),
luabind::value("crescent", Zones::CRESCENT),
luabind::value("moors", Zones::MOORS),
luabind::value("stonehive", Zones::STONEHIVE),
luabind::value("mesa", Zones::MESA),
luabind::value("roost", Zones::ROOST),
luabind::value("steppes", Zones::STEPPES),
luabind::value("icefall", Zones::ICEFALL),
luabind::value("valdeholm", Zones::VALDEHOLM),
luabind::value("frostcrypt", Zones::FROSTCRYPT),
luabind::value("sunderock", Zones::SUNDEROCK),
luabind::value("vergalid", Zones::VERGALID),
luabind::value("direwind", Zones::DIREWIND),
luabind::value("ashengate", Zones::ASHENGATE),
luabind::value("highpasshold", Zones::HIGHPASSHOLD),
luabind::value("commonlands", Zones::COMMONLANDS),
luabind::value("oceanoftears", Zones::OCEANOFTEARS),
luabind::value("kithforest", Zones::KITHFOREST),
luabind::value("befallenb", Zones::BEFALLENB),
luabind::value("highpasskeep", Zones::HIGHPASSKEEP),
luabind::value("innothuleb", Zones::INNOTHULEB),
luabind::value("toxxulia", Zones::TOXXULIA),
luabind::value("mistythicket", Zones::MISTYTHICKET),
luabind::value("kattacastrum", Zones::KATTACASTRUM),
luabind::value("thalassius", Zones::THALASSIUS),
luabind::value("atiiki", Zones::ATIIKI),
luabind::value("zhisza", Zones::ZHISZA),
luabind::value("silyssar", Zones::SILYSSAR),
luabind::value("solteris", Zones::SOLTERIS),
luabind::value("barren", Zones::BARREN),
luabind::value("buriedsea", Zones::BURIEDSEA),
luabind::value("jardelshook", Zones::JARDELSHOOK),
luabind::value("monkeyrock", Zones::MONKEYROCK),
luabind::value("suncrest", Zones::SUNCREST),
luabind::value("deadbone", Zones::DEADBONE),
luabind::value("blacksail", Zones::BLACKSAIL),
luabind::value("maidensgrave", Zones::MAIDENSGRAVE),
luabind::value("redfeather", Zones::REDFEATHER),
luabind::value("shipmvp", Zones::SHIPMVP),
luabind::value("shipmvu", Zones::SHIPMVU),
luabind::value("shippvu", Zones::SHIPPVU),
luabind::value("shipuvu", Zones::SHIPUVU),
luabind::value("shipmvm", Zones::SHIPMVM),
luabind::value("mechanotus", Zones::MECHANOTUS),
luabind::value("mansion", Zones::MANSION),
luabind::value("steamfactory", Zones::STEAMFACTORY),
luabind::value("shipworkshop", Zones::SHIPWORKSHOP),
luabind::value("gyrospireb", Zones::GYROSPIREB),
luabind::value("gyrospirez", Zones::GYROSPIREZ),
luabind::value("dragonscale", Zones::DRAGONSCALE),
luabind::value("lopingplains", Zones::LOPINGPLAINS),
luabind::value("hillsofshade", Zones::HILLSOFSHADE),
luabind::value("bloodmoon", Zones::BLOODMOON),
luabind::value("crystallos", Zones::CRYSTALLOS),
luabind::value("guardian", Zones::GUARDIAN),
luabind::value("steamfontmts", Zones::STEAMFONTMTS),
luabind::value("cryptofshade", Zones::CRYPTOFSHADE),
luabind::value("dragonscaleb", Zones::DRAGONSCALEB),
luabind::value("oldfieldofbone", Zones::OLDFIELDOFBONE),
luabind::value("oldkaesoraa", Zones::OLDKAESORAA),
luabind::value("oldkaesorab", Zones::OLDKAESORAB),
luabind::value("oldkurn", Zones::OLDKURN),
luabind::value("oldkithicor", Zones::OLDKITHICOR),
luabind::value("oldcommons", Zones::OLDCOMMONS),
luabind::value("oldhighpass", Zones::OLDHIGHPASS),
luabind::value("thevoida", Zones::THEVOIDA),
luabind::value("thevoidb", Zones::THEVOIDB),
luabind::value("thevoidc", Zones::THEVOIDC),
luabind::value("thevoidd", Zones::THEVOIDD),
luabind::value("thevoide", Zones::THEVOIDE),
luabind::value("thevoidf", Zones::THEVOIDF),
luabind::value("thevoidg", Zones::THEVOIDG),
luabind::value("oceangreenhills", Zones::OCEANGREENHILLS),
luabind::value("oceangreenvillage", Zones::OCEANGREENVILLAGE),
luabind::value("oldblackburrow", Zones::OLDBLACKBURROW),
luabind::value("bertoxtemple", Zones::BERTOXTEMPLE),
luabind::value("discord", Zones::DISCORD),
luabind::value("discordtower", Zones::DISCORDTOWER),
luabind::value("oldbloodfield", Zones::OLDBLOODFIELD),
luabind::value("precipiceofwar", Zones::PRECIPICEOFWAR),
luabind::value("olddranik", Zones::OLDDRANIK),
luabind::value("toskirakk", Zones::TOSKIRAKK),
luabind::value("korascian", Zones::KORASCIAN),
luabind::value("rathechamber", Zones::RATHECHAMBER),
luabind::value("brellsrest", Zones::BRELLSREST),
luabind::value("fungalforest", Zones::FUNGALFOREST),
luabind::value("underquarry", Zones::UNDERQUARRY),
luabind::value("coolingchamber", Zones::COOLINGCHAMBER),
luabind::value("shiningcity", Zones::SHININGCITY),
luabind::value("arthicrex", Zones::ARTHICREX),
luabind::value("foundation", Zones::FOUNDATION),
luabind::value("lichencreep", Zones::LICHENCREEP),
luabind::value("pellucid", Zones::PELLUCID),
luabind::value("stonesnake", Zones::STONESNAKE),
luabind::value("brellstemple", Zones::BRELLSTEMPLE),
luabind::value("convorteum", Zones::CONVORTEUM),
luabind::value("brellsarena", Zones::BRELLSARENA),
luabind::value("weddingchapel", Zones::WEDDINGCHAPEL),
luabind::value("weddingchapeldark", Zones::WEDDINGCHAPELDARK),
luabind::value("dragoncrypt", Zones::DRAGONCRYPT),
luabind::value("feerrott2", Zones::FEERROTT2),
luabind::value("thulehouse1", Zones::THULEHOUSE1),
luabind::value("thulehouse2", Zones::THULEHOUSE2),
luabind::value("housegarden", Zones::HOUSEGARDEN),
luabind::value("thulelibrary", Zones::THULELIBRARY),
luabind::value("well", Zones::WELL),
luabind::value("fallen", Zones::FALLEN),
luabind::value("morellcastle", Zones::MORELLCASTLE),
luabind::value("somnium", Zones::SOMNIUM),
luabind::value("alkabormare", Zones::ALKABORMARE),
luabind::value("miragulmare", Zones::MIRAGULMARE),
luabind::value("thuledream", Zones::THULEDREAM),
luabind::value("neighborhood", Zones::NEIGHBORHOOD),
luabind::value("argath", Zones::ARGATH),
luabind::value("arelis", Zones::ARELIS),
luabind::value("sarithcity", Zones::SARITHCITY),
luabind::value("rubak", Zones::RUBAK),
luabind::value("beastdomain", Zones::BEASTDOMAIN),
luabind::value("resplendent", Zones::RESPLENDENT),
luabind::value("pillarsalra", Zones::PILLARSALRA),
luabind::value("windsong", Zones::WINDSONG),
luabind::value("cityofbronze", Zones::CITYOFBRONZE),
luabind::value("sepulcher", Zones::SEPULCHER),
luabind::value("eastsepulcher", Zones::EASTSEPULCHER),
luabind::value("westsepulcher", Zones::WESTSEPULCHER),
luabind::value("shardslanding", Zones::SHARDSLANDING),
luabind::value("xorbb", Zones::XORBB),
luabind::value("kaelshard", Zones::KAELSHARD),
luabind::value("eastwastesshard", Zones::EASTWASTESSHARD),
luabind::value("crystalshard", Zones::CRYSTALSHARD),
luabind::value("breedinggrounds", Zones::BREEDINGGROUNDS),
luabind::value("eviltree", Zones::EVILTREE),
luabind::value("grelleth", Zones::GRELLETH),
luabind::value("chapterhouse", Zones::CHAPTERHOUSE),
luabind::value("arttest", Zones::ARTTEST),
luabind::value("fhalls", Zones::FHALLS),
luabind::value("apprentice", Zones::APPRENTICE)
)];
}
luabind::scope lua_register_languages() {
return luabind::class_<LanguageIDs>("Language")
.enum_("constants")
[(
luabind::value("CommonTongue", Language::CommonTongue),
luabind::value("Barbarian", Language::Barbarian),
luabind::value("Erudian", Language::Erudian),
luabind::value("Elvish", Language::Elvish),
luabind::value("DarkElvish", Language::DarkElvish),
luabind::value("Dwarvish", Language::Dwarvish),
luabind::value("Troll", Language::Troll),
luabind::value("Ogre", Language::Ogre),
luabind::value("Gnomish", Language::Gnomish),
luabind::value("Halfling", Language::Halfling),
luabind::value("ThievesCant", Language::ThievesCant),
luabind::value("OldErudian", Language::OldErudian),
luabind::value("ElderElvish", Language::ElderElvish),
luabind::value("Froglok", Language::Froglok),
luabind::value("Goblin", Language::Goblin),
luabind::value("Gnoll", Language::Gnoll),
luabind::value("CombineTongue", Language::CombineTongue),
luabind::value("ElderTeirDal", Language::ElderTeirDal),
luabind::value("Lizardman", Language::Lizardman),
luabind::value("Orcish", Language::Orcish),
luabind::value("Faerie", Language::Faerie),
luabind::value("Dragon", Language::Dragon),
luabind::value("ElderDragon", Language::ElderDragon),
luabind::value("DarkSpeech", Language::DarkSpeech),
luabind::value("VahShir", Language::VahShir),
luabind::value("Alaran", Language::Alaran),
luabind::value("Hadal", Language::Hadal),
luabind::value("Unknown27", Language::Unknown27),
luabind::value("MaxValue", Language::MaxValue)
)];
}
luabind::scope lua_register_rules_const() {
return luabind::class_<Rule>("Rule")
.enum_("constants")
+2
View File
@@ -15,6 +15,8 @@ luabind::scope lua_register_skills();
luabind::scope lua_register_bodytypes();
luabind::scope lua_register_filters();
luabind::scope lua_register_message_types();
luabind::scope lua_register_zone_types();
luabind::scope lua_register_languages();
luabind::scope lua_register_rules_const();
luabind::scope lua_register_rulei();
luabind::scope lua_register_ruler();
+28
View File
@@ -3333,6 +3333,30 @@ void Lua_Mob::RestoreMana()
self->RestoreMana();
}
std::string Lua_Mob::GetArchetypeName()
{
Lua_Safe_Call_String();
return self->GetArchetypeName();
}
bool Lua_Mob::IsIntelligenceCasterClass()
{
Lua_Safe_Call_Bool();
return self->IsIntelligenceCasterClass();
}
bool Lua_Mob::IsPureMeleeClass()
{
Lua_Safe_Call_Bool();
return self->IsPureMeleeClass();
}
bool Lua_Mob::IsWisdomCasterClass()
{
Lua_Safe_Call_Bool();
return self->IsWisdomCasterClass();
}
luabind::scope lua_register_mob() {
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
.def(luabind::constructor<>())
@@ -3524,6 +3548,7 @@ luabind::scope lua_register_mob() {
.def("GetAggroRange", (float(Lua_Mob::*)(void))&Lua_Mob::GetAggroRange)
.def("GetAllowBeneficial", (bool(Lua_Mob::*)(void))&Lua_Mob::GetAllowBeneficial)
.def("GetAppearance", (uint32(Lua_Mob::*)(void))&Lua_Mob::GetAppearance)
.def("GetArchetypeName", &Lua_Mob::GetArchetypeName)
.def("GetAssistRange", (float(Lua_Mob::*)(void))&Lua_Mob::GetAssistRange)
.def("GetBaseGender", &Lua_Mob::GetBaseGender)
.def("GetBaseRace", &Lua_Mob::GetBaseRace)
@@ -3732,6 +3757,7 @@ luabind::scope lua_register_mob() {
.def("IsFindable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsFindable)
.def("IsHorse", &Lua_Mob::IsHorse)
.def("IsImmuneToSpell", (bool(Lua_Mob::*)(int,Lua_Mob))&Lua_Mob::IsImmuneToSpell)
.def("IsIntelligenceCasterClass", &Lua_Mob::IsIntelligenceCasterClass)
.def("IsInvisible", (bool(Lua_Mob::*)(Lua_Mob))&Lua_Mob::IsInvisible)
.def("IsInvisible", (bool(Lua_Mob::*)(void))&Lua_Mob::IsInvisible)
.def("IsMeleeDisabled", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMeleeDisabled)
@@ -3742,6 +3768,7 @@ luabind::scope lua_register_mob() {
.def("IsPetOwnerBot", &Lua_Mob::IsPetOwnerBot)
.def("IsPetOwnerClient", &Lua_Mob::IsPetOwnerClient)
.def("IsPetOwnerNPC", &Lua_Mob::IsPetOwnerNPC)
.def("IsPureMeleeClass", &Lua_Mob::IsPureMeleeClass)
.def("IsRoamer", (bool(Lua_Mob::*)(void))&Lua_Mob::IsRoamer)
.def("IsRooted", (bool(Lua_Mob::*)(void))&Lua_Mob::IsRooted)
.def("IsRunning", (bool(Lua_Mob::*)(void))&Lua_Mob::IsRunning)
@@ -3753,6 +3780,7 @@ luabind::scope lua_register_mob() {
.def("IsTemporaryPet", &Lua_Mob::IsTemporaryPet)
.def("IsTrackable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTrackable)
.def("IsWarriorClass", &Lua_Mob::IsWarriorClass)
.def("IsWisdomCasterClass", &Lua_Mob::IsWisdomCasterClass)
.def("Kill", (void(Lua_Mob::*)(void))&Lua_Mob::Kill)
.def("Mesmerize", (void(Lua_Mob::*)(void))&Lua_Mob::Mesmerize)
.def("Message", &Lua_Mob::Message)
+4
View File
@@ -586,6 +586,10 @@ public:
void RestoreEndurance();
void RestoreHealth();
void RestoreMana();
std::string GetArchetypeName();
bool IsIntelligenceCasterClass();
bool IsPureMeleeClass();
bool IsWisdomCasterClass();
};
#endif
+184
View File
@@ -37,6 +37,7 @@ void LuaMod::Init()
m_has_get_experience_for_kill = parser_->HasFunction("GetExperienceForKill", package_name_);
m_has_common_outgoing_hit_success = parser_->HasFunction("CommonOutgoingHitSuccess", package_name_);
m_has_calc_spell_effect_value_formula = parser_->HasFunction("CalcSpellEffectValue_formula", package_name_);
m_has_register_bug = parser_->HasFunction("RegisterBug", package_name_);
}
void PutDamageHitInfo(lua_State *L, luabind::adl::object &e, DamageHitInfo &hit) {
@@ -678,4 +679,187 @@ void LuaMod::CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_
}
}
void LuaMod::RegisterBug(Client *self, BaseBugReportsRepository::BugReports bug, bool &ignore_default)
{
int start = lua_gettop(L);
try {
if (!m_has_register_bug) {
return;
}
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
lua_getfield(L, -1, "RegisterBug");
Lua_Client l_self(self);
luabind::adl::object e = luabind::newtable(L);
e["self"] = l_self;
e["zone"] = bug.zone;
e["client_version_id"] = bug.client_version_id;
e["client_version_name"] = bug.client_version_name;
e["account_id"] = bug.account_id;
e["character_id"] = bug.character_id;
e["character_name"] = bug.character_name;
e["reporter_spoof"] = bug.reporter_spoof;
e["category_id"] = bug.category_id;
e["category_name"] = bug.category_name;
e["reporter_name"] = bug.reporter_name;
e["ui_path"] = bug.ui_path;
e["pos_x"] = bug.pos_x;
e["pos_y"] = bug.pos_y;
e["pos_z"] = bug.pos_z;
e["heading"] = bug.heading;
e["time_played"] = bug.time_played;
e["target_id"] = bug.target_id;
e["target_name"] = bug.target_name;
e["optional_info_mask"] = bug.optional_info_mask;
e["_can_duplicate"] = bug._can_duplicate;
e["_crash_bug"] = bug._crash_bug;
e["_target_info"] = bug._target_info;
e["_character_flags"] = bug._character_flags;
e["_unknown_value"] = bug._unknown_value;
e["bug_report"] = bug.bug_report;
e["system_info"] = bug.system_info;
e.push(L);
if (lua_pcall(L, 1, 1, 0)) {
std::string error = lua_tostring(L, -1);
parser_->AddError(error);
lua_pop(L, 2);
return;
}
if (lua_type(L, -1) == LUA_TTABLE) {
luabind::adl::object ret(luabind::from_stack(L, -1));
auto ignore_default_obj = ret["ignore_default"];
if (luabind::type(ignore_default_obj) == LUA_TBOOLEAN) {
ignore_default = ignore_default || luabind::object_cast<bool>(ignore_default_obj);
}
}
}
catch (std::exception &ex) {
parser_->AddError(ex.what());
}
int end = lua_gettop(L);
int n = end - start;
if (n > 0) {
lua_pop(L, n);
}
}
void LuaMod::CommonDamage(Mob *self, Mob* attacker, int64 value, uint16 spell_id, int skill_used, bool avoidable, int8 buff_slot, bool buff_tic, int special, int64 &return_value, bool &ignore_default)
{
int start = lua_gettop(L);
try {
if (!m_has_common_damage) {
return;
}
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
lua_getfield(L, -1, "CommonDamage");
Lua_Mob l_self(self);
Lua_Mob l_other(attacker);
luabind::adl::object e = luabind::newtable(L);
e["self"] = l_self;
e["attacker"] = l_other;
e["value"] = value;
e["spell_id"] = spell_id;
e["skill_used"] = skill_used;
e["avoidable"] = avoidable;
e["buff_slot"] = buff_slot;
e["buff_tic"] = buff_tic;
e["special"] = special;
e.push(L);
if (lua_pcall(L, 1, 1, 0)) {
std::string error = lua_tostring(L, -1);
parser_->AddError(error);
lua_pop(L, 2);
return;
}
if (lua_type(L, -1) == LUA_TTABLE) {
luabind::adl::object ret(luabind::from_stack(L, -1));
auto ignore_default_obj = ret["ignore_default"];
if (luabind::type(ignore_default_obj) == LUA_TBOOLEAN) {
ignore_default = ignore_default || luabind::object_cast<bool>(ignore_default_obj);
}
auto return_value_obj = ret["return_value"];
if (luabind::type(return_value_obj) == LUA_TNUMBER) {
return_value = luabind::object_cast<int64>(return_value_obj);
}
}
}
catch (std::exception &ex) {
parser_->AddError(ex.what());
}
int end = lua_gettop(L);
int n = end - start;
if (n > 0) {
lua_pop(L, n);
}
}
void LuaMod::HealDamage(Mob *self, Mob* caster, uint64 value, uint16 spell_id, uint64 &return_value, bool &ignore_default)
{
int start = lua_gettop(L);
try {
if (!m_has_heal_damage) {
return;
}
lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str());
lua_getfield(L, -1, "HealDamage");
Lua_Mob l_self(self);
Lua_Mob l_other(caster);
luabind::adl::object e = luabind::newtable(L);
e["self"] = l_self;
e["caster"] = l_other;
e["value"] = value;
e["spell_id"] = spell_id;
e.push(L);
if (lua_pcall(L, 1, 1, 0)) {
std::string error = lua_tostring(L, -1);
parser_->AddError(error);
lua_pop(L, 2);
return;
}
if (lua_type(L, -1) == LUA_TTABLE) {
luabind::adl::object ret(luabind::from_stack(L, -1));
auto ignore_default_obj = ret["ignore_default"];
if (luabind::type(ignore_default_obj) == LUA_TBOOLEAN) {
ignore_default = ignore_default || luabind::object_cast<bool>(ignore_default_obj);
}
auto return_value_obj = ret["return_value"];
if (luabind::type(return_value_obj) == LUA_TNUMBER) {
return_value = luabind::object_cast<int64>(return_value_obj);
}
}
}
catch (std::exception &ex) {
parser_->AddError(ex.what());
}
int end = lua_gettop(L);
int n = end - start;
if (n > 0) {
lua_pop(L, n);
}
}
#endif
+7
View File
@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include "../common/repositories/bug_reports_repository.h"
struct lua_State;
@@ -27,6 +28,9 @@ public:
void GetEXPForLevel(Client *self, uint16 level, uint32 &returnValue, bool &ignoreDefault);
void GetExperienceForKill(Client *self, Mob *against, uint64 &returnValue, bool &ignoreDefault);
void CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining, int64 &returnValue, bool &ignoreDefault);
void RegisterBug(Client *self, BaseBugReportsRepository::BugReports bug, bool &ignore_default);
void CommonDamage(Mob *self, Mob* attacker, int64 value, uint16 spell_id, int skill_used, bool avoidable, int8 buff_slot, bool buff_tic, int special, int64 &return_value, bool &ignore_default);
void HealDamage(Mob *self, Mob* caster, uint64 value, uint16 spell_id, uint64 &return_value, bool &ignore_default);
private:
LuaParser *parser_;
lua_State *L;
@@ -42,4 +46,7 @@ private:
bool m_has_get_exp_for_level;
bool m_has_get_experience_for_kill;
bool m_has_calc_spell_effect_value_formula;
bool m_has_register_bug;
bool m_has_common_damage;
bool m_has_heal_damage;
};
+129 -18
View File
@@ -32,34 +32,39 @@ void Lua_NPC::AddItem(int item_id, int charges, bool equip) {
self->AddItem(item_id, charges, equip);
}
void Lua_NPC::AddItem(int item_id, int charges, bool equip, int aug1) {
void Lua_NPC::AddItem(int item_id, int charges, bool equip, bool quest) {
Lua_Safe_Call_Void();
self->AddItem(item_id, charges, equip, aug1);
self->AddItem(item_id, charges, equip, quest);
}
void Lua_NPC::AddItem(int item_id, int charges, bool equip, int aug1, int aug2) {
void Lua_NPC::AddItem(int item_id, int charges, bool equip, bool quest, int aug1) {
Lua_Safe_Call_Void();
self->AddItem(item_id, charges, equip, aug1, aug2);
self->AddItem(item_id, charges, equip, quest, aug1);
}
void Lua_NPC::AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3) {
void Lua_NPC::AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2) {
Lua_Safe_Call_Void();
self->AddItem(item_id, charges, equip, aug1, aug2, aug3);
self->AddItem(item_id, charges, equip, quest, aug1, aug2);
}
void Lua_NPC::AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3, int aug4) {
void Lua_NPC::AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3) {
Lua_Safe_Call_Void();
self->AddItem(item_id, charges, equip, aug1, aug2, aug3, aug4);
self->AddItem(item_id, charges, equip, quest, aug1, aug2, aug3);
}
void Lua_NPC::AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3, int aug4, int aug5) {
void Lua_NPC::AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3, int aug4) {
Lua_Safe_Call_Void();
self->AddItem(item_id, charges, equip, aug1, aug2, aug3, aug4, aug5);
self->AddItem(item_id, charges, equip, quest, aug1, aug2, aug3, aug4);
}
void Lua_NPC::AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3, int aug4, int aug5, int aug6) {
void Lua_NPC::AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3, int aug4, int aug5) {
Lua_Safe_Call_Void();
self->AddItem(item_id, charges, equip, aug1, aug2, aug3, aug4, aug5, aug6);
self->AddItem(item_id, charges, equip, quest, aug1, aug2, aug3, aug4, aug5);
}
void Lua_NPC::AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3, int aug4, int aug5, int aug6) {
Lua_Safe_Call_Void();
self->AddItem(item_id, charges, equip, quest, aug1, aug2, aug3, aug4, aug5, aug6);
}
void Lua_NPC::AddLootTable() {
@@ -831,6 +836,96 @@ uint32 Lua_NPC::GetNPCSpellsEffectsID()
return self->GetNPCSpellsEffectsID();
}
void Lua_NPC::AddQuestLoot(int itemid)
{
Lua_Safe_Call_Void();
self->AddQuestLoot(itemid);
}
void Lua_NPC::AddQuestLoot(int itemid, int charges)
{
Lua_Safe_Call_Void();
self->AddQuestLoot(itemid, charges);
}
bool Lua_NPC::GetQuestLoot(int itemid)
{
Lua_Safe_Call_Bool();
return self->HasQuestLootItem(itemid);
}
bool Lua_NPC::HasQuestLoot()
{
Lua_Safe_Call_Bool();
return self->HasQuestLoot();
}
void Lua_NPC::AddPetLoot(int itemid)
{
Lua_Safe_Call_Void();
self->AddPetLoot(itemid, 1, true);
}
void Lua_NPC::AddPetLoot(int itemid, int charges)
{
Lua_Safe_Call_Void();
self->AddPetLoot(itemid, charges, true);
}
bool Lua_NPC::GetPetLoot(int itemid)
{
Lua_Safe_Call_Bool();
return self->HasPetLootItem(itemid);
}
void Lua_NPC::DeleteQuestLoot()
{
Lua_Safe_Call_Void();
self->DeleteQuestLoot(0);
}
void Lua_NPC::DeleteQuestLoot(int itemid1)
{
Lua_Safe_Call_Void();
self->DeleteQuestLoot(itemid1);
}
void Lua_NPC::DeleteQuestLoot(int itemid1, int itemid2)
{
Lua_Safe_Call_Void();
self->DeleteQuestLoot(itemid1, itemid2);
}
void Lua_NPC::DeleteQuestLoot(int itemid1, int itemid2, int itemid3)
{
Lua_Safe_Call_Void();
self->DeleteQuestLoot(itemid1, itemid2, itemid3);
}
void Lua_NPC::DeleteQuestLoot(int itemid1, int itemid2, int itemid3, int itemid4)
{
Lua_Safe_Call_Void();
self->DeleteQuestLoot(itemid1, itemid2, itemid3, itemid4);
}
bool Lua_NPC::HasRequiredQuestLoot(int itemid1, int itemid2, int itemid3, int itemid4)
{
Lua_Safe_Call_Bool();
return self->HasRequiredQuestLoot(itemid1, itemid2, itemid3, itemid4);
}
int Lua_NPC::QuestLootCount(int itemid)
{
Lua_Safe_Call_Int();
return self->CountQuestItem(itemid);
}
bool Lua_NPC::CanTalk()
{
Lua_Safe_Call_Bool();
return self->CanTalk();
}
luabind::scope lua_register_npc() {
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
.def(luabind::constructor<>())
@@ -842,16 +937,22 @@ luabind::scope lua_register_npc() {
.def("AddCash", (void(Lua_NPC::*)(uint32,uint32,uint32,uint32))&Lua_NPC::AddLootCash)
.def("AddItem", (void(Lua_NPC::*)(int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,int,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,int,int,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,int,int,int,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,int,int,int,int,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,bool)) & Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,bool,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,bool,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,bool,int,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,bool,int,int,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,bool,int,int,int,int,int))&Lua_NPC::AddItem)
.def("AddItem", (void(Lua_NPC::*)(int,int,bool,bool,int,int,int,int,int,int))&Lua_NPC::AddItem)
.def("AddLootTable", (void(Lua_NPC::*)(int))&Lua_NPC::AddLootTable)
.def("AddLootTable", (void(Lua_NPC::*)(void))&Lua_NPC::AddLootTable)
.def("AddQuestLoot", (void(Lua_NPC::*)(int)) & Lua_NPC::AddQuestLoot)
.def("AddQuestLoot", (void(Lua_NPC::*)(int,int)) & Lua_NPC::AddQuestLoot)
.def("AddPetLoot", (void(Lua_NPC:: *)(int)) & Lua_NPC::AddPetLoot)
.def("AddPetLoot", (void(Lua_NPC:: *)(int, int)) & Lua_NPC::AddPetLoot)
.def("AssignWaypoints", (void(Lua_NPC::*)(int))&Lua_NPC::AssignWaypoints)
.def("CalculateNewWaypoint", (void(Lua_NPC::*)(void))&Lua_NPC::CalculateNewWaypoint)
.def("CanTalk", (bool(Lua_NPC:: *)(void)) & Lua_NPC::CanTalk)
.def("ChangeLastName", (void(Lua_NPC::*)(std::string))&Lua_NPC::ChangeLastName)
.def("CheckNPCFactionAlly", (int(Lua_NPC::*)(int))&Lua_NPC::CheckNPCFactionAlly)
.def("ClearItemList", (void(Lua_NPC::*)(void))&Lua_NPC::ClearLootItems)
@@ -859,6 +960,11 @@ luabind::scope lua_register_npc() {
.def("CountItem", (uint16(Lua_NPC::*)(uint32))&Lua_NPC::CountItem)
.def("CountLoot", (int(Lua_NPC::*)(void))&Lua_NPC::CountLoot)
.def("DeleteBucket", (void(Lua_NPC::*)(std::string))&Lua_NPC::DeleteBucket)
.def("DeleteQuestLoot", (void(Lua_NPC:: *)(void)) & Lua_NPC::DeleteQuestLoot)
.def("DeleteQuestLoot", (void(Lua_NPC:: *)(int)) & Lua_NPC::DeleteQuestLoot)
.def("DeleteQuestLoot", (void(Lua_NPC:: *)(int, int)) & Lua_NPC::DeleteQuestLoot)
.def("DeleteQuestLoot", (void(Lua_NPC:: *)(int, int, int)) & Lua_NPC::DeleteQuestLoot)
.def("DeleteQuestLoot", (void(Lua_NPC:: *)(int, int, int, int)) & Lua_NPC::DeleteQuestLoot)
.def("DisplayWaypointInfo", (void(Lua_NPC::*)(Lua_Client))&Lua_NPC::DisplayWaypointInfo)
.def("DoClassAttacks", (void(Lua_NPC::*)(Lua_Mob))&Lua_NPC::DoClassAttacks)
.def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating)
@@ -896,10 +1002,12 @@ luabind::scope lua_register_npc() {
.def("GetNPCSpellsEffectsID", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsEffectsID)
.def("GetNPCSpellsID", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID)
.def("GetNPCStat", (float(Lua_NPC::*)(std::string))&Lua_NPC::GetNPCStat)
.def("GetPetLoot", (bool(Lua_NPC:: *)(int)) & Lua_NPC::GetPetLoot)
.def("GetPetSpellID", (int(Lua_NPC::*)(void))&Lua_NPC::GetPetSpellID)
.def("GetPlatinum", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetPlatinum)
.def("GetPrimSkill", (int(Lua_NPC::*)(void))&Lua_NPC::GetPrimSkill)
.def("GetPrimaryFaction", (int(Lua_NPC::*)(void))&Lua_NPC::GetPrimaryFaction)
.def("GetQuestLoot", (bool(Lua_NPC:: *)(int)) & Lua_NPC::GetQuestLoot)
.def("GetRawAC", (int(Lua_NPC::*)(void))&Lua_NPC::GetRawAC)
.def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore)
.def("GetSecSkill", (int(Lua_NPC::*)(void))&Lua_NPC::GetSecSkill)
@@ -920,6 +1028,8 @@ luabind::scope lua_register_npc() {
.def("GetWaypointMax", (int(Lua_NPC::*)(void))&Lua_NPC::GetWaypointMax)
.def("HasAISpellEffect", (bool(Lua_NPC::*)(int))&Lua_NPC::HasAISpellEffect)
.def("HasItem", (bool(Lua_NPC::*)(uint32))&Lua_NPC::HasItem)
.def("HasQuestLoot", (bool(Lua_NPC::*)(void)) & Lua_NPC::HasQuestLoot)
.def("HasRequiredQuestLoot", (bool(Lua_NPC::*)(int,int,int,int)) &Lua_NPC::HasRequiredQuestLoot)
.def("IsAnimal", (bool(Lua_NPC::*)(void))&Lua_NPC::IsAnimal)
.def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding)
.def("IsLDoNLocked", (bool(Lua_NPC::*)(void))&Lua_NPC::IsLDoNLocked)
@@ -937,6 +1047,7 @@ luabind::scope lua_register_npc() {
.def("NextGuardPosition", (void(Lua_NPC::*)(void))&Lua_NPC::NextGuardPosition)
.def("PauseWandering", (void(Lua_NPC::*)(int))&Lua_NPC::PauseWandering)
.def("PickPocket", (void(Lua_NPC::*)(Lua_Client))&Lua_NPC::PickPocket)
.def("QuestLootCount", (int(Lua_NPC::*)(int)) &Lua_NPC::QuestLootCount)
.def("RecalculateSkills", (void(Lua_NPC::*)(void))&Lua_NPC::RecalculateSkills)
.def("ReloadSpells", (void(Lua_NPC::*)(void))&Lua_NPC::ReloadSpells)
.def("RemoveAISpell", (void(Lua_NPC::*)(int))&Lua_NPC::RemoveAISpell)
+22 -6
View File
@@ -33,12 +33,13 @@ public:
int CheckNPCFactionAlly(int faction);
void AddItem(int item_id, int charges);
void AddItem(int item_id, int charges, bool equip);
void AddItem(int item_id, int charges, bool equip, int aug1);
void AddItem(int item_id, int charges, bool equip, int aug1, int aug2);
void AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3);
void AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3, int aug4);
void AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3, int aug4, int aug5);
void AddItem(int item_id, int charges, bool equip, int aug1, int aug2, int aug3, int aug4, int aug5, int aug6);
void AddItem(int item_id, int charges, bool equip, bool quest);
void AddItem(int item_id, int charges, bool equip, bool quest, int aug1);
void AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2);
void AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3);
void AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3, int aug4);
void AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3, int aug4, int aug5);
void AddItem(int item_id, int charges, bool equip, bool quest, int aug1, int aug2, int aug3, int aug4, int aug5, int aug6);
void AddLootTable();
void AddLootTable(int id);
void RemoveItem(int item_id);
@@ -185,6 +186,21 @@ public:
bool GetNPCAggro();
void SetNPCAggro(bool in_npc_aggro);
uint32 GetNPCSpellsEffectsID();
void AddQuestLoot(int itemid); //
void AddQuestLoot(int itemid, int charges); //
void AddPetLoot(int itemid); //
void AddPetLoot(int itemid, int charges); //
bool GetQuestLoot(int itemid); //
bool GetPetLoot(int itemid); //
bool HasQuestLoot(); //
void DeleteQuestLoot();
void DeleteQuestLoot(int itemid1);
void DeleteQuestLoot(int itemid1, int itemid2);
void DeleteQuestLoot(int itemid1, int itemid2, int itemid3);
void DeleteQuestLoot(int itemid1, int itemid2, int itemid3, int itemid4);
bool HasRequiredQuestLoot(int itemid1, int itemid2, int itemid3, int itemid4);
int QuestLootCount(int itemid);
bool CanTalk();
};
#endif
+33 -1
View File
@@ -183,7 +183,8 @@ const char *LuaEvents[_LargestEventID] = {
"event_entity_variable_delete",
"event_entity_variable_set",
"event_entity_variable_update",
"event_aa_loss"
"event_aa_loss",
"event_spell_blocked"
};
extern Zone *zone;
@@ -257,6 +258,7 @@ LuaParser::LuaParser() {
NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_DELETE] = handle_npc_entity_variable;
NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_npc_entity_variable;
NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_npc_entity_variable;
NPCArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_npc_spell_blocked;
PlayerArgumentDispatch[EVENT_SAY] = handle_player_say;
PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage;
@@ -345,6 +347,7 @@ LuaParser::LuaParser() {
PlayerArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_player_entity_variable;
PlayerArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_player_entity_variable;
PlayerArgumentDispatch[EVENT_AA_LOSS] = handle_player_aa_loss;
PlayerArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_player_spell_blocked;
ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click;
ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click;
@@ -399,6 +402,7 @@ LuaParser::LuaParser() {
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_DELETE] = handle_bot_entity_variable;
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_bot_entity_variable;
BotArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_bot_entity_variable;
BotArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_bot_spell_blocked;
#endif
L = nullptr;
@@ -1264,6 +1268,8 @@ void LuaParser::MapFunctions(lua_State *L) {
lua_register_bodytypes(),
lua_register_filters(),
lua_register_message_types(),
lua_register_zone_types(),
lua_register_languages(),
lua_register_entity(),
lua_register_encounter(),
lua_register_mob(),
@@ -1577,6 +1583,25 @@ uint64 LuaParser::GetExperienceForKill(Client *self, Mob *against, bool &ignoreD
return retval;
}
int64 LuaParser::CommonDamage(Mob *self, Mob* attacker, int64 value, uint16 spell_id, int skill_used, bool avoidable, int8 buff_slot, bool buff_tic, int special, bool &ignore_default)
{
int64 retval = 0;
for (auto &mod : mods_) {
mod.CommonDamage(self, attacker, value, spell_id, skill_used, avoidable, buff_slot, buff_tic, special, retval, ignore_default);
}
return retval;
}
uint64 LuaParser::HealDamage(Mob *self, Mob* caster, uint64 value, uint16 spell_id, bool &ignore_default)
{
uint64 retval = 0;
for (auto &mod : mods_) {
mod.HealDamage(self, caster, value, spell_id, retval, ignore_default);
}
return retval;
}
int64 LuaParser::CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining, bool &ignoreDefault)
{
int64 retval = 0;
@@ -1586,6 +1611,13 @@ int64 LuaParser::CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 b
return retval;
}
void LuaParser::RegisterBug(Client *self, BaseBugReportsRepository::BugReports bug, bool &ignore_default)
{
for (auto &mod : mods_) {
mod.RegisterBug(self, bug, ignore_default);
}
}
int LuaParser::EventBot(
QuestEventID evt,
Bot *bot,
+6 -1
View File
@@ -12,6 +12,8 @@
#include "zone_config.h"
#include "lua_mod.h"
#include "../common/repositories/bug_reports_repository.h"
extern const ZoneConfig *Config;
struct lua_State;
@@ -196,7 +198,10 @@ public:
uint32 GetEXPForLevel(Client *self, uint16 level, bool &ignoreDefault);
uint64 GetExperienceForKill(Client *self, Mob *against, bool &ignoreDefault);
int64 CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining, bool &ignoreDefault);
void RegisterBug(Client *self, BaseBugReportsRepository::BugReports bug, bool &ignore_default);
int64 CommonDamage(Mob *self, Mob* attacker, int64 value, uint16 spell_id, int skill_used, bool avoidable, int8 buff_slot, bool buff_tic, int special, bool &ignore_default);
uint64 HealDamage(Mob *self, Mob* caster, uint64 value, uint16 spell_id, bool &ignore_default);
private:
LuaParser();
LuaParser(const LuaParser&);
+103 -4
View File
@@ -626,6 +626,39 @@ void handle_npc_entity_variable(
}
}
void handle_npc_spell_blocked(
QuestInterface *parse,
lua_State* L,
NPC* npc,
Mob *init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
)
{
Seperator sep(data.c_str());
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[0]));
lua_setfield(L, -2, "blocking_spell_id");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "cast_spell_id");
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell_one(IsValidSpell(blocking_spell_id) ? &spells[blocking_spell_id] : nullptr);
luabind::adl::object l_spell_one_o = luabind::adl::object(L, l_spell_one);
l_spell_one_o.push(L);
lua_setfield(L, -2, "blocking_spell");
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell_two(IsValidSpell(cast_spell_id) ? &spells[cast_spell_id] : nullptr);
luabind::adl::object l_spell_two_o = luabind::adl::object(L, l_spell_two);
l_spell_two_o.push(L);
lua_setfield(L, -2, "cast_spell");
}
// Player
void handle_player_say(
QuestInterface *parse,
@@ -1245,9 +1278,9 @@ void handle_player_consider(
lua_setfield(L, -2, "entity_id");
if (extra_pointers && extra_pointers->size() == 1) {
Lua_NPC l_npc(std::any_cast<NPC*>(extra_pointers->at(0)));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L);
Lua_Mob l_mob(std::any_cast<Mob*>(extra_pointers->at(0)));
luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob);
l_mob_o.push(L);
lua_setfield(L, -2, "other");
}
}
@@ -1674,11 +1707,44 @@ void handle_player_aa_loss(
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
) {
)
{
lua_pushinteger(L, Strings::ToInt(data));
lua_setfield(L, -2, "aa_lost");
}
void handle_player_spell_blocked(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
)
{
Seperator sep(data.c_str());
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[0]));
lua_setfield(L, -2, "blocking_spell_id");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "cast_spell_id");
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell_one(IsValidSpell(blocking_spell_id) ? &spells[blocking_spell_id] : nullptr);
luabind::adl::object l_spell_one_o = luabind::adl::object(L, l_spell_one);
l_spell_one_o.push(L);
lua_setfield(L, -2, "blocking_spell");
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell_two(IsValidSpell(cast_spell_id) ? &spells[cast_spell_id] : nullptr);
luabind::adl::object l_spell_two_o = luabind::adl::object(L, l_spell_two);
l_spell_two_o.push(L);
lua_setfield(L, -2, "cast_spell");
}
// Item
void handle_item_click(
QuestInterface *parse,
@@ -2690,4 +2756,37 @@ void handle_bot_entity_variable(
}
}
void handle_bot_spell_blocked(
QuestInterface *parse,
lua_State* L,
Bot* bot,
Mob *init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
)
{
Seperator sep(data.c_str());
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[0]));
lua_setfield(L, -2, "blocking_spell_id");
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1]));
lua_setfield(L, -2, "cast_spell_id");
const uint32 blocking_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell_one(IsValidSpell(blocking_spell_id) ? &spells[blocking_spell_id] : nullptr);
luabind::adl::object l_spell_one_o = luabind::adl::object(L, l_spell_one);
l_spell_one_o.push(L);
lua_setfield(L, -2, "blocking_spell");
const uint32 cast_spell_id = Strings::ToUnsignedInt(sep.arg[0]);
Lua_Spell l_spell_two(IsValidSpell(cast_spell_id) ? &spells[cast_spell_id] : nullptr);
luabind::adl::object l_spell_two_o = luabind::adl::object(L, l_spell_two);
l_spell_two_o.push(L);
lua_setfield(L, -2, "cast_spell");
}
#endif
+29
View File
@@ -250,6 +250,16 @@ void handle_npc_entity_variable(
std::vector<std::any> *extra_pointers
);
void handle_npc_spell_blocked(
QuestInterface *parse,
lua_State* L,
NPC* npc,
Mob *init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
// Player
void handle_player_say(
QuestInterface *parse,
@@ -836,6 +846,15 @@ void handle_player_aa_loss(
std::vector<std::any> *extra_pointers
);
void handle_player_spell_blocked(
QuestInterface *parse,
lua_State* L,
Client* client,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
// Item
void handle_item_click(
QuestInterface *parse,
@@ -1230,5 +1249,15 @@ void handle_bot_entity_variable(
std::vector<std::any> *extra_pointers
);
void handle_bot_spell_blocked(
QuestInterface *parse,
lua_State* L,
Bot* bot,
Mob* init,
std::string data,
uint32 extra_data,
std::vector<std::any> *extra_pointers
);
#endif
#endif
+4 -4
View File
@@ -86,6 +86,7 @@ extern volatile bool is_zone_loaded;
#include "../common/events/player_event_logs.h"
#include "../common/path_manager.h"
#include "../common/database/database_update.h"
#include "../common/skill_caps.h"
#include "zone_event_scheduler.h"
#include "zone_cli.h"
@@ -108,6 +109,7 @@ WorldContentService content_service;
PathManager path;
PlayerEventLogs player_event_logs;
DatabaseUpdate database_update;
SkillCaps skill_caps;
const SPDat_Spell_Struct* spells;
int32 SPDAT_RECORDS = -1;
@@ -307,6 +309,8 @@ int main(int argc, char **argv)
player_event_logs.SetDatabase(&database)->Init();
skill_caps.SetContentDatabase(&content_db)->LoadSkillCaps();
const auto c = EQEmuConfig::get();
if (c->auto_database_updates) {
if (database_update.SetDatabase(&database)->HasPendingUpdates()) {
@@ -372,10 +376,6 @@ int main(int argc, char **argv)
LogError("Failed. But ignoring error and going on..");
}
if (!content_db.LoadSkillCaps(std::string(hotfix_name))) {
LogError("Loading skill caps failed!");
return 1;
}
if (!database.LoadSpells(hotfix_name, &SPDAT_RECORDS, &spells)) {
LogError("Loading spells failed!");
return 1;
+24 -38
View File
@@ -8,6 +8,7 @@
#include "zone.h"
#include "string_ids.h"
#include "../common/skill_caps.h"
extern volatile bool is_zone_loaded;
@@ -65,7 +66,7 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
int r;
for (r = 0; r <= EQ::skills::HIGHEST_SKILL; r++) {
skills[r] = content_db.GetSkillCap(GetClass(), (EQ::skills::SkillType)r, GetLevel());
skills[r] = skill_caps.GetSkillCap(GetClass(), (EQ::skills::SkillType)r, GetLevel()).cap;
}
size = d->size;
@@ -460,15 +461,13 @@ int64 Merc::CalcMaxHP() {
//but the actual effect sent on live causes the client
//to apply it to (basehp + itemhp).. I will oblige to the client's whims over
//the aa description
nd += aabonuses.MaxHP; //Natural Durability, Physical Enhancement, Planar Durability
nd += aabonuses.MaxHP + spellbonuses.MaxHPChange + itembonuses.MaxHPChange; //Natural Durability, Physical Enhancement, Planar Durability
max_hp = (float)max_hp * (float)nd / (float)10000; //this is to fix the HP-above-495k issue
max_hp += spellbonuses.HP + aabonuses.HP;
max_hp += GroupLeadershipAAHealthEnhancement();
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
if (current_hp > max_hp)
current_hp = max_hp;
@@ -489,23 +488,12 @@ int64 Merc::CalcBaseHP()
int64 Merc::CalcMaxMana()
{
switch(GetCasterClass())
{
case 'I':
case 'W': {
if (IsIntelligenceCasterClass() || IsWisdomCasterClass()) {
max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement());
break;
}
case 'N': {
} else {
max_mana = 0;
break;
}
default: {
LogDebug("Invalid Class [{}] in CalcMaxMana", GetCasterClass());
max_mana = 0;
break;
}
}
if (max_mana < 0) {
max_mana = 0;
}
@@ -565,12 +553,13 @@ int64 Merc::CalcManaRegen()
regen = mana_regen + spellbonuses.ManaRegen + itembonuses.ManaRegen;
}
if(GetCasterClass() == 'I')
if (IsIntelligenceCasterClass()) {
regen += (itembonuses.HeroicINT / 25);
else if(GetCasterClass() == 'W')
} else if (IsWisdomCasterClass()) {
regen += (itembonuses.HeroicWIS / 25);
else
} else {
regen = 0;
}
//AAs
regen += aabonuses.ManaRegen;
@@ -581,14 +570,11 @@ int64 Merc::CalcManaRegen()
int64 Merc::CalcManaRegenCap()
{
int64 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap;
switch(GetCasterClass())
{
case 'I':
if (IsIntelligenceCasterClass()) {
cap += (itembonuses.HeroicINT / 25);
break;
case 'W':
} else if (IsWisdomCasterClass()) {
cap += (itembonuses.HeroicWIS / 25);
break;
}
return (cap * RuleI(Character, ManaRegenMultiplier) / 100);
@@ -783,16 +769,16 @@ void Merc::CalcRestState() {
}
bool Merc::HasSkill(EQ::skills::SkillType skill_id) const {
return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id));
return ((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id));
}
bool Merc::CanHaveSkill(EQ::skills::SkillType skill_id) const {
return(content_db.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0);
return skill_caps.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)).cap > 0;
//if you don't have it by max level, then odds are you never will?
}
uint16 Merc::MaxSkill(EQ::skills::SkillType skillid, uint16 class_, uint16 level) const {
return(content_db.GetSkillCap(class_, skillid, level));
return skill_caps.GetSkillCap(class_, skillid, level).cap;
}
void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) {
@@ -1166,7 +1152,7 @@ void Merc::AI_Process() {
float newX = 0;
float newY = 0;
float newZ = 0;
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) {
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != Archetype::Caster) {
RunTo(newX, newY, newZ);
return;
}
@@ -1314,7 +1300,7 @@ void Merc::AI_Process() {
if(AI_EngagedCastCheck()) {
MercMeditate(false);
}
else if(GetArchetype() == ARCHETYPE_CASTER)
else if(GetArchetype() == Archetype::Caster)
MercMeditate(true);
}
}
@@ -1337,7 +1323,7 @@ void Merc::AI_Process() {
//TODO: Implement passive stances.
//if(GetStance() != MercStancePassive) {
if(!AI_IdleCastCheck() && !IsCasting()) {
if(GetArchetype() == ARCHETYPE_CASTER) {
if(GetArchetype() == Archetype::Caster) {
MercMeditate(true);
}
}
@@ -1792,7 +1778,7 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) {
if( !IsImmuneToSpell(selectedMercSpell.spellid, this)
&& (CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) {
if( GetArchetype() == ARCHETYPE_MELEE && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) {
if( GetArchetype() == Archetype::Melee && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) {
continue;
}
@@ -1819,7 +1805,7 @@ bool Merc::AICastSpell(int8 iChance, uint32 iSpellTypes) {
if( !tar->IsImmuneToSpell(selectedMercSpell.spellid, this)
&& (tar->CanBuffStack(selectedMercSpell.spellid, mercLevel, true) >= 0)) {
if( tar->GetArchetype() == ARCHETYPE_MELEE && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) {
if( tar->GetArchetype() == Archetype::Melee && IsEffectInSpell(selectedMercSpell.spellid, SE_IncreaseSpellHaste)) {
continue;
}
@@ -4215,7 +4201,7 @@ const char* Merc::GetRandomName(){
//name must begin with an upper-case letter.
valid = false;
}
else if (database.CheckUsedName(rndname)) {
else if (!database.IsNameUsed(rndname)) {
valid = true;
}
else {
@@ -5390,7 +5376,7 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) {
{
if(merc->GetMercenaryCharacterID() != 0)
{
database.SetGroupID(merc->GetName(), 0, merc->GetMercenaryCharacterID(), true);
Group::RemoveFromGroup(merc);
}
}
}
@@ -5475,7 +5461,7 @@ bool Merc::MercJoinClientGroup() {
if (AddMercToGroup(this, g))
{
database.SetGroupID(mercOwner->GetName(), g->GetID(), mercOwner->CharacterID(), false);
g->AddToGroup(mercOwner);
database.SetGroupLeaderName(g->GetID(), mercOwner->GetName());
database.RefreshGroupFromDB(mercOwner);
g->SaveGroupLeaderAA();
+154 -125
View File
@@ -940,19 +940,16 @@ int Mob::_GetFearSpeed() const {
return speed_mod;
}
int64 Mob::CalcMaxMana() {
switch (GetCasterClass()) {
case 'I':
max_mana = (((GetINT()/2)+1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
break;
case 'W':
max_mana = (((GetWIS()/2)+1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
break;
case 'N':
default:
max_mana = 0;
break;
int64 Mob::CalcMaxMana()
{
if (IsIntelligenceCasterClass()) {
max_mana = (((GetINT() / 2) + 1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
} else if (IsWisdomCasterClass()) {
max_mana = (((GetWIS() / 2) + 1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
} else {
max_mana = 0;
}
if (max_mana < 0) {
max_mana = 0;
}
@@ -981,90 +978,155 @@ int64 Mob::GetSpellHPBonuses() {
return spell_hp;
}
char Mob::GetCasterClass() const {
switch(class_)
{
case Class::Cleric:
case Class::Paladin:
case Class::Ranger:
case Class::Druid:
case Class::Shaman:
case Class::Beastlord:
case Class::ClericGM:
case Class::PaladinGM:
case Class::RangerGM:
case Class::DruidGM:
case Class::ShamanGM:
case Class::BeastlordGM:
return 'W';
break;
case Class::ShadowKnight:
case Class::Bard:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
case Class::ShadowKnightGM:
case Class::BardGM:
case Class::NecromancerGM:
case Class::WizardGM:
case Class::MagicianGM:
case Class::EnchanterGM:
return 'I';
break;
default:
return 'N';
break;
bool Mob::IsIntelligenceCasterClass() const
{
switch (GetClass()) {
case Class::ShadowKnight:
case Class::Bard:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
case Class::ShadowKnightGM:
case Class::BardGM:
case Class::NecromancerGM:
case Class::WizardGM:
case Class::MagicianGM:
case Class::EnchanterGM:
return true;
}
return false;
}
uint8 Mob::GetArchetype() const {
switch(class_)
{
case Class::Paladin:
case Class::Ranger:
case Class::ShadowKnight:
case Class::Bard:
case Class::Beastlord:
case Class::PaladinGM:
case Class::RangerGM:
case Class::ShadowKnightGM:
case Class::BardGM:
case Class::BeastlordGM:
return ARCHETYPE_HYBRID;
break;
case Class::Cleric:
case Class::Druid:
case Class::Shaman:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
case Class::ClericGM:
case Class::DruidGM:
case Class::ShamanGM:
case Class::NecromancerGM:
case Class::WizardGM:
case Class::MagicianGM:
case Class::EnchanterGM:
return ARCHETYPE_CASTER;
break;
case Class::Warrior:
case Class::Monk:
case Class::Rogue:
case Class::Berserker:
case Class::WarriorGM:
case Class::MonkGM:
case Class::RogueGM:
case Class::BerserkerGM:
return ARCHETYPE_MELEE;
break;
default:
return ARCHETYPE_HYBRID;
break;
bool Mob::IsPureMeleeClass() const
{
switch (GetClass()) {
case Class::Warrior:
case Class::Monk:
case Class::Rogue:
case Class::Berserker:
case Class::WarriorGM:
case Class::MonkGM:
case Class::RogueGM:
case Class::BerserkerGM:
return true;
default:
break;
}
return false;
}
bool Mob::IsWarriorClass() const
{
switch (GetClass()) {
case Class::Warrior:
case Class::Paladin:
case Class::Ranger:
case Class::ShadowKnight:
case Class::Monk:
case Class::Bard:
case Class::Rogue:
case Class::Beastlord:
case Class::Berserker:
case Class::WarriorGM:
case Class::PaladinGM:
case Class::RangerGM:
case Class::ShadowKnightGM:
case Class::MonkGM:
case Class::BardGM:
case Class::RogueGM:
case Class::BeastlordGM:
case Class::BerserkerGM:
return true;
default:
break;
}
return false;
}
bool Mob::IsWisdomCasterClass() const
{
switch (GetClass()) {
case Class::Cleric:
case Class::Paladin:
case Class::Ranger:
case Class::Druid:
case Class::Shaman:
case Class::Beastlord:
case Class::ClericGM:
case Class::PaladinGM:
case Class::RangerGM:
case Class::DruidGM:
case Class::ShamanGM:
case Class::BeastlordGM:
return true;
}
return false;
}
uint8 Mob::GetArchetype() const
{
switch (GetClass()) {
case Class::Paladin:
case Class::Ranger:
case Class::ShadowKnight:
case Class::Bard:
case Class::Beastlord:
case Class::PaladinGM:
case Class::RangerGM:
case Class::ShadowKnightGM:
case Class::BardGM:
case Class::BeastlordGM:
return Archetype::Hybrid;
case Class::Cleric:
case Class::Druid:
case Class::Shaman:
case Class::Necromancer:
case Class::Wizard:
case Class::Magician:
case Class::Enchanter:
case Class::ClericGM:
case Class::DruidGM:
case Class::ShamanGM:
case Class::NecromancerGM:
case Class::WizardGM:
case Class::MagicianGM:
case Class::EnchanterGM:
return Archetype::Caster;
case Class::Warrior:
case Class::Monk:
case Class::Rogue:
case Class::Berserker:
case Class::WarriorGM:
case Class::MonkGM:
case Class::RogueGM:
case Class::BerserkerGM:
return Archetype::Melee;
default:
break;
}
return Archetype::Hybrid;
}
const std::string Mob::GetArchetypeName()
{
switch (GetArchetype()) {
case Archetype::Hybrid:
return "Hybrid";
case Archetype::Caster:
return "Caster";
case Archetype::Melee:
return "Melee";
default:
break;
}
return "Hybrid";
}
void Mob::SetSpawnLastNameByClass(NewSpawn_Struct* ns)
@@ -4586,39 +4648,6 @@ bool Mob::CanThisClassTripleAttack() const
}
}
bool Mob::IsWarriorClass(void) const
{
switch(GetClass())
{
case Class::Warrior:
case Class::WarriorGM:
case Class::Rogue:
case Class::RogueGM:
case Class::Monk:
case Class::MonkGM:
case Class::Paladin:
case Class::PaladinGM:
case Class::ShadowKnight:
case Class::ShadowKnightGM:
case Class::Ranger:
case Class::RangerGM:
case Class::Beastlord:
case Class::BeastlordGM:
case Class::Berserker:
case Class::BerserkerGM:
case Class::Bard:
case Class::BardGM:
{
return true;
}
default:
{
return false;
}
}
}
bool Mob::CanThisClassParry(void) const
{
if(!IsClient()) {
+5 -1
View File
@@ -838,8 +838,11 @@ public:
virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr);
virtual void MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, const char *petname = nullptr, float in_size = 0.0f);
bool IsWarriorClass() const;
char GetCasterClass() const;
bool IsIntelligenceCasterClass() const;
bool IsPureMeleeClass() const;
bool IsWisdomCasterClass() const;
uint8 GetArchetype() const;
const std::string GetArchetypeName();
void SetZone(uint32 zone_id, uint32 instance_id);
void SendStatsWindow(Client* c, bool use_window);
void ShowStats(Client* client);
@@ -992,6 +995,7 @@ public:
inline void SetDualWieldingSameDelayWeapons(int32 val) { dw_same_delay = val; }
bool IsTargetedFocusEffect(int focus_type);
bool HasPersistDeathIllusion(int32 spell_id);
void DoShieldDamageOnShielderSpellEffect(Mob* shield_target, int64 hit_damage_done, EQ::skills::SkillType skillInUse);
bool TryDoubleMeleeRoundEffect();
+18 -24
View File
@@ -48,6 +48,7 @@
#include "npc_scale_manager.h"
#include "bot.h"
#include "../common/skill_caps.h"
#include <stdio.h>
#include <string>
@@ -363,7 +364,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
//give NPCs skill values...
int r;
for (r = 0; r <= EQ::skills::HIGHEST_SKILL; r++) {
skills[r] = content_db.GetSkillCap(GetClass(), (EQ::skills::SkillType)r, moblevel);
skills[r] = skill_caps.GetSkillCap(GetClass(), (EQ::skills::SkillType)r, moblevel).cap;
}
// some overrides -- really we need to be able to set skills for mobs in the DB
// There are some known low level SHM/BST pets that do not follow this, which supports
@@ -2756,35 +2757,28 @@ void NPC::SetSwarmTarget(int target_id)
int64 NPC::CalcMaxMana()
{
if (npc_mana == 0) {
switch (GetCasterClass()) {
case 'I':
max_mana = (((GetINT() / 2) + 1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
break;
case 'W':
max_mana = (((GetWIS() / 2) + 1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
break;
default:
max_mana = 0;
break;
if (IsIntelligenceCasterClass()) {
max_mana = (((GetINT() / 2) + 1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
} else if (IsWisdomCasterClass()) {
max_mana = (((GetWIS() / 2) + 1) * GetLevel()) + spellbonuses.Mana + itembonuses.Mana;
} else {
max_mana = 0;
}
if (max_mana < 0) {
max_mana = 0;
}
return max_mana;
}
else {
switch (GetCasterClass()) {
case 'I':
max_mana = npc_mana + spellbonuses.Mana + itembonuses.Mana;
break;
case 'W':
max_mana = npc_mana + spellbonuses.Mana + itembonuses.Mana;
break;
default:
max_mana = 0;
break;
} else {
if (IsIntelligenceCasterClass()) {
max_mana = npc_mana + spellbonuses.Mana + itembonuses.Mana;
} else if (IsWisdomCasterClass()) {
max_mana = npc_mana + spellbonuses.Mana + itembonuses.Mana;
} else {
max_mana = 0;
}
if (max_mana < 0) {
max_mana = 0;
}
@@ -3444,7 +3438,7 @@ void NPC::RecalculateSkills()
{
int r;
for (r = 0; r <= EQ::skills::HIGHEST_SKILL; r++) {
skills[r] = content_db.GetSkillCap(GetClass(), (EQ::skills::SkillType)r, level);
skills[r] = skill_caps.GetSkillCap(GetClass(), (EQ::skills::SkillType)r, level).cap;
}
// some overrides -- really we need to be able to set skills for mobs in the DB
+22 -1
View File
@@ -197,11 +197,12 @@ public:
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
// loot
void AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item = true);
void AddItem(const EQ::ItemData *item, uint16 charges, bool equip_item = true, bool quest = false);
void AddItem(
uint32 item_id,
uint16 charges,
bool equip_item = true,
bool quest = false,
uint32 augment_one = 0,
uint32 augment_two = 0,
uint32 augment_three = 0,
@@ -214,10 +215,12 @@ public:
void AddLootDropTable(uint32 lootdrop_id, uint8 drop_limit, uint8 min_drop);
void CheckGlobalLootTables();
void RemoveItem(uint32 item_id, uint16 quantity = 0, uint16 slot = 0);
void RemoveItem(LootItem *item_data, uint8 quantity = 0);
void CheckTrivialMinMaxLevelDrop(Mob *killer);
void ClearLootItems();
inline const LootItems &GetLootItems() { return m_loot_items; }
LootItem *GetItem(int slot_id);
LootItem *GetItemByItemID(int16 itemid);
void AddLootCash(uint32 in_copper, uint32 in_silver, uint32 in_gold, uint32 in_platinum);
void RemoveLootCash();
void QueryLoot(Client *to, bool is_pet_query = false);
@@ -238,6 +241,22 @@ public:
inline void SetGold(uint32 amt) { m_loot_gold = amt; }
inline void SetPlatinum(uint32 amt) { m_loot_platinum = amt; }
// MultiQuest
bool HasQuestLootItem(int16 itemid);
bool HasQuestLoot();
bool RemoveQuestLootItems(int16 itemid);
bool HasRequiredQuestLoot(int16 itemid1, int16 itemid2, int16 itemid3, int16 itemid4);
void CleanQuestLootItems();
uint8 CountQuestItem(uint16 itemid);
uint8 CountQuestItems();
bool AddQuestLoot(int16 itemid, int8 charges = 1);
void DeleteQuestLoot(int16 itemid1, int16 itemid2 = 0, int16 itemid3 = 0, int16 itemid4 = 0);
void DeleteInvalidQuestLoot();
bool AddPetLoot(int16 itemid, int8 charges = 1, bool fromquest = false);
bool HasPetLootItem(int16 itemid);
bool RemovePetLootItems(int16 itemid);
void DescribeAggro(Client *to_who, Mob *mob, bool verbose);
virtual void UpdateEquipmentLight();
virtual int64 CalcMaxMana();
@@ -326,6 +345,8 @@ public:
const EQ::ItemData *item2,
LootdropEntriesRepository::LootdropEntries loot_drop,
bool wear_change = false,
bool quest = false,
bool pet = false,
uint32 augment_one = 0,
uint32 augment_two = 0,
uint32 augment_three = 0,

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