mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-24 22:32:29 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e19b969541 | |||
| 4241556f75 | |||
| 961332b40c | |||
| a1a861e0c4 | |||
| 4bbb1aa92f | |||
| 1212ccefef | |||
| c203fec9b4 | |||
| 16ab1839e8 | |||
| f5e4c6a127 | |||
| 166c87c931 | |||
| 345dd442dd | |||
| 565baec675 | |||
| 9884c442e9 | |||
| ad0b5d6a1c | |||
| b82b32e1d2 | |||
| 2fb72e5729 | |||
| 3791bc788f | |||
| 833fa55fdf | |||
| 4fc3c27715 | |||
| cea3ad6a42 | |||
| d8926cd5f3 | |||
| efb03164c7 | |||
| 455eb2e6d9 | |||
| b5b0e53da2 | |||
| 68cb94b39c | |||
| 3d95b6c184 | |||
| 7db7631308 | |||
| f053cd3b56 | |||
| cf27f2bc88 | |||
| 79918ebaba | |||
| 2a648507f2 | |||
| f395ee0508 | |||
| 7166fcc650 | |||
| ae8e58ddc5 | |||
| 26e72c6857 |
@@ -1,3 +1,81 @@
|
||||
## [22.28.0] - 10/15/2023
|
||||
|
||||
### Bots
|
||||
|
||||
* Adjust Bot Movement Speed ([#3615](https://github.com/EQEmu/Server/pull/3615)) @Kinglykrab 2023-10-14
|
||||
* Fix bot removal on zone, regression from #3611 ([#3631](https://github.com/EQEmu/Server/pull/3631)) @Akkadius 2023-10-16
|
||||
|
||||
### Crash
|
||||
|
||||
* Fix Crash with #summon ([#3618](https://github.com/EQEmu/Server/pull/3618)) @Kinglykrab 2023-10-14
|
||||
* Fix crash in Mob::ShowBuffs ([#3632](https://github.com/EQEmu/Server/pull/3632)) @Akkadius 2023-10-16
|
||||
* Resolve crash when assigning empty raid note. ([#3628](https://github.com/EQEmu/Server/pull/3628)) @Aeadoin 2023-10-15
|
||||
|
||||
### Feature
|
||||
|
||||
* Add Extra Kick Classes ([#3613](https://github.com/EQEmu/Server/pull/3613)) @Kinglykrab 2023-10-11
|
||||
* Add Immune to Assassinate Special Ability ([#3622](https://github.com/EQEmu/Server/pull/3622)) @Kinglykrab 2023-10-14
|
||||
* Add Immune to Headshot Special Ability ([#3624](https://github.com/EQEmu/Server/pull/3624)) @Kinglykrab 2023-10-14
|
||||
* Update Raid Functions for Titanium and Underfoot ([#3524](https://github.com/EQEmu/Server/pull/3524)) @neckkola 2023-10-14
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix #cast defaulting to cast time ([#3617](https://github.com/EQEmu/Server/pull/3617)) @Kinglykrab 2023-10-14
|
||||
|
||||
### Parser Fix
|
||||
|
||||
* Fix SendIllusion Spire parsing ([#3623](https://github.com/EQEmu/Server/pull/3623)) @Kinglykrab 2023-10-14
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add GrantAllAAPoints() to Perl/Lua and Modify #grantaa ([#3616](https://github.com/EQEmu/Server/pull/3616)) @Kinglykrab 2023-10-14
|
||||
* Add target ID and spell exports to events ([#3620](https://github.com/EQEmu/Server/pull/3620)) @Kinglykrab 2023-10-15
|
||||
|
||||
### Scripts
|
||||
|
||||
* Update 13th Floor importer ([#3630](https://github.com/EQEmu/Server/pull/3630)) @joligario 2023-10-16
|
||||
* Update 13th Floor script for legacy research tome bagtypes ([#3621](https://github.com/EQEmu/Server/pull/3621)) @joligario 2023-10-14
|
||||
|
||||
## [22.27.0] - 10/07/2023
|
||||
|
||||
### Crash
|
||||
|
||||
* Bot member zoned crash fix ([#3607](https://github.com/EQEmu/Server/pull/3607)) @Akkadius 2023-10-07
|
||||
* Fix #summon crash ([#3608](https://github.com/EQEmu/Server/pull/3608)) @Akkadius 2023-10-07
|
||||
* Fix CanUseAlternateAdvancementRank crash ([#3609](https://github.com/EQEmu/Server/pull/3609)) @Akkadius 2023-10-07
|
||||
* Fix crash in #movechar ([#3612](https://github.com/EQEmu/Server/pull/3612)) @Akkadius 2023-10-07
|
||||
* Fix crash in CastSpell Quest API input cast ([#3610](https://github.com/EQEmu/Server/pull/3610)) @Akkadius 2023-10-07
|
||||
* Fix dangling pointer crash observed in SendHPPacketsFrom ([#3611](https://github.com/EQEmu/Server/pull/3611)) @Akkadius 2023-10-07
|
||||
* Fix rarer crash with File::Makedir ([#3606](https://github.com/EQEmu/Server/pull/3606)) @Akkadius 2023-10-07
|
||||
|
||||
### Fixes
|
||||
|
||||
* Add Validation to #find, #set, and #show args ([#3598](https://github.com/EQEmu/Server/pull/3598)) @Kinglykrab 2023-09-18
|
||||
* Ensure Linux builds report failures @Akkadius 2023-10-03
|
||||
* Fix #show group_info Popup ([#3605](https://github.com/EQEmu/Server/pull/3605)) @Kinglykrab 2023-10-04
|
||||
* Fix swarm pet names to use '_' instead of ' ' ([#3601](https://github.com/EQEmu/Server/pull/3601)) @noudess 2023-09-19
|
||||
* Invis vs. Undead/Animal Breaks Charm for Pets ([#3587](https://github.com/EQEmu/Server/pull/3587)) @crdunwel 2023-09-19
|
||||
|
||||
### Logs
|
||||
|
||||
* Change pathing log messages from Error to Pathing. ([#3604](https://github.com/EQEmu/Server/pull/3604)) @joligario 2023-09-29
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add Caster ID Parameter to FindBuff in Perl/Lua ([#3590](https://github.com/EQEmu/Server/pull/3590)) @Kinglykrab 2023-09-29
|
||||
|
||||
## [22.26.2] - 09/18/2023
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix an issue with schema versioning for the AA update
|
||||
|
||||
## [22.26.1] - 09/17/2023
|
||||
|
||||
### Fixes
|
||||
|
||||
* Add Validation to #find, #set, and #show args ([#3598](https://github.com/EQEmu/Server/pull/3598)) @Kinglykrab 2023-09-17
|
||||
|
||||
## [22.26.0] - 09/17/2023
|
||||
|
||||
### Bug
|
||||
|
||||
@@ -589,6 +589,7 @@ SET(common_headers
|
||||
ptimer.h
|
||||
queue.h
|
||||
races.h
|
||||
raid.h
|
||||
random.h
|
||||
rdtsc.h
|
||||
rulesys.h
|
||||
|
||||
@@ -4941,6 +4941,21 @@ CREATE TABLE `character_stats_record` (
|
||||
.sql = R"(
|
||||
ALTER TABLE `aa_ability` ADD COLUMN `auto_grant_enabled` TINYINT(4) NOT NULL DEFAULT '0' AFTER `reset_on_death`;
|
||||
UPDATE `aa_ability` SET `auto_grant_enabled` = 1 WHERE `grant_only` = 0 AND `charges` = 0 AND `category` = -1;
|
||||
)"
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9237,
|
||||
.description = "2023_10_15_import_13th_floor.sql",
|
||||
.check = "SHOW COLUMNS FROM `items` LIKE 'bardeffect';",
|
||||
.condition = "contains",
|
||||
.match = "mediumint",
|
||||
.sql = R"(
|
||||
ALTER TABLE `items`
|
||||
MODIFY COLUMN `scriptfileid` MEDIUMINT(6) NOT NULL DEFAULT 0,
|
||||
MODIFY COLUMN `powersourcecapacity` MEDIUMINT(7) NOT NULL DEFAULT 0,
|
||||
MODIFY COLUMN `augdistiller` INT(11) UNSIGNED NOT NULL DEFAULT 0,
|
||||
MODIFY COLUMN `scrollunk1` INT(11) UNSIGNED NOT NULL DEFAULT 0,
|
||||
MODIFY COLUMN `bardeffect` MEDIUMINT(6) NOT NULL DEFAULT 0;
|
||||
)"
|
||||
},
|
||||
|
||||
|
||||
@@ -4164,7 +4164,6 @@ struct RaidGeneral_Struct {
|
||||
/*68*/ uint32 unknown1;
|
||||
/*72*/ char leader_name[64];
|
||||
/*136*/ uint32 parameter;
|
||||
/*200*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidAddMember_Struct {
|
||||
@@ -4175,9 +4174,14 @@ struct RaidAddMember_Struct {
|
||||
/*139*/ uint8 flags[5]; //no idea if these are needed...
|
||||
};
|
||||
|
||||
struct RaidNote_Struct {
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidMOTD_Struct {
|
||||
/*000*/ RaidGeneral_Struct general; // leader_name and action only used
|
||||
/*136*/ char motd[0]; // max size is 1024, but reply is variable
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char motd[1024];
|
||||
};
|
||||
|
||||
struct RaidLeadershipUpdate_Struct {
|
||||
|
||||
@@ -250,9 +250,7 @@ enum {
|
||||
commandMovecharSelfOnly = 80, //below this == only self move allowed
|
||||
commandMovecharToSpecials = 200, //ability to send people to cshom/load zones
|
||||
commandCastSpecials = 100, //can cast special spells
|
||||
commandInstacast = 100, //insta-cast all #casted spells
|
||||
commandDoAnimOthers = 100, //can #doanim on others
|
||||
commandLockZones = 101, //can lock or unlock zones
|
||||
commandEditPlayerCorpses = 150, //can Edit Player Corpses
|
||||
commandInterrogateInv = 100, //below this == only log on error state and self-only target dump
|
||||
commandInvSnapshot = 150 //ability to clear/restore snapshots
|
||||
|
||||
+8
-2
@@ -55,8 +55,14 @@ bool File::Exists(const std::string &name)
|
||||
*/
|
||||
void File::Makedir(const std::string &directory_name)
|
||||
{
|
||||
fs::create_directory(directory_name);
|
||||
fs::permissions(directory_name, fs::perms::owner_all);
|
||||
try {
|
||||
fs::create_directory(directory_name);
|
||||
fs::permissions(directory_name, fs::perms::owner_all);
|
||||
}
|
||||
catch (const fs::filesystem_error &ex) {
|
||||
std::cout << "Failed to create directory: " << directory_name << std::endl;
|
||||
std::cout << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string File::FindEqemuConfigPath()
|
||||
|
||||
+135
-88
@@ -34,6 +34,7 @@
|
||||
#include "../rulesys.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../races.h"
|
||||
#include "../raid.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -2608,88 +2609,124 @@ namespace RoF
|
||||
|
||||
ENCODE(OP_RaidJoin)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct* emu = (RaidCreate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct* general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
general->action = 8;
|
||||
general->parameter = 1;
|
||||
strn0cpy(general->leader_name, raid_create->leader_name, 64);
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
general->action = raidCreate;
|
||||
general->parameter = RaidCommandAcceptInvite;
|
||||
strn0cpy(general->leader_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
strn0cpy(general->player_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
safe_delete(inapp);
|
||||
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct *raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct* raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
if (raid_gen->action == 0) // raid add has longer length than other raid updates
|
||||
switch (raid_gen->action)
|
||||
{
|
||||
RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer;
|
||||
case raidAdd:
|
||||
{
|
||||
RaidAddMember_Struct* emu = (RaidAddMember_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct));
|
||||
structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
structs::RaidAddMember_Struct* eq = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
|
||||
add_member->raidGen.action = in_add_member->raidGen.action;
|
||||
add_member->raidGen.parameter = in_add_member->raidGen.parameter;
|
||||
strn0cpy(add_member->raidGen.leader_name, in_add_member->raidGen.leader_name, 64);
|
||||
strn0cpy(add_member->raidGen.player_name, in_add_member->raidGen.player_name, 64);
|
||||
add_member->_class = in_add_member->_class;
|
||||
add_member->level = in_add_member->level;
|
||||
add_member->isGroupLeader = in_add_member->isGroupLeader;
|
||||
add_member->flags[0] = in_add_member->flags[0];
|
||||
add_member->flags[1] = in_add_member->flags[1];
|
||||
add_member->flags[2] = in_add_member->flags[2];
|
||||
add_member->flags[3] = in_add_member->flags[3];
|
||||
add_member->flags[4] = in_add_member->flags[4];
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
else if (raid_gen->action == 35)
|
||||
{
|
||||
RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) +
|
||||
strlen(inmotd->motd) + 1);
|
||||
structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer;
|
||||
OUT(raidGen.action);
|
||||
OUT(raidGen.parameter);
|
||||
OUT_str(raidGen.leader_name);
|
||||
OUT_str(raidGen.player_name);
|
||||
OUT(_class);
|
||||
OUT(level);
|
||||
OUT(isGroupLeader);
|
||||
OUT(flags[0]);
|
||||
OUT(flags[1]);
|
||||
OUT(flags[2]);
|
||||
OUT(flags[3]);
|
||||
OUT(flags[4]);
|
||||
|
||||
outmotd->general.action = inmotd->general.action;
|
||||
strn0cpy(outmotd->general.player_name, inmotd->general.player_name, 64);
|
||||
strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else if (raid_gen->action == 14 || raid_gen->action == 30)
|
||||
case raidSetMotd:
|
||||
{
|
||||
RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer;
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
RaidMOTD_Struct* emu = (RaidMOTD_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct));
|
||||
structs::RaidMOTD_Struct* eq = (structs::RaidMOTD_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(motd);
|
||||
|
||||
outlaa->action = inlaa->action;
|
||||
strn0cpy(outlaa->player_name, inlaa->player_name, 64);
|
||||
strn0cpy(outlaa->leader_name, inlaa->leader_name, 64);
|
||||
memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
case raidSetLeaderAbilities:
|
||||
case raidMakeLeader:
|
||||
{
|
||||
RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer;
|
||||
RaidLeadershipUpdate_Struct* emu = (RaidLeadershipUpdate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct* eq = (structs::RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT_str(player_name);
|
||||
OUT_str(leader_name);
|
||||
memcpy(&eq->raid, &emu->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
auto emu = (RaidNote_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidNote_Struct));
|
||||
auto eq = (structs::RaidNote_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(note);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidNoRaid:
|
||||
{
|
||||
dest->QueuePacket(inapp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
RaidGeneral_Struct* emu = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64);
|
||||
strn0cpy(raid_general->player_name, in_raid_general->player_name, 64);
|
||||
raid_general->action = in_raid_general->action;
|
||||
raid_general->parameter = in_raid_general->parameter;
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
structs::RaidGeneral_Struct* eq = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT(parameter);
|
||||
OUT_str(leader_name);
|
||||
OUT_str(player_name);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
@@ -4861,37 +4898,47 @@ namespace RoF
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
|
||||
// This is a switch on the RaidGeneral action
|
||||
switch (*(uint32 *)__packet->pBuffer) {
|
||||
case 35: { // raidMOTD
|
||||
// we don't have a nice macro for this
|
||||
structs::RaidMOTD_Struct *__eq_buffer = (structs::RaidMOTD_Struct *)__packet->pBuffer;
|
||||
__eq_buffer->motd[1023] = '\0';
|
||||
size_t motd_size = strlen(__eq_buffer->motd) + 1;
|
||||
__packet->size = sizeof(RaidMOTD_Struct) + motd_size;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
RaidMOTD_Struct *emu = (RaidMOTD_Struct *)__packet->pBuffer;
|
||||
structs::RaidMOTD_Struct *eq = (structs::RaidMOTD_Struct *)__eq_buffer;
|
||||
strn0cpy(emu->general.player_name, eq->general.player_name, 64);
|
||||
strn0cpy(emu->motd, eq->motd, motd_size);
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case 36: { // raidPlayerNote unhandled
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct);
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
strn0cpy(emu->leader_name, eq->leader_name, 64);
|
||||
strn0cpy(emu->player_name, eq->player_name, 64);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
RaidGeneral_Struct* rgs = (RaidGeneral_Struct*)__packet->pBuffer;
|
||||
|
||||
switch (rgs->action)
|
||||
{
|
||||
case raidSetMotd:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidMOTD_Struct, structs::RaidMOTD_Struct, motd);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(motd);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidNote_Struct, structs::RaidNote_Struct, note);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(note);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
IN_str(leader_name);
|
||||
IN_str(player_name);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+133
-99
@@ -35,7 +35,7 @@
|
||||
#include "../path_manager.h"
|
||||
#include "../classes.h"
|
||||
#include "../races.h"
|
||||
#include "../../zone/raids.h"
|
||||
#include "../raid.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -2678,100 +2678,124 @@ namespace RoF2
|
||||
|
||||
ENCODE(OP_RaidJoin)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct* emu = (RaidCreate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct* general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
general->action = 8;
|
||||
general->parameter = 1;
|
||||
strn0cpy(general->leader_name, raid_create->leader_name, 64);
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
general->action = raidCreate;
|
||||
general->parameter = RaidCommandAcceptInvite;
|
||||
strn0cpy(general->leader_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
strn0cpy(general->player_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
safe_delete(inapp);
|
||||
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct *raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct* raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
if (raid_gen->action == 0) // raid add has longer length than other raid updates
|
||||
switch (raid_gen->action)
|
||||
{
|
||||
RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer;
|
||||
case raidAdd:
|
||||
{
|
||||
RaidAddMember_Struct* emu = (RaidAddMember_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct));
|
||||
structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
structs::RaidAddMember_Struct* eq = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
|
||||
add_member->raidGen.action = in_add_member->raidGen.action;
|
||||
add_member->raidGen.parameter = in_add_member->raidGen.parameter;
|
||||
strn0cpy(add_member->raidGen.leader_name, in_add_member->raidGen.leader_name, 64);
|
||||
strn0cpy(add_member->raidGen.player_name, in_add_member->raidGen.player_name, 64);
|
||||
add_member->_class = in_add_member->_class;
|
||||
add_member->level = in_add_member->level;
|
||||
add_member->isGroupLeader = in_add_member->isGroupLeader;
|
||||
add_member->flags[0] = in_add_member->flags[0];
|
||||
add_member->flags[1] = in_add_member->flags[1];
|
||||
add_member->flags[2] = in_add_member->flags[2];
|
||||
add_member->flags[3] = in_add_member->flags[3];
|
||||
add_member->flags[4] = in_add_member->flags[4];
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
else if (raid_gen->action == 35)
|
||||
{
|
||||
RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) +
|
||||
strlen(inmotd->motd) + 1);
|
||||
structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer;
|
||||
OUT(raidGen.action);
|
||||
OUT(raidGen.parameter);
|
||||
OUT_str(raidGen.leader_name);
|
||||
OUT_str(raidGen.player_name);
|
||||
OUT(_class);
|
||||
OUT(level);
|
||||
OUT(isGroupLeader);
|
||||
OUT(flags[0]);
|
||||
OUT(flags[1]);
|
||||
OUT(flags[2]);
|
||||
OUT(flags[3]);
|
||||
OUT(flags[4]);
|
||||
|
||||
outmotd->general.action = inmotd->general.action;
|
||||
strn0cpy(outmotd->general.player_name, inmotd->general.player_name, 64);
|
||||
strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else if (raid_gen->action == 14 || raid_gen->action == 30)
|
||||
case raidSetMotd:
|
||||
{
|
||||
RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer;
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
RaidMOTD_Struct* emu = (RaidMOTD_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct));
|
||||
structs::RaidMOTD_Struct* eq = (structs::RaidMOTD_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(motd);
|
||||
|
||||
outlaa->action = inlaa->action;
|
||||
strn0cpy(outlaa->player_name, inlaa->player_name, 64);
|
||||
strn0cpy(outlaa->leader_name, inlaa->leader_name, 64);
|
||||
memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else if (raid_gen->action == raidSetNote)
|
||||
case raidSetLeaderAbilities:
|
||||
case raidMakeLeader:
|
||||
{
|
||||
auto in_note = (RaidGeneral_Struct*)__emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
auto note = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
note->action = raidSetNote;
|
||||
strn0cpy(note->leader_name, in_note->leader_name, sizeof(note->leader_name));
|
||||
strn0cpy(note->player_name, in_note->player_name, sizeof(note->leader_name));
|
||||
strn0cpy(note->note, in_note->note, sizeof(note->note));
|
||||
dest->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
RaidLeadershipUpdate_Struct* emu = (RaidLeadershipUpdate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct* eq = (structs::RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT_str(player_name);
|
||||
OUT_str(leader_name);
|
||||
memcpy(&eq->raid, &emu->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
case raidSetNote:
|
||||
{
|
||||
RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer;
|
||||
auto emu = (RaidNote_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidNote_Struct));
|
||||
auto eq = (structs::RaidNote_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(note);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidNoRaid:
|
||||
{
|
||||
dest->QueuePacket(inapp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
RaidGeneral_Struct* emu = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64);
|
||||
strn0cpy(raid_general->player_name, in_raid_general->player_name, 64);
|
||||
raid_general->action = in_raid_general->action;
|
||||
raid_general->parameter = in_raid_general->parameter;
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
structs::RaidGeneral_Struct* eq = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT(parameter);
|
||||
OUT_str(leader_name);
|
||||
OUT_str(player_name);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
@@ -5091,37 +5115,47 @@ namespace RoF2
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
|
||||
// This is a switch on the RaidGeneral action
|
||||
switch (*(uint32 *)__packet->pBuffer) {
|
||||
case 35: { // raidMOTD
|
||||
// we don't have a nice macro for this
|
||||
structs::RaidMOTD_Struct *__eq_buffer = (structs::RaidMOTD_Struct *)__packet->pBuffer;
|
||||
__eq_buffer->motd[1023] = '\0';
|
||||
size_t motd_size = strlen(__eq_buffer->motd) + 1;
|
||||
__packet->size = sizeof(RaidMOTD_Struct) + motd_size;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
RaidMOTD_Struct *emu = (RaidMOTD_Struct *)__packet->pBuffer;
|
||||
structs::RaidMOTD_Struct *eq = (structs::RaidMOTD_Struct *)__eq_buffer;
|
||||
strn0cpy(emu->general.player_name, eq->general.player_name, 64);
|
||||
strn0cpy(emu->motd, eq->motd, motd_size);
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case 36: { // raidPlayerNote unhandled
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct);
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
strn0cpy(emu->leader_name, eq->leader_name, 64);
|
||||
strn0cpy(emu->player_name, eq->player_name, 64);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
RaidGeneral_Struct* rgs = (RaidGeneral_Struct*)__packet->pBuffer;
|
||||
|
||||
switch (rgs->action)
|
||||
{
|
||||
case raidSetMotd:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidMOTD_Struct, structs::RaidMOTD_Struct, motd);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(motd);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidNote_Struct, structs::RaidNote_Struct, note);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(note);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
IN_str(leader_name);
|
||||
IN_str(player_name);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4198,9 +4198,14 @@ struct RaidAddMember_Struct {
|
||||
/*139*/ uint8 flags[5]; //no idea if these are needed...
|
||||
};
|
||||
|
||||
struct RaidNote_Struct {
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidMOTD_Struct {
|
||||
/*000*/ RaidGeneral_Struct general; // leader_name and action only used
|
||||
/*140*/ char motd[0]; // max size 1024, but reply is variable
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char motd[1024];
|
||||
};
|
||||
|
||||
struct RaidLeadershipUpdate_Struct {
|
||||
|
||||
@@ -4136,9 +4136,14 @@ struct RaidAddMember_Struct {
|
||||
/*139*/ uint8 flags[5]; //no idea if these are needed...
|
||||
};
|
||||
|
||||
struct RaidNote_Struct {
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidMOTD_Struct {
|
||||
/*000*/ RaidGeneral_Struct general; // leader_name and action only used
|
||||
/*140*/ char motd[0]; // max size 1024, but reply is variable
|
||||
/*140*/ char motd[1024]; // max size is 1024, but reply is variable
|
||||
};
|
||||
|
||||
struct RaidLeadershipUpdate_Struct {
|
||||
|
||||
+135
-88
@@ -34,6 +34,7 @@
|
||||
#include "../rulesys.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../races.h"
|
||||
#include "../raid.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -1686,88 +1687,124 @@ namespace SoD
|
||||
|
||||
ENCODE(OP_RaidJoin)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct* emu = (RaidCreate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct* general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
general->action = 8;
|
||||
general->parameter = 1;
|
||||
strn0cpy(general->leader_name, raid_create->leader_name, 64);
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
general->action = raidCreate;
|
||||
general->parameter = RaidCommandAcceptInvite;
|
||||
strn0cpy(general->leader_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
strn0cpy(general->player_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
safe_delete(inapp);
|
||||
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct *raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct* raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
if (raid_gen->action == 0) // raid add has longer length than other raid updates
|
||||
switch (raid_gen->action)
|
||||
{
|
||||
RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer;
|
||||
case raidAdd:
|
||||
{
|
||||
RaidAddMember_Struct* emu = (RaidAddMember_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct));
|
||||
structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
structs::RaidAddMember_Struct* eq = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
|
||||
add_member->raidGen.action = in_add_member->raidGen.action;
|
||||
add_member->raidGen.parameter = in_add_member->raidGen.parameter;
|
||||
strn0cpy(add_member->raidGen.leader_name, in_add_member->raidGen.leader_name, 64);
|
||||
strn0cpy(add_member->raidGen.player_name, in_add_member->raidGen.player_name, 64);
|
||||
add_member->_class = in_add_member->_class;
|
||||
add_member->level = in_add_member->level;
|
||||
add_member->isGroupLeader = in_add_member->isGroupLeader;
|
||||
add_member->flags[0] = in_add_member->flags[0];
|
||||
add_member->flags[1] = in_add_member->flags[1];
|
||||
add_member->flags[2] = in_add_member->flags[2];
|
||||
add_member->flags[3] = in_add_member->flags[3];
|
||||
add_member->flags[4] = in_add_member->flags[4];
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
else if (raid_gen->action == 35)
|
||||
{
|
||||
RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) +
|
||||
strlen(inmotd->motd) + 1);
|
||||
structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer;
|
||||
OUT(raidGen.action);
|
||||
OUT(raidGen.parameter);
|
||||
OUT_str(raidGen.leader_name);
|
||||
OUT_str(raidGen.player_name);
|
||||
OUT(_class);
|
||||
OUT(level);
|
||||
OUT(isGroupLeader);
|
||||
OUT(flags[0]);
|
||||
OUT(flags[1]);
|
||||
OUT(flags[2]);
|
||||
OUT(flags[3]);
|
||||
OUT(flags[4]);
|
||||
|
||||
outmotd->general.action = inmotd->general.action;
|
||||
strn0cpy(outmotd->general.player_name, inmotd->general.player_name, 64);
|
||||
strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else if (raid_gen->action == 14 || raid_gen->action == 30)
|
||||
case raidSetMotd:
|
||||
{
|
||||
RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer;
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
RaidMOTD_Struct* emu = (RaidMOTD_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct));
|
||||
structs::RaidMOTD_Struct* eq = (structs::RaidMOTD_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(motd);
|
||||
|
||||
outlaa->action = inlaa->action;
|
||||
strn0cpy(outlaa->player_name, inlaa->player_name, 64);
|
||||
strn0cpy(outlaa->leader_name, inlaa->leader_name, 64);
|
||||
memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
case raidSetLeaderAbilities:
|
||||
case raidMakeLeader:
|
||||
{
|
||||
RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer;
|
||||
RaidLeadershipUpdate_Struct* emu = (RaidLeadershipUpdate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct* eq = (structs::RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT_str(player_name);
|
||||
OUT_str(leader_name);
|
||||
memcpy(&eq->raid, &emu->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
auto emu = (RaidNote_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidNote_Struct));
|
||||
auto eq = (structs::RaidNote_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(note);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidNoRaid:
|
||||
{
|
||||
dest->QueuePacket(inapp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
RaidGeneral_Struct* emu = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64);
|
||||
strn0cpy(raid_general->player_name, in_raid_general->player_name, 64);
|
||||
raid_general->action = in_raid_general->action;
|
||||
raid_general->parameter = in_raid_general->parameter;
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
structs::RaidGeneral_Struct* eq = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT(parameter);
|
||||
OUT_str(leader_name);
|
||||
OUT_str(player_name);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
@@ -3338,37 +3375,47 @@ namespace SoD
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
|
||||
// This is a switch on the RaidGeneral action
|
||||
switch (*(uint32 *)__packet->pBuffer) {
|
||||
case 35: { // raidMOTD
|
||||
// we don't have a nice macro for this
|
||||
structs::RaidMOTD_Struct *__eq_buffer = (structs::RaidMOTD_Struct *)__packet->pBuffer;
|
||||
__eq_buffer->motd[1023] = '\0';
|
||||
size_t motd_size = strlen(__eq_buffer->motd) + 1;
|
||||
__packet->size = sizeof(RaidMOTD_Struct) + motd_size;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
RaidMOTD_Struct *emu = (RaidMOTD_Struct *)__packet->pBuffer;
|
||||
structs::RaidMOTD_Struct *eq = (structs::RaidMOTD_Struct *)__eq_buffer;
|
||||
strn0cpy(emu->general.player_name, eq->general.player_name, 64);
|
||||
strn0cpy(emu->motd, eq->motd, motd_size);
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case 36: { // raidPlayerNote unhandled
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct);
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
strn0cpy(emu->leader_name, eq->leader_name, 64);
|
||||
strn0cpy(emu->player_name, eq->player_name, 64);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
RaidGeneral_Struct* rgs = (RaidGeneral_Struct*)__packet->pBuffer;
|
||||
|
||||
switch (rgs->action)
|
||||
{
|
||||
case raidSetMotd:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidMOTD_Struct, structs::RaidMOTD_Struct, motd);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(motd);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidNote_Struct, structs::RaidNote_Struct, note);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(note);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
IN_str(leader_name);
|
||||
IN_str(player_name);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3592,9 +3592,14 @@ struct RaidAddMember_Struct {
|
||||
/*139*/ uint8 flags[5]; //no idea if these are needed...
|
||||
};
|
||||
|
||||
struct RaidNote_Struct {
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidMOTD_Struct {
|
||||
/*000*/ RaidGeneral_Struct general; // leader_name and action only used
|
||||
/*140*/ char motd[0]; // max size 1024, but reply is variable
|
||||
/*140*/ char motd[1024]; // max size is 1024, but reply is variable
|
||||
};
|
||||
|
||||
struct RaidLeadershipUpdate_Struct {
|
||||
|
||||
+135
-88
@@ -33,6 +33,7 @@
|
||||
#include "sof_structs.h"
|
||||
#include "../rulesys.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../raid.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -1356,88 +1357,124 @@ namespace SoF
|
||||
|
||||
ENCODE(OP_RaidJoin)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct* emu = (RaidCreate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct* general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
general->action = 8;
|
||||
general->parameter = 1;
|
||||
strn0cpy(general->leader_name, raid_create->leader_name, 64);
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
general->action = raidCreate;
|
||||
general->parameter = RaidCommandAcceptInvite;
|
||||
strn0cpy(general->leader_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
strn0cpy(general->player_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
safe_delete(inapp);
|
||||
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct *raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct* raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
if (raid_gen->action == 0) // raid add has longer length than other raid updates
|
||||
switch (raid_gen->action)
|
||||
{
|
||||
RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer;
|
||||
case raidAdd:
|
||||
{
|
||||
RaidAddMember_Struct* emu = (RaidAddMember_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct));
|
||||
structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
structs::RaidAddMember_Struct* eq = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
|
||||
add_member->raidGen.action = in_add_member->raidGen.action;
|
||||
add_member->raidGen.parameter = in_add_member->raidGen.parameter;
|
||||
strn0cpy(add_member->raidGen.leader_name, in_add_member->raidGen.leader_name, 64);
|
||||
strn0cpy(add_member->raidGen.player_name, in_add_member->raidGen.player_name, 64);
|
||||
add_member->_class = in_add_member->_class;
|
||||
add_member->level = in_add_member->level;
|
||||
add_member->isGroupLeader = in_add_member->isGroupLeader;
|
||||
add_member->flags[0] = in_add_member->flags[0];
|
||||
add_member->flags[1] = in_add_member->flags[1];
|
||||
add_member->flags[2] = in_add_member->flags[2];
|
||||
add_member->flags[3] = in_add_member->flags[3];
|
||||
add_member->flags[4] = in_add_member->flags[4];
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
else if (raid_gen->action == 35)
|
||||
{
|
||||
RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) +
|
||||
strlen(inmotd->motd) + 1);
|
||||
structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer;
|
||||
OUT(raidGen.action);
|
||||
OUT(raidGen.parameter);
|
||||
OUT_str(raidGen.leader_name);
|
||||
OUT_str(raidGen.player_name);
|
||||
OUT(_class);
|
||||
OUT(level);
|
||||
OUT(isGroupLeader);
|
||||
OUT(flags[0]);
|
||||
OUT(flags[1]);
|
||||
OUT(flags[2]);
|
||||
OUT(flags[3]);
|
||||
OUT(flags[4]);
|
||||
|
||||
outmotd->general.action = inmotd->general.action;
|
||||
strn0cpy(outmotd->general.player_name, inmotd->general.player_name, 64);
|
||||
strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else if (raid_gen->action == 14 || raid_gen->action == 30)
|
||||
case raidSetMotd:
|
||||
{
|
||||
RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer;
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
RaidMOTD_Struct* emu = (RaidMOTD_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct));
|
||||
structs::RaidMOTD_Struct* eq = (structs::RaidMOTD_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(motd);
|
||||
|
||||
outlaa->action = inlaa->action;
|
||||
strn0cpy(outlaa->player_name, inlaa->player_name, 64);
|
||||
strn0cpy(outlaa->leader_name, inlaa->leader_name, 64);
|
||||
memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
case raidSetLeaderAbilities:
|
||||
case raidMakeLeader:
|
||||
{
|
||||
RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer;
|
||||
RaidLeadershipUpdate_Struct* emu = (RaidLeadershipUpdate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct* eq = (structs::RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT_str(player_name);
|
||||
OUT_str(leader_name);
|
||||
memcpy(&eq->raid, &emu->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
auto emu = (RaidNote_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidNote_Struct));
|
||||
auto eq = (structs::RaidNote_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(note);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidNoRaid:
|
||||
{
|
||||
dest->QueuePacket(inapp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
RaidGeneral_Struct* emu = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64);
|
||||
strn0cpy(raid_general->player_name, in_raid_general->player_name, 64);
|
||||
raid_general->action = in_raid_general->action;
|
||||
raid_general->parameter = in_raid_general->parameter;
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
structs::RaidGeneral_Struct* eq = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT(parameter);
|
||||
OUT_str(leader_name);
|
||||
OUT_str(player_name);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
@@ -2743,37 +2780,47 @@ namespace SoF
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
|
||||
// This is a switch on the RaidGeneral action
|
||||
switch (*(uint32 *)__packet->pBuffer) {
|
||||
case 35: { // raidMOTD
|
||||
// we don't have a nice macro for this
|
||||
structs::RaidMOTD_Struct *__eq_buffer = (structs::RaidMOTD_Struct *)__packet->pBuffer;
|
||||
__eq_buffer->motd[1023] = '\0';
|
||||
size_t motd_size = strlen(__eq_buffer->motd) + 1;
|
||||
__packet->size = sizeof(RaidMOTD_Struct) + motd_size;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
RaidMOTD_Struct *emu = (RaidMOTD_Struct *)__packet->pBuffer;
|
||||
structs::RaidMOTD_Struct *eq = (structs::RaidMOTD_Struct *)__eq_buffer;
|
||||
strn0cpy(emu->general.player_name, eq->general.player_name, 64);
|
||||
strn0cpy(emu->motd, eq->motd, motd_size);
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case 36: { // raidPlayerNote unhandled
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct);
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
strn0cpy(emu->leader_name, eq->leader_name, 64);
|
||||
strn0cpy(emu->player_name, eq->player_name, 64);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
RaidGeneral_Struct* rgs = (RaidGeneral_Struct*)__packet->pBuffer;
|
||||
|
||||
switch (rgs->action)
|
||||
{
|
||||
case raidSetMotd:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidMOTD_Struct, structs::RaidMOTD_Struct, motd);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(motd);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidNote_Struct, structs::RaidNote_Struct, note);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(note);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
IN_str(leader_name);
|
||||
IN_str(player_name);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3517,9 +3517,14 @@ struct RaidAddMember_Struct {
|
||||
/*139*/ uint8 flags[5]; //no idea if these are needed...
|
||||
};
|
||||
|
||||
struct RaidNote_Struct {
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidMOTD_Struct {
|
||||
/*000*/ RaidGeneral_Struct general; // leader_name and action only used
|
||||
/*140*/ char motd[0]; // max size 1024, but reply is variable
|
||||
/*140*/ char motd[1024]; // max size is 1024, but reply is variable
|
||||
};
|
||||
|
||||
struct RaidLeadershipUpdate_Struct {
|
||||
|
||||
@@ -128,6 +128,15 @@
|
||||
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
||||
eq_struct *eq = (eq_struct *) __eq_buffer;
|
||||
|
||||
#define SETUP_VAR_DECODE(emu_struct, eq_struct, var_field) \
|
||||
unsigned char *__eq_buffer = __packet->pBuffer; \
|
||||
eq_struct* in = (eq_struct*)__packet->pBuffer; \
|
||||
auto size = strlen(in->var_field); \
|
||||
__packet->size = sizeof(emu_struct) + size + 1; \
|
||||
__packet->pBuffer = new unsigned char[__packet->size]; \
|
||||
emu_struct *emu = (emu_struct *) __packet->pBuffer; \
|
||||
eq_struct *eq = (eq_struct *) __eq_buffer;
|
||||
|
||||
#define MEMSET_IN(emu_struct) \
|
||||
memset(__packet->pBuffer, 0, sizeof(emu_struct));
|
||||
|
||||
@@ -146,6 +155,9 @@
|
||||
delete[] __eq_buffer; \
|
||||
p->SetOpcode(OP_Unknown);
|
||||
|
||||
#define FINISH_VAR_DECODE() \
|
||||
delete[] __eq_buffer;
|
||||
|
||||
//call to finish an encoder using SETUP_DIRECT_DECODE
|
||||
#define FINISH_DIRECT_DECODE() \
|
||||
delete[] __eq_buffer;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "../item_instance.h"
|
||||
#include "titanium_structs.h"
|
||||
#include "../path_manager.h"
|
||||
#include "../raid.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@@ -1245,6 +1246,119 @@ namespace Titanium
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_MarkRaidNPC)
|
||||
{
|
||||
ENCODE_LENGTH_EXACT(MarkNPC_Struct);
|
||||
SETUP_DIRECT_ENCODE(MarkNPC_Struct, MarkNPC_Struct);
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MarkNPC, sizeof(MarkNPC_Struct));
|
||||
MarkNPC_Struct* mnpcs = (MarkNPC_Struct*)outapp->pBuffer;
|
||||
mnpcs->TargetID = emu->TargetID;
|
||||
mnpcs->Number = emu->Number;
|
||||
dest->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
{
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct* raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
switch (raid_gen->action)
|
||||
{
|
||||
case raidAdd:
|
||||
{
|
||||
RaidAddMember_Struct* emu = (RaidAddMember_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct));
|
||||
structs::RaidAddMember_Struct* eq = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(raidGen.action);
|
||||
OUT(raidGen.parameter);
|
||||
OUT_str(raidGen.leader_name);
|
||||
OUT_str(raidGen.player_name);
|
||||
OUT(_class);
|
||||
OUT(level);
|
||||
OUT(isGroupLeader);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
|
||||
}
|
||||
case raidSetMotd:
|
||||
{
|
||||
RaidMOTD_Struct* emu = (RaidMOTD_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct));
|
||||
structs::RaidMOTD_Struct* eq = (structs::RaidMOTD_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(motd);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidSetLeaderAbilities:
|
||||
case raidMakeLeader:
|
||||
{
|
||||
RaidLeadershipUpdate_Struct* emu = (RaidLeadershipUpdate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct* eq = (structs::RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT_str(player_name);
|
||||
OUT_str(leader_name);
|
||||
memcpy(&eq->raid, &emu->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
auto emu = (RaidNote_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidNote_Struct));
|
||||
auto eq = (structs::RaidNote_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(note);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidNoRaid:
|
||||
{
|
||||
dest->QueuePacket(inapp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
RaidGeneral_Struct* emu = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct* eq = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT(parameter);
|
||||
OUT_str(leader_name);
|
||||
OUT_str(player_name);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
ENCODE(OP_ReadBook)
|
||||
{
|
||||
// no apparent slot translation needed
|
||||
@@ -2272,6 +2386,63 @@ namespace Titanium
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_RaidInvite)
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
RaidGeneral_Struct* rgs = (RaidGeneral_Struct*)__packet->pBuffer;
|
||||
|
||||
switch (rgs->action)
|
||||
{
|
||||
case raidSetMotd:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidMOTD_Struct, structs::RaidMOTD_Struct, motd);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
|
||||
auto len = 0;
|
||||
if (__packet->size < sizeof(structs::RaidMOTD_Struct)) {
|
||||
len = __packet->size - sizeof(structs::RaidGeneral_Struct);
|
||||
}
|
||||
else {
|
||||
len = sizeof(eq->motd);
|
||||
}
|
||||
|
||||
strn0cpy(emu->motd, eq->motd, len > 1024 ? 1024 : len);
|
||||
emu->motd[len - 1] = '\0';
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidNote_Struct, structs::RaidNote_Struct, note);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(note);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
IN_str(leader_name);
|
||||
IN_str(player_name);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_ReadBook)
|
||||
{
|
||||
// no apparent slot translation needed
|
||||
|
||||
@@ -61,6 +61,8 @@ E(OP_OnLevelMessage)
|
||||
E(OP_PetBuffWindow)
|
||||
E(OP_PlayerProfile)
|
||||
E(OP_NewSpawn)
|
||||
E(OP_MarkRaidNPC)
|
||||
E(OP_RaidUpdate)
|
||||
E(OP_ReadBook)
|
||||
E(OP_RespondAA)
|
||||
E(OP_SendCharInfo)
|
||||
@@ -106,6 +108,7 @@ D(OP_LoadSpellSet)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_PetCommands)
|
||||
D(OP_RaidInvite)
|
||||
D(OP_ReadBook)
|
||||
D(OP_SetServerFilter)
|
||||
D(OP_ShopPlayerSell)
|
||||
|
||||
@@ -3017,23 +3017,39 @@ struct leadExpUpdateStruct {
|
||||
/*0028*/ uint32 unknown0028;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct RaidGeneral_Struct {
|
||||
/*00*/ uint32 action; //=10
|
||||
/*04*/ char player_name[64]; //should both be the player's name
|
||||
/*04*/ char leader_name[64];
|
||||
/*000*/ uint32 action; //=10
|
||||
/*004*/ char player_name[64]; //should both be the player's name
|
||||
/*068*/ char leader_name[64];
|
||||
/*132*/ uint32 parameter;
|
||||
};
|
||||
|
||||
struct RaidAdd_Struct {
|
||||
/*000*/ uint32 action; //=0
|
||||
/*004*/ char player_name[64]; //should both be the player's name
|
||||
/*068*/ char leader_name[64];
|
||||
/*132*/ uint8 _class;
|
||||
/*133*/ uint8 level;
|
||||
/*134*/ uint8 has_group;
|
||||
/*135*/ uint8 unknown135; //seems to be 0x42 or 0
|
||||
struct RaidAddMember_Struct {
|
||||
/*000*/ RaidGeneral_Struct raidGen;
|
||||
/*136*/ uint8 _class;
|
||||
/*137*/ uint8 level;
|
||||
/*138*/ uint8 isGroupLeader;
|
||||
/*139*/ uint8 unknown139; //seems to be 0x42 or 0
|
||||
};
|
||||
|
||||
struct RaidNote_Struct {
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*136*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidMOTD_Struct {
|
||||
/*000*/ RaidGeneral_Struct general; // leader_name and action only used
|
||||
/*136*/ char motd[1024]; // max size is 1024, but reply is variable
|
||||
};
|
||||
|
||||
struct RaidLeadershipUpdate_Struct {
|
||||
/*000*/ uint32 action;
|
||||
/*004*/ char player_name[64];
|
||||
// /*068*/ uint32 Unknown068;
|
||||
/*072*/ char leader_name[64];
|
||||
/*136*/ GroupLeadershipAA_Struct group; //unneeded
|
||||
/*200*/ RaidLeadershipAA_Struct raid;
|
||||
/*264*/ char Unknown264[128];
|
||||
};
|
||||
|
||||
struct RaidCreate_Struct {
|
||||
|
||||
+135
-89
@@ -35,6 +35,7 @@
|
||||
#include "../path_manager.h"
|
||||
#include "../classes.h"
|
||||
#include "../races.h"
|
||||
#include "../raid.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@@ -1931,88 +1932,124 @@ namespace UF
|
||||
|
||||
ENCODE(OP_RaidJoin)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidCreate_Struct* emu = (RaidCreate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct* general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
general->action = 8;
|
||||
general->parameter = 1;
|
||||
strn0cpy(general->leader_name, raid_create->leader_name, 64);
|
||||
strn0cpy(general->player_name, raid_create->leader_name, 64);
|
||||
general->action = raidCreate;
|
||||
general->parameter = RaidCommandAcceptInvite;
|
||||
strn0cpy(general->leader_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
strn0cpy(general->player_name, emu->leader_name, sizeof(emu->leader_name));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
|
||||
dest->FastQueuePacket(&outapp_create);
|
||||
safe_delete(inapp);
|
||||
|
||||
}
|
||||
|
||||
ENCODE(OP_RaidUpdate)
|
||||
{
|
||||
EQApplicationPacket *inapp = *p;
|
||||
EQApplicationPacket* inapp = *p;
|
||||
*p = nullptr;
|
||||
unsigned char * __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct *raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
unsigned char* __emu_buffer = inapp->pBuffer;
|
||||
RaidGeneral_Struct* raid_gen = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
if (raid_gen->action == 0) // raid add has longer length than other raid updates
|
||||
switch (raid_gen->action)
|
||||
{
|
||||
RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer;
|
||||
case raidAdd:
|
||||
{
|
||||
RaidAddMember_Struct* emu = (RaidAddMember_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct));
|
||||
structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
structs::RaidAddMember_Struct* eq = (structs::RaidAddMember_Struct*)outapp->pBuffer;
|
||||
|
||||
add_member->raidGen.action = in_add_member->raidGen.action;
|
||||
add_member->raidGen.parameter = in_add_member->raidGen.parameter;
|
||||
strn0cpy(add_member->raidGen.leader_name, in_add_member->raidGen.leader_name, 64);
|
||||
strn0cpy(add_member->raidGen.player_name, in_add_member->raidGen.player_name, 64);
|
||||
add_member->_class = in_add_member->_class;
|
||||
add_member->level = in_add_member->level;
|
||||
add_member->isGroupLeader = in_add_member->isGroupLeader;
|
||||
add_member->flags[0] = in_add_member->flags[0];
|
||||
add_member->flags[1] = in_add_member->flags[1];
|
||||
add_member->flags[2] = in_add_member->flags[2];
|
||||
add_member->flags[3] = in_add_member->flags[3];
|
||||
add_member->flags[4] = in_add_member->flags[4];
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
else if (raid_gen->action == 35)
|
||||
{
|
||||
RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) +
|
||||
strlen(inmotd->motd) + 1);
|
||||
structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer;
|
||||
OUT(raidGen.action);
|
||||
OUT(raidGen.parameter);
|
||||
OUT_str(raidGen.leader_name);
|
||||
OUT_str(raidGen.player_name);
|
||||
OUT(_class);
|
||||
OUT(level);
|
||||
OUT(isGroupLeader);
|
||||
OUT(flags[0]);
|
||||
OUT(flags[1]);
|
||||
OUT(flags[2]);
|
||||
OUT(flags[3]);
|
||||
OUT(flags[4]);
|
||||
|
||||
outmotd->general.action = inmotd->general.action;
|
||||
strn0cpy(outmotd->general.player_name, inmotd->general.player_name, 64);
|
||||
strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1);
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else if (raid_gen->action == 14 || raid_gen->action == 30)
|
||||
case raidSetMotd:
|
||||
{
|
||||
RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer;
|
||||
auto outapp =
|
||||
new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
RaidMOTD_Struct* emu = (RaidMOTD_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct));
|
||||
structs::RaidMOTD_Struct* eq = (structs::RaidMOTD_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(motd);
|
||||
|
||||
outlaa->action = inlaa->action;
|
||||
strn0cpy(outlaa->player_name, inlaa->player_name, 64);
|
||||
strn0cpy(outlaa->leader_name, inlaa->leader_name, 64);
|
||||
memcpy(&outlaa->raid, &inlaa->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
case raidSetLeaderAbilities:
|
||||
case raidMakeLeader:
|
||||
{
|
||||
RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer;
|
||||
RaidLeadershipUpdate_Struct* emu = (RaidLeadershipUpdate_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct));
|
||||
structs::RaidLeadershipUpdate_Struct* eq = (structs::RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT_str(player_name);
|
||||
OUT_str(leader_name);
|
||||
memcpy(&eq->raid, &emu->raid, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
auto emu = (RaidNote_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidNote_Struct));
|
||||
auto eq = (structs::RaidNote_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(general.action);
|
||||
OUT_str(general.leader_name);
|
||||
OUT_str(general.player_name);
|
||||
OUT_str(note);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
case raidNoRaid:
|
||||
{
|
||||
dest->QueuePacket(inapp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
RaidGeneral_Struct* emu = (RaidGeneral_Struct*)__emu_buffer;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct));
|
||||
structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64);
|
||||
strn0cpy(raid_general->player_name, in_raid_general->player_name, 64);
|
||||
raid_general->action = in_raid_general->action;
|
||||
raid_general->parameter = in_raid_general->parameter;
|
||||
dest->FastQueuePacket(&outapp);
|
||||
}
|
||||
structs::RaidGeneral_Struct* eq = (structs::RaidGeneral_Struct*)outapp->pBuffer;
|
||||
|
||||
OUT(action);
|
||||
OUT(parameter);
|
||||
OUT_str(leader_name);
|
||||
OUT_str(player_name);
|
||||
|
||||
dest->FastQueuePacket(&outapp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(inapp);
|
||||
}
|
||||
|
||||
@@ -3637,39 +3674,48 @@ namespace UF
|
||||
{
|
||||
DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct);
|
||||
|
||||
// This is a switch on the RaidGeneral action
|
||||
switch (*(uint32 *)__packet->pBuffer) {
|
||||
case 35: { // raidMOTD
|
||||
// we don't have a nice macro for this
|
||||
structs::RaidMOTD_Struct *__eq_buffer = (structs::RaidMOTD_Struct *)__packet->pBuffer;
|
||||
__eq_buffer->motd[1023] = '\0';
|
||||
size_t motd_size = strlen(__eq_buffer->motd) + 1;
|
||||
__packet->size = sizeof(RaidMOTD_Struct) + motd_size;
|
||||
__packet->pBuffer = new unsigned char[__packet->size];
|
||||
RaidMOTD_Struct *emu = (RaidMOTD_Struct *)__packet->pBuffer;
|
||||
structs::RaidMOTD_Struct *eq = (structs::RaidMOTD_Struct *)__eq_buffer;
|
||||
strn0cpy(emu->general.player_name, eq->general.player_name, 64);
|
||||
strn0cpy(emu->motd, eq->motd, motd_size);
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
case 36: { // raidPlayerNote unhandled
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct);
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
strn0cpy(emu->leader_name, eq->leader_name, 64);
|
||||
strn0cpy(emu->player_name, eq->player_name, 64);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
RaidGeneral_Struct* rgs = (RaidGeneral_Struct*)__packet->pBuffer;
|
||||
|
||||
switch (rgs->action)
|
||||
{
|
||||
case raidSetMotd:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidMOTD_Struct, structs::RaidMOTD_Struct, motd);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(motd);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
case raidSetNote:
|
||||
{
|
||||
SETUP_VAR_DECODE(RaidNote_Struct, structs::RaidNote_Struct, note);
|
||||
|
||||
IN(general.action);
|
||||
IN(general.parameter);
|
||||
IN_str(general.leader_name);
|
||||
IN_str(general.player_name);
|
||||
IN_str(note);
|
||||
|
||||
FINISH_VAR_DECODE();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct);
|
||||
IN(action);
|
||||
IN(parameter);
|
||||
IN_str(leader_name);
|
||||
IN_str(player_name);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECODE(OP_ReadBook)
|
||||
|
||||
@@ -3647,9 +3647,14 @@ struct RaidAddMember_Struct {
|
||||
/*139*/ uint8 flags[5]; //no idea if these are needed...
|
||||
};
|
||||
|
||||
struct RaidNote_Struct {
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char note[64];
|
||||
};
|
||||
|
||||
struct RaidMOTD_Struct {
|
||||
/*000*/ RaidGeneral_Struct general; // leader_name and action only used
|
||||
/*140*/ char motd[0]; // max size 1024, but reply is variable
|
||||
/*000*/ RaidGeneral_Struct general;
|
||||
/*140*/ char motd[1024];
|
||||
};
|
||||
|
||||
struct RaidLeadershipUpdate_Struct {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org)
|
||||
|
||||
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 RAID_H
|
||||
#define RAID_H
|
||||
|
||||
enum { //raid packet types:
|
||||
raidAdd = 0,
|
||||
raidRemove2 = 1, //parameter=0
|
||||
raidMemberNameChange = 2,
|
||||
raidRemove1 = 3, //parameter=0xFFFFFFFF
|
||||
raidNoLongerLeader = 4,
|
||||
raidDisband = 5,
|
||||
raidMembers = 6, //len 395+, details + members list
|
||||
raidNoAssignLeadership = 7,
|
||||
raidCreate = 8, //len 72
|
||||
raidUnknown = 9, // unused?
|
||||
raidNoRaid = 10, //parameter=0
|
||||
raidChangeLootType = 11,
|
||||
raidStringID = 12,
|
||||
raidChangeGroupLeader = 13, //136 raid leader, new group leader, group_id?
|
||||
raidSetLeaderAbilities = 14, //472
|
||||
raidSetLeaderData = 15, // 14,15 SoE names, not sure on difference, 14 packet has 0x100 bytes 15 0x214 in addition to raid general
|
||||
raidChangeGroup = 16, //?? len 136 old leader, new leader, 0 (preceeded with a remove2)
|
||||
raidLock = 17, //len 136 leader?, leader, 0
|
||||
raidUnlock = 18, //len 136 leader?, leader, 0
|
||||
raidRedStringID = 19,
|
||||
raidSetLeader = 20, //len 388, contains 'details' struct without members; also used for "invite to raid"
|
||||
raidMakeLeader = 30,
|
||||
raidSetMotd = 35,
|
||||
raidSetNote = 36,
|
||||
};
|
||||
|
||||
|
||||
enum { //raid command types
|
||||
RaidCommandInviteIntoExisting = 0, //in use
|
||||
RaidCommandAcceptInvite = 1, //in use
|
||||
RaidCommandInvite = 3, //in use
|
||||
RaidCommandDisband = 5, //in use
|
||||
RaidCommandMoveGroup = 6, //in use
|
||||
RaidCommandRemoveGroupLeader = 7,
|
||||
RaidCommandRaidLock = 8, //in use
|
||||
RaidCommandRaidUnlock = 9, //in use
|
||||
RaidCommandLootType = 20, //in use
|
||||
RaidCommandAddLooter = 21, //in use
|
||||
RaidCommandRemoveLooter = 22, //in use
|
||||
RaidCommandMakeLeader = 30,
|
||||
RaidCommandInviteFail = 31, //already in raid, waiting on invite from other raid, etc
|
||||
RaidCommandLootType2 = 32, //in use
|
||||
RaidCommandAddLooter2 = 33, //in use
|
||||
RaidCommandRemoveLooter2 = 34, //in use
|
||||
RaidCommandSetMotd = 35,
|
||||
RaidCommandSetNote = 36,
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -530,6 +530,7 @@ RULE_BOOL(Combat, BackstabIgnoresElemental, false, "Enable or disable Elemental
|
||||
RULE_BOOL(Combat, BackstabIgnoresBane, false, "Enable or disable Bane weapon damage affecting backstab damage, false by default.")
|
||||
RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a player when already in melee range of the summoner.")
|
||||
RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.")
|
||||
RULE_INT(Combat, ExtraAllowedKickClassesBitmask, 0, "Bitmask for allowing extra classes beyond Warrior, Ranger, Beastlord, and Berserker to kick, No Extra Classes (0) by default")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
|
||||
+1
-1
@@ -1077,7 +1077,7 @@ struct ServerRaidMessage_Struct {
|
||||
|
||||
struct ServerRaidMOTD_Struct {
|
||||
uint32 rid;
|
||||
char motd[0];
|
||||
char motd[1024];
|
||||
};
|
||||
|
||||
struct ServerRaidNote_Struct {
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.26.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.28.0-dev" // always append -dev to the current version for custom-builds
|
||||
#define LOGIN_VERSION "0.8.0"
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
@@ -42,7 +42,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9235
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9237
|
||||
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9039
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.26.0",
|
||||
"version": "22.28.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -423,6 +423,8 @@ OP_CancelInvite=0x0000
|
||||
OP_RaidJoin=0x1f21 # ShowEQ 10/27/05
|
||||
OP_RaidInvite=0x5891 # ShowEQ 10/27/05
|
||||
OP_RaidUpdate=0x1f21 # EQEmu 06/29/05
|
||||
OP_RaidDelegateAbility=0x56eb
|
||||
OP_RaidClearNPCMarks=0x1794
|
||||
|
||||
OP_InspectBuffs=0x4FB6
|
||||
|
||||
|
||||
@@ -534,6 +534,8 @@ OP_LFGResponse=0x0000 #
|
||||
OP_RaidInvite=0x60b5 # C
|
||||
OP_RaidUpdate=0x4d8b # C
|
||||
OP_RaidJoin=0x0000 #
|
||||
OP_RaidDelegateAbility=0x0297
|
||||
OP_RaidClearNPCMarks=0x2af4
|
||||
|
||||
# Button-push commands
|
||||
OP_Taunt=0x30e2 # C
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
set -ex
|
||||
|
||||
sudo chown eqemu:eqemu /drone/src/ * -R
|
||||
sudo chown eqemu:eqemu /home/eqemu/.ccache/ * -R
|
||||
|
||||
@@ -10,7 +10,7 @@ require (
|
||||
require (
|
||||
github.com/golang/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.1.0 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
)
|
||||
|
||||
@@ -10,12 +10,12 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
||||
+240
-220
@@ -1,4 +1,4 @@
|
||||
#! /usr/bin/perl
|
||||
#!/usr/bin/perl
|
||||
|
||||
########################################################################
|
||||
#::: 13th floor import script
|
||||
@@ -9,247 +9,267 @@
|
||||
use DBI;
|
||||
use DBD::mysql;
|
||||
|
||||
my $database_name = "";
|
||||
my $db_host = "";
|
||||
my $db_port = "";
|
||||
my $db_name = "";
|
||||
my $db_user = "";
|
||||
my $db_pass = "";
|
||||
my $total_items = 0;
|
||||
my $read_items_file = "items.txt"; #default
|
||||
my $dbh = LoadMysql();
|
||||
|
||||
read_eqemu_config_json();
|
||||
|
||||
my $dbh = DBI->connect("DBI:mysql:database=$db_name;host=$db_host;port=$db_port", $db_user, $db_pass) or die "Cannot connect to MySql.";
|
||||
|
||||
read_items_file_from_13th_floor_text();
|
||||
update_items_table();
|
||||
|
||||
sub LoadMysql{
|
||||
#::: Config Variables
|
||||
my $confile = "eqemu_config.xml";
|
||||
open(F, "<$confile") or die "Unable to open config: $confile\n";
|
||||
my $indb = 0;
|
||||
while(<F>) {
|
||||
s/\r//g;
|
||||
if(/<database>/i) { $indb = 1; }
|
||||
next unless($indb == 1);
|
||||
if(/<\/database>/i) { $indb = 0; last; }
|
||||
if(/<host>(.*)<\/host>/i) { $host = $1; }
|
||||
elsif(/<username>(.*)<\/username>/i) { $user = $1; }
|
||||
elsif(/<password>(.*)<\/password>/i) { $pass = $1; }
|
||||
elsif(/<db>(.*)<\/db>/i) { $db = $1; }
|
||||
}
|
||||
$database_name = $db;
|
||||
#::: DATA SOURCE NAME
|
||||
$dsn = "dbi:mysql:$db:localhost:3306";
|
||||
#::: PERL DBI CONNECT
|
||||
$connect = DBI->connect($dsn, $user, $pass);
|
||||
return $connect;
|
||||
print "\n\nImport complete!\n\n";
|
||||
|
||||
sub read_eqemu_config_json {
|
||||
use JSON;
|
||||
my $json = new JSON();
|
||||
my $config;
|
||||
my $config_file = "eqemu_config.json";
|
||||
|
||||
my $content;
|
||||
open(my $fh, '<', $config_file) or die "cannot open file $config_file"; {
|
||||
local $/;
|
||||
$content = <$fh>;
|
||||
}
|
||||
close($fh);
|
||||
|
||||
$config = $json->decode($content);
|
||||
|
||||
$db_host = $config->{"server"}{"database"}{"host"};
|
||||
$db_port = $config->{"server"}{"database"}{"port"};
|
||||
$db_name = $config->{"server"}{"database"}{"db"};
|
||||
$db_user = $config->{"server"}{"database"}{"username"};
|
||||
$db_pass = $config->{"server"}{"database"}{"password"};
|
||||
}
|
||||
|
||||
sub read_items_file_from_13th_floor_text {
|
||||
|
||||
#::: Read from file and place into array
|
||||
open(F, "<" . $read_items_file) or die "Unable to open itemfile: " . $read_items_file . "\n";
|
||||
my @item_file_lines = <F>;
|
||||
close(F);
|
||||
#::: Read from file and place into array
|
||||
open(F, "<" . $read_items_file) or die "Unable to open itemfile: " . $read_items_file . "\n";
|
||||
my @item_file_lines = <F>;
|
||||
close(F);
|
||||
|
||||
#::: Chomp this array...
|
||||
my @newitem_file_lines;
|
||||
chomp($item_file_lines[0]);
|
||||
@fields = split("(?<!\\\\)\\|", $item_file_lines[0]);
|
||||
|
||||
my $sth = $dbh->prepare("SHOW TABLES LIKE 'items_floor'");
|
||||
$sth->execute();
|
||||
my $has_items_floor = $sth->fetchrow_array();
|
||||
|
||||
#::: If we have items_floor
|
||||
if ($has_items_floor eq '') {
|
||||
$dbh->do("CREATE TABLE `items_floor` (`" . join("` VARCHAR(64) NOT NULL DEFAULT '', `", @fields). "` VARCHAR(64) NOT NULL DEFAULT '', UNIQUE INDEX `ID` (`id`)) COLLATE='latin1_swedish_ci' ENGINE=MyISAM");
|
||||
$dbh->do("ALTER TABLE `items_floor` CHANGE `id` `id` INT(11) NOT NULL DEFAULT '0'");
|
||||
printf "Database items_floor created\n";
|
||||
}
|
||||
|
||||
#::: Create REPLACE INTO header and define worker variables...
|
||||
$master_insert = "REPLACE INTO `items_floor` (" . join(",", @fields) . ") VALUES ";
|
||||
$query_insert_ph = ""; #::: Used for building placeholder values in query Ex: (?, ?, ?)
|
||||
@field_values = (); #::: Used for stuffing mysql field values
|
||||
$query_count = 0; #::: Used for chunking query updates
|
||||
$print_cycle = 0; #::: Counter for console updates
|
||||
$start_time = time(); #::: Start time for import
|
||||
$total_items_file = scalar(grep $_, @item_file_lines) - 1; #::: Total items in text file
|
||||
#::: Chomp this array...
|
||||
my @newitem_file_lines;
|
||||
chomp($item_file_lines[0]);
|
||||
@fields = split("(?<!\\\\)\\|", $item_file_lines[0]);
|
||||
|
||||
#::: Iterate through each item in items.txt
|
||||
for (1 .. $#item_file_lines) {
|
||||
@f = split("(?<!\\\\)\\|", $item_file_lines[$_]);
|
||||
my $sth = $dbh->prepare("SHOW TABLES LIKE 'items_floor'");
|
||||
$sth->execute();
|
||||
my $has_items_floor = $sth->fetchrow_array();
|
||||
|
||||
#::: Build our individual prepared statement (?, ?) values in the insert_ph
|
||||
#::: ?, ? placeholders will be resolved via @field_values in the execute
|
||||
$query_insert_ph .= " (";
|
||||
foreach (@f) {
|
||||
push (@field_values, trim($_));
|
||||
$query_insert_ph .= "?, ";
|
||||
}
|
||||
$query_insert_ph = substr($query_insert_ph, 0, -2);
|
||||
$query_insert_ph .= "), ";
|
||||
#::: If we don't have items_floor table
|
||||
if ($has_items_floor eq '') {
|
||||
$dbh->do("CREATE TABLE `items_floor` (`" . join("` VARCHAR(64) NOT NULL DEFAULT '', `", @fields). "` VARCHAR(64) NOT NULL DEFAULT '', UNIQUE INDEX `ID` (`id`)) COLLATE='latin1_swedish_ci' ENGINE=MyISAM");
|
||||
$dbh->do("ALTER TABLE `items_floor` CHANGE `id` `id` INT(11) NOT NULL DEFAULT '0'");
|
||||
printf "Database items_floor created\n";
|
||||
}
|
||||
|
||||
#::: Let's chunk our updates so we can break up the amount of individual queries
|
||||
if($query_count > 500){
|
||||
$query_insert_ph = substr($query_insert_ph, 0, -2);
|
||||
$dbh->prepare($master_insert . " " . $query_insert_ph)->execute(@field_values);
|
||||
$query_count = 0;
|
||||
$query_insert_ph = "";
|
||||
@field_values = ();
|
||||
}
|
||||
|
||||
#::: Print updates to console
|
||||
if($print_cycle > 25){
|
||||
print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r";
|
||||
$print_cycle = 0;
|
||||
}
|
||||
#::: Create REPLACE INTO header and define worker variables...
|
||||
$master_insert = "REPLACE INTO `items_floor` (" . join(",", @fields) . ") VALUES ";
|
||||
$query_insert_ph = ""; #::: Used for building placeholder values in query Ex: (?, ?, ?)
|
||||
@field_values = (); #::: Used for stuffing mysql field values
|
||||
$query_count = 0; #::: Used for chunking query updates
|
||||
$print_cycle = 0; #::: Counter for console updates
|
||||
$start_time = time(); #::: Start time for import
|
||||
$total_items_file = scalar(grep $_, @item_file_lines) - 1; #::: Total items in text file
|
||||
|
||||
#::: Counters
|
||||
$total_items++;
|
||||
$query_count++;
|
||||
$print_cycle++;
|
||||
}
|
||||
|
||||
#::: One last processing print
|
||||
print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r";
|
||||
|
||||
printf "\n" . $total_items . " items added to database... Took " . (time() - $start_time) . " second(s)... \n";
|
||||
|
||||
print "Flipping slots 21 and 22...";
|
||||
$rows_affected = $dbh->prepare("
|
||||
UPDATE `items_floor`
|
||||
SET `slots` = (`slots` ^ 6291456)
|
||||
WHERE (`slots` & 6291456)
|
||||
IN (2097152, 4194304)")->execute();
|
||||
print " Rows affected (" . $rows_affected . ")\n";
|
||||
#::: Iterate through each item in items.txt
|
||||
for (1 .. $#item_file_lines) {
|
||||
@f = split("(?<!\\\\)\\|", $item_file_lines[$_]);
|
||||
|
||||
#::: Build our individual prepared statement (?, ?) values in the insert_ph
|
||||
#::: ?, ? placeholders will be resolved via @field_values in the execute
|
||||
$query_insert_ph .= " (";
|
||||
foreach (@f) {
|
||||
push (@field_values, trim($_));
|
||||
$query_insert_ph .= "?, ";
|
||||
}
|
||||
$query_insert_ph = substr($query_insert_ph, 0, -2);
|
||||
$query_insert_ph .= "), ";
|
||||
|
||||
#::: Let's chunk our updates so we can break up the amount of individual queries
|
||||
if($query_count > 500){
|
||||
$query_insert_ph = substr($query_insert_ph, 0, -2);
|
||||
$dbh->prepare($master_insert . " " . $query_insert_ph)->execute(@field_values);
|
||||
$query_count = 0;
|
||||
$query_insert_ph = "";
|
||||
@field_values = ();
|
||||
}
|
||||
|
||||
#::: Print updates to console
|
||||
if($print_cycle > 25){
|
||||
print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r";
|
||||
$print_cycle = 0;
|
||||
}
|
||||
|
||||
#::: Counters
|
||||
$total_items++;
|
||||
$query_count++;
|
||||
$print_cycle++;
|
||||
}
|
||||
|
||||
#::: One last processing print
|
||||
print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r";
|
||||
|
||||
printf "\n" . $total_items . " items imported... Took " . (time() - $start_time) . " second(s)... \n";
|
||||
|
||||
#::: Process slots 21, 22
|
||||
print "Flipping slots 21 and 22...";
|
||||
$rows_affected = $dbh->prepare("
|
||||
UPDATE `items_floor`
|
||||
SET `slots` = (`slots` ^ 6291456)
|
||||
WHERE (`slots` & 6291456)
|
||||
IN (2097152, 4194304)")->execute();
|
||||
print " :: Rows affected (" . $rows_affected . ")\n";
|
||||
|
||||
#::: Update idfile entries
|
||||
print "Updating idfile entries...";
|
||||
$rows_affected = $dbh->prepare("
|
||||
UPDATE `items_floor`
|
||||
SET `idfile` = CONCAT('IT', `idfile`)")->execute();
|
||||
print " :: Rows affected(" . $rows_affected . ")\n";
|
||||
}
|
||||
|
||||
sub update_items_table {
|
||||
|
||||
#::: Keep Items table sane
|
||||
$query_handle = $dbh->prepare("
|
||||
ALTER TABLE `items`
|
||||
MODIFY COLUMN `UNK132` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL;
|
||||
");
|
||||
$query_handle->execute();
|
||||
|
||||
my @matching_table;
|
||||
my @missing_items_table;
|
||||
my @missing_items_floor_table;
|
||||
|
||||
#::: Get columns from `items`
|
||||
my $sth = $dbh->prepare("SHOW COLUMNS FROM `items`;");
|
||||
$sth->execute();
|
||||
my @items_table;
|
||||
while (my @row = $sth->fetchrow_array()) {
|
||||
push(@items_table, $row[0]);
|
||||
}
|
||||
|
||||
#::: Get columns from `items_floor`
|
||||
$sth2 = $dbh->prepare("SHOW COLUMNS FROM `items_floor`");
|
||||
$sth2->execute();
|
||||
my @items_floor_table;
|
||||
while (my @row = $sth2->fetchrow_array()) {
|
||||
push(@items_floor_table, $row[0]);
|
||||
}
|
||||
|
||||
#::: Go through the original items table columns and line them up with what columns match on 13th floor
|
||||
#::: This is so we can use the matching columns to update and insert item data into `items` table
|
||||
foreach $value (@items_table) {
|
||||
if ( grep( /^$value$/i, @items_floor_table ) ) {
|
||||
push(@matching_table, $value);
|
||||
} else {
|
||||
#::: What values are we missing from EMU items table..
|
||||
push(@missing_items_table, $value);
|
||||
}
|
||||
}
|
||||
|
||||
#::: What values are we missing from.. 13thFloor
|
||||
foreach $value (@items_floor_table) {
|
||||
if ( grep( /^$value$/i, @items_table ) ) {
|
||||
#DO NOTHING...
|
||||
} else {
|
||||
push(@missing_items_floor_table, $value);
|
||||
}
|
||||
}
|
||||
print "Updating items table...\n";
|
||||
|
||||
#::: Go through the matched columns and build our query strings...
|
||||
|
||||
my $items_field_list = ""; #::: Build the field list for the INSERT (field1, field2)
|
||||
my $items_floor_field_list = ""; #::: What fields we will select from items_floor table to insert into items (matched columns)
|
||||
my $update_fields = ""; #::: To update an existing item entry if it exists...
|
||||
my @matching_table;
|
||||
my @missing_items_table;
|
||||
my @missing_items_floor_table;
|
||||
|
||||
foreach $match (@matching_table) {
|
||||
$match = lc($match);
|
||||
$update_fields .= "`" . $match . "` = fi.`" . $match . "`, ";
|
||||
$items_field_list .= "`" . $match . "`, ";
|
||||
$items_floor_field_list .= "fi.`" . $match . "`, ";
|
||||
}
|
||||
#::: Trim ', ' off the ends
|
||||
$update_fields = substr($update_fields, 0, -2);
|
||||
$items_field_list = substr($items_field_list, 0, -2);
|
||||
$items_floor_field_list = substr($items_floor_field_list, 0, -2);
|
||||
|
||||
#::: Mixed up fields...
|
||||
$items_floor_field_list =~ s/booktype/booklang/g; #our booktype is mixed with theirs...
|
||||
$update_fields =~ s/`booktype` = fi.`booktype`/`booktype` = fi.`booklang`/g;
|
||||
print "Comparing table structure...\n";
|
||||
#::: Get columns from `items`
|
||||
my $sth = $dbh->prepare("SHOW COLUMNS FROM `items`;");
|
||||
$sth->execute();
|
||||
my @items_table;
|
||||
while (my @row = $sth->fetchrow_array()) {
|
||||
push(@items_table, $row[0]);
|
||||
}
|
||||
|
||||
#::: FIELDS THAT DO NOT MATCH GO HERE
|
||||
my @items_add = (
|
||||
"casttime_", "endur", "range", "attuneable", "evolvinglevel", "herosforgemodel", "scrolltype",
|
||||
"scriptfileid", "powersourcecapacity", "augslot1unk2", "augslot2unk2", "augslot3unk2", "augslot4unk2",
|
||||
"augslot5unk2", "augslot6unk2", "recskill", "book"
|
||||
);
|
||||
my @items_floor_add = (
|
||||
"foodduration", "endurance", "therange", "attunable", "evolvl", "heroforge1", "scrolleffecttype",
|
||||
"rightclickscriptid", "powersourcecap", "augslot1unk", "augslot2unk", "augslot3unk", "augslot4unk",
|
||||
"augslot5unk", "augslot6unk", "reqskill", "booktype"
|
||||
);
|
||||
|
||||
#::: Match the mis-matched fields...
|
||||
my $spot = 0;
|
||||
foreach $value (@items_add) {
|
||||
$items_field_list .= ", `" . $value . "`";
|
||||
$update_fields .= ", `" . $value . "` = fi.`" . $items_floor_add[$spot] . "`";
|
||||
$spot++;
|
||||
@missing_items_table = grep {$_ ne $value} @missing_items_table;
|
||||
}
|
||||
foreach $value (@items_floor_add) {
|
||||
$items_floor_field_list .= ", fi.`" . $value . "`";
|
||||
@missing_items_floor_table = grep {$_ ne $value} @missing_items_floor_table;
|
||||
}
|
||||
|
||||
my $update_query = "
|
||||
INSERT INTO items (" . $items_field_list . ")
|
||||
SELECT " . $items_floor_field_list . "
|
||||
FROM items_floor fi
|
||||
ON DUPLICATE KEY UPDATE " . $update_fields;
|
||||
|
||||
#::: Print missing fields to file
|
||||
my $write_file = "missing_item_fields.txt";
|
||||
|
||||
open(F, ">$write_file") or die "Unable to open questfile: $write_file\n";
|
||||
print F "$update_query \n\n";
|
||||
print F "EQEMU items Table missing fields\n";
|
||||
foreach $value (@missing_items_table) {
|
||||
print F "$value\n";
|
||||
}
|
||||
print F "\n\n13thFloor items Table missing fields\n";
|
||||
foreach $value (@missing_items_floor_table) {
|
||||
print F "$value\n";
|
||||
}
|
||||
close(F);
|
||||
|
||||
#::: Number of rows affected by query
|
||||
$rows = $dbh->do($update_query);
|
||||
|
||||
#::: Update stackables
|
||||
$dbh->do("UPDATE items i SET i.stackable = 1 WHERE i.stacksize > 1");
|
||||
|
||||
print "Added all new items to Items table (" . $rows . ")!\n";
|
||||
|
||||
#::: Get columns from `items_floor`
|
||||
$sth2 = $dbh->prepare("SHOW COLUMNS FROM `items_floor`");
|
||||
$sth2->execute();
|
||||
my @items_floor_table;
|
||||
while (my @row = $sth2->fetchrow_array()) {
|
||||
push(@items_floor_table, $row[0]);
|
||||
}
|
||||
|
||||
#::: Go through the original items table columns and line them up with what columns match on 13th floor
|
||||
#::: This is so we can use the matching columns to update and insert item data into `items` table
|
||||
foreach $value (@items_table) {
|
||||
if ( grep( /^$value$/i, @items_floor_table ) ) {
|
||||
push(@matching_table, $value);
|
||||
} else {
|
||||
#::: What values are we missing from EMU items table..
|
||||
push(@missing_items_table, $value);
|
||||
}
|
||||
}
|
||||
|
||||
#::: What values are we missing from.. 13thFloor
|
||||
foreach $value (@items_floor_table) {
|
||||
if ( grep( /^$value$/i, @items_table ) ) {
|
||||
#DO NOTHING...
|
||||
} else {
|
||||
push(@missing_items_floor_table, $value);
|
||||
}
|
||||
}
|
||||
|
||||
#::: Go through the matched columns and build our query strings...
|
||||
|
||||
my $items_field_list = ""; #::: Build the field list for the INSERT (field1, field2)
|
||||
my $items_floor_field_list = ""; #::: What fields we will select from items_floor table to insert into items (matched columns)
|
||||
my $update_fields = ""; #::: To update an existing item entry if it exists...
|
||||
|
||||
foreach $match (@matching_table) {
|
||||
$match = lc($match);
|
||||
$update_fields .= "`" . $match . "` = fi.`" . $match . "`, ";
|
||||
$items_field_list .= "`" . $match . "`, ";
|
||||
$items_floor_field_list .= "fi.`" . $match . "`, ";
|
||||
}
|
||||
#::: Trim ', ' off the ends
|
||||
$update_fields = substr($update_fields, 0, -2);
|
||||
$items_field_list = substr($items_field_list, 0, -2);
|
||||
$items_floor_field_list = substr($items_floor_field_list, 0, -2);
|
||||
|
||||
#::: Mixed up fields...
|
||||
$items_floor_field_list =~ s/booktype/booklang/g; #our booktype is mixed with theirs...
|
||||
$update_fields =~ s/`booktype` = fi.`booktype`/`booktype` = fi.`booklang`/g;
|
||||
|
||||
#::: FIELDS THAT DO NOT MATCH GO HERE
|
||||
my @items_add = (
|
||||
"casttime_", "endur", "range", "attuneable", "evolvinglevel", "herosforgemodel", "scrolltype",
|
||||
"scriptfileid", "powersourcecapacity", "augslot1unk2", "augslot2unk2", "augslot3unk2", "augslot4unk2",
|
||||
"augslot5unk2", "augslot6unk2", "recskill", "book", "procunk1"
|
||||
);
|
||||
my @items_floor_add = (
|
||||
"foodduration", "endurance", "therange", "attunable", "evolvl", "heroforge1", "scrolleffecttype",
|
||||
"rightclickscriptid", "powersourcecap", "augslot1unk", "augslot2unk", "augslot3unk", "augslot4unk",
|
||||
"augslot5unk", "augslot6unk", "reqskill", "booktype", "prockunk1"
|
||||
);
|
||||
|
||||
#::: Match the mis-matched fields...
|
||||
print "Matching fields...\n";
|
||||
my $spot = 0;
|
||||
foreach $value (@items_add) {
|
||||
$items_field_list .= ", `" . $value . "`";
|
||||
$update_fields .= ", `" . $value . "` = fi.`" . $items_floor_add[$spot] . "`";
|
||||
$spot++;
|
||||
@missing_items_table = grep {$_ ne $value} @missing_items_table;
|
||||
}
|
||||
foreach $value (@items_floor_add) {
|
||||
$items_floor_field_list .= ", fi.`" . $value . "`";
|
||||
@missing_items_floor_table = grep {$_ ne $value} @missing_items_floor_table;
|
||||
}
|
||||
|
||||
my $update_query = "
|
||||
INSERT INTO items (" . $items_field_list . ")
|
||||
SELECT " . $items_floor_field_list . "
|
||||
FROM items_floor fi
|
||||
ON DUPLICATE KEY UPDATE " . $update_fields;
|
||||
|
||||
#::: Print missing fields to file
|
||||
print "Writing query and discrepencies to file...\n";
|
||||
my $write_file = "missing_item_fields.txt";
|
||||
|
||||
open(F, ">$write_file") or die "Unable to open file: $write_file\n";
|
||||
print F "$update_query \n\n";
|
||||
print F "EQEMU items table extra fields:\n";
|
||||
foreach $value (@missing_items_table) {
|
||||
print F "$value\n";
|
||||
}
|
||||
print F "\n\n13thFloor items table extra fields:\n";
|
||||
foreach $value (@missing_items_floor_table) {
|
||||
print F "$value\n";
|
||||
}
|
||||
close(F);
|
||||
|
||||
#::: Number of rows affected by query
|
||||
$rows = $dbh->do($update_query);
|
||||
print "Added or updated " . $rows . " entries.\n";
|
||||
|
||||
#::: Update stackables
|
||||
print "Updating stackable field...\n";
|
||||
$dbh->do("UPDATE items i SET i.stackable = 1 WHERE i.stacksize > 1");
|
||||
|
||||
#::: Update legacy research tome bagtypes
|
||||
print "Updating legacy research tomes...\n";
|
||||
$dbh->do("UPDATE items i SET i.bagtype = 24 WHERE i.id IN (17655, 17903)"); #RESEARCHWIZ
|
||||
$dbh->do("UPDATE items i SET i.bagtype = 25 WHERE i.id IN (17502, 17653)"); #RESEARCHMAG
|
||||
$dbh->do("UPDATE items i SET i.bagtype = 26 WHERE i.id IN (17501, 17654)"); #RESEARCHNEC
|
||||
$dbh->do("UPDATE items i SET i.bagtype = 27 WHERE i.id IN (17500, 17652)"); #RESEARCHENC
|
||||
}
|
||||
|
||||
sub trim($) {
|
||||
my $string = shift;
|
||||
$string =~ s/^\s+//;
|
||||
$string =~ s/\s+$//;
|
||||
return $string;
|
||||
}
|
||||
my $string = shift;
|
||||
$string =~ s/^\s+//;
|
||||
$string =~ s/\s+$//;
|
||||
return $string;
|
||||
}
|
||||
|
||||
+24
-22
@@ -1576,6 +1576,10 @@ bool Mob::SetAA(uint32 rank_id, uint32 new_value, uint32 charges) {
|
||||
|
||||
|
||||
bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
|
||||
if (!rank) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AA::Ability *ability = rank->base_ability;
|
||||
|
||||
if(!ability)
|
||||
@@ -2149,30 +2153,28 @@ void Client::AutoGrantAAPoints() {
|
||||
SendAlternateAdvancementStats();
|
||||
}
|
||||
|
||||
void Client::GrantAllAAPoints()
|
||||
void Client::GrantAllAAPoints(uint8 unlock_level)
|
||||
{
|
||||
//iterate through every AA
|
||||
for (auto& iter : zone->aa_abilities) {
|
||||
auto ability = iter.second.get();
|
||||
for (auto& aa : zone->aa_abilities) {
|
||||
AA::Ability* ability = aa.second.get();
|
||||
|
||||
if (ability->charges > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto level = GetLevel();
|
||||
auto p = 1;
|
||||
auto rank = ability->first;
|
||||
while (rank != nullptr) {
|
||||
if (CanUseAlternateAdvancementRank(rank)) {
|
||||
if (rank->level_req <= level && !HasAlreadyPurchasedRank(rank)) {
|
||||
FinishAlternateAdvancementPurchase(rank, true, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const uint8 level = unlock_level ? unlock_level : GetLevel();
|
||||
|
||||
AA::Rank* rank = ability->first;
|
||||
while (rank) {
|
||||
if (!CanUseAlternateAdvancementRank(rank)) {
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
if (rank->level_req <= level && !HasAlreadyPurchasedRank(rank)) {
|
||||
FinishAlternateAdvancementPurchase(rank, true, false);
|
||||
}
|
||||
|
||||
rank = rank->next;
|
||||
}
|
||||
}
|
||||
@@ -2184,18 +2186,18 @@ void Client::GrantAllAAPoints()
|
||||
SendAlternateAdvancementStats();
|
||||
}
|
||||
|
||||
bool Client::HasAlreadyPurchasedRank(AA::Rank *rank) {
|
||||
auto iter = aa_ranks.find(rank->base_ability->id);
|
||||
|
||||
if (iter == aa_ranks.end()) {
|
||||
bool Client::HasAlreadyPurchasedRank(AA::Rank* rank) {
|
||||
const auto& aa = aa_ranks.find(rank->base_ability->id);
|
||||
if (aa == aa_ranks.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(iter->first, iter->second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto current = ability_rank.second;
|
||||
const auto& ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa->first, aa->second.first);
|
||||
|
||||
while (current != nullptr) {
|
||||
AA::Ability* ability = ability_rank.first;
|
||||
AA::Rank* current = ability_rank.second;
|
||||
|
||||
while (current) {
|
||||
if (current == rank) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+12
-16
@@ -465,6 +465,14 @@ Bot::~Bot() {
|
||||
}
|
||||
|
||||
entity_list.RemoveBot(GetID());
|
||||
|
||||
if (GetGroup()) {
|
||||
GetGroup()->MemberZoned(this);
|
||||
}
|
||||
|
||||
if (GetRaid()) {
|
||||
GetRaid()->MemberZoned(CastToClient());
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::SetBotID(uint32 botID) {
|
||||
@@ -643,7 +651,7 @@ NPCType *Bot::FillNPCTypeStruct(
|
||||
n->current_hp = hp;
|
||||
n->max_hp = hp;
|
||||
n->size = size;
|
||||
n->runspeed = 0.7f;
|
||||
n->runspeed = 1.25f;
|
||||
n->gender = gender;
|
||||
n->race = botRace;
|
||||
n->class_ = botClass;
|
||||
@@ -2219,10 +2227,10 @@ void Bot::AI_Process()
|
||||
// OK TO IDLE
|
||||
|
||||
// Ok to idle
|
||||
if (TryIdleChecks(fm_distance)) {
|
||||
if (TryNonCombatMovementChecks(bot_owner, follow_mob, Goal)) {
|
||||
return;
|
||||
}
|
||||
if (TryNonCombatMovementChecks(bot_owner, follow_mob, Goal)) {
|
||||
if (TryIdleChecks(fm_distance)) {
|
||||
return;
|
||||
}
|
||||
if (TryBardMovementCasts()) {
|
||||
@@ -2255,23 +2263,11 @@ bool Bot::TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, g
|
||||
if ((!bot_owner->GetBotPulling() || PULLING_BOT) && (destination_distance > GetFollowDistance())) {
|
||||
|
||||
if (!IsRooted()) {
|
||||
|
||||
if (rest_timer.Enabled()) {
|
||||
rest_timer.Disable();
|
||||
}
|
||||
|
||||
bool running = true;
|
||||
|
||||
if (destination_distance < GetFollowDistance() + BOT_FOLLOW_DISTANCE_WALK) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
if (running) {
|
||||
RunTo(Goal.x, Goal.y, Goal.z);
|
||||
}
|
||||
else {
|
||||
WalkTo(Goal.x, Goal.y, Goal.z);
|
||||
}
|
||||
RunTo(Goal.x, Goal.y, Goal.z);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
|
||||
constexpr uint32 BOT_FOLLOW_DISTANCE_DEFAULT = 184; // as DSq value (~13.565 units)
|
||||
constexpr uint32 BOT_FOLLOW_DISTANCE_DEFAULT_MAX = 2500; // as DSq value (50 units)
|
||||
constexpr uint32 BOT_FOLLOW_DISTANCE_WALK = 1000; // as DSq value (~31.623 units)
|
||||
|
||||
constexpr uint32 BOT_KEEP_ALIVE_INTERVAL = 5000; // 5 seconds
|
||||
|
||||
|
||||
+1
-1
@@ -906,7 +906,7 @@ public:
|
||||
int GetSpentAA() { return m_pp.aapoints_spent; }
|
||||
uint32 GetRequiredAAExperience();
|
||||
void AutoGrantAAPoints();
|
||||
void GrantAllAAPoints();
|
||||
void GrantAllAAPoints(uint8 unlock_level = 0);
|
||||
bool HasAlreadyPurchasedRank(AA::Rank* rank);
|
||||
|
||||
bool SendGMCommand(std::string message, bool ignore_status = false);
|
||||
|
||||
@@ -18,6 +18,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "../common/global_define.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/raid.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
@@ -12578,8 +12580,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app)
|
||||
if (!raid) {
|
||||
break;
|
||||
}
|
||||
|
||||
raid->SaveRaidNote(raid_command_packet->leader_name, raid_command_packet->note);
|
||||
RaidNote_Struct* note = (RaidNote_Struct*)app->pBuffer;
|
||||
raid->SaveRaidNote(raid_command_packet->leader_name, note->note);
|
||||
raid->SendRaidNotesToWorld();
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ int command_init(void)
|
||||
command_add("givemoney", "[Platinum] [Gold] [Silver] [Copper] - Gives specified amount of money to you or your player target", AccountStatus::GMMgmt, command_givemoney) ||
|
||||
command_add("gmzone", "[Zone ID|Zone Short Name] [Version] [Instance Identifier] - Zones to a private GM instance (Version defaults to 0 and Instance Identifier defaults to 'gmzone' if not used)", AccountStatus::GMAdmin, command_gmzone) ||
|
||||
command_add("goto", "[playername] or [x y z] [h] - Teleport to the provided coordinates or to your target", AccountStatus::Steward, command_goto) ||
|
||||
command_add("grantaa", "Grants a player all available AA points for their level.", AccountStatus::GMMgmt, command_grantaa) ||
|
||||
command_add("grantaa", "[level] - Grants a player all available AA points up the specified level, all AAs are granted if no level is specified.", AccountStatus::GMMgmt, command_grantaa) ||
|
||||
command_add("grid", "[add/delete] [grid_num] [wandertype] [pausetype] - Create/delete a wandering grid", AccountStatus::GMAreas, command_grid) ||
|
||||
command_add("guild", "Guild manipulation commands. Use argument help for more info.", AccountStatus::Steward, command_guild) ||
|
||||
command_add("help", "[Search Criteria] - List available commands and their description, specify partial command as argument to search", AccountStatus::Player, command_help) ||
|
||||
|
||||
@@ -207,6 +207,8 @@ enum {
|
||||
MODIFY_AVOID_DAMAGE = 51, //Modify by percent the NPCs chance to riposte, block, parry or dodge individually, or for all skills
|
||||
IMMUNE_FADING_MEMORIES = 52,
|
||||
IMMUNE_OPEN = 53,
|
||||
IMMUNE_ASSASSINATE = 54,
|
||||
IMMUNE_HEADSHOT = 55,
|
||||
MAX_SPECIAL_ATTACK
|
||||
};
|
||||
|
||||
|
||||
+68
-2
@@ -1560,6 +1560,7 @@ void PerlembParser::ExportEventVariables(
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "target", "Mob", std::any_cast<Mob*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1606,9 +1607,11 @@ void PerlembParser::ExportEventVariables(
|
||||
case EVENT_CLICK_DOOR: {
|
||||
ExportVar(package_name.c_str(), "doorid", data);
|
||||
ExportVar(package_name.c_str(), "version", zone->GetInstanceVersion());
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "door", "Doors", std::any_cast<Doors*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1649,6 +1652,16 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "spell_id", sep.arg[0]);
|
||||
ExportVar(package_name.c_str(), "caster_id", sep.arg[1]);
|
||||
ExportVar(package_name.c_str(), "caster_level", sep.arg[2]);
|
||||
ExportVar(package_name.c_str(), "target_id", sep.arg[3]);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "target", "Mob", std::any_cast<Mob*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
if (IsValidSpell(Strings::ToUnsignedInt(sep.arg[0]))) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[Strings::ToUnsignedInt(sep.arg[0])]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1683,9 +1696,11 @@ void PerlembParser::ExportEventVariables(
|
||||
case EVENT_PLAYER_PICKUP: {
|
||||
ExportVar(package_name.c_str(), "picked_up_id", data);
|
||||
ExportVar(package_name.c_str(), "picked_up_entity_id", extradata);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1731,12 +1746,18 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "itemname", item_inst->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
ExportVar(package_name.c_str(), "spell_id", item_inst->GetItem()->Click.Effect);
|
||||
|
||||
if (IsValidSpell(item_inst->GetItem()->Click.Effect)) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[item_inst->GetItem()->Click.Effect]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_ITEM_CLICK_CAST_CLIENT:
|
||||
case EVENT_ITEM_CLICK_CLIENT: {
|
||||
ExportVar(package_name.c_str(), "slot_id", data);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
auto* item = std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0));
|
||||
if (item) {
|
||||
@@ -1744,8 +1765,13 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "item_name", item->GetItem()->Name);
|
||||
ExportVar(package_name.c_str(), "spell_id", item->GetItem()->Click.Effect);
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", item);
|
||||
|
||||
if (IsValidSpell(item->GetItem()->Click.Effect)) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[item->GetItem()->Click.Effect]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1776,6 +1802,11 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "tics_remaining", sep.arg[1]);
|
||||
ExportVar(package_name.c_str(), "caster_level", sep.arg[2]);
|
||||
ExportVar(package_name.c_str(), "buff_slot", sep.arg[3]);
|
||||
|
||||
if (IsValidSpell(objid)) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[objid]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1789,34 +1820,42 @@ void PerlembParser::ExportEventVariables(
|
||||
|
||||
case EVENT_FORAGE_SUCCESS: {
|
||||
ExportVar(package_name.c_str(), "foraged_item", extradata);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_FISH_SUCCESS: {
|
||||
ExportVar(package_name.c_str(), "fished_item", extradata);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_CLICK_OBJECT: {
|
||||
ExportVar(package_name.c_str(), "objectid", data);
|
||||
ExportVar(package_name.c_str(), "clicker_id", extradata);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "object", "Object", std::any_cast<Object*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_DISCOVER_ITEM: {
|
||||
ExportVar(package_name.c_str(), "itemid", extradata);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1843,6 +1882,10 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
|
||||
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
|
||||
|
||||
if (IsValidSpell(Strings::ToUnsignedInt(sep.arg[2]))) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[Strings::ToUnsignedInt(sep.arg[2])]);
|
||||
}
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
Mob* killed = std::any_cast<Mob*>(extra_pointers->at(0));
|
||||
if (killed) {
|
||||
@@ -1867,6 +1910,10 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
|
||||
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
|
||||
|
||||
if (IsValidSpell(Strings::ToUnsignedInt(sep.arg[2]))) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[Strings::ToUnsignedInt(sep.arg[2])]);
|
||||
}
|
||||
|
||||
if (extra_pointers && extra_pointers->size() >= 1) {
|
||||
Corpse* corpse = std::any_cast<Corpse*>(extra_pointers->at(0));
|
||||
if (corpse) {
|
||||
@@ -1909,6 +1956,7 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "slot_id", extradata);
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", item_instance);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1936,8 +1984,7 @@ void PerlembParser::ExportEventVariables(
|
||||
std::string tradeskill_id = "-1";
|
||||
if (strcmp(sep.arg[0], "check_zone") == 0) {
|
||||
zone_id = sep.arg[1];
|
||||
}
|
||||
else if (strcmp(sep.arg[0], "check_tradeskill") == 0) {
|
||||
} else if (strcmp(sep.arg[0], "check_tradeskill") == 0) {
|
||||
tradeskill_id = sep.arg[1];
|
||||
}
|
||||
|
||||
@@ -1966,17 +2013,21 @@ void PerlembParser::ExportEventVariables(
|
||||
|
||||
case EVENT_CONSIDER: {
|
||||
ExportVar(package_name.c_str(), "entity_id", Strings::ToInt(data));
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "target", "Mob", std::any_cast<Mob*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_CONSIDER_CORPSE: {
|
||||
ExportVar(package_name.c_str(), "corpse_entity_id", Strings::ToInt(data));
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "corpse", "Corpse", std::any_cast<Corpse*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1991,9 +2042,11 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "item_id", extradata);
|
||||
ExportVar(package_name.c_str(), "item_quantity", sep.arg[0]);
|
||||
ExportVar(package_name.c_str(), "slot_id", sep.arg[1]);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2003,9 +2056,11 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "item_id", extradata);
|
||||
ExportVar(package_name.c_str(), "item_quantity", sep.arg[0]);
|
||||
ExportVar(package_name.c_str(), "slot_id", sep.arg[1]);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", std::any_cast<EQ::ItemInstance*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2111,9 +2166,11 @@ void PerlembParser::ExportEventVariables(
|
||||
|
||||
case EVENT_INSPECT: {
|
||||
ExportVar(package_name.c_str(), "target_id", extradata);
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
ExportVar(package_name.c_str(), "target", "Mob", std::any_cast<Mob*>(extra_pointers->at(0)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2138,6 +2195,7 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "area_id", *std::any_cast<int*>(extra_pointers->at(0)));
|
||||
ExportVar(package_name.c_str(), "area_type", *std::any_cast<int*>(extra_pointers->at(1)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2177,6 +2235,11 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "buff_slot", sep.arg[6]);
|
||||
ExportVar(package_name.c_str(), "is_buff_tic", sep.arg[7]);
|
||||
ExportVar(package_name.c_str(), "special_attack", sep.arg[8]);
|
||||
|
||||
if (IsValidSpell(Strings::ToUnsignedInt(sep.arg[2]))) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[Strings::ToUnsignedInt(sep.arg[2])]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2188,6 +2251,7 @@ void PerlembParser::ExportEventVariables(
|
||||
ExportVar(package_name.c_str(), "quantity", inst->IsStackable() ? inst->GetCharges() : 1);
|
||||
ExportVar(package_name.c_str(), "item", "QuestItem", inst);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2198,9 +2262,11 @@ void PerlembParser::ExportEventVariables(
|
||||
Seperator sep(data);
|
||||
ExportVar(package_name.c_str(), "slot_id", sep.arg[0]);
|
||||
ExportVar(package_name.c_str(), "spell_id", sep.arg[1]);
|
||||
|
||||
if (IsValidSpell(Strings::ToUnsignedInt(sep.arg[1]))) {
|
||||
ExportVar(package_name.c_str(), "spell", "Spell", (void*)&spells[Strings::ToUnsignedInt(sep.arg[1])]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,8 @@ void command_castspell(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
const bool can_instant_cast = c->Admin() >= commandInstacast;
|
||||
bool instant_cast = false;
|
||||
if (can_instant_cast && sep->IsNumber(2)) {
|
||||
instant_cast = Strings::ToBool(sep->arg[2]);
|
||||
}
|
||||
|
||||
const uint16 target_id = t->GetID();
|
||||
const bool instant_cast = sep->IsNumber(2) ? Strings::ToBool(sep->arg[2]) : true;
|
||||
const uint16 target_id = t->GetID();
|
||||
|
||||
if (instant_cast) {
|
||||
c->SpellFinished(spell_id, t);
|
||||
|
||||
@@ -72,7 +72,9 @@ void command_find(Client *c, const Seperator *sep)
|
||||
|
||||
// skip the first arg
|
||||
for (auto i = 1; i <= arguments; i++) {
|
||||
args.emplace_back(sep->arg[i]);
|
||||
if (sep->arg[i]) {
|
||||
args.emplace_back(sep->arg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// build the rewrite string
|
||||
|
||||
@@ -7,14 +7,24 @@ void command_grantaa(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8 unlock_level = sep->IsNumber(1) ? static_cast<uint8>(Strings::ToUnsignedInt(sep->arg[1])) : 0;
|
||||
|
||||
auto t = c->GetTarget()->CastToClient();
|
||||
t->GrantAllAAPoints();
|
||||
t->GrantAllAAPoints(unlock_level);
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Successfully granted all Alternate Advancements for {}.",
|
||||
c->GetTargetDescription(t)
|
||||
"Successfully granted all Alternate Advancements for {}{}.",
|
||||
c->GetTargetDescription(t),
|
||||
(
|
||||
unlock_level ?
|
||||
fmt::format(
|
||||
" up to level {}",
|
||||
unlock_level
|
||||
) :
|
||||
""
|
||||
)
|
||||
).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,12 @@ void command_movechar(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
auto zone_id = ZoneID(zone_short_name);
|
||||
std::string zone_long_name = ZoneLongName(zone_id);
|
||||
auto z = GetZone(zone_id);
|
||||
|
||||
if (!z) {
|
||||
c->Message(Chat::Red, "Invalid zone.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_special_zone = (
|
||||
zone_short_name.find("cshome") != std::string::npos ||
|
||||
@@ -59,7 +64,7 @@ void command_movechar(Client *c, const Seperator *sep)
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"{} ({}) is a special zone and you cannot move someone there.",
|
||||
zone_long_name,
|
||||
z->long_name,
|
||||
zone_short_name
|
||||
).c_str()
|
||||
);
|
||||
@@ -91,7 +96,7 @@ void command_movechar(Client *c, const Seperator *sep)
|
||||
fmt::format(
|
||||
"Character Move {} | Zone: {} ({}) ID: {}",
|
||||
moved_string,
|
||||
zone_long_name,
|
||||
z->long_name,
|
||||
zone_short_name,
|
||||
zone_id
|
||||
).c_str()
|
||||
|
||||
@@ -136,7 +136,9 @@ void command_set(Client *c, const Seperator *sep)
|
||||
|
||||
// skip the first arg
|
||||
for (auto i = 1; i <= arguments; i++) {
|
||||
args.emplace_back(sep->arg[i]);
|
||||
if (sep->arg[i]) {
|
||||
args.emplace_back(sep->arg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// build the rewrite string
|
||||
|
||||
@@ -115,7 +115,9 @@ void command_show(Client *c, const Seperator *sep)
|
||||
|
||||
// skip the first arg
|
||||
for (auto i = 1; i <= arguments; i++) {
|
||||
args.emplace_back(sep->arg[i]);
|
||||
if (sep->arg[i]) {
|
||||
args.emplace_back(sep->arg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// build the rewrite string
|
||||
|
||||
@@ -46,7 +46,7 @@ void ShowGroupInfo(Client *c, const Seperator *sep)
|
||||
);
|
||||
|
||||
const std::string yes = DialogueWindow::ColorMessage("forest_green", "Y");
|
||||
const std::string no = DialogueWindow::ColorMessage("red1", "N");
|
||||
const std::string no = DialogueWindow::ColorMessage("red_1", "N");
|
||||
|
||||
for (int group_member = 0; group_member < MAX_GROUP_MEMBERS; group_member++) {
|
||||
if (g->membername[group_member][0] == '\0') {
|
||||
@@ -60,8 +60,8 @@ void ShowGroupInfo(Client *c, const Seperator *sep)
|
||||
popup_table += DialogueWindow::TableRow(
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}",
|
||||
group_member,
|
||||
(
|
||||
DialogueWindow::TableCell(std::to_string(group_member)),
|
||||
DialogueWindow::TableCell(
|
||||
strcmp(g->membername[group_member], c->GetCleanName()) ?
|
||||
g->membername[group_member] :
|
||||
fmt::format(
|
||||
@@ -69,10 +69,10 @@ void ShowGroupInfo(Client *c, const Seperator *sep)
|
||||
g->membername[group_member]
|
||||
)
|
||||
),
|
||||
g->members[group_member] ? yes : no,
|
||||
is_assist ? yes : no,
|
||||
is_puller ? yes : no,
|
||||
is_tank ? yes : no
|
||||
DialogueWindow::TableCell(g->members[group_member] ? yes : no),
|
||||
DialogueWindow::TableCell(is_assist ? yes : no),
|
||||
DialogueWindow::TableCell(is_puller ? yes : no),
|
||||
DialogueWindow::TableCell(is_tank ? yes : no)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ void ShowZoneData(Client *c, const Seperator *sep)
|
||||
fmt::format(
|
||||
"{} {} {}",
|
||||
DialogueWindow::ColorMessage(
|
||||
"red1",
|
||||
"red_1",
|
||||
std::to_string(zone->newzone_data.fog_red[fog_index])
|
||||
),
|
||||
DialogueWindow::ColorMessage(
|
||||
@@ -206,7 +206,7 @@ void ShowZoneData(Client *c, const Seperator *sep)
|
||||
DialogueWindow::TableCell(
|
||||
zone->newzone_data.suspend_buffs ?
|
||||
DialogueWindow::ColorMessage("forest_green", "Y") :
|
||||
DialogueWindow::ColorMessage("red1", "N")
|
||||
DialogueWindow::ColorMessage("red_1", "N")
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+17
-12
@@ -15,7 +15,7 @@ void command_summon(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
Mob* target;
|
||||
Mob* t = c;
|
||||
|
||||
if (arguments == 1) {
|
||||
std::string character_name = sep->arg[1];
|
||||
@@ -33,7 +33,7 @@ void command_summon(Client *c, const Seperator *sep)
|
||||
|
||||
auto search_client = entity_list.GetClientByName(character_name.c_str());
|
||||
if (search_client) {
|
||||
target = search_client->CastToMob();
|
||||
t = search_client->CastToMob();
|
||||
} else {
|
||||
if (!worldserver.Connected()) {
|
||||
c->Message(Chat::White, "World server is currently disconnected.");
|
||||
@@ -56,19 +56,24 @@ void command_summon(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
} else if (c->GetTarget()) {
|
||||
target = c->GetTarget();
|
||||
t = c->GetTarget();
|
||||
}
|
||||
|
||||
if (c == target) {
|
||||
|
||||
if (c == t) {
|
||||
c->Message(Chat::White, "You cannot summon yourself.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!t) {
|
||||
c->Message(Chat::White, "You must have a target to summon.");
|
||||
return;
|
||||
}
|
||||
|
||||
c->Message(
|
||||
Chat::White,
|
||||
fmt::format(
|
||||
"Summoning {} to {:.2f}, {:.2f}, {:.2f} in {} ({}).",
|
||||
c->GetTargetDescription(target),
|
||||
c->GetTargetDescription(t),
|
||||
c->GetX(),
|
||||
c->GetY(),
|
||||
c->GetZ(),
|
||||
@@ -77,8 +82,8 @@ void command_summon(Client *c, const Seperator *sep)
|
||||
).c_str()
|
||||
);
|
||||
|
||||
if (target->IsClient()) {
|
||||
target->CastToClient()->MovePC(
|
||||
if (t->IsClient()) {
|
||||
t->CastToClient()->MovePC(
|
||||
zone->GetZoneID(),
|
||||
zone->GetInstanceID(),
|
||||
c->GetX(),
|
||||
@@ -91,10 +96,10 @@ void command_summon(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
target->GMMove(c->GetPosition());
|
||||
t->GMMove(c->GetPosition());
|
||||
|
||||
if (target->IsNPC()) {
|
||||
target->CastToNPC()->SaveGuardSpot(glm::vec4(0.0f));
|
||||
if (t->IsNPC()) {
|
||||
t->CastToNPC()->SaveGuardSpot(glm::vec4(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -555,8 +555,13 @@ void Group::MemberZoned(Mob* removemob) {
|
||||
|
||||
//should NOT clear the name, it is used for world communication.
|
||||
for (auto & m : members) {
|
||||
if (m && (m == removemob || (m->IsBot() && m->CastToBot()->GetBotOwner() == removemob))) {
|
||||
m = nullptr;
|
||||
if (m) {
|
||||
if (m->IsBot() && m->CastToBot()->GetBotOwner() && m->CastToBot()->GetBotOwner() == removemob) {
|
||||
m = nullptr;
|
||||
}
|
||||
else if (m == removemob) {
|
||||
m = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3164,6 +3164,18 @@ void Lua_Client::SetBucket(std::string bucket_name, std::string bucket_value, st
|
||||
self->SetBucket(bucket_name, bucket_value, expiration);
|
||||
}
|
||||
|
||||
void Lua_Client::GrantAllAAPoints()
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->GrantAllAAPoints();
|
||||
}
|
||||
|
||||
void Lua_Client::GrantAllAAPoints(uint8 unlock_level)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
self->GrantAllAAPoints(unlock_level);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_client() {
|
||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -3414,6 +3426,8 @@ luabind::scope lua_register_client() {
|
||||
.def("GetPEQZoneFlags", (luabind::object(Lua_Client::*)(lua_State*))&Lua_Client::GetPEQZoneFlags)
|
||||
.def("GetZoneFlags", (luabind::object(Lua_Client::*)(lua_State*))&Lua_Client::GetZoneFlags)
|
||||
.def("GoFish", (void(Lua_Client::*)(void))&Lua_Client::GoFish)
|
||||
.def("GrantAllAAPoints", (void(Lua_Client::*)(void))&Lua_Client::GrantAllAAPoints)
|
||||
.def("GrantAllAAPoints", (void(Lua_Client::*)(uint8))&Lua_Client::GrantAllAAPoints)
|
||||
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility)
|
||||
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility)
|
||||
.def("GuildID", (uint32(Lua_Client::*)(void))&Lua_Client::GuildID)
|
||||
|
||||
@@ -480,6 +480,8 @@ public:
|
||||
std::string GetBucketRemaining(std::string bucket_name);
|
||||
void SetBucket(std::string bucket_name, std::string bucket_value);
|
||||
void SetBucket(std::string bucket_name, std::string bucket_value, std::string expiration);
|
||||
void GrantAllAAPoints();
|
||||
void GrantAllAAPoints(uint8 unlock_level);
|
||||
|
||||
void ApplySpell(int spell_id);
|
||||
void ApplySpell(int spell_id, int duration);
|
||||
|
||||
+18
-4
@@ -315,11 +315,16 @@ void Lua_Mob::SetInvisible(int state) {
|
||||
self->SetInvisible(state);
|
||||
}
|
||||
|
||||
bool Lua_Mob::FindBuff(int spell_id) {
|
||||
bool Lua_Mob::FindBuff(uint16 spell_id) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->FindBuff(spell_id);
|
||||
}
|
||||
|
||||
bool Lua_Mob::FindBuff(uint16 spell_id, uint16 caster_id) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->FindBuff(spell_id, caster_id);
|
||||
}
|
||||
|
||||
uint16 Lua_Mob::FindBuffBySlot(int slot) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->FindBuffBySlot(slot);
|
||||
@@ -873,7 +878,13 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id) {
|
||||
|
||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQ::spells::CastingSlot>(slot));
|
||||
|
||||
int cast_slot = 0;
|
||||
if (slot >= 0 || slot <= 23 || slot == 255) {
|
||||
cast_slot = slot;
|
||||
}
|
||||
|
||||
return self->CastSpell(spell_id, target_id, static_cast<EQ::spells::CastingSlot>(cast_slot));
|
||||
}
|
||||
|
||||
bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time) {
|
||||
@@ -3324,7 +3335,8 @@ luabind::scope lua_register_mob() {
|
||||
.def("Emote", &Lua_Mob::Emote)
|
||||
.def("EntityVariableExists", &Lua_Mob::EntityVariableExists)
|
||||
.def("FaceTarget", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::FaceTarget)
|
||||
.def("FindBuff", &Lua_Mob::FindBuff)
|
||||
.def("FindBuff", (bool(Lua_Mob::*)(uint16))&Lua_Mob::FindBuff)
|
||||
.def("FindBuff", (bool(Lua_Mob::*)(uint16,uint16))&Lua_Mob::FindBuff)
|
||||
.def("FindBuffBySlot", (uint16(Lua_Mob::*)(int))&Lua_Mob::FindBuffBySlot)
|
||||
.def("FindGroundZ", (double(Lua_Mob::*)(double,double))&Lua_Mob::FindGroundZ)
|
||||
.def("FindGroundZ", (double(Lua_Mob::*)(double,double,double))&Lua_Mob::FindGroundZ)
|
||||
@@ -3745,7 +3757,9 @@ luabind::scope lua_register_special_abilities() {
|
||||
luabind::value("immune_aggro_client", static_cast<int>(IMMUNE_AGGRO_CLIENT)),
|
||||
luabind::value("immune_aggro_npc", static_cast<int>(IMMUNE_AGGRO_NPC)),
|
||||
luabind::value("modify_avoid_damage", static_cast<int>(MODIFY_AVOID_DAMAGE)),
|
||||
luabind::value("immune_open", static_cast<int>(IMMUNE_OPEN))
|
||||
luabind::value("immune_open", static_cast<int>(IMMUNE_OPEN)),
|
||||
luabind::value("immune_assassinate", static_cast<int>(IMMUNE_ASSASSINATE)),
|
||||
luabind::value("immune_headshot", static_cast<int>(IMMUNE_HEADSHOT))
|
||||
)];
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -90,7 +90,8 @@ public:
|
||||
uint8 GetInvisibleUndeadLevel();
|
||||
void SetSeeInvisibleLevel(uint8 invisible_level);
|
||||
void SetSeeInvisibleUndeadLevel(uint8 invisible_level);
|
||||
bool FindBuff(int spell_id);
|
||||
bool FindBuff(uint16 spell_id);
|
||||
bool FindBuff(uint16 spell_id, uint16 caster_id);
|
||||
uint16 FindBuffBySlot(int slot);
|
||||
uint32 BuffCount();
|
||||
uint32 BuffCount(bool is_beneficial);
|
||||
|
||||
@@ -354,6 +354,16 @@ void handle_npc_cast(
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[2]));
|
||||
lua_setfield(L, -2, "caster_level");
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[3]));
|
||||
lua_setfield(L, -2, "target_id");
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
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, "target");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_npc_area(
|
||||
@@ -715,6 +725,16 @@ void handle_player_cast(
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[2]));
|
||||
lua_setfield(L, -2, "caster_level");
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[3]));
|
||||
lua_setfield(L, -2, "target_id");
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
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, "target");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_player_task_fail(
|
||||
@@ -1955,6 +1975,16 @@ void handle_bot_cast(
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[2]));
|
||||
lua_setfield(L, -2, "caster_level");
|
||||
|
||||
lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[3]));
|
||||
lua_setfield(L, -2, "target_id");
|
||||
|
||||
if (extra_pointers && extra_pointers->size() == 1) {
|
||||
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, "target");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_bot_combat(
|
||||
|
||||
+39
-39
@@ -593,42 +593,49 @@ void Mob::CalcSeeInvisibleLevel()
|
||||
see_invis = std::max({ spellbonuses.SeeInvis, itembonuses.SeeInvis, aabonuses.SeeInvis, innate_see_invis });
|
||||
}
|
||||
|
||||
void Mob::CalcInvisibleLevel()
|
||||
{
|
||||
bool is_invisible = invisible;
|
||||
bool Mob::HasAnInvisibilityEffect() {
|
||||
return invisible || hidden || improved_hidden || invisible_animals || invisible_undead;
|
||||
}
|
||||
|
||||
invisible = std::max({ spellbonuses.invisibility, nobuff_invisible });
|
||||
invisible_undead = spellbonuses.invisibility_verse_undead;
|
||||
invisible_animals = spellbonuses.invisibility_verse_animal;
|
||||
|
||||
if (!is_invisible && invisible) {
|
||||
SetInvisible(Invisibility::Invisible, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_invisible && !invisible) {
|
||||
SetInvisible(invisible, true);
|
||||
return;
|
||||
void Mob::BreakCharmPetIfConditionsMet() {
|
||||
auto pet = GetPet();
|
||||
if (pet && pet->GetPetType() == petCharmed && HasAnInvisibilityEffect()) {
|
||||
if (RuleB(Pets, LivelikeBreakCharmOnInvis) || IsInvisible(pet)) {
|
||||
pet->BuffFadeByEffect(SE_Charm);
|
||||
}
|
||||
LogRules(
|
||||
"Pets:LivelikeBreakCharmOnInvis for [{}] invisible [{}] hidden [{}] improved_hidden (shroud of stealth) [{}] invisible_animals [{}] invisible_undead [{}]",
|
||||
GetCleanName(),
|
||||
invisible,
|
||||
hidden,
|
||||
improved_hidden,
|
||||
invisible_animals,
|
||||
invisible_undead
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SetInvisible(uint8 state, bool set_on_bonus_calc)
|
||||
void Mob::CalcInvisibleLevel()
|
||||
{
|
||||
/*
|
||||
If you set an NPC to invisible you will only be able to see it on
|
||||
your client if your see invisible level is greater than equal to the invisible level.
|
||||
Note, the clients spell file must match the servers see invisible level on the spell.
|
||||
*/
|
||||
bool was_invisible = invisible;
|
||||
|
||||
invisible = std::max({spellbonuses.invisibility, nobuff_invisible});
|
||||
invisible_undead = spellbonuses.invisibility_verse_undead;
|
||||
invisible_animals = spellbonuses.invisibility_verse_animal;
|
||||
|
||||
if (was_invisible != invisible) {
|
||||
SetInvisible(invisible, true);
|
||||
return;
|
||||
}
|
||||
|
||||
BreakCharmPetIfConditionsMet();
|
||||
}
|
||||
|
||||
void Mob::SetInvisible(uint8 state, bool set_on_bonus_calc) {
|
||||
if (state == Invisibility::Visible) {
|
||||
SendAppearancePacket(AT_Invis, Invisibility::Visible);
|
||||
ZeroInvisibleVars(InvisType::T_INVISIBLE);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
if your setting invisible from a script, or escape/fading memories effect then
|
||||
we use the internal invis variable which allows invisible without a buff on mob.
|
||||
*/
|
||||
} else {
|
||||
if (!set_on_bonus_calc) {
|
||||
nobuff_invisible = state;
|
||||
CalcInvisibleLevel();
|
||||
@@ -636,14 +643,7 @@ void Mob::SetInvisible(uint8 state, bool set_on_bonus_calc)
|
||||
SendAppearancePacket(AT_Invis, invisible);
|
||||
}
|
||||
|
||||
// Invis and hide breaks charms
|
||||
auto pet = GetPet();
|
||||
if (pet && pet->GetPetType() == petCharmed && (invisible || hidden || improved_hidden || invisible_animals || invisible_undead)) {
|
||||
if (RuleB(Pets, LivelikeBreakCharmOnInvis) || IsInvisible(pet)) {
|
||||
pet->BuffFadeByEffect(SE_Charm);
|
||||
}
|
||||
LogRules("Pets:LivelikeBreakCharmOnInvis for [{}] | Invis [{}] - Hidden [{}] - Shroud of Stealth [{}] - IVA [{}] - IVU [{}]", GetCleanName(), invisible, hidden, improved_hidden, invisible_animals, invisible_undead);
|
||||
}
|
||||
BreakCharmPetIfConditionsMet();
|
||||
}
|
||||
|
||||
void Mob::ZeroInvisibleVars(uint8 invisible_type)
|
||||
@@ -3460,10 +3460,10 @@ void Mob::ShowBuffs(Client* c) {
|
||||
);
|
||||
|
||||
for (auto i = 0; i < GetMaxTotalSlots(); i++) {
|
||||
const auto spell_id = buffs[i].spellid;
|
||||
const auto buff_duration_formula = spells[spell_id].buff_duration_formula;
|
||||
const auto spell_id = buffs[i].spellid;
|
||||
if (IsValidSpell(spell_id)) {
|
||||
const auto is_permanent = (
|
||||
const auto buff_duration_formula = spells[spell_id].buff_duration_formula;
|
||||
const auto is_permanent = (
|
||||
buff_duration_formula == DF_Aura ||
|
||||
buff_duration_formula == DF_Permanent
|
||||
);
|
||||
@@ -5114,7 +5114,7 @@ std::string Mob::GetTargetDescription(Mob* target, uint8 description_type, uint1
|
||||
auto d = fmt::format(
|
||||
"{}",
|
||||
(
|
||||
this == target ?
|
||||
target && this == target ?
|
||||
self_return :
|
||||
fmt::format(
|
||||
"{} ({})",
|
||||
|
||||
+3
-1
@@ -269,6 +269,8 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
bool HasAnInvisibilityEffect();
|
||||
void BreakCharmPetIfConditionsMet();
|
||||
//Invisible
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
void SetInvisible(uint8 state, bool set_on_bonus_calc = false);
|
||||
@@ -464,7 +466,7 @@ public:
|
||||
void DamageShield(Mob* other, bool spell_ds = false);
|
||||
int32 RuneAbsorb(int64 damage, uint16 type);
|
||||
std::vector<uint16> GetBuffSpellIDs();
|
||||
bool FindBuff(uint16 spell_id);
|
||||
bool FindBuff(uint16 spell_id, uint16 caster_id = 0);
|
||||
uint16 FindBuffBySlot(int slot);
|
||||
uint32 BuffCount(bool is_beneficial = true, bool is_detrimental = true);
|
||||
bool FindType(uint16 type, bool bOffensive = false, uint16 threshold = 100);
|
||||
|
||||
@@ -2982,6 +2982,16 @@ void Perl_Client_SetLDoNPoints(Client* self, uint32 theme_id, uint32 points)
|
||||
self->SetLDoNPoints(theme_id, points);
|
||||
}
|
||||
|
||||
void Perl_Client_GrantAllAAPoints(Client* self)
|
||||
{
|
||||
self->GrantAllAAPoints();
|
||||
}
|
||||
|
||||
void Perl_Client_GrantAllAAPoints(Client* self, uint8 unlock_level)
|
||||
{
|
||||
self->GrantAllAAPoints(unlock_level);
|
||||
}
|
||||
|
||||
void perl_register_client()
|
||||
{
|
||||
perl::interpreter perl(PERL_GET_THX);
|
||||
@@ -3232,6 +3242,8 @@ void perl_register_client()
|
||||
package.add("GetPEQZoneFlags", &Perl_Client_GetPEQZoneFlags);
|
||||
package.add("GetZoneFlags", &Perl_Client_GetZoneFlags);
|
||||
package.add("GoFish", &Perl_Client_GoFish);
|
||||
package.add("GrantAllAAPoints", (void(*)(Client*))&Perl_Client_GrantAllAAPoints);
|
||||
package.add("GrantAllAAPoints", (void(*)(Client*, uint8))&Perl_Client_GrantAllAAPoints);
|
||||
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int))&Perl_Client_GrantAlternateAdvancementAbility);
|
||||
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int, bool))&Perl_Client_GrantAlternateAdvancementAbility);
|
||||
package.add("GuildID", &Perl_Client_GuildID);
|
||||
|
||||
+18
-133
@@ -362,6 +362,11 @@ bool Perl_Mob_FindBuff(Mob* self, uint16 spell_id) // @categories Spells and Dis
|
||||
return self->FindBuff(spell_id);
|
||||
}
|
||||
|
||||
bool Perl_Mob_FindBuff(Mob* self, uint16 spell_id, uint16 caster_id) // @categories Spells and Disciplines, Script Utility
|
||||
{
|
||||
return self->FindBuff(spell_id, caster_id);
|
||||
}
|
||||
|
||||
int Perl_Mob_FindBuffBySlot(Mob* self, int slot) // @categories Spells and Disciplines, Script Utility
|
||||
{
|
||||
return self->FindBuffBySlot(slot);
|
||||
@@ -1897,13 +1902,7 @@ void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 tex
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -1915,14 +1914,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -1935,15 +1927,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -1957,16 +1941,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -1981,17 +1956,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color,
|
||||
uint8 beard
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color, uint8 beard) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -2007,18 +1972,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color,
|
||||
uint8 beard,
|
||||
uint8 beard_color
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color, uint8 beard, uint8 beard_color) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -2035,19 +1989,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color,
|
||||
uint8 beard,
|
||||
uint8 beard_color,
|
||||
uint32 drakkin_heritage
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color, uint8 beard, uint8 beard_color, uint32 drakkin_heritage) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -2065,20 +2007,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color,
|
||||
uint8 beard,
|
||||
uint8 beard_color,
|
||||
uint32 drakkin_heritage,
|
||||
uint32 drakkin_tattoo
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color, uint8 beard, uint8 beard_color, uint32 drakkin_heritage, uint32 drakkin_tattoo) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -2097,21 +2026,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color,
|
||||
uint8 beard,
|
||||
uint8 beard_color,
|
||||
uint32 drakkin_heritage,
|
||||
uint32 drakkin_tattoo,
|
||||
uint32 drakkin_details
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color, uint8 beard, uint8 beard_color, uint32 drakkin_heritage, uint32 drakkin_tattoo, uint32 drakkin_details) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -2131,22 +2046,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color,
|
||||
uint8 beard,
|
||||
uint8 beard_color,
|
||||
uint32 drakkin_heritage,
|
||||
uint32 drakkin_tattoo,
|
||||
uint32 drakkin_details,
|
||||
float size
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color, uint8 beard, uint8 beard_color, uint32 drakkin_heritage, uint32 drakkin_tattoo, uint32 drakkin_details, float size) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -2167,23 +2067,7 @@ void Perl_Mob_SendIllusion(
|
||||
);
|
||||
}
|
||||
|
||||
void Perl_Mob_SendIllusion(
|
||||
Mob *self,
|
||||
uint16 race_id,
|
||||
uint8 gender_id,
|
||||
uint8 texture,
|
||||
uint8 helmet_texture,
|
||||
uint8 face,
|
||||
uint8 hair,
|
||||
uint8 hair_color,
|
||||
uint8 beard,
|
||||
uint8 beard_color,
|
||||
uint32 drakkin_heritage,
|
||||
uint32 drakkin_tattoo,
|
||||
uint32 drakkin_details,
|
||||
float size,
|
||||
Client *target
|
||||
) // @categories Script Utility
|
||||
void Perl_Mob_SendIllusion(Mob *self, uint16 race_id, uint8 gender_id, uint8 texture, uint8 helmet_texture, uint8 face, uint8 hair, uint8 hair_color, uint8 beard, uint8 beard_color, uint32 drakkin_heritage, uint32 drakkin_tattoo, uint32 drakkin_details, float size, Client *target) // @categories Script Utility
|
||||
{
|
||||
self->SendIllusionPacket(
|
||||
AppearanceStruct{
|
||||
@@ -3570,7 +3454,8 @@ void perl_register_mob()
|
||||
package.add("EntityVariableExists", &Perl_Mob_EntityVariableExists);
|
||||
package.add("FaceTarget", (void(*)(Mob*))&Perl_Mob_FaceTarget);
|
||||
package.add("FaceTarget", (void(*)(Mob*, Mob*))&Perl_Mob_FaceTarget);
|
||||
package.add("FindBuff", &Perl_Mob_FindBuff);
|
||||
package.add("FindBuff", (bool(*)(Mob*, uint16))&Perl_Mob_FindBuff);
|
||||
package.add("FindBuff", (bool(*)(Mob*, uint16, uint16))&Perl_Mob_FindBuff);
|
||||
package.add("FindBuffBySlot", &Perl_Mob_FindBuffBySlot);
|
||||
package.add("FindGroundZ", (float(*)(Mob*, float, float))&Perl_Mob_FindGroundZ);
|
||||
package.add("FindGroundZ", (float(*)(Mob*, float, float, float))&Perl_Mob_FindGroundZ);
|
||||
|
||||
+51
-46
@@ -20,6 +20,8 @@
|
||||
#include "../common/events/player_event_logs.h"
|
||||
#include "../common/repositories/raid_details_repository.h"
|
||||
#include "../common/repositories/raid_members_repository.h"
|
||||
#include "../common/raid.h"
|
||||
|
||||
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
@@ -1547,21 +1549,22 @@ void Raid::SendRaidGroupRemove(const char *who, uint32 gid)
|
||||
|
||||
void Raid::SendRaidMOTD(Client *c)
|
||||
{
|
||||
if (!c || motd.empty()) {
|
||||
if (!c || motd.empty() || c->IsBot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity_list.GetBotByBotName(c->GetName())) {
|
||||
return;
|
||||
}
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidMOTD_Struct));
|
||||
auto data = (RaidMOTD_Struct*)outapp->pBuffer;
|
||||
|
||||
size_t size = motd.size() + 1;
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidMOTD_Struct) + size);
|
||||
auto rmotd = (RaidMOTD_Struct *)outapp->pBuffer;
|
||||
rmotd->general.action = raidSetMotd;
|
||||
strn0cpy(rmotd->general.player_name, c->GetName(), 64);
|
||||
strn0cpy(rmotd->motd, motd.c_str(), size);
|
||||
c->FastQueuePacket(&outapp);
|
||||
data->general.action = raidSetMotd;
|
||||
data->general.parameter = 0;
|
||||
data->general.unknown1 = 0;
|
||||
strn0cpy(data->general.leader_name, c->GetName(), sizeof(c->GetName()));
|
||||
strn0cpy(data->general.player_name, GetLeaderName().c_str(), 64);
|
||||
strn0cpy(data->motd, motd.c_str(), sizeof(data->motd));
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Raid::SendRaidMOTD()
|
||||
@@ -1587,11 +1590,10 @@ void Raid::SendRaidMOTDToWorld()
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = motd.size() + 1;
|
||||
auto pack = new ServerPacket(ServerOP_RaidMOTD, sizeof(ServerRaidMOTD_Struct) + size);
|
||||
auto pack = new ServerPacket(ServerOP_RaidMOTD, sizeof(ServerRaidMOTD_Struct));
|
||||
auto smotd = (ServerRaidMOTD_Struct *)pack->pBuffer;
|
||||
smotd->rid = GetID();
|
||||
strn0cpy(smotd->motd, motd.c_str(), size);
|
||||
strn0cpy(smotd->motd, motd.c_str(), sizeof(smotd->motd));
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
@@ -1705,33 +1707,31 @@ bool Raid::LearnMembers()
|
||||
{
|
||||
memset(members, 0, (sizeof(RaidMember) * MAX_RAID_MEMBERS));
|
||||
|
||||
const auto query = fmt::format(
|
||||
"SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter, is_marker, is_assister, bot_id, note "
|
||||
"FROM raid_members WHERE raidid = {} ORDER BY groupid",
|
||||
GetID()
|
||||
auto raid_members = RaidMembersRepository::GetWhere(
|
||||
content_db,
|
||||
fmt::format(
|
||||
"raidid = {}",
|
||||
GetID()
|
||||
)
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!results.RowCount()) {
|
||||
if (raid_members.empty()) {
|
||||
disbandCheck = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (auto row: results) {
|
||||
if (!row[0]) {
|
||||
for (const auto &e: raid_members) {
|
||||
if (e.name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
members[i].member = nullptr;
|
||||
strn0cpy(members[i].member_name, row[0], sizeof(members[i].member_name));
|
||||
strn0cpy(members[i].note, row[10], sizeof(members[i].note));
|
||||
uint32 group_id = Strings::ToUnsignedInt(row[1]);
|
||||
strn0cpy(members[i].member_name, e.name.c_str(), sizeof(members[i].member_name));
|
||||
uint32 group_id = e.groupid;
|
||||
if (!e.note.empty()) {
|
||||
members[i].note = e.note;
|
||||
}
|
||||
|
||||
if (group_id >= MAX_RAID_GROUPS) {
|
||||
members[i].group_number = RAID_GROUPLESS;
|
||||
@@ -1740,14 +1740,14 @@ bool Raid::LearnMembers()
|
||||
members[i].group_number = group_id;
|
||||
}
|
||||
|
||||
members[i]._class = Strings::ToUnsignedInt(row[2]);
|
||||
members[i].level = Strings::ToUnsignedInt(row[3]);
|
||||
members[i].is_group_leader = Strings::ToBool(row[4]);
|
||||
members[i].is_raid_leader = Strings::ToBool(row[5]);
|
||||
members[i].is_looter = Strings::ToBool(row[6]);
|
||||
members[i].main_marker = Strings::ToUnsignedInt(row[7]);
|
||||
members[i].main_assister = Strings::ToUnsignedInt(row[8]);
|
||||
members[i].is_bot = Strings::ToBool(row[9]) > 0;
|
||||
members[i]._class = e._class;
|
||||
members[i].level = e.level;
|
||||
members[i].is_group_leader = e.isgroupleader;
|
||||
members[i].is_raid_leader = e.israidleader;
|
||||
members[i].is_looter = e.islooter;
|
||||
members[i].main_marker = e.is_marker;
|
||||
members[i].main_assister = e.is_assister;
|
||||
members[i].is_bot = e.bot_id > 0;
|
||||
++i;
|
||||
}
|
||||
return true;
|
||||
@@ -2275,7 +2275,7 @@ std::vector<RaidMember> Raid::GetMembersWithNotes()
|
||||
{
|
||||
std::vector<RaidMember> raid_members;
|
||||
for (const auto& m : members) {
|
||||
if (strlen(m.note) != 0) {
|
||||
if (!m.note.empty()) {
|
||||
raid_members.emplace_back(m);
|
||||
}
|
||||
}
|
||||
@@ -2288,12 +2288,17 @@ void Raid::SendRaidNotes()
|
||||
VerifyRaid();
|
||||
|
||||
for (const auto& c : GetMembersWithNotes()) {
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
auto note = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
note->action = raidSetNote;
|
||||
strn0cpy(note->leader_name, c.member_name, 64);
|
||||
strn0cpy(note->player_name, GetLeaderName().c_str(), 64);
|
||||
strn0cpy(note->note, c.note, 64);
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidNote_Struct));
|
||||
auto data = (RaidNote_Struct*)outapp->pBuffer;
|
||||
|
||||
data->general.action = raidSetNote;
|
||||
data->general.parameter = 0;
|
||||
data->general.unknown1 = 0;
|
||||
strn0cpy(data->general.leader_name, c.member_name, sizeof(c.member_name));
|
||||
strn0cpy(data->general.player_name, GetLeaderName().c_str(), GetLeaderName().length());
|
||||
strn0cpy(data->note, c.note.c_str(), sizeof(data->note));
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -2552,7 +2557,7 @@ void Raid::UpdateXTargetType(XTargetType Type, Mob *m, const char *name)
|
||||
}
|
||||
|
||||
if (name) {
|
||||
strncpy(rm.member->XTargets[i].Name, name, 64);
|
||||
strn0cpy(rm.member->XTargets[i].Name, name, 64);
|
||||
}
|
||||
|
||||
rm.member->SendXTargetPacket(i, m);
|
||||
|
||||
+1
-50
@@ -27,55 +27,6 @@ class Client;
|
||||
class EQApplicationPacket;
|
||||
class Mob;
|
||||
|
||||
enum { //raid packet types:
|
||||
raidAdd = 0,
|
||||
raidRemove2 = 1, //parameter=0
|
||||
raidMemberNameChange = 2,
|
||||
raidRemove1 = 3, //parameter=0xFFFFFFFF
|
||||
raidNoLongerLeader = 4,
|
||||
raidDisband = 5,
|
||||
raidMembers = 6, //len 395+, details + members list
|
||||
raidNoAssignLeadership = 7,
|
||||
raidCreate = 8, //len 72
|
||||
raidUnknown = 9, // unused?
|
||||
raidNoRaid = 10, //parameter=0
|
||||
raidChangeLootType = 11,
|
||||
raidStringID = 12,
|
||||
raidChangeGroupLeader = 13, //136 raid leader, new group leader, group_id?
|
||||
raidSetLeaderAbilities = 14, //472
|
||||
raidSetLeaderData = 15, // 14,15 SoE names, not sure on difference, 14 packet has 0x100 bytes 15 0x214 in addition to raid general
|
||||
raidChangeGroup = 16, //?? len 136 old leader, new leader, 0 (preceeded with a remove2)
|
||||
raidLock = 17, //len 136 leader?, leader, 0
|
||||
raidUnlock = 18, //len 136 leader?, leader, 0
|
||||
raidRedStringID = 19,
|
||||
raidSetLeader = 20, //len 388, contains 'details' struct without members; also used for "invite to raid"
|
||||
raidMakeLeader = 30,
|
||||
raidSetMotd = 35,
|
||||
raidSetNote = 36,
|
||||
};
|
||||
|
||||
|
||||
enum { //raid command types
|
||||
RaidCommandInviteIntoExisting = 0, //in use
|
||||
RaidCommandAcceptInvite = 1, //in use
|
||||
RaidCommandInvite = 3, //in use
|
||||
RaidCommandDisband = 5, //in use
|
||||
RaidCommandMoveGroup = 6, //in use
|
||||
RaidCommandRemoveGroupLeader = 7,
|
||||
RaidCommandRaidLock = 8, //in use
|
||||
RaidCommandRaidUnlock = 9, //in use
|
||||
RaidCommandLootType = 20, //in use
|
||||
RaidCommandAddLooter = 21, //in use
|
||||
RaidCommandRemoveLooter = 22, //in use
|
||||
RaidCommandMakeLeader = 30,
|
||||
RaidCommandInviteFail = 31, //already in raid, waiting on invite from other raid, etc
|
||||
RaidCommandLootType2 = 32, //in use
|
||||
RaidCommandAddLooter2 = 33, //in use
|
||||
RaidCommandRemoveLooter2 = 34, //in use
|
||||
RaidCommandSetMotd = 35,
|
||||
RaidCommandSetNote = 36,
|
||||
};
|
||||
|
||||
enum {
|
||||
FindNextMarkerSlot = 1,
|
||||
FindNextAssisterSlot = 2,
|
||||
@@ -129,7 +80,7 @@ struct RaidMember{
|
||||
uint32 group_number;
|
||||
uint8 _class;
|
||||
uint8 level;
|
||||
char note[64];
|
||||
std::string note;
|
||||
bool is_group_leader;
|
||||
bool is_raid_leader;
|
||||
bool is_looter;
|
||||
|
||||
+182
-109
@@ -281,41 +281,54 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int32 bas
|
||||
// We should probably refactor this to take the struct not the packet
|
||||
void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
||||
{
|
||||
if (!GetTarget())
|
||||
if (!GetTarget()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure were actually able to use such an attack. (Bards can throw while casting. ~Kayen confirmed on live 1/22)
|
||||
if ((spellend_timer.Enabled() && GetClass() != BARD)|| IsFeared() || IsStunned() || IsMezzed() || DivineAura() || dead)
|
||||
if (
|
||||
(spellend_timer.Enabled() && GetClass() != BARD) ||
|
||||
IsFeared() ||
|
||||
IsStunned() ||
|
||||
IsMezzed() ||
|
||||
DivineAura() ||
|
||||
dead
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
pTimerType timer = pTimerCombatAbility;
|
||||
// RoF2+ Tiger Claw is unlinked from other monk skills, if they ever do that for other classes there will need
|
||||
// to be more checks here
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::RoF2 && ca_atk->m_skill == EQ::skills::SkillTigerClaw)
|
||||
if (ClientVersion() >= EQ::versions::ClientVersion::RoF2 && ca_atk->m_skill == EQ::skills::SkillTigerClaw) {
|
||||
timer = pTimerCombatAbility2;
|
||||
}
|
||||
|
||||
bool CanBypassSkillCheck = false;
|
||||
bool bypass_skill_check = false;
|
||||
|
||||
if (ca_atk->m_skill == EQ::skills::SkillBash) { // SLAM - Bash without a shield equipped
|
||||
switch (GetRace())
|
||||
{
|
||||
case OGRE:
|
||||
case TROLL:
|
||||
case BARBARIAN:
|
||||
CanBypassSkillCheck = true;
|
||||
default:
|
||||
break;
|
||||
switch (GetRace()) {
|
||||
case OGRE:
|
||||
case TROLL:
|
||||
case BARBARIAN:
|
||||
bypass_skill_check = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if actually have skill */
|
||||
if (!MaxSkill(static_cast<EQ::skills::SkillType>(ca_atk->m_skill)) && !CanBypassSkillCheck)
|
||||
// Check to see if actually have skill
|
||||
if (!MaxSkill(static_cast<EQ::skills::SkillType>(ca_atk->m_skill)) && !bypass_skill_check) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetTarget()->GetID() != ca_atk->m_target)
|
||||
return; // invalid packet.
|
||||
|
||||
if (!IsAttackAllowed(GetTarget()))
|
||||
if (GetTarget()->GetID() != ca_atk->m_target) { // invalid packet.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsAttackAllowed(GetTarget())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// These two are not subject to the combat ability timer, as they
|
||||
// allready do their checking in conjunction with the attack timer
|
||||
@@ -324,146 +337,194 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
||||
if (ca_atk->m_skill == EQ::skills::SkillThrowing) {
|
||||
SetAttackTimer();
|
||||
ThrowingAttack(GetTarget());
|
||||
if (CheckDoubleRangedAttack())
|
||||
|
||||
if (CheckDoubleRangedAttack()) {
|
||||
ThrowingAttack(GetTarget(), true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ranged attack (archery)
|
||||
if (ca_atk->m_skill == EQ::skills::SkillArchery) {
|
||||
SetAttackTimer();
|
||||
RangedAttack(GetTarget());
|
||||
if (CheckDoubleRangedAttack())
|
||||
|
||||
if (CheckDoubleRangedAttack()) {
|
||||
RangedAttack(GetTarget(), true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// could we return here? Im not sure is m_atk 11 is used for real specials
|
||||
}
|
||||
|
||||
// check range for all these abilities, they are all close combat stuff
|
||||
if (!CombatRange(GetTarget()))
|
||||
if (!CombatRange(GetTarget())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!p_timers.Expired(&database, timer, false)) {
|
||||
Message(Chat::Red, "Ability recovery time not yet met.");
|
||||
return;
|
||||
}
|
||||
|
||||
int ReuseTime = 0;
|
||||
int ClientHaste = GetHaste();
|
||||
int HasteMod = 0;
|
||||
int reuse_time = 0;
|
||||
int haste = GetHaste();
|
||||
int haste_modifier = 0;
|
||||
|
||||
if (ClientHaste >= 0)
|
||||
HasteMod = (10000 / (100 + ClientHaste)); //+100% haste = 2x as many attacks
|
||||
else
|
||||
HasteMod = (100 - ClientHaste); //-100% haste = 1/2 as many attacks
|
||||
if (haste >= 0) {
|
||||
haste_modifier = (10000 / (100 + haste)); //+100% haste = 2x as many attacks
|
||||
} else {
|
||||
haste_modifier = (100 - haste); //-100% haste = 1/2 as many attacks
|
||||
}
|
||||
|
||||
int64 dmg = 0;
|
||||
int64 damage = 0;
|
||||
int16 skill_reduction = GetSkillReuseTime(ca_atk->m_skill);
|
||||
|
||||
int32 skill_reduction = GetSkillReuseTime(ca_atk->m_skill);
|
||||
|
||||
// not sure what the '100' indicates..if ->m_atk is not used as 'slot' reference, then change SlotRange above back to '11'
|
||||
if (ca_atk->m_atk == 100 &&
|
||||
ca_atk->m_skill == EQ::skills::SkillBash) { // SLAM - Bash without a shield equipped
|
||||
// not sure what the '100' indicates, if ->m_atk is not used as 'slot' reference, then change SlotRange above back to '11'
|
||||
if (
|
||||
ca_atk->m_atk == 100 &&
|
||||
ca_atk->m_skill == EQ::skills::SkillBash
|
||||
) { // SLAM - Bash without a shield equipped
|
||||
if (GetTarget() != this) {
|
||||
|
||||
CheckIncreaseSkill(EQ::skills::SkillBash, GetTarget(), 10);
|
||||
DoAnim(animTailRake, 0, false);
|
||||
|
||||
int32 ht = 0;
|
||||
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotSecondary)) <= 0 &&
|
||||
GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotShoulders)) <= 0)
|
||||
dmg = -5;
|
||||
else
|
||||
ht = dmg = GetBaseSkillDamage(EQ::skills::SkillBash, GetTarget());
|
||||
int hate_override = 0;
|
||||
|
||||
ReuseTime = BashReuseTime - 1 - skill_reduction;
|
||||
ReuseTime = (ReuseTime * HasteMod) / 100;
|
||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillBash, dmg, 0, ht, ReuseTime);
|
||||
if (ReuseTime > 0)
|
||||
p_timers.Start(timer, ReuseTime);
|
||||
if (
|
||||
GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotSecondary)) <= 0 &&
|
||||
GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotShoulders)) <= 0
|
||||
) {
|
||||
damage = -5;
|
||||
} else {
|
||||
hate_override = damage = GetBaseSkillDamage(EQ::skills::SkillBash, GetTarget());
|
||||
}
|
||||
|
||||
reuse_time = BashReuseTime - 1 - skill_reduction;
|
||||
reuse_time = (reuse_time * haste_modifier) / 100;
|
||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillBash, damage, 0, hate_override, reuse_time);
|
||||
|
||||
if (reuse_time) {
|
||||
p_timers.Start(timer, reuse_time);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ca_atk->m_atk == 100 && ca_atk->m_skill == EQ::skills::SkillFrenzy) {
|
||||
int attack_rounds = 1;
|
||||
int max_dmg = GetBaseSkillDamage(EQ::skills::SkillFrenzy, GetTarget());
|
||||
|
||||
CheckIncreaseSkill(EQ::skills::SkillFrenzy, GetTarget(), 10);
|
||||
int AtkRounds = 1;
|
||||
int32 max_dmg = GetBaseSkillDamage(EQ::skills::SkillFrenzy, GetTarget());
|
||||
DoAnim(anim1HWeapon, 0, false);
|
||||
|
||||
if (GetClass() == BERSERKER) {
|
||||
int chance = GetLevel() * 2 + GetSkill(EQ::skills::SkillFrenzy);
|
||||
if (zone->random.Roll0(450) < chance)
|
||||
AtkRounds++;
|
||||
if (zone->random.Roll0(450) < chance)
|
||||
AtkRounds++;
|
||||
|
||||
if (zone->random.Roll0(450) < chance) {
|
||||
attack_rounds++;
|
||||
}
|
||||
|
||||
if (zone->random.Roll0(450) < chance) {
|
||||
attack_rounds++;
|
||||
}
|
||||
}
|
||||
|
||||
ReuseTime = FrenzyReuseTime - 1 - skill_reduction;
|
||||
ReuseTime = (ReuseTime * HasteMod) / 100;
|
||||
reuse_time = FrenzyReuseTime - 1 - skill_reduction;
|
||||
reuse_time = (reuse_time * haste_modifier) / 100;
|
||||
|
||||
auto primary_in_use = GetInv().GetItem(EQ::invslot::slotPrimary);
|
||||
const EQ::ItemInstance* primary_in_use = GetInv().GetItem(EQ::invslot::slotPrimary);
|
||||
if (primary_in_use && GetWeaponDamage(GetTarget(), primary_in_use) <= 0) {
|
||||
max_dmg = DMG_INVULNERABLE;
|
||||
}
|
||||
|
||||
while (AtkRounds > 0) {
|
||||
if (GetTarget())
|
||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillFrenzy, max_dmg, 0, max_dmg, ReuseTime);
|
||||
AtkRounds--;
|
||||
while (attack_rounds > 0) {
|
||||
if (GetTarget()) {
|
||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillFrenzy, max_dmg, 0, max_dmg, reuse_time);
|
||||
}
|
||||
|
||||
attack_rounds--;
|
||||
}
|
||||
|
||||
if (reuse_time) {
|
||||
p_timers.Start(timer, reuse_time);
|
||||
}
|
||||
|
||||
if (ReuseTime > 0)
|
||||
p_timers.Start(timer, ReuseTime);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (GetClass()) {
|
||||
case BERSERKER:
|
||||
case WARRIOR:
|
||||
case RANGER:
|
||||
case BEASTLORD:
|
||||
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQ::skills::SkillKick)
|
||||
break;
|
||||
const uint8 class_id = GetClass();
|
||||
|
||||
// Warrior, Ranger, Monk, Beastlord, and Berserker can kick always
|
||||
const uint32 allowed_kick_classes = RuleI(Combat, ExtraAllowedKickClassesBitmask);
|
||||
|
||||
const bool can_use_kick = (
|
||||
class_id == WARRIOR ||
|
||||
class_id == RANGER ||
|
||||
class_id == MONK ||
|
||||
class_id == BEASTLORD ||
|
||||
class_id == BERSERKER ||
|
||||
allowed_kick_classes & GetPlayerClassBit(class_id)
|
||||
);
|
||||
|
||||
bool found_skill = false;
|
||||
|
||||
if (
|
||||
ca_atk->m_atk == 100 &&
|
||||
ca_atk->m_skill == EQ::skills::SkillKick &&
|
||||
can_use_kick
|
||||
) {
|
||||
if (GetTarget() != this) {
|
||||
CheckIncreaseSkill(EQ::skills::SkillKick, GetTarget(), 10);
|
||||
DoAnim(animKick, 0, false);
|
||||
|
||||
int32 ht = 0;
|
||||
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotFeet)) <= 0)
|
||||
dmg = -5;
|
||||
else
|
||||
ht = dmg = GetBaseSkillDamage(EQ::skills::SkillKick, GetTarget());
|
||||
int hate_override = 0;
|
||||
if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQ::invslot::slotFeet)) <= 0) {
|
||||
damage = -5;
|
||||
} else {
|
||||
hate_override = damage = GetBaseSkillDamage(EQ::skills::SkillKick, GetTarget());
|
||||
}
|
||||
|
||||
ReuseTime = KickReuseTime - 1 - skill_reduction;
|
||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillKick, dmg, 0, ht, ReuseTime);
|
||||
reuse_time = KickReuseTime - 1 - skill_reduction;
|
||||
DoSpecialAttackDamage(GetTarget(), EQ::skills::SkillKick, damage, 0, hate_override, reuse_time);
|
||||
|
||||
found_skill = true;
|
||||
}
|
||||
break;
|
||||
case MONK: {
|
||||
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
||||
}
|
||||
|
||||
if (class_id == MONK) {
|
||||
reuse_time = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
||||
|
||||
// Live AA - Technique of Master Wu
|
||||
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||
int wu_chance = (
|
||||
itembonuses.DoubleSpecialAttack +
|
||||
spellbonuses.DoubleSpecialAttack +
|
||||
aabonuses.DoubleSpecialAttack
|
||||
);
|
||||
|
||||
if (wuchance) {
|
||||
const int MonkSPA[5] = {
|
||||
if (wu_chance) {
|
||||
const int monk_special_attacks[5] = {
|
||||
EQ::skills::SkillFlyingKick,
|
||||
EQ::skills::SkillDragonPunch,
|
||||
EQ::skills::SkillEagleStrike,
|
||||
EQ::skills::SkillTigerClaw,
|
||||
EQ::skills::SkillRoundKick
|
||||
};
|
||||
|
||||
int extra = 0;
|
||||
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
||||
while (wuchance > 0) {
|
||||
if (zone->random.Roll(wuchance)) {
|
||||
while (wu_chance > 0) {
|
||||
if (zone->random.Roll(wu_chance)) {
|
||||
++extra;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
wuchance /= 4;
|
||||
|
||||
wu_chance /= 4;
|
||||
}
|
||||
|
||||
if (extra) {
|
||||
SendColoredText(
|
||||
400,
|
||||
@@ -474,37 +535,47 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
||||
)
|
||||
);
|
||||
}
|
||||
auto classic = RuleB(Combat, ClassicMasterWu);
|
||||
|
||||
const bool is_classic_master_wu = RuleB(Combat, ClassicMasterWu);
|
||||
while (extra) {
|
||||
MonkSpecialAttack(GetTarget(), (classic ? MonkSPA[zone->random.Int(0, 4)] : ca_atk->m_skill));
|
||||
MonkSpecialAttack(
|
||||
GetTarget(),
|
||||
(is_classic_master_wu ? monk_special_attacks[zone->random.Int(0, 4)] : ca_atk->m_skill)
|
||||
);
|
||||
--extra;
|
||||
}
|
||||
}
|
||||
|
||||
if (ReuseTime < 100) {
|
||||
if (reuse_time < 100) {
|
||||
// hackish... but we return a huge reuse time if this is an
|
||||
// invalid skill, otherwise, we can safely assume it is a
|
||||
// valid monk skill and just cast it to a SkillType
|
||||
CheckIncreaseSkill((EQ::skills::SkillType)ca_atk->m_skill, GetTarget(), 10);
|
||||
CheckIncreaseSkill((EQ::skills::SkillType) ca_atk->m_skill, GetTarget(), 10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ROGUE: {
|
||||
if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQ::skills::SkillBackstab)
|
||||
break;
|
||||
ReuseTime = BackstabReuseTime-1 - skill_reduction;
|
||||
TryBackstab(GetTarget(), ReuseTime);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
//they have no abilities... wtf? make em wait a bit
|
||||
ReuseTime = 9 - skill_reduction;
|
||||
break;
|
||||
|
||||
found_skill = true;
|
||||
}
|
||||
|
||||
ReuseTime = (ReuseTime * HasteMod) / 100;
|
||||
if (ReuseTime > 0) {
|
||||
p_timers.Start(timer, ReuseTime);
|
||||
if (
|
||||
ca_atk->m_atk == 100 &&
|
||||
ca_atk->m_skill == EQ::skills::SkillBackstab &&
|
||||
class_id == ROGUE
|
||||
) {
|
||||
reuse_time = BackstabReuseTime - 1 - skill_reduction;
|
||||
TryBackstab(GetTarget(), reuse_time);
|
||||
found_skill = true;
|
||||
}
|
||||
|
||||
if (!found_skill) {
|
||||
reuse_time = 9 - skill_reduction;
|
||||
}
|
||||
|
||||
reuse_time = (reuse_time * haste_modifier) / 100;
|
||||
|
||||
reuse_time = EQ::Clamp(reuse_time, 0, reuse_time);
|
||||
|
||||
if (reuse_time) {
|
||||
p_timers.Start(timer, reuse_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2230,7 +2301,8 @@ int Mob::TryHeadShot(Mob *defender, EQ::skills::SkillType skillInUse)
|
||||
!defender->IsClient() &&
|
||||
skillInUse == EQ::skills::SkillArchery &&
|
||||
GetTarget() == defender &&
|
||||
(defender->GetBodyType() == BT_Humanoid || !RuleB(Combat, HeadshotOnlyHumanoids))
|
||||
(defender->GetBodyType() == BT_Humanoid || !RuleB(Combat, HeadshotOnlyHumanoids)) &&
|
||||
!defender->GetSpecialAbility(IMMUNE_HEADSHOT)
|
||||
) {
|
||||
uint32 HeadShot_Dmg = aabonuses.HeadShot[SBIndex::FINISHING_EFFECT_DMG] + spellbonuses.HeadShot[SBIndex::FINISHING_EFFECT_DMG] + itembonuses.HeadShot[SBIndex::FINISHING_EFFECT_DMG];
|
||||
uint8 HeadShot_Level = 0; // Get Highest Headshot Level
|
||||
@@ -2266,7 +2338,8 @@ int Mob::TryAssassinate(Mob *defender, EQ::skills::SkillType skillInUse)
|
||||
!defender->IsClient() &&
|
||||
GetLevel() >= 60 &&
|
||||
(skillInUse == EQ::skills::SkillBackstab || skillInUse == EQ::skills::SkillThrowing) &&
|
||||
(defender->GetBodyType() == BT_Humanoid || !RuleB(Combat, AssassinateOnlyHumanoids))
|
||||
(defender->GetBodyType() == BT_Humanoid || !RuleB(Combat, AssassinateOnlyHumanoids)) &&
|
||||
!defender->GetSpecialAbility(IMMUNE_ASSASSINATE)
|
||||
) {
|
||||
int chance = GetDEX();
|
||||
if (skillInUse == EQ::skills::SkillBackstab) {
|
||||
|
||||
@@ -2266,7 +2266,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
if((spell_id != 6882) && (spell_id != 6884)) // Chaotic Jester/Steadfast Servant
|
||||
{
|
||||
char pet_name[64];
|
||||
snprintf(pet_name, sizeof(pet_name), "%s`s pet", caster->GetCleanName());
|
||||
snprintf(pet_name, sizeof(pet_name), "%s`s_pet", caster->GetCleanName());
|
||||
caster->TemporaryPets(spell_id, this, pet_name);
|
||||
}
|
||||
else
|
||||
@@ -2443,7 +2443,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
{
|
||||
if(caster && caster->IsClient()) {
|
||||
char pet_name[64];
|
||||
snprintf(pet_name, sizeof(pet_name), "%s`s doppelganger", caster->GetCleanName());
|
||||
snprintf(pet_name, sizeof(pet_name), "%s`s_doppelganger", caster->GetCleanName());
|
||||
int pet_count = spells[spell_id].base_value[i];
|
||||
int pet_duration = spells[spell_id].max_value[i];
|
||||
caster->CastToClient()->Doppelganger(spell_id, this, pet_name, pet_count, pet_duration);
|
||||
|
||||
+72
-32
@@ -238,13 +238,16 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
|
||||
if (IsClient()) {
|
||||
if (parse->PlayerHasQuestSub(EVENT_CAST_BEGIN)) {
|
||||
Mob* spell_target = entity_list.GetMobID(target_id);
|
||||
std::vector<std::any> args = { spell_target };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
GetCasterLevel(spell_id)
|
||||
GetCasterLevel(spell_id),
|
||||
target_id
|
||||
);
|
||||
if (parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), export_string, 0) != 0) {
|
||||
if (parse->EventPlayer(EVENT_CAST_BEGIN, CastToClient(), export_string, 0, &args) != 0) {
|
||||
if (IsDiscipline(spell_id)) {
|
||||
CastToClient()->SendDisciplineTimer(spells[spell_id].timer_id, 0);
|
||||
}
|
||||
@@ -256,23 +259,29 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
}
|
||||
} else if (IsNPC()) {
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_CAST_BEGIN)) {
|
||||
Mob* spell_target = entity_list.GetMobID(target_id);
|
||||
std::vector<std::any> args = { spell_target };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
GetCasterLevel(spell_id)
|
||||
GetCasterLevel(spell_id),
|
||||
target_id
|
||||
);
|
||||
parse->EventNPC(EVENT_CAST_BEGIN, CastToNPC(), nullptr, export_string, 0);
|
||||
parse->EventNPC(EVENT_CAST_BEGIN, CastToNPC(), nullptr, export_string, 0, &args);
|
||||
}
|
||||
} else if (IsBot()) {
|
||||
if (parse->BotHasQuestSub(EVENT_CAST_BEGIN)) {
|
||||
Mob* spell_target = entity_list.GetMobID(target_id);
|
||||
std::vector<std::any> args = { spell_target };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
GetCasterLevel(spell_id)
|
||||
GetCasterLevel(spell_id),
|
||||
target_id
|
||||
);
|
||||
parse->EventBot(EVENT_CAST_BEGIN, CastToBot(), nullptr, export_string, 0);
|
||||
parse->EventBot(EVENT_CAST_BEGIN, CastToBot(), nullptr, export_string, 0, &args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1648,24 +1657,41 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
// at this point the spell has successfully been cast
|
||||
//
|
||||
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
GetCasterLevel(spell_id)
|
||||
);
|
||||
|
||||
if (IsClient()) {
|
||||
if (parse->PlayerHasQuestSub(EVENT_CAST)) {
|
||||
parse->EventPlayer(EVENT_CAST, CastToClient(), export_string, 0);
|
||||
std::vector<std::any> args = { spell_target };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
GetCasterLevel(spell_id),
|
||||
target_id
|
||||
);
|
||||
parse->EventPlayer(EVENT_CAST, CastToClient(), export_string, 0, &args);
|
||||
}
|
||||
} else if (IsNPC()) {
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_CAST)) {
|
||||
parse->EventNPC(EVENT_CAST, CastToNPC(), nullptr, export_string, 0);
|
||||
std::vector<std::any> args = { spell_target };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
GetCasterLevel(spell_id),
|
||||
target_id
|
||||
);
|
||||
parse->EventNPC(EVENT_CAST, CastToNPC(), nullptr, export_string, 0, &args);
|
||||
}
|
||||
} else if (IsBot()) {
|
||||
if (parse->BotHasQuestSub(EVENT_CAST)) {
|
||||
parse->EventBot(EVENT_CAST, CastToBot(), nullptr, export_string, 0);
|
||||
std::vector<std::any> args = { spell_target };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
GetCasterLevel(spell_id),
|
||||
target_id
|
||||
);
|
||||
parse->EventBot(EVENT_CAST, CastToBot(), nullptr, export_string, 0, &args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3664,10 +3690,14 @@ bool Mob::SpellOnTarget(
|
||||
}
|
||||
|
||||
// select target
|
||||
uint16 target_id = 0;
|
||||
|
||||
if (IsEffectInSpell(spell_id, SE_BindSight)) {
|
||||
action->target = GetID();
|
||||
target_id = GetID();
|
||||
} else {
|
||||
action->target = spelltar->GetID();
|
||||
target_id = spelltar->GetID();
|
||||
}
|
||||
|
||||
action->spell_level = action->level = caster_level; // caster level, for animation only
|
||||
@@ -3700,33 +3730,39 @@ bool Mob::SpellOnTarget(
|
||||
|
||||
if (spelltar->IsNPC()) {
|
||||
if (parse->HasQuestSub(spelltar->GetNPCTypeID(), EVENT_CAST_ON)) {
|
||||
std::vector<std::any> args = { spelltar };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
caster_level
|
||||
caster_level,
|
||||
target_id
|
||||
);
|
||||
parse->EventNPC(EVENT_CAST_ON, spelltar->CastToNPC(), this, export_string, 0);
|
||||
parse->EventNPC(EVENT_CAST_ON, spelltar->CastToNPC(), this, export_string, 0, &args);
|
||||
}
|
||||
} else if (spelltar->IsClient()) {
|
||||
if (parse->PlayerHasQuestSub(EVENT_CAST_ON)) {
|
||||
std::vector<std::any> args = { spelltar };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
caster_level
|
||||
caster_level,
|
||||
target_id
|
||||
);
|
||||
parse->EventPlayer(EVENT_CAST_ON, spelltar->CastToClient(), export_string, 0);
|
||||
parse->EventPlayer(EVENT_CAST_ON, spelltar->CastToClient(), export_string, 0, &args);
|
||||
}
|
||||
} else if (spelltar->IsBot()) {
|
||||
if (parse->BotHasQuestSub(EVENT_CAST_ON)) {
|
||||
std::vector<std::any> args = { spelltar };
|
||||
const auto& export_string = fmt::format(
|
||||
"{} {} {}",
|
||||
"{} {} {} {}",
|
||||
spell_id,
|
||||
GetID(),
|
||||
caster_level
|
||||
caster_level,
|
||||
target_id
|
||||
);
|
||||
parse->EventBot(EVENT_CAST_ON, spelltar->CastToBot(), this, export_string, 0);
|
||||
parse->EventBot(EVENT_CAST_ON, spelltar->CastToBot(), this, export_string, 0, &args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4411,14 +4447,18 @@ std::vector<uint16> Mob::GetBuffSpellIDs()
|
||||
return l;
|
||||
}
|
||||
|
||||
bool Mob::FindBuff(uint16 spell_id)
|
||||
bool Mob::FindBuff(uint16 spell_id, uint16 caster_id)
|
||||
{
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
const int buff_count = GetMaxTotalSlots();
|
||||
for (int buff_slot = 0; buff_slot < buff_count; buff_slot++) {
|
||||
auto current_spell_id = buffs[buff_slot].spellid;
|
||||
const uint16 current_spell_id = buffs[buff_slot].spellid;
|
||||
if (
|
||||
IsValidSpell(current_spell_id) &&
|
||||
current_spell_id == spell_id
|
||||
current_spell_id == spell_id &&
|
||||
(
|
||||
!caster_id ||
|
||||
buffs[buff_slot].casterid == caster_id
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+3
-3
@@ -157,7 +157,7 @@ void NPC::ResumeWandering()
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError("NPC not paused - can't resume wandering: [{}]", (unsigned long)GetNPCTypeID());
|
||||
LogPathing("NPC not paused - can't resume wandering: [{}]", (unsigned long)GetNPCTypeID());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ void NPC::ResumeWandering()
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError("NPC not on grid - can't resume wandering: [{}]", (unsigned long)GetNPCTypeID());
|
||||
LogPathing("NPC not on grid - can't resume wandering: [{}]", (unsigned long)GetNPCTypeID());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -195,7 +195,7 @@ void NPC::PauseWandering(int pausetime)
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogError("NPC not on grid - can't pause wandering: [{}]", (unsigned long)GetNPCTypeID());
|
||||
LogPathing("NPC not on grid - can't pause wandering: [{}]", (unsigned long)GetNPCTypeID());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user