mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 09:06:46 +00:00
Merge branch 'master' into nats
# Conflicts: # world/client.cpp # zone/attack.cpp # zone/map.cpp # zone/map.h # zone/spells.cpp
This commit is contained in:
@@ -28,6 +28,7 @@ SET(zone_sources
|
||||
encounter.cpp
|
||||
entity.cpp
|
||||
exp.cpp
|
||||
fastmath.cpp
|
||||
fearpath.cpp
|
||||
forage.cpp
|
||||
groups.cpp
|
||||
@@ -159,6 +160,7 @@ SET(zone_headers
|
||||
entity.h
|
||||
errmsg.h
|
||||
event_codes.h
|
||||
fastmath.h
|
||||
forage.h
|
||||
global_loot_manager.h
|
||||
groups.h
|
||||
|
||||
+22
-11
@@ -33,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "zone.h"
|
||||
#include "lua_parser.h"
|
||||
#include "nats_manager.h"
|
||||
#include "fastmath.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
@@ -44,6 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
extern QueryServ* QServ;
|
||||
extern WorldServer worldserver;
|
||||
extern FastMath g_Math;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define snprintf _snprintf
|
||||
@@ -3614,26 +3616,35 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
||||
a->special = 2;
|
||||
else
|
||||
a->special = 0;
|
||||
a->meleepush_xy = attacker ? attacker->GetHeading() : 0.0f;
|
||||
a->hit_heading = attacker ? attacker->GetHeading() : 0.0f;
|
||||
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
|
||||
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
|
||||
a->force = EQEmu::skills::GetSkillMeleePushForce(skill_used);
|
||||
if (IsNPC()) {
|
||||
if (attacker->IsNPC())
|
||||
a->force = 0.0f; // 2013 change that disabled NPC vs NPC push
|
||||
else
|
||||
a->force *= 0.10f; // force against NPCs is divided by 10 I guess? ex bash is 0.3, parsed 0.03 against an NPC
|
||||
}
|
||||
// update NPC stuff
|
||||
auto new_pos = glm::vec3(m_Position.x + (a->force * std::cos(a->meleepush_xy) + m_Delta.x),
|
||||
m_Position.y + (a->force * std::sin(a->meleepush_xy) + m_Delta.y), m_Position.z);
|
||||
if (zone->zonemap && zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable.
|
||||
if (IsNPC()) {
|
||||
// Is this adequate?
|
||||
if (a->force != 0.0f) {
|
||||
auto new_pos = glm::vec3(
|
||||
m_Position.x + (a->force * g_Math.FastSin(a->hit_heading) + m_Delta.x),
|
||||
m_Position.y + (a->force * g_Math.FastCos(a->hit_heading) + m_Delta.y), m_Position.z);
|
||||
if ((!IsNPC() || position_update_melee_push_timer.Check()) && zone->zonemap &&
|
||||
zone->zonemap->CheckLoS(
|
||||
glm::vec3(m_Position),
|
||||
new_pos)) { // If we have LoS on the new loc it should be reachable.
|
||||
if (IsNPC()) {
|
||||
// Is this adequate?
|
||||
|
||||
Teleport(new_pos);
|
||||
if (position_update_melee_push_timer.Check()) {
|
||||
Teleport(new_pos);
|
||||
SendPositionUpdate();
|
||||
}
|
||||
} else {
|
||||
a->force = 0.0f; // we couldn't move there, so lets not
|
||||
}
|
||||
}
|
||||
else {
|
||||
a->force = 0.0f; // we couldn't move there, so lets not
|
||||
}
|
||||
}
|
||||
|
||||
//Note: if players can become pets, they will not receive damage messages of their own
|
||||
|
||||
@@ -616,6 +616,7 @@ bool Aura::Process()
|
||||
it = spawned_for.erase(it);
|
||||
}
|
||||
}
|
||||
safe_delete(app);
|
||||
}
|
||||
// TODO: waypoints?
|
||||
|
||||
@@ -757,6 +758,8 @@ void Mob::MakeAura(uint16 spell_id)
|
||||
|
||||
auto npc = new Aura(npc_type, this, record);
|
||||
npc->SetAuraID(spell_id);
|
||||
if (trap)
|
||||
npc->TryMoveAlong(5.0f, 0.0f, false); // try to place 5 units in front
|
||||
entity_list.AddNPC(npc, false);
|
||||
|
||||
if (trap)
|
||||
|
||||
+18
-8
@@ -3053,7 +3053,7 @@ void Bot::Depop() {
|
||||
NPC::Depop(false);
|
||||
}
|
||||
|
||||
void Bot::Spawn(Client* botCharacterOwner) {
|
||||
bool Bot::Spawn(Client* botCharacterOwner) {
|
||||
if(GetBotID() > 0 && _botOwnerCharacterID > 0 && botCharacterOwner && botCharacterOwner->CharacterID() == _botOwnerCharacterID) {
|
||||
// Rename the bot name to make sure that Mob::GetName() matches Mob::GetCleanName() so we dont have a bot named "Jesuschrist001"
|
||||
strcpy(name, GetCleanName());
|
||||
@@ -3097,7 +3097,11 @@ void Bot::Spawn(Client* botCharacterOwner) {
|
||||
this->SendWearChange(materialFromSlot);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deletes the inventory record for the specified item from the database for this bot.
|
||||
@@ -3246,16 +3250,20 @@ void Bot::LoadAndSpawnAllZonedBots(Client* botOwner) {
|
||||
if(!ActiveBots.empty()) {
|
||||
for(std::list<uint32>::iterator itr = ActiveBots.begin(); itr != ActiveBots.end(); ++itr) {
|
||||
Bot* activeBot = Bot::LoadBot(*itr);
|
||||
if (!activeBot)
|
||||
continue;
|
||||
|
||||
if(activeBot) {
|
||||
activeBot->Spawn(botOwner);
|
||||
g->UpdatePlayer(activeBot);
|
||||
// follow the bot owner, not the group leader we just zoned with our owner.
|
||||
if(g->IsGroupMember(botOwner) && g->IsGroupMember(activeBot))
|
||||
activeBot->SetFollowID(botOwner->GetID());
|
||||
if (!activeBot->Spawn(botOwner)) {
|
||||
safe_delete(activeBot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(activeBot && !botOwner->HasGroup())
|
||||
g->UpdatePlayer(activeBot);
|
||||
// follow the bot owner, not the group leader we just zoned with our owner.
|
||||
if (g->IsGroupMember(botOwner) && g->IsGroupMember(activeBot))
|
||||
activeBot->SetFollowID(botOwner->GetID());
|
||||
|
||||
if(!botOwner->HasGroup())
|
||||
database.SetGroupID(activeBot->GetCleanName(), 0, activeBot->GetBotID());
|
||||
}
|
||||
}
|
||||
@@ -8886,6 +8894,8 @@ bool Bot::DyeArmor(int16 slot_id, uint32 rgb, bool all_flag, bool save_flag)
|
||||
|
||||
std::string Bot::CreateSayLink(Client* c, const char* message, const char* name)
|
||||
{
|
||||
// TODO: review
|
||||
|
||||
int saylink_size = strlen(message);
|
||||
char* escaped_string = new char[saylink_size * 2];
|
||||
|
||||
|
||||
+1
-1
@@ -275,7 +275,7 @@ public:
|
||||
static bool IsValidRaceClassCombo(uint16 r, uint8 c);
|
||||
bool IsValidName();
|
||||
static bool IsValidName(std::string& name);
|
||||
void Spawn(Client* botCharacterOwner);
|
||||
bool Spawn(Client* botCharacterOwner);
|
||||
virtual void SetLevel(uint8 in_level, bool command = false);
|
||||
virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
|
||||
virtual bool Process();
|
||||
|
||||
+21
-10
@@ -5049,7 +5049,11 @@ void bot_subcommand_bot_spawn(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
my_bot->Spawn(c);
|
||||
if (!my_bot->Spawn(c)) {
|
||||
c->Message(m_fail, "Failed to spawn bot '%s' (id: %i)", bot_name.c_str(), bot_id);
|
||||
safe_delete(my_bot);
|
||||
return;
|
||||
}
|
||||
|
||||
static const char* bot_spawn_message[16] = {
|
||||
"A solid weapon is my ally!", // WARRIOR / 'generic'
|
||||
@@ -5805,18 +5809,22 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
if (!leader_id) {
|
||||
c->Message(m_fail, "Can not locate bot-group leader id for '%s'", botgroup_name_arg.c_str());
|
||||
c->Message(m_fail, "Cannot locate bot-group leader id for '%s'", botgroup_name_arg.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto botgroup_leader = Bot::LoadBot(leader_id);
|
||||
if (!botgroup_leader) {
|
||||
c->Message(m_fail, "Could not spawn bot-group leader for '%s'", botgroup_name_arg.c_str());
|
||||
c->Message(m_fail, "Could not load bot-group leader for '%s'", botgroup_name_arg.c_str());
|
||||
safe_delete(botgroup_leader);
|
||||
return;
|
||||
}
|
||||
|
||||
botgroup_leader->Spawn(c);
|
||||
if (!botgroup_leader->Spawn(c)) {
|
||||
c->Message(m_fail, "Could not spawn bot-group leader %s for '%s'", botgroup_leader->GetName(), botgroup_name_arg.c_str());
|
||||
safe_delete(botgroup_leader);
|
||||
return;
|
||||
}
|
||||
|
||||
Group* group_inst = new Group(botgroup_leader);
|
||||
|
||||
@@ -5835,7 +5843,12 @@ void bot_subcommand_botgroup_load(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
botgroup_member->Spawn(c);
|
||||
if (!botgroup_member->Spawn(c)) {
|
||||
c->Message(m_fail, "Could not spawn bot '%s' (id: %i)", botgroup_member->GetName(), member_iter);
|
||||
safe_delete(botgroup_member);
|
||||
return;
|
||||
}
|
||||
|
||||
Bot::AddBotToGroup(botgroup_member, group_inst);
|
||||
}
|
||||
|
||||
@@ -7072,7 +7085,6 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep)
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
bool is2Hweapon = false;
|
||||
|
||||
std::string item_link;
|
||||
EQEmu::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
|
||||
@@ -7093,8 +7105,7 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
linker.SetItemInst(inst);
|
||||
item_link = linker.GenerateLink();
|
||||
c->Message(m_message, "Using %s in my %s (slot %i)", item_link.c_str(), GetBotEquipSlotName(i), (i == 22 ? EQEmu::inventory::slotPowerSource : i));
|
||||
c->Message(m_message, "Using %s in my %s (slot %i)", linker.GenerateLink().c_str(), GetBotEquipSlotName(i), (i == 22 ? EQEmu::inventory::slotPowerSource : i));
|
||||
|
||||
++inventory_count;
|
||||
}
|
||||
@@ -7237,8 +7248,8 @@ void bot_subcommand_inventory_window(Client *c, const Seperator *sep)
|
||||
|
||||
std::string window_text;
|
||||
//std::string item_link;
|
||||
//Client::TextLink linker;
|
||||
//linker.SetLinkType(linker.linkItemInst);
|
||||
//EQEmu::SayLinkEngine linker;
|
||||
//linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
|
||||
for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= (EQEmu::legacy::EQUIPMENT_END + 1); ++i) {
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
|
||||
@@ -273,7 +273,10 @@ bool BotDatabase::LoadBotID(const uint32 owner_id, const std::string& bot_name,
|
||||
if (!owner_id || bot_name.empty())
|
||||
return false;
|
||||
|
||||
query = StringFormat("SELECT `bot_id` FROM `bot_data` WHERE `name` = '%s' LIMIT 1", bot_name.c_str());
|
||||
query = StringFormat(
|
||||
"SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u' AND `name` = '%s' LIMIT 1",
|
||||
owner_id, bot_name.c_str()
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
+3
-2
@@ -254,7 +254,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
mercSlot = 0;
|
||||
InitializeMercInfo();
|
||||
SetMerc(0);
|
||||
|
||||
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true, false);
|
||||
logging_enabled = CLIENT_DEFAULT_LOGGING_ENABLED;
|
||||
|
||||
//for good measure:
|
||||
@@ -337,6 +337,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
m_pp.InnateSkills[i] = InnateDisabled;
|
||||
|
||||
temp_pvp = false;
|
||||
is_client_moving = false;
|
||||
|
||||
AI_Init();
|
||||
}
|
||||
@@ -7907,7 +7908,7 @@ void Client::GarbleMessage(char *message, uint8 variance)
|
||||
for (size_t i = 0; i < strlen(message); i++) {
|
||||
// Client expects hex values inside of a text link body
|
||||
if (message[i] == delimiter) {
|
||||
if (!(delimiter_count & 1)) { i += EQEmu::legacy::TEXT_LINK_BODY_LENGTH; }
|
||||
if (!(delimiter_count & 1)) { i += EQEmu::constants::SayLinkBodySize; }
|
||||
++delimiter_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
+145
-34
@@ -75,6 +75,7 @@ extern NatsManager nats;
|
||||
|
||||
typedef void (Client::*ClientPacketProc)(const EQApplicationPacket *app);
|
||||
|
||||
|
||||
//Use a map for connecting opcodes since it dosent get used a lot and is sparse
|
||||
std::map<uint32, ClientPacketProc> ConnectingOpcodes;
|
||||
//Use a static array for connected, for speed
|
||||
@@ -318,6 +319,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_PurchaseLeadershipAA] = &Client::Handle_OP_PurchaseLeadershipAA;
|
||||
ConnectedOpcodes[OP_PVPLeaderBoardDetailsRequest] = &Client::Handle_OP_PVPLeaderBoardDetailsRequest;
|
||||
ConnectedOpcodes[OP_PVPLeaderBoardRequest] = &Client::Handle_OP_PVPLeaderBoardRequest;
|
||||
ConnectedOpcodes[OP_QueryUCSServerStatus] = &Client::Handle_OP_QueryUCSServerStatus;
|
||||
ConnectedOpcodes[OP_RaidInvite] = &Client::Handle_OP_RaidCommand;
|
||||
ConnectedOpcodes[OP_RandomReq] = &Client::Handle_OP_RandomReq;
|
||||
ConnectedOpcodes[OP_ReadBook] = &Client::Handle_OP_ReadBook;
|
||||
@@ -794,7 +796,7 @@ void Client::CompleteConnect()
|
||||
}
|
||||
|
||||
if (zone)
|
||||
zone->weatherSend();
|
||||
zone->weatherSend(this);
|
||||
|
||||
TotalKarma = database.GetKarma(AccountID());
|
||||
SendDisciplineTimers();
|
||||
@@ -2866,41 +2868,60 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app)
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 ApplyPoisonSuccessResult = 0;
|
||||
ApplyPoison_Struct* ApplyPoisonData = (ApplyPoison_Struct*)app->pBuffer;
|
||||
const EQEmu::ItemInstance* PrimaryWeapon = GetInv().GetItem(EQEmu::inventory::slotPrimary);
|
||||
const EQEmu::ItemInstance* SecondaryWeapon = GetInv().GetItem(EQEmu::inventory::slotSecondary);
|
||||
const EQEmu::ItemInstance* PoisonItemInstance = GetInv()[ApplyPoisonData->inventorySlot];
|
||||
const EQEmu::ItemData* poison=PoisonItemInstance->GetItem();
|
||||
const EQEmu::ItemData* primary=nullptr;
|
||||
const EQEmu::ItemData* secondary=nullptr;
|
||||
bool IsPoison = PoisonItemInstance &&
|
||||
(poison->ItemType == EQEmu::item::ItemTypePoison);
|
||||
|
||||
bool IsPoison = PoisonItemInstance && (PoisonItemInstance->GetItem()->ItemType == EQEmu::item::ItemTypePoison);
|
||||
|
||||
if (!IsPoison)
|
||||
{
|
||||
Log(Logs::Detail, Logs::Spells, "Item used to cast spell effect from a poison item was missing from inventory slot %d "
|
||||
"after casting, or is not a poison!", ApplyPoisonData->inventorySlot);
|
||||
|
||||
Message(0, "Error: item not found for inventory slot #%i or is not a poison", ApplyPoisonData->inventorySlot);
|
||||
if (PrimaryWeapon) {
|
||||
primary=PrimaryWeapon->GetItem();
|
||||
}
|
||||
else if (GetClass() == ROGUE)
|
||||
{
|
||||
if ((PrimaryWeapon && PrimaryWeapon->GetItem()->ItemType == EQEmu::item::ItemType1HPiercing) ||
|
||||
(SecondaryWeapon && SecondaryWeapon->GetItem()->ItemType == EQEmu::item::ItemType1HPiercing)) {
|
||||
float SuccessChance = (GetSkill(EQEmu::skills::SkillApplyPoison) + GetLevel()) / 400.0f;
|
||||
|
||||
if (SecondaryWeapon) {
|
||||
secondary=SecondaryWeapon->GetItem();
|
||||
}
|
||||
|
||||
if (IsPoison && GetClass() == ROGUE) {
|
||||
|
||||
// Live always checks for skillup, even when poison is too high
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillApplyPoison, nullptr, 10);
|
||||
|
||||
if (poison->Proc.Level2 > GetLevel()) {
|
||||
// Poison is too high to apply.
|
||||
Message_StringID(clientMessageTradeskill, POISON_TOO_HIGH);
|
||||
}
|
||||
else if ((primary &&
|
||||
primary->ItemType == EQEmu::item::ItemType1HPiercing) ||
|
||||
(secondary &&
|
||||
secondary->ItemType == EQEmu::item::ItemType1HPiercing)) {
|
||||
|
||||
double ChanceRoll = zone->random.Real(0, 1);
|
||||
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillApplyPoison, nullptr, 10);
|
||||
// Poisons that use this skill (old world poisons) almost
|
||||
// never fail to apply. I did 25 applies of a trivial 120+
|
||||
// poison with an apply skill of 48 and they all worked.
|
||||
// Also did 25 straight poisons at apply skill 248 for very
|
||||
// high end and they never failed.
|
||||
// Apply poison ranging from 1-9, 28/30 worked for a level 18..
|
||||
// Poisons that don't proc until a level higher than the
|
||||
// rogue simply won't apply at all, no skill check done.
|
||||
|
||||
if (ChanceRoll < SuccessChance) {
|
||||
if (ChanceRoll < (.9 + GetLevel()/1000)) {
|
||||
ApplyPoisonSuccessResult = 1;
|
||||
// NOTE: Someone may want to tweak the chance to proc the poison effect that is added to the weapon here.
|
||||
// My thinking was that DEX should be apart of the calculation.
|
||||
AddProcToWeapon(PoisonItemInstance->GetItem()->Proc.Effect, false, (GetDEX() / 100) + 103);
|
||||
AddProcToWeapon(poison->Proc.Effect, false,
|
||||
(GetDEX() / 100) + 103);
|
||||
}
|
||||
|
||||
DeleteItemInInventory(ApplyPoisonData->inventorySlot, 1, true);
|
||||
|
||||
Log(Logs::General, Logs::None, "Chance to Apply Poison was %f. Roll was %f. Result is %u.", SuccessChance, ChanceRoll, ApplyPoisonSuccessResult);
|
||||
}
|
||||
|
||||
// Live always deletes the item, success or failure. Even if too high.
|
||||
DeleteItemInInventory(ApplyPoisonData->inventorySlot, 1, true);
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_ApplyPoison, nullptr, sizeof(ApplyPoison_Struct));
|
||||
@@ -3965,12 +3986,23 @@ void Client::Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_Bug(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(BugStruct))
|
||||
printf("Wrong size of BugStruct got %d expected %zu!\n", app->size, sizeof(BugStruct));
|
||||
else {
|
||||
BugStruct* bug = (BugStruct*)app->pBuffer;
|
||||
database.UpdateBug(bug);
|
||||
if (!RuleB(Bugs, ReportingSystemActive)) {
|
||||
Message(0, "Bug reporting is disabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->size != sizeof(BugReport_Struct)) {
|
||||
printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct));
|
||||
}
|
||||
else {
|
||||
BugReport_Struct* bug_report = (BugReport_Struct*)app->pBuffer;
|
||||
|
||||
if (RuleB(Bugs, UseOldReportingMethod))
|
||||
database.RegisterBug(bug_report);
|
||||
else
|
||||
database.RegisterBug(this, bug_report);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6716,7 +6748,11 @@ void Client::Handle_OP_GroupFollow2(const EQApplicationPacket *app)
|
||||
// Inviter and Invitee are in the same zone
|
||||
if (inviter != nullptr && inviter->IsClient())
|
||||
{
|
||||
if (GroupFollow(inviter->CastToClient()))
|
||||
if (!inviter->CastToClient()->Connected())
|
||||
{
|
||||
Log(Logs::General, Logs::Error, "%s attempted to join group while leader %s was zoning.", GetName(), inviter->GetName());
|
||||
}
|
||||
else if (GroupFollow(inviter->CastToClient()))
|
||||
{
|
||||
strn0cpy(gf->name1, inviter->GetName(), sizeof(gf->name1));
|
||||
strn0cpy(gf->name2, GetName(), sizeof(gf->name2));
|
||||
@@ -10573,11 +10609,8 @@ void Client::Handle_OP_Petition(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_PetitionBug(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(PetitionBug_Struct))
|
||||
printf("Wrong size of BugStruct! Expected: %zu, Got: %i\n", sizeof(PetitionBug_Struct), app->size);
|
||||
else {
|
||||
Message(0, "Petition Bugs are not supported, please use /bug.");
|
||||
}
|
||||
Message(0, "Petition Bugs are not supported, please use /bug.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10997,6 +11030,84 @@ void Client::Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app)
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app)
|
||||
{
|
||||
if (zone->IsUCSServerAvailable()) {
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
std::string buffer;
|
||||
|
||||
std::string MailKey = database.GetMailKey(CharacterID(), true);
|
||||
EQEmu::versions::UCSVersion ConnectionType = EQEmu::versions::ucsUnknown;
|
||||
|
||||
// chat server packet
|
||||
switch (ClientVersion()) {
|
||||
case EQEmu::versions::ClientVersion::Titanium:
|
||||
ConnectionType = EQEmu::versions::ucsTitaniumChat;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::SoF:
|
||||
ConnectionType = EQEmu::versions::ucsSoFCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::SoD:
|
||||
ConnectionType = EQEmu::versions::ucsSoDCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::UF:
|
||||
ConnectionType = EQEmu::versions::ucsUFCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::RoF:
|
||||
ConnectionType = EQEmu::versions::ucsRoFCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::RoF2:
|
||||
ConnectionType = EQEmu::versions::ucsRoF2Combined;
|
||||
break;
|
||||
default:
|
||||
ConnectionType = EQEmu::versions::ucsUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%s",
|
||||
Config->ChatHost.c_str(),
|
||||
Config->ChatPort,
|
||||
Config->ShortName.c_str(),
|
||||
GetName(),
|
||||
ConnectionType,
|
||||
MailKey.c_str()
|
||||
);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1));
|
||||
memcpy(outapp->pBuffer, buffer.c_str(), buffer.length());
|
||||
outapp->pBuffer[buffer.length()] = '\0';
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// mail server packet
|
||||
switch (ClientVersion()) {
|
||||
case EQEmu::versions::ClientVersion::Titanium:
|
||||
ConnectionType = EQEmu::versions::ucsTitaniumMail;
|
||||
break;
|
||||
default:
|
||||
// retain value from previous switch
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%s",
|
||||
Config->MailHost.c_str(),
|
||||
Config->MailPort,
|
||||
Config->ShortName.c_str(),
|
||||
GetName(),
|
||||
ConnectionType,
|
||||
MailKey.c_str()
|
||||
);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1));
|
||||
memcpy(outapp->pBuffer, buffer.c_str(), buffer.length());
|
||||
outapp->pBuffer[buffer.length()] = '\0';
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size < sizeof(RaidGeneral_Struct)) {
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardDetailsRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_QueryUCSServerStatus(const EQApplicationPacket *app);
|
||||
void Handle_OP_RaidCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_RandomReq(const EQApplicationPacket *app);
|
||||
void Handle_OP_ReadBook(const EQApplicationPacket *app);
|
||||
|
||||
+119
-69
@@ -391,6 +391,7 @@ int command_init(void)
|
||||
command_add("traindisc", "[level] - Trains all the disciplines usable by the target, up to level specified. (may freeze client for a few seconds)", 150, command_traindisc) ||
|
||||
command_add("trapinfo", "- Gets infomation about the traps currently spawned in the zone.", 81, command_trapinfo) ||
|
||||
command_add("tune", "Calculate ideal statical values related to combat.", 100, command_tune) ||
|
||||
command_add("ucs", "- Attempts to reconnect to the UCS server", 0, command_ucs) ||
|
||||
command_add("undyeme", "- Remove dye from all of your armor slots", 0, command_undyeme) ||
|
||||
command_add("unfreeze", "- Unfreeze your target", 80, command_unfreeze) ||
|
||||
command_add("unlock", "- Unlock the worldserver", 150, command_unlock) ||
|
||||
@@ -2326,14 +2327,18 @@ void command_race(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *t=c->CastToMob();
|
||||
|
||||
// Need to figure out max race for LoY/LDoN: going with upper bound of 500 now for testing
|
||||
if (sep->IsNumber(1) && atoi(sep->arg[1]) >= 0 && atoi(sep->arg[1]) <= 724) {
|
||||
if ((c->GetTarget()) && c->Admin() >= commandRaceOthers)
|
||||
t=c->GetTarget();
|
||||
t->SendIllusionPacket(atoi(sep->arg[1]));
|
||||
if (sep->IsNumber(1)) {
|
||||
auto race = atoi(sep->arg[1]);
|
||||
if ((race >= 0 && race <= 732) || (race >= 2253 && race <= 2259)) {
|
||||
if ((c->GetTarget()) && c->Admin() >= commandRaceOthers)
|
||||
t = c->GetTarget();
|
||||
t->SendIllusionPacket(race);
|
||||
} else {
|
||||
c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)");
|
||||
}
|
||||
} else {
|
||||
c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)");
|
||||
}
|
||||
else
|
||||
c->Message(0, "Usage: #race [0-724] (0 for back to normal)");
|
||||
}
|
||||
|
||||
void command_gender(Client *c, const Seperator *sep)
|
||||
@@ -2553,7 +2558,7 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
const EQEmu::ItemInstance* inst_main = nullptr;
|
||||
const EQEmu::ItemInstance* inst_sub = nullptr;
|
||||
const EQEmu::ItemData* item_data = nullptr;
|
||||
std::string item_link;
|
||||
|
||||
EQEmu::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
|
||||
@@ -2565,10 +2570,8 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i",
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
}
|
||||
|
||||
if ((scopeWhere & peekWorn) && (targetClient->ClientVersion() >= EQEmu::versions::ClientVersion::SoF)) {
|
||||
@@ -2576,10 +2579,8 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i",
|
||||
EQEmu::inventory::slotPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
EQEmu::inventory::slotPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
}
|
||||
|
||||
// inv
|
||||
@@ -2588,20 +2589,16 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "InvSlot: %i, Item: %i (%s), Charges: %i",
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
|
||||
for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) {
|
||||
inst_sub = inst_main->GetItem(indexSub);
|
||||
item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem();
|
||||
linker.SetItemInst(inst_sub);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), " InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2610,10 +2607,8 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
if (targetClient->GetInv().CursorEmpty()) {
|
||||
linker.SetItemInst(nullptr);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message(1, "CursorSlot: %i, Item: %i (%s), Charges: %i",
|
||||
EQEmu::inventory::slotCursor, 0, item_link.c_str(), 0);
|
||||
EQEmu::inventory::slotCursor, 0, linker.GenerateLink().c_str(), 0);
|
||||
}
|
||||
else {
|
||||
int cursorDepth = 0;
|
||||
@@ -2622,20 +2617,16 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i",
|
||||
EQEmu::inventory::slotCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
EQEmu::inventory::slotCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
|
||||
for (uint8 indexSub = EQEmu::inventory::containerBegin; (cursorDepth == 0) && inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) {
|
||||
inst_sub = inst_main->GetItem(indexSub);
|
||||
item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem();
|
||||
linker.SetItemInst(inst_sub);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), " CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
|
||||
EQEmu::InventoryProfile::CalcSlotId(EQEmu::inventory::slotCursor, indexSub), EQEmu::inventory::slotCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
EQEmu::InventoryProfile::CalcSlotId(EQEmu::inventory::slotCursor, indexSub), EQEmu::inventory::slotCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2647,10 +2638,8 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "TributeSlot: %i, Item: %i (%s), Charges: %i",
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
}
|
||||
|
||||
// bank
|
||||
@@ -2659,20 +2648,16 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "BankSlot: %i, Item: %i (%s), Charges: %i",
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
|
||||
for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) {
|
||||
inst_sub = inst_main->GetItem(indexSub);
|
||||
item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem();
|
||||
linker.SetItemInst(inst_sub);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), " BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2681,20 +2666,16 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "SharedBankSlot: %i, Item: %i (%s), Charges: %i",
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
|
||||
for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) {
|
||||
inst_sub = inst_main->GetItem(indexSub);
|
||||
item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem();
|
||||
linker.SetItemInst(inst_sub);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), " SharedBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2704,20 +2685,16 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "TradeSlot: %i, Item: %i (%s), Charges: %i",
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
indexMain, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
|
||||
for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) {
|
||||
inst_sub = inst_main->GetItem(indexSub);
|
||||
item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem();
|
||||
linker.SetItemInst(inst_sub);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), " TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
EQEmu::InventoryProfile::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2736,20 +2713,16 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem();
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), "WorldSlot: %i, Item: %i (%s), Charges: %i",
|
||||
(EQEmu::legacy::WORLD_BEGIN + indexMain), ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
(EQEmu::legacy::WORLD_BEGIN + indexMain), ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges()));
|
||||
|
||||
for (uint8 indexSub = EQEmu::inventory::containerBegin; inst_main && inst_main->IsType(EQEmu::item::ItemClassBag) && (indexSub < EQEmu::inventory::ContainerCount); ++indexSub) {
|
||||
inst_sub = inst_main->GetItem(indexSub);
|
||||
item_data = (inst_sub == nullptr) ? nullptr : inst_sub->GetItem();
|
||||
linker.SetItemInst(inst_sub);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message((item_data == nullptr), " WorldBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i",
|
||||
INVALID_INDEX, indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
INVALID_INDEX, indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), linker.GenerateLink().c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4404,9 +4377,7 @@ void command_iteminfo(Client *c, const Seperator *sep)
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
c->Message(0, "*** Item Info for [%s] ***", item_link.c_str());
|
||||
c->Message(0, "*** Item Info for [%s] ***", linker.GenerateLink().c_str());
|
||||
c->Message(0, ">> ID: %u, ItemUseType: %u, ItemClassType: %u", item->ID, item->ItemType, item->ItemClass);
|
||||
c->Message(0, ">> IDFile: '%s', IconID: %u", item->IDFile, item->Icon);
|
||||
c->Message(0, ">> Size: %u, Weight: %u, Price: %u, LDoNPrice: %u", item->Size, item->Weight, item->Price, item->LDoNPrice);
|
||||
@@ -5550,9 +5521,9 @@ void command_summonitem(Client *c, const Seperator *sep)
|
||||
std::string cmd_msg = sep->msg;
|
||||
size_t link_open = cmd_msg.find('\x12');
|
||||
size_t link_close = cmd_msg.find_last_of('\x12');
|
||||
if (link_open != link_close && (cmd_msg.length() - link_open) > EQEmu::legacy::TEXT_LINK_BODY_LENGTH) {
|
||||
if (link_open != link_close && (cmd_msg.length() - link_open) > EQEmu::constants::SayLinkBodySize) {
|
||||
EQEmu::SayLinkBody_Struct link_body;
|
||||
EQEmu::saylink::DegenerateLinkBody(link_body, cmd_msg.substr(link_open + 1, EQEmu::legacy::TEXT_LINK_BODY_LENGTH));
|
||||
EQEmu::saylink::DegenerateLinkBody(link_body, cmd_msg.substr(link_open + 1, EQEmu::constants::SayLinkBodySize));
|
||||
itemid = link_body.item_id;
|
||||
}
|
||||
else if (!sep->IsNumber(1)) {
|
||||
@@ -5661,7 +5632,6 @@ void command_itemsearch(Client *c, const Seperator *sep)
|
||||
const char *search_criteria=sep->argplus[1];
|
||||
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
std::string item_link;
|
||||
EQEmu::SayLinkEngine linker;
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemData);
|
||||
|
||||
@@ -5670,9 +5640,7 @@ void command_itemsearch(Client *c, const Seperator *sep)
|
||||
if (item) {
|
||||
linker.SetItemData(item);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message(0, "%u: %s", item->ID, item_link.c_str());
|
||||
c->Message(0, "%u: %s", item->ID, linker.GenerateLink().c_str());
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Item #%s not found", search_criteria);
|
||||
@@ -5695,9 +5663,7 @@ void command_itemsearch(Client *c, const Seperator *sep)
|
||||
if (pdest != nullptr) {
|
||||
linker.SetItemData(item);
|
||||
|
||||
item_link = linker.GenerateLink();
|
||||
|
||||
c->Message(0, "%u: %s", item->ID, item_link.c_str());
|
||||
c->Message(0, "%u: %s", item->ID, linker.GenerateLink().c_str());
|
||||
|
||||
++count;
|
||||
}
|
||||
@@ -7201,6 +7167,90 @@ void command_undye(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void command_ucs(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
Log(Logs::Detail, Logs::UCS_Server, "Character %s attempting ucs reconnect while ucs server is %savailable",
|
||||
c->GetName(), (zone->IsUCSServerAvailable() ? "" : "un"));
|
||||
|
||||
if (zone->IsUCSServerAvailable()) {
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
std::string buffer;
|
||||
|
||||
std::string MailKey = database.GetMailKey(c->CharacterID(), true);
|
||||
EQEmu::versions::UCSVersion ConnectionType = EQEmu::versions::ucsUnknown;
|
||||
|
||||
// chat server packet
|
||||
switch (c->ClientVersion()) {
|
||||
case EQEmu::versions::ClientVersion::Titanium:
|
||||
ConnectionType = EQEmu::versions::ucsTitaniumChat;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::SoF:
|
||||
ConnectionType = EQEmu::versions::ucsSoFCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::SoD:
|
||||
ConnectionType = EQEmu::versions::ucsSoDCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::UF:
|
||||
ConnectionType = EQEmu::versions::ucsUFCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::RoF:
|
||||
ConnectionType = EQEmu::versions::ucsRoFCombined;
|
||||
break;
|
||||
case EQEmu::versions::ClientVersion::RoF2:
|
||||
ConnectionType = EQEmu::versions::ucsRoF2Combined;
|
||||
break;
|
||||
default:
|
||||
ConnectionType = EQEmu::versions::ucsUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%s",
|
||||
Config->ChatHost.c_str(),
|
||||
Config->ChatPort,
|
||||
Config->ShortName.c_str(),
|
||||
c->GetName(),
|
||||
ConnectionType,
|
||||
MailKey.c_str()
|
||||
);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1));
|
||||
memcpy(outapp->pBuffer, buffer.c_str(), buffer.length());
|
||||
outapp->pBuffer[buffer.length()] = '\0';
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// mail server packet
|
||||
switch (c->ClientVersion()) {
|
||||
case EQEmu::versions::ClientVersion::Titanium:
|
||||
ConnectionType = EQEmu::versions::ucsTitaniumMail;
|
||||
break;
|
||||
default:
|
||||
// retain value from previous switch
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%s",
|
||||
Config->MailHost.c_str(),
|
||||
Config->MailPort,
|
||||
Config->ShortName.c_str(),
|
||||
c->GetName(),
|
||||
ConnectionType,
|
||||
MailKey.c_str()
|
||||
);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1));
|
||||
memcpy(outapp->pBuffer, buffer.c_str(), buffer.length());
|
||||
outapp->pBuffer[buffer.length()] = '\0';
|
||||
|
||||
c->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
|
||||
void command_undyeme(Client *c, const Seperator *sep)
|
||||
{
|
||||
if(c) {
|
||||
@@ -10839,7 +10889,7 @@ void command_hotfix(Client *c, const Seperator *sep) {
|
||||
}
|
||||
worldserver.SendPacket(&pack);
|
||||
|
||||
c->Message(0, "Hotfix applied");
|
||||
if (c) c->Message(0, "Hotfix applied");
|
||||
});
|
||||
|
||||
t1.detach();
|
||||
|
||||
@@ -302,6 +302,7 @@ void command_titlesuffix(Client *c, const Seperator *sep);
|
||||
void command_traindisc(Client *c, const Seperator *sep);
|
||||
void command_trapinfo(Client* c, const Seperator *sep);
|
||||
void command_tune(Client *c, const Seperator *sep);
|
||||
void command_ucs(Client *c, const Seperator *sep);
|
||||
void command_undye(Client *c, const Seperator *sep);
|
||||
void command_undyeme(Client *c, const Seperator *sep);
|
||||
void command_unfreeze(Client *c, const Seperator *sep);
|
||||
|
||||
+4
-4
@@ -1253,20 +1253,20 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
linker.SetItemInst(inst);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
linker.GenerateLink();
|
||||
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
|
||||
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, linker.Link().c_str());
|
||||
|
||||
if (!IsPlayerCorpse()) {
|
||||
Group *g = client->GetGroup();
|
||||
if (g != nullptr) {
|
||||
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
|
||||
client->GetName(), item_link.c_str());
|
||||
client->GetName(), linker.Link().c_str());
|
||||
} else {
|
||||
Raid *r = client->GetRaid();
|
||||
if (r != nullptr) {
|
||||
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
|
||||
client->GetName(), item_link.c_str());
|
||||
client->GetName(), linker.Link().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,6 +831,8 @@ void Client::SetLevel(uint8 set_level, bool command)
|
||||
SetHP(CalcMaxHP()); // Why not, lets give them a free heal
|
||||
}
|
||||
|
||||
if (RuleI(World, PVPMinLevel) > 0 && level >= RuleI(World, PVPMinLevel) && m_pp.pvp == 0) SetPVP(true);
|
||||
|
||||
DoTributeUpdate();
|
||||
SendHPUpdate();
|
||||
SetMana(CalcMaxMana());
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#if defined(_MSC_VER)
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cmath>
|
||||
#include "fastmath.h"
|
||||
|
||||
FastMath g_Math;
|
||||
|
||||
// This should match EQ's sin/cos LUTs
|
||||
// Some values didn't match on linux, but they were the "same" float :P
|
||||
FastMath::FastMath()
|
||||
{
|
||||
int ci = 0;
|
||||
int si = 128;
|
||||
float res;
|
||||
do {
|
||||
res = std::cos(static_cast<float>(ci) * M_PI * 2 / 512);
|
||||
lut_cos[ci] = res;
|
||||
if (si == 512)
|
||||
si = 0;
|
||||
lut_sin[si] = res;
|
||||
++ci;
|
||||
++si;
|
||||
} while (ci < 512);
|
||||
|
||||
lut_sin[0] = 0.0f;
|
||||
lut_sin[128] = 1.0f;
|
||||
lut_sin[256] = 0.0f;
|
||||
lut_sin[384] = -1.0f;
|
||||
|
||||
lut_cos[0] = 1.0f;
|
||||
lut_cos[128] = 0.0f;
|
||||
lut_cos[384] = 0.0f;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef FASTMATH_H
|
||||
#define FASTMATH_H
|
||||
|
||||
class FastMath
|
||||
{
|
||||
private:
|
||||
float lut_cos[512];
|
||||
float lut_sin[512];
|
||||
|
||||
public:
|
||||
FastMath();
|
||||
|
||||
inline float FastSin(float a) { return lut_sin[static_cast<int>(a) & 0x1ff]; }
|
||||
inline float FastCos(float a) { return lut_cos[static_cast<int>(a) & 0x1ff]; }
|
||||
|
||||
};
|
||||
|
||||
#endif /* !FASTMATH_H */
|
||||
+1
-1
@@ -1329,7 +1329,7 @@ int Client::GetItemLinkHash(const EQEmu::ItemInstance* inst) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
// This appears to still be in use... The core of this should be incorporated into class Client::TextLink
|
||||
// This appears to still be in use... The core of this should be incorporated into class EQEmu::SayLinkEngine
|
||||
void Client::SendItemLink(const EQEmu::ItemInstance* inst, bool send_to_all)
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -282,6 +282,16 @@ void Lua_Mob::GMMove(double x, double y, double z, double heading, bool send_upd
|
||||
self->GMMove(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(heading), send_update);
|
||||
}
|
||||
|
||||
void Lua_Mob::TryMoveAlong(float distance, float angle) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->TryMoveAlong(distance, angle);
|
||||
}
|
||||
|
||||
void Lua_Mob::TryMoveAlong(float distance, float angle, bool send) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->TryMoveAlong(distance, angle, send);
|
||||
}
|
||||
|
||||
bool Lua_Mob::HasProcs() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasProcs();
|
||||
@@ -2197,6 +2207,8 @@ luabind::scope lua_register_mob() {
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::GMMove)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double,double))&Lua_Mob::GMMove)
|
||||
.def("GMMove", (void(Lua_Mob::*)(double,double,double,double,bool))&Lua_Mob::GMMove)
|
||||
.def("TryMoveAlong", (void(Lua_Mob::*)(float,float))&Lua_Mob::TryMoveAlong)
|
||||
.def("TryMoveAlong", (void(Lua_Mob::*)(float,float,bool))&Lua_Mob::TryMoveAlong)
|
||||
.def("HasProcs", &Lua_Mob::HasProcs)
|
||||
.def("IsInvisible", (bool(Lua_Mob::*)(void))&Lua_Mob::IsInvisible)
|
||||
.def("IsInvisible", (bool(Lua_Mob::*)(Lua_Mob))&Lua_Mob::IsInvisible)
|
||||
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
void GMMove(double x, double y, double z);
|
||||
void GMMove(double x, double y, double z, double heading);
|
||||
void GMMove(double x, double y, double z, double heading, bool send_update);
|
||||
void TryMoveAlong(float distance, float heading);
|
||||
void TryMoveAlong(float distance, float heading, bool send);
|
||||
bool HasProcs();
|
||||
bool IsInvisible();
|
||||
bool IsInvisible(Lua_Mob other);
|
||||
|
||||
+1038
-1027
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -30,7 +30,7 @@
|
||||
#define BEST_Z_INVALID -99999
|
||||
|
||||
extern const ZoneConfig *Config;
|
||||
namespace EQEmu
|
||||
namespace EQEmu
|
||||
{
|
||||
class Map
|
||||
{
|
||||
@@ -43,6 +43,7 @@ namespace EQEmu
|
||||
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
|
||||
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
|
||||
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
|
||||
bool DoCollisionCheck(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outnorm, float &distance) const;
|
||||
|
||||
#ifdef USE_MAP_MMFS
|
||||
bool Load(std::string filename, bool force_mmf_overwrite = false);
|
||||
@@ -67,4 +68,4 @@ namespace EQEmu
|
||||
impl *imp;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+2
-1
@@ -117,7 +117,7 @@ Mob::Mob(const char* in_name,
|
||||
fix_z_timer(300),
|
||||
fix_z_timer_engaged(100),
|
||||
attack_anim_timer(1000),
|
||||
position_update_melee_push_timer(1000),
|
||||
position_update_melee_push_timer(500),
|
||||
mHateListCleanup(6000)
|
||||
{
|
||||
targeted = 0;
|
||||
@@ -395,6 +395,7 @@ Mob::Mob(const char* in_name,
|
||||
permarooted = (runspeed > 0) ? false : true;
|
||||
|
||||
movetimercompleted = false;
|
||||
ForcedMovement = 0;
|
||||
roamer = false;
|
||||
rooted = false;
|
||||
charmed = false;
|
||||
|
||||
@@ -50,6 +50,8 @@ struct AuraRecord;
|
||||
struct NewSpawn_Struct;
|
||||
struct PlayerPositionUpdateServer_Struct;
|
||||
|
||||
const int COLLISION_BOX_SIZE = 4;
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
struct ItemData;
|
||||
@@ -578,6 +580,8 @@ public:
|
||||
void SetFlyMode(uint8 flymode);
|
||||
inline void Teleport(glm::vec3 NewPosition) { m_Position.x = NewPosition.x; m_Position.y = NewPosition.y;
|
||||
m_Position.z = NewPosition.z; };
|
||||
void TryMoveAlong(float distance, float angle, bool send = true);
|
||||
void ProcessForcedMovement();
|
||||
|
||||
//AI
|
||||
static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel);
|
||||
@@ -1313,6 +1317,9 @@ protected:
|
||||
char lastname[64];
|
||||
|
||||
glm::vec4 m_Delta;
|
||||
// just locs around them to double check, if we do expand collision this should be cached on movement
|
||||
// ideally we should use real models, but this should be quick and work mostly
|
||||
glm::vec4 m_CollisionBox[COLLISION_BOX_SIZE];
|
||||
|
||||
EQEmu::LightSourceProfile m_Light;
|
||||
|
||||
@@ -1423,6 +1430,7 @@ protected:
|
||||
std::unique_ptr<Timer> AI_movement_timer;
|
||||
std::unique_ptr<Timer> AI_target_check_timer;
|
||||
bool movetimercompleted;
|
||||
int8 ForcedMovement; // push
|
||||
bool permarooted;
|
||||
std::unique_ptr<Timer> AI_scan_area_timer;
|
||||
std::unique_ptr<Timer> AI_walking_timer;
|
||||
|
||||
+105
-19
@@ -29,12 +29,16 @@
|
||||
#include "quest_parser_collection.h"
|
||||
#include "string_ids.h"
|
||||
#include "water_map.h"
|
||||
#include "fastmath.h"
|
||||
|
||||
#include <glm/gtx/projection.hpp>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <math.h>
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern FastMath g_Math;
|
||||
|
||||
extern Zone *zone;
|
||||
|
||||
@@ -918,29 +922,26 @@ void Client::AI_Process()
|
||||
}
|
||||
}
|
||||
|
||||
if(IsPet())
|
||||
{
|
||||
Mob* owner = GetOwner();
|
||||
if(owner == nullptr)
|
||||
if (IsPet()) {
|
||||
Mob *owner = GetOwner();
|
||||
if (owner == nullptr)
|
||||
return;
|
||||
|
||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
||||
if (dist >= 400)
|
||||
{
|
||||
if(AI_movement_timer->Check())
|
||||
{
|
||||
int nspeed = (dist >= 5625 ? GetRunspeed() : GetWalkspeed());
|
||||
if (dist >= 202500) { // >= 450 distance
|
||||
Teleport(static_cast<glm::vec3>(owner->GetPosition()));
|
||||
SendPositionUpdate(); // this shouldn't happen a lot (and hard to make it) so lets not rate limit
|
||||
} else if (dist >= 400) { // >=20
|
||||
if (AI_movement_timer->Check()) {
|
||||
int nspeed = (dist >= 1225 ? GetRunspeed() : GetWalkspeed()); // >= 35
|
||||
animation = nspeed;
|
||||
nspeed *= 2;
|
||||
SetCurrentSpeed(nspeed);
|
||||
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(moved)
|
||||
{
|
||||
} else {
|
||||
if (moved) {
|
||||
SetCurrentSpeed(0);
|
||||
moved = false;
|
||||
}
|
||||
@@ -949,6 +950,71 @@ void Client::AI_Process()
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::ProcessForcedMovement()
|
||||
{
|
||||
// we are being pushed, we will hijack this movement timer
|
||||
// this also needs to be done before casting to have a chance to interrupt
|
||||
// this flag won't be set if the mob can't be pushed (rooted etc)
|
||||
if (AI_movement_timer->Check()) {
|
||||
bool bPassed = true;
|
||||
auto z_off = GetZOffset();
|
||||
glm::vec3 normal;
|
||||
glm::vec3 new_pos = m_Position + m_Delta;
|
||||
|
||||
// no zone map = fucked
|
||||
if (zone->HasMap()) {
|
||||
// in front
|
||||
m_CollisionBox[0].x = m_Position.x + 3.0f * g_Math.FastSin(0.0f);
|
||||
m_CollisionBox[0].y = m_Position.y + 3.0f * g_Math.FastCos(0.0f);
|
||||
m_CollisionBox[0].z = m_Position.z + z_off;
|
||||
|
||||
// to right
|
||||
m_CollisionBox[1].x = m_Position.x + 3.0f * g_Math.FastSin(128.0f);
|
||||
m_CollisionBox[1].y = m_Position.y + 3.0f * g_Math.FastCos(128.0f);
|
||||
m_CollisionBox[1].z = m_Position.z + z_off;
|
||||
|
||||
// behind
|
||||
m_CollisionBox[2].x = m_Position.x + 3.0f * g_Math.FastSin(256.0f);
|
||||
m_CollisionBox[2].y = m_Position.y + 3.0f * g_Math.FastCos(256.0f);
|
||||
m_CollisionBox[2].z = m_Position.z + z_off;
|
||||
|
||||
// to left
|
||||
m_CollisionBox[3].x = m_Position.x + 3.0f * g_Math.FastSin(384.0f);
|
||||
m_CollisionBox[3].y = m_Position.y + 3.0f * g_Math.FastCos(384.0f);
|
||||
m_CollisionBox[3].z = m_Position.z + z_off;
|
||||
|
||||
// collision happened, need to move along the wall
|
||||
float distance = 0.0f, shortest = std::numeric_limits<float>::infinity();
|
||||
glm::vec3 tmp_nrm;
|
||||
for (auto &vec : m_CollisionBox) {
|
||||
if (zone->zonemap->DoCollisionCheck(vec, new_pos, tmp_nrm, distance)) {
|
||||
bPassed = false; // lets try with new projection next pass
|
||||
if (distance < shortest) {
|
||||
normal = tmp_nrm;
|
||||
shortest = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bPassed) {
|
||||
ForcedMovement = 0;
|
||||
m_Delta = glm::vec4();
|
||||
Teleport(new_pos);
|
||||
SendPositionUpdate();
|
||||
pLastChange = Timer::GetCurrentTime();
|
||||
FixZ(); // so we teleport to the ground locally, we want the client to interpolate falling etc
|
||||
} else if (--ForcedMovement) {
|
||||
auto proj = glm::proj(static_cast<glm::vec3>(m_Delta), normal);
|
||||
m_Delta.x -= proj.x;
|
||||
m_Delta.y -= proj.y;
|
||||
m_Delta.z -= proj.z;
|
||||
} else {
|
||||
m_Delta = glm::vec4(); // well, we failed to find a spot to be forced to, lets give up
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::AI_Process() {
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
@@ -956,6 +1022,7 @@ void Mob::AI_Process() {
|
||||
if (!(AI_think_timer->Check() || attack_timer.Check(false)))
|
||||
return;
|
||||
|
||||
|
||||
if (IsCasting())
|
||||
return;
|
||||
|
||||
@@ -1428,10 +1495,10 @@ void Mob::AI_Process() {
|
||||
if (dist >= 400 || distz > 100)
|
||||
{
|
||||
int speed = GetWalkspeed();
|
||||
if (dist >= 5625)
|
||||
if (dist >= 1225) // 35
|
||||
speed = GetRunspeed();
|
||||
|
||||
if (distz > 100)
|
||||
if (dist >= 202500 || distz > 100) // dist >= 450
|
||||
{
|
||||
m_Position = ownerPos;
|
||||
SendPositionUpdate();
|
||||
@@ -2074,15 +2141,34 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
|
||||
if (m_target) {
|
||||
if (m_target == GetTarget())
|
||||
continue;
|
||||
if (CombatRange(m_target)) {
|
||||
if (DistanceSquaredNoZ(GetPosition(), m_target->GetPosition()) <= NPC_RAMPAGE_RANGE2) {
|
||||
ProcessAttackRounds(m_target, opts);
|
||||
index_hit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets)
|
||||
ProcessAttackRounds(GetTarget(), opts);
|
||||
if (RuleB(Combat, RampageHitsTarget)) {
|
||||
if (index_hit < rampage_targets)
|
||||
ProcessAttackRounds(GetTarget(), opts);
|
||||
} else { // let's do correct behavior here, if they set above rule we can assume they want non-live like behavior
|
||||
if (index_hit < rampage_targets) {
|
||||
// so we go over in reverse order and skip range check
|
||||
// lets do it this way to still support non-live-like >1 rampage targets
|
||||
// likely live is just a fall through of the last valid mob
|
||||
for (auto i = RampageArray.crbegin(); i != RampageArray.crend(); ++i) {
|
||||
if (index_hit >= rampage_targets)
|
||||
break;
|
||||
auto m_target = entity_list.GetMob(*i);
|
||||
if (m_target) {
|
||||
if (m_target == GetTarget())
|
||||
continue;
|
||||
ProcessAttackRounds(m_target, opts);
|
||||
index_hit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_specialattacks = eSpecialAttacks::None;
|
||||
|
||||
|
||||
@@ -679,7 +679,6 @@ void NatsManager::OnSpawnEvent(const EmuOpcode op, uint32 entity_id, Spawn_Struc
|
||||
event.set_equip_chest2(spawn->equip_chest2);
|
||||
event.set_mount_color(spawn->mount_color);
|
||||
event.set_spawnid(spawn->spawnId);
|
||||
event.set_unknown0344(*spawn->unknown0344);
|
||||
event.set_ismercenary(spawn->IsMercenary);
|
||||
//event.set_equipment_tint(spawn->equipment_tint);
|
||||
event.set_lfg(spawn->lfg);
|
||||
@@ -800,8 +799,8 @@ void NatsManager::OnDamageEvent(uint32 entity_id, CombatDamage_Struct *cd) {
|
||||
event.set_spellid(cd->spellid);
|
||||
event.set_damage(cd->damage);
|
||||
event.set_force(cd->force);
|
||||
event.set_meleepush_xy(cd->meleepush_xy);
|
||||
event.set_meleepush_z(cd->meleepush_z);
|
||||
event.set_meleepush_xy(cd->hit_heading);
|
||||
event.set_meleepush_z(cd->hit_pitch);
|
||||
|
||||
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
|
||||
auto finalEvent = eqproto::Event();
|
||||
|
||||
+5
-3
@@ -583,9 +583,7 @@ void NPC::QueryLoot(Client* to)
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkLootItem);
|
||||
linker.SetLootData(*cur);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), (*cur)->item_id, (*cur)->min_level, (*cur)->max_level);
|
||||
to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", linker.GenerateLink().c_str(), (*cur)->item_id, (*cur)->min_level, (*cur)->max_level);
|
||||
}
|
||||
|
||||
to->Message(0, "%i items on %s.", x, GetName());
|
||||
@@ -764,6 +762,10 @@ bool NPC::Process()
|
||||
reface_timer->Disable();
|
||||
}
|
||||
|
||||
// needs to be done before mez and stun
|
||||
if (ForcedMovement)
|
||||
ProcessForcedMovement();
|
||||
|
||||
if (IsMezzed())
|
||||
return true;
|
||||
|
||||
|
||||
+8
-5
@@ -560,7 +560,8 @@ void PathManager::SpawnPathNodes()
|
||||
sprintf(npc_type->lastname, "%i", PathNodes[i].id);
|
||||
npc_type->cur_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 151;
|
||||
npc_type->race = 2253;
|
||||
npc_type->size = 3.0f;
|
||||
npc_type->gender = 2;
|
||||
npc_type->class_ = 9;
|
||||
npc_type->deity= 1;
|
||||
@@ -1377,7 +1378,7 @@ void PathManager::ShowPathNodeNeighbours(Client *c)
|
||||
Mob *m = entity_list.GetMob(Name);
|
||||
|
||||
if(m)
|
||||
m->SendIllusionPacket(151);
|
||||
m->ChangeSize(3.0f);
|
||||
}
|
||||
|
||||
std::stringstream Neighbours;
|
||||
@@ -1401,7 +1402,7 @@ void PathManager::ShowPathNodeNeighbours(Client *c)
|
||||
Mob *m = entity_list.GetMob(Name);
|
||||
|
||||
if(m)
|
||||
m->SendIllusionPacket(46);
|
||||
m->ChangeSize(5.0f);
|
||||
}
|
||||
c->Message(0, "Neighbours: %s", Neighbours.str().c_str());
|
||||
}
|
||||
@@ -1560,7 +1561,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques
|
||||
sprintf(npc_type->lastname, "%i", new_id);
|
||||
npc_type->cur_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 151;
|
||||
npc_type->race = 2253;
|
||||
npc_type->size = 3.0f;
|
||||
npc_type->gender = 2;
|
||||
npc_type->class_ = 9;
|
||||
npc_type->deity= 1;
|
||||
@@ -1621,7 +1623,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques
|
||||
sprintf(npc_type->lastname, "%i", new_id);
|
||||
npc_type->cur_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 151;
|
||||
npc_type->race = 2253;
|
||||
npc_type->size = 3.0f;
|
||||
npc_type->gender = 2;
|
||||
npc_type->class_ = 9;
|
||||
npc_type->deity= 1;
|
||||
|
||||
+38
-76
@@ -28,6 +28,8 @@
|
||||
#include "pets.h"
|
||||
#include "zonedb.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef BOTS
|
||||
#include "bot.h"
|
||||
#endif
|
||||
@@ -38,82 +40,42 @@
|
||||
#endif
|
||||
|
||||
|
||||
const char *GetRandPetName()
|
||||
// need to pass in a char array of 64 chars
|
||||
void GetRandPetName(char *name)
|
||||
{
|
||||
static const char *petnames[] = { "Gabaner","Gabann","Gabantik","Gabarab","Gabarer","Gabarn","Gabartik",
|
||||
"Gabekab","Gabeker","Gabekn","Gaber","Gabn","Gabobab","Gabobn","Gabtik",
|
||||
"Ganer","Gann","Gantik","Garab","Garaner","Garann","Garantik","Gararn",
|
||||
"Garekn","Garer","Garn","Gartik","Gasaner","Gasann","Gasantik","Gasarer",
|
||||
"Gasartik","Gasekn","Gaser","Gebann","Gebantik","Gebarer","Gebarn","Gebartik",
|
||||
"Gebeker","Gebekn","Gebn","Gekab","Geker","Gekn","Genaner","Genann","Genantik",
|
||||
"Genarer","Genarn","Gener","Genn","Genobtik","Gibaner","Gibann","Gibantik",
|
||||
"Gibarn","Gibartik","Gibekn","Giber","Gibn","Gibobtik","Gibtik","Gobaber",
|
||||
"Gobaner","Gobann","Gobarn","Gobartik","Gober","Gobn","Gobober","Gobobn",
|
||||
"Gobobtik","Gobtik","Gonaner","Gonann","Gonantik","Gonarab","Gonarer",
|
||||
"Gonarn","Gonartik","Gonekab","Gonekn","Goner","Gonobtik","Gontik","Gotik",
|
||||
"Jabaner","Jabann","Jabantik","Jabarab","Jabarer","Jabarn","Jabartik",
|
||||
"Jabekab","Jabeker","Jabekn","Jaber","Jabn","Jabobtik","Jabtik","Janab",
|
||||
"Janer","Jann","Jantik","Jarab","Jaranab","Jaraner","Jararer","Jararn",
|
||||
"Jarartik","Jareker","Jarekn","Jarer","Jarn","Jarobn","Jarobtik","Jartik",
|
||||
"Jasab","Jasaner","Jasantik","Jasarer","Jasartik","Jasekab","Jaseker",
|
||||
"Jasekn","Jaser","Jasn","Jasobab","Jasober","Jastik","Jebanab","Jebann",
|
||||
"Jebantik","Jebarab","Jebarar","Jebarer","Jebarn","Jebartik","Jebeker",
|
||||
"Jebekn","Jeber","Jebobn","Jebtik","Jekab","Jeker","Jekn","Jenann",
|
||||
"Jenantik","Jenarer","Jeneker","Jenekn","Jentik","Jibaner","Jibann",
|
||||
"Jibantik","Jibarer","Jibarn","Jibartik","Jibeker","Jibn","Jibobn",
|
||||
"Jibtik","Jobab","Jobaner","Jobann","Jobantik","Jobarn","Jobartik",
|
||||
"Jobekab","Jobeker","Jober","Jobn","Jobtik","Jonanab","Jonaner",
|
||||
"Jonann","Jonantik","Jonarer","Jonarn","Jonartik","Jonekab","Joneker",
|
||||
"Jonekn","Joner","Jonn","Jonnarn","Jonober","Jonobn","Jonobtik","Jontik",
|
||||
"Kabanab","Kabaner","Kabann","Kabantik","Kabarer","Kabarn","Kabartik",
|
||||
"Kabeker","Kabekn","Kaber","Kabn","Kabober","Kabobn","Kabobtik","Kabtik",
|
||||
"Kanab","Kaner","Kann","Kantik","Karab","Karanab","Karaner","Karann",
|
||||
"Karantik","Kararer","Karartik","Kareker","Karer","Karn","Karobab","Karobn",
|
||||
"Kartik","Kasaner","Kasann","Kasarer","Kasartik","Kaseker","Kasekn","Kaser",
|
||||
"Kasn","Kasober","Kastik","Kebann","Kebantik","Kebarab","Kebartik","Kebeker",
|
||||
"Kebekn","Kebn","Kebobab","Kebtik","Kekab","Keker","Kekn","Kenab","Kenaner",
|
||||
"Kenantik","Kenarer","Kenarn","Keneker","Kener","Kenn","Kenobn","Kenobtik",
|
||||
"Kentik","Kibab","Kibaner","Kibantik","Kibarn","Kibartik","Kibekab","Kibeker",
|
||||
"Kibekn","Kibn","Kibobn","Kibobtik","Kobab","Kobanab","Kobaner","Kobann",
|
||||
"Kobantik","Kobarer","Kobarn","Kobartik","Kobeker","Kobekn","Kober","Kobn",
|
||||
"Kobober","Kobobn","Kobtik","Konanab","Konaner","Konann","Konantik","Konarab",
|
||||
"Konarer","Konarn","Konekab","Koneker","Konekn","Koner","Konn","Konobn",
|
||||
"Konobtik","Kontik","Labanab","Labaner","Labann","Labarab","Labarer",
|
||||
"Labarn","Labartik","Labeker","Labekn","Laner","Lann","Larab","Larantik",
|
||||
"Lararer","Lararn","Larartik","Lareker","Larer","Larn","Lartik","Lasaner",
|
||||
"Lasann","Lasarer","Laseker","Laser","Lasik","Lasn","Lastik","Lebaner",
|
||||
"Lebarer","Lebartik","Lebekn","Lebtik","Lekab","Lekn","Lenanab","Lenaner",
|
||||
"Lenann","Lenartik","Lenekab","Leneker","Lenekn","Lentik","Libab","Libaner",
|
||||
"Libann","Libantik","Libarer","Libarn","Libartik","Libeker","Libekn","Lobann",
|
||||
"Lobarab","Lobarn","Lobartik","Lobekn","Lobn","Lobober","Lobobn","Lobtik",
|
||||
"Lonaner","Lonann","Lonantik","Lonarab","Lonarer","Lonarn","Lonartik","Lonekn",
|
||||
"Loner","Lonobtik","Lontik","Vabanab","Vabaner","Vabann","Vabantik","Vabarer",
|
||||
"Vabarn","Vabartik","Vabeker","Vabekn","Vabtik","Vanikk","Vann","Varartik","Varn",
|
||||
"Vartik","Vasann","Vasantik","Vasarab","Vasarer","Vaseker","Vebaner","Vebantik",
|
||||
"Vebarab","Vebeker","Vebekn","Vebobn","Vekab","Veker","Venaner","Venantik","Venar",
|
||||
"Venarn","Vener","Ventik","Vibann","Vibantik","Viber","Vibobtik","Vobann",
|
||||
"Vobarer","Vobartik","Vobekn","Vober","Vobn","Vobtik","Vonaner","Vonann",
|
||||
"Vonantik","Vonarab","Vonarn","Vonartik","Voneker","Vonn","Xabanab","Xabaner",
|
||||
"Xabarer","Xabarn","Xabartik","Xabekab","Xabeker","Xabekn","Xaber","Xabober",
|
||||
"Xaner","Xann","Xarab","Xaranab","Xarann","Xarantik","Xararer","Xarartik","Xarer",
|
||||
"Xarn","Xartik","Xasaner","Xasann","Xasarab","Xasarn","Xasekab","Xaseker",
|
||||
"Xebarer","Xebarn","Xebeker","Xeber","Xebober","Xebtik","Xekab","Xeker",
|
||||
"Xekn","Xenann","Xenantik","Xenarer","Xenartik","Xenekn","Xener","Xenober",
|
||||
"Xentik","Xibantik","Xibarer","Xibekab","Xibeker","Xibobab","Xibober","Xibobn",
|
||||
"Xobaner","Xobann","Xobarab","Xobarn","Xobekab","Xobeker","Xobekn","Xober",
|
||||
"Xobn","Xobobn","Xobtik","Xonaner","Xonann","Xonantik","Xonarer","Xonartik",
|
||||
"Xonekab","Xoneker","Xonekn","Xoner","Xonober","Xtik","Zabaner","Zabantik",
|
||||
"Zabarab","Zabekab","Zabekn","Zaber","Zabn","Zabobab","Zabober","Zabtik",
|
||||
"Zaner","Zantik","Zarann","Zarantik","Zararn","Zarartik","Zareker","Zarekn",
|
||||
"Zarer","Zarn","Zarober","Zartik","Zasaner","Zasarer","Zaseker","Zasekn","Zasn",
|
||||
"Zebantik","Zebarer","Zebarn","Zebartik","Zebobab","Zekab","Zekn","Zenann",
|
||||
"Zenantik","Zenarer","Zenarn","Zenekab","Zeneker","Zenobtik","Zibanab","Zibaner",
|
||||
"Zibann","Zibarer","Zibartik","Zibekn","Zibn","Zibobn","Zobaner","Zobann",
|
||||
"Zobarn","Zober","Zobn","Zonanab","Zonaner","Zonann","Zonantik","Zonarer",
|
||||
"Zonartik","Zonobn","Zonobtik","Zontik","Ztik" };
|
||||
int r = zone->random.Int(0, (sizeof(petnames)/sizeof(const char *))-1);
|
||||
printf("Pet being created: %s\n",petnames[r]); // DO NOT COMMENT THIS OUT!
|
||||
return petnames[r];
|
||||
std::string temp;
|
||||
temp.reserve(64);
|
||||
// note these orders are used to make the exclusions cheap :P
|
||||
static const char *part1[] = {"G", "J", "K", "L", "V", "X", "Z"};
|
||||
static const char *part2[] = {nullptr, "ab", "ar", "as", "eb", "en", "ib", "ob", "on"};
|
||||
static const char *part3[] = {nullptr, "an", "ar", "ek", "ob"};
|
||||
static const char *part4[] = {"er", "ab", "n", "tik"};
|
||||
|
||||
const char *first = part1[zone->random.Int(0, (sizeof(part1) / sizeof(const char *)) - 1)];
|
||||
const char *second = part2[zone->random.Int(0, (sizeof(part2) / sizeof(const char *)) - 1)];
|
||||
const char *third = part3[zone->random.Int(0, (sizeof(part3) / sizeof(const char *)) - 1)];
|
||||
const char *fourth = part4[zone->random.Int(0, (sizeof(part4) / sizeof(const char *)) - 1)];
|
||||
|
||||
// if both of these are empty, we would get an illegally short name
|
||||
if (second == nullptr && third == nullptr)
|
||||
fourth = part4[(sizeof(part4) / sizeof(const char *)) - 1];
|
||||
|
||||
// "ektik" isn't allowed either I guess?
|
||||
if (third == part3[3] && fourth == part4[3])
|
||||
fourth = part4[zone->random.Int(0, (sizeof(part4) / sizeof(const char *)) - 2)];
|
||||
|
||||
// "Laser" isn't allowed either I guess?
|
||||
if (first == part1[3] && second == part2[3] && third == nullptr && fourth == part4[0])
|
||||
fourth = part4[zone->random.Int(1, (sizeof(part4) / sizeof(const char *)) - 2)];
|
||||
|
||||
temp += first;
|
||||
if (second != nullptr)
|
||||
temp += second;
|
||||
if (third != nullptr)
|
||||
temp += third;
|
||||
temp += fourth;
|
||||
|
||||
strn0cpy(name, temp.c_str(), 64);
|
||||
}
|
||||
|
||||
//not used anymore
|
||||
@@ -325,7 +287,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
} else if (record.petnaming == 4) {
|
||||
// Keep the DB name
|
||||
} else if (record.petnaming == 3 && IsClient()) {
|
||||
strcpy(npc_type->name, GetRandPetName());
|
||||
GetRandPetName(npc_type->name);
|
||||
} else if (record.petnaming == 5 && IsClient()) {
|
||||
strcpy(npc_type->name, this->GetName());
|
||||
npc_type->name[24] = '\0';
|
||||
|
||||
+6
-10
@@ -1319,9 +1319,7 @@ void QuestManager::itemlink(int item_id) {
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemData);
|
||||
linker.SetItemData(item);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
|
||||
initiator->Message(0, "%s tells you, %s", owner->GetCleanName(), item_link.c_str());
|
||||
initiator->Message(0, "%s tells you, %s", owner->GetCleanName(), linker.GenerateLink().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1989,8 +1987,8 @@ void QuestManager::npcfeature(char *feature, int setting)
|
||||
QuestManagerCurrentQuestVars();
|
||||
uint16 Race = owner->GetRace();
|
||||
uint8 Gender = owner->GetGender();
|
||||
uint8 Texture = 0xFF;
|
||||
uint8 HelmTexture = 0xFF;
|
||||
uint8 Texture = owner->GetTexture();
|
||||
uint8 HelmTexture = owner->GetHelmTexture();
|
||||
uint8 HairColor = owner->GetHairColor();
|
||||
uint8 BeardColor = owner->GetBeardColor();
|
||||
uint8 EyeColor1 = owner->GetEyeColor1();
|
||||
@@ -2549,9 +2547,8 @@ const char* QuestManager::varlink(char* perltext, int item_id) {
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemData);
|
||||
linker.SetItemData(item);
|
||||
|
||||
auto item_link = linker.GenerateLink();
|
||||
strcpy(perltext, item_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
|
||||
|
||||
strcpy(perltext, linker.GenerateLink().c_str());
|
||||
|
||||
return perltext;
|
||||
}
|
||||
|
||||
@@ -2773,8 +2770,7 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam
|
||||
linker.SetProxyAugment1ID(sayid);
|
||||
linker.SetProxyText(LinkName);
|
||||
|
||||
auto say_link = linker.GenerateLink();
|
||||
strcpy(Phrase, say_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
|
||||
strcpy(Phrase, linker.GenerateLink().c_str());
|
||||
|
||||
return Phrase;
|
||||
}
|
||||
|
||||
@@ -1443,7 +1443,7 @@ void Mob::SendItemAnimation(Mob *to, const EQEmu::ItemData *item, EQEmu::skills:
|
||||
|
||||
//these angle and tilt used together seem to make the arrow/knife throw as straight as I can make it
|
||||
|
||||
as->launch_angle = CalculateHeadingToTarget(to->GetX(), to->GetY()) * 2;
|
||||
as->launch_angle = CalculateHeadingToTarget(to->GetX(), to->GetY());
|
||||
as->tilt = 125;
|
||||
as->arc = 50;
|
||||
|
||||
|
||||
+11
-63
@@ -915,16 +915,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
action->source = caster ? caster->GetID() : GetID();
|
||||
action->level = 65;
|
||||
action->instrument_mod = 10;
|
||||
action->sequence = static_cast<uint32>((GetHeading() * 12345 / 2));
|
||||
action->hit_heading = GetHeading();
|
||||
action->type = 231;
|
||||
action->spell = spell_id;
|
||||
action->buff_unknown = 4;
|
||||
action->effect_flag = 4;
|
||||
|
||||
cd->target = action->target;
|
||||
cd->source = action->source;
|
||||
cd->type = action->type;
|
||||
cd->spellid = action->spell;
|
||||
cd->meleepush_xy = action->sequence;
|
||||
cd->hit_heading = action->hit_heading;
|
||||
|
||||
CastToClient()->QueuePacket(action_packet);
|
||||
if(caster && caster->IsClient() && caster != this)
|
||||
@@ -967,16 +967,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
action->source = caster ? caster->GetID() : GetID();
|
||||
action->level = 65;
|
||||
action->instrument_mod = 10;
|
||||
action->sequence = static_cast<uint32>((GetHeading() * 12345 / 2));
|
||||
action->hit_heading = GetHeading();
|
||||
action->type = 231;
|
||||
action->spell = spell_id;
|
||||
action->buff_unknown = 4;
|
||||
action->effect_flag = 4;
|
||||
|
||||
cd->target = action->target;
|
||||
cd->source = action->source;
|
||||
cd->type = action->type;
|
||||
cd->spellid = action->spell;
|
||||
cd->meleepush_xy = action->sequence;
|
||||
cd->hit_heading = action->hit_heading;
|
||||
|
||||
CastToClient()->QueuePacket(action_packet);
|
||||
if(caster->IsClient() && caster != this)
|
||||
@@ -1006,16 +1006,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
action->source = caster ? caster->GetID() : GetID();
|
||||
action->level = 65;
|
||||
action->instrument_mod = 10;
|
||||
action->sequence = static_cast<uint32>((GetHeading() * 12345 / 2));
|
||||
action->hit_heading = GetHeading();
|
||||
action->type = 231;
|
||||
action->spell = spell_id;
|
||||
action->buff_unknown = 4;
|
||||
action->effect_flag = 4;
|
||||
|
||||
cd->target = action->target;
|
||||
cd->source = action->source;
|
||||
cd->type = action->type;
|
||||
cd->spellid = action->spell;
|
||||
cd->meleepush_xy = action->sequence;
|
||||
cd->hit_heading = action->hit_heading;
|
||||
|
||||
CastToClient()->QueuePacket(action_packet);
|
||||
if(caster->IsClient() && caster != this)
|
||||
@@ -2080,61 +2080,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Toss Up: %d", effect_value);
|
||||
#endif
|
||||
double toss_amt = (double)spells[spell_id].base[i];
|
||||
if(toss_amt < 0)
|
||||
toss_amt = -toss_amt;
|
||||
|
||||
if(IsNPC())
|
||||
{
|
||||
Stun(static_cast<int>(toss_amt));
|
||||
if (IsNPC()) {
|
||||
Damage(caster, std::abs(effect_value), spell_id, spell.skill, false, buffslot, false);
|
||||
}
|
||||
toss_amt = sqrt(toss_amt)-2.0;
|
||||
|
||||
if(toss_amt < 0.0)
|
||||
toss_amt = 0.0;
|
||||
|
||||
if(toss_amt > 20.0)
|
||||
toss_amt = 20.0;
|
||||
|
||||
if(IsClient())
|
||||
{
|
||||
CastToClient()->SetKnockBackExemption(true);
|
||||
}
|
||||
|
||||
double look_heading = GetHeading();
|
||||
look_heading /= 256;
|
||||
look_heading *= 360;
|
||||
look_heading += 180;
|
||||
if(look_heading > 360)
|
||||
look_heading -= 360;
|
||||
|
||||
//x and y are crossed mkay
|
||||
double new_x = spells[spell_id].pushback * sin(double(look_heading * 3.141592 / 180.0));
|
||||
double new_y = spells[spell_id].pushback * cos(double(look_heading * 3.141592 / 180.0));
|
||||
|
||||
auto outapp_push =
|
||||
new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)outapp_push->pBuffer;
|
||||
|
||||
spu->spawn_id = GetID();
|
||||
spu->x_pos = FloatToEQ19(GetX());
|
||||
spu->y_pos = FloatToEQ19(GetY());
|
||||
spu->z_pos = FloatToEQ19(GetZ());
|
||||
spu->delta_x = FloatToEQ13(new_x);
|
||||
spu->delta_y = FloatToEQ13(new_y);
|
||||
spu->delta_z = FloatToEQ13(toss_amt);
|
||||
spu->heading = FloatToEQ12(GetHeading());
|
||||
spu->padding0002 =0;
|
||||
spu->padding0006 =7;
|
||||
spu->padding0014 =0x7f;
|
||||
spu->padding0018 =0x5df27;
|
||||
spu->animation = 0;
|
||||
spu->delta_heading = FloatToEQ10(0);
|
||||
outapp_push->priority = 5;
|
||||
entity_list.QueueClients(this, outapp_push, true);
|
||||
if(IsClient())
|
||||
CastToClient()->FastQueuePacket(&outapp_push);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+35
-87
@@ -82,6 +82,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
#include "nats_manager.h"
|
||||
#include "fastmath.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
@@ -106,6 +107,7 @@ extern Zone* zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern WorldServer worldserver;
|
||||
extern NatsManager nats;
|
||||
extern FastMath g_Math;
|
||||
|
||||
using EQEmu::CastingSlot;
|
||||
|
||||
@@ -1213,7 +1215,10 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
|
||||
// handle the components for traditional casters
|
||||
else {
|
||||
if(c->GetInv().HasItem(component, component_count, invWhereWorn|invWherePersonal) == -1) // item not found
|
||||
if (!RuleB(Character, PetsUseReagents) && IsEffectInSpell(spell_id, SE_SummonPet)) {
|
||||
//bypass reagent cost
|
||||
}
|
||||
else if(c->GetInv().HasItem(component, component_count, invWhereWorn|invWherePersonal) == -1) // item not found
|
||||
{
|
||||
if (!missingreags)
|
||||
{
|
||||
@@ -1243,6 +1248,9 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!RuleB(Character, PetsUseReagents) && IsEffectInSpell(spell_id, SE_SummonPet)) {
|
||||
//bypass reagent cost
|
||||
}
|
||||
else if (!bard_song_mode)
|
||||
{
|
||||
int noexpend;
|
||||
@@ -2651,20 +2659,18 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
|
||||
action->source = caster->GetID();
|
||||
action->target = GetID();
|
||||
action->spell = spell_id;
|
||||
action->sequence = (uint32) (GetHeading()); // just some random number
|
||||
action->force = spells[spell_id].pushback;
|
||||
action->hit_heading = GetHeading();
|
||||
action->hit_pitch = spells[spell_id].pushup;
|
||||
action->instrument_mod = caster->GetInstrumentMod(spell_id);
|
||||
action->buff_unknown = 0;
|
||||
action->level = buffs[buffs_i].casterlevel;
|
||||
action->effect_flag = 0;
|
||||
action->spell_level = action->level = buffs[buffs_i].casterlevel;
|
||||
action->type = DamageTypeSpell;
|
||||
entity_list.QueueCloseClients(this, packet, false, RuleI(Range, SongMessages), 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
|
||||
|
||||
action->buff_unknown = 4;
|
||||
action->effect_flag = 4;
|
||||
|
||||
if(IsEffectInSpell(spell_id, SE_TossUp))
|
||||
{
|
||||
action->buff_unknown = 0;
|
||||
}
|
||||
else if(spells[spell_id].pushback > 0 || spells[spell_id].pushup > 0)
|
||||
if(spells[spell_id].pushback != 0.0f || spells[spell_id].pushup != 0.0f)
|
||||
{
|
||||
if(IsClient())
|
||||
{
|
||||
@@ -2672,38 +2678,6 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
|
||||
{
|
||||
CastToClient()->SetKnockBackExemption(true);
|
||||
|
||||
action->buff_unknown = 0;
|
||||
auto outapp_push = new EQApplicationPacket(
|
||||
OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)outapp_push->pBuffer;
|
||||
|
||||
double look_heading = caster->CalculateHeadingToTarget(GetX(), GetY());
|
||||
look_heading /= 256;
|
||||
look_heading *= 360;
|
||||
if(look_heading > 360)
|
||||
look_heading -= 360;
|
||||
|
||||
//x and y are crossed mkay
|
||||
double new_x = spells[spell_id].pushback * sin(double(look_heading * 3.141592 / 180.0));
|
||||
double new_y = spells[spell_id].pushback * cos(double(look_heading * 3.141592 / 180.0));
|
||||
|
||||
spu->spawn_id = GetID();
|
||||
spu->x_pos = FloatToEQ19(GetX());
|
||||
spu->y_pos = FloatToEQ19(GetY());
|
||||
spu->z_pos = FloatToEQ19(GetZ());
|
||||
spu->delta_x = FloatToEQ13(new_x);
|
||||
spu->delta_y = FloatToEQ13(new_y);
|
||||
spu->delta_z = FloatToEQ13(spells[spell_id].pushup);
|
||||
spu->heading = FloatToEQ12(GetHeading());
|
||||
spu->padding0002 =0;
|
||||
spu->padding0006 =7;
|
||||
spu->padding0014 =0x7f;
|
||||
spu->padding0018 =0x5df27;
|
||||
spu->animation = 0;
|
||||
spu->delta_heading = FloatToEQ10(0);
|
||||
outapp_push->priority = 6;
|
||||
entity_list.QueueClients(this, outapp_push, true);
|
||||
CastToClient()->FastQueuePacket(&outapp_push);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2724,7 +2698,9 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
|
||||
cd->source = action->source;
|
||||
cd->type = DamageTypeSpell;
|
||||
cd->spellid = action->spell;
|
||||
cd->meleepush_xy = action->sequence;
|
||||
cd->force = action->force;
|
||||
cd->hit_heading = action->hit_heading;
|
||||
cd->hit_pitch = action->hit_pitch;
|
||||
cd->damage = 0;
|
||||
if(!IsEffectInSpell(spell_id, SE_BindAffinity))
|
||||
{
|
||||
@@ -3532,12 +3508,14 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
||||
action->target = spelltar->GetID();
|
||||
}
|
||||
|
||||
action->level = caster_level; // caster level, for animation only
|
||||
action->spell_level = action->level = caster_level; // caster level, for animation only
|
||||
action->type = 231; // 231 means a spell
|
||||
action->spell = spell_id;
|
||||
action->sequence = (uint32) (GetHeading()); // just some random number
|
||||
action->force = spells[spell_id].pushback;
|
||||
action->hit_heading = GetHeading();
|
||||
action->hit_pitch = spells[spell_id].pushup;
|
||||
action->instrument_mod = GetInstrumentMod(spell_id);
|
||||
action->buff_unknown = 0;
|
||||
action->effect_flag = 0;
|
||||
|
||||
if(spelltar != this && spelltar->IsClient()) // send to target
|
||||
spelltar->CastToClient()->QueuePacket(action_packet);
|
||||
@@ -3964,53 +3942,21 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
||||
// NOTE: this is what causes the buff icon to appear on the client, if
|
||||
// this is a buff - but it sortof relies on the first packet.
|
||||
// the complete sequence is 2 actions and 1 damage message
|
||||
action->buff_unknown = 0x04; // this is a success flag
|
||||
action->effect_flag = 0x04; // this is a success flag
|
||||
|
||||
if(IsEffectInSpell(spell_id, SE_TossUp))
|
||||
{
|
||||
action->buff_unknown = 0;
|
||||
}
|
||||
else if(spells[spell_id].pushback > 0 || spells[spell_id].pushup > 0)
|
||||
if(spells[spell_id].pushback != 0.0f || spells[spell_id].pushup != 0.0f)
|
||||
{
|
||||
if(spelltar->IsClient())
|
||||
{
|
||||
if(!IsBuffSpell(spell_id))
|
||||
{
|
||||
spelltar->CastToClient()->SetKnockBackExemption(true);
|
||||
|
||||
action->buff_unknown = 0;
|
||||
auto outapp_push =
|
||||
new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||
PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)outapp_push->pBuffer;
|
||||
|
||||
double look_heading = CalculateHeadingToTarget(spelltar->GetX(), spelltar->GetY());
|
||||
look_heading /= 256;
|
||||
look_heading *= 360;
|
||||
if(look_heading > 360)
|
||||
look_heading -= 360;
|
||||
|
||||
//x and y are crossed mkay
|
||||
double new_x = spells[spell_id].pushback * sin(double(look_heading * 3.141592 / 180.0));
|
||||
double new_y = spells[spell_id].pushback * cos(double(look_heading * 3.141592 / 180.0));
|
||||
|
||||
spu->spawn_id = spelltar->GetID();
|
||||
spu->x_pos = FloatToEQ19(spelltar->GetX());
|
||||
spu->y_pos = FloatToEQ19(spelltar->GetY());
|
||||
spu->z_pos = FloatToEQ19(spelltar->GetZ());
|
||||
spu->delta_x = FloatToEQ13(new_x);
|
||||
spu->delta_y = FloatToEQ13(new_y);
|
||||
spu->delta_z = FloatToEQ13(spells[spell_id].pushup);
|
||||
spu->heading = FloatToEQ12(spelltar->GetHeading());
|
||||
spu->padding0002 =0;
|
||||
spu->padding0006 =7;
|
||||
spu->padding0014 =0x7f;
|
||||
spu->padding0018 =0x5df27;
|
||||
spu->animation = 0;
|
||||
spu->delta_heading = FloatToEQ10(0);
|
||||
outapp_push->priority = 6;
|
||||
entity_list.QueueClients(this, outapp_push, true);
|
||||
spelltar->CastToClient()->FastQueuePacket(&outapp_push);
|
||||
}
|
||||
} else if (RuleB(Spells, NPCSpellPush) && !spelltar->IsRooted() && spelltar->ForcedMovement == 0) {
|
||||
spelltar->m_Delta.x += action->force * g_Math.FastSin(action->hit_heading);
|
||||
spelltar->m_Delta.y += action->force * g_Math.FastCos(action->hit_heading);
|
||||
spelltar->m_Delta.z += action->hit_pitch;
|
||||
spelltar->ForcedMovement = 6;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4038,7 +3984,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
||||
cd->source = action->source;
|
||||
cd->type = action->type;
|
||||
cd->spellid = action->spell;
|
||||
cd->meleepush_xy = action->sequence;
|
||||
cd->force = action->force;
|
||||
cd->hit_heading = action->hit_heading;
|
||||
cd->hit_pitch = action->hit_pitch;
|
||||
cd->damage = 0;
|
||||
if(!IsEffectInSpell(spell_id, SE_BindAffinity)){
|
||||
entity_list.QueueCloseClients(
|
||||
@@ -5722,7 +5670,7 @@ void Client::SendSpellAnim(uint16 targetid, uint16 spell_id)
|
||||
a->source = this->GetID();
|
||||
a->type = 231;
|
||||
a->spell = spell_id;
|
||||
a->sequence = 231;
|
||||
a->hit_heading = GetHeading();
|
||||
|
||||
app.priority = 1;
|
||||
entity_list.QueueCloseClients(this, &app, false, RuleI(Range, SpellParticles));
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
#define FAIL_DISARM_DETECTED_TRAP 370 //You fail to disarm the detected trap.
|
||||
#define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one.
|
||||
#define PICK_LORE 379 //You cannot pick up a lore item you already possess.
|
||||
#define POISON_TOO_HIGH 382 // This poison is too high level for you to apply.
|
||||
#define CONSENT_DENIED 390 //You do not have consent to summon that corpse.
|
||||
#define DISCIPLINE_RDY 393 //You are ready to use a new discipline now.
|
||||
#define CONSENT_INVALID_NAME 397 //Not a valid consent name.
|
||||
|
||||
+1
-2
@@ -2804,8 +2804,7 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN
|
||||
if (strlen(Tasks[TaskID]->Reward) != 0)
|
||||
linker.SetProxyText(Tasks[TaskID]->Reward);
|
||||
|
||||
auto reward_link = linker.GenerateLink();
|
||||
reward_text.append(reward_link);
|
||||
reward_text.append(linker.GenerateLink());
|
||||
}
|
||||
else {
|
||||
reward_text.append(Tasks[TaskID]->Reward);
|
||||
|
||||
+1
-1
@@ -218,7 +218,7 @@ void Trap::Trigger(Mob* trigger)
|
||||
int dmg = zone->random.Int(effectvalue, effectvalue2);
|
||||
trigger->SetHP(trigger->GetHP() - dmg);
|
||||
a->damage = dmg;
|
||||
a->meleepush_xy = zone->random.Int(0, 1234567);
|
||||
a->hit_heading = 0.0f;
|
||||
a->source = GetHiddenTrigger()!=nullptr ? GetHiddenTrigger()->GetID() : trigger->GetID();
|
||||
a->spellid = 0;
|
||||
a->target = trigger->GetID();
|
||||
|
||||
@@ -29,10 +29,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "npc.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "water_map.h"
|
||||
#include "fastmath.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern FastMath g_Math;
|
||||
|
||||
struct wp_distance
|
||||
{
|
||||
float dist;
|
||||
@@ -990,6 +993,35 @@ float Mob::GetZOffset() const {
|
||||
return 0.2 * GetSize() * offset;
|
||||
}
|
||||
|
||||
// This function will try to move the mob along the relative angle a set distance
|
||||
// if it can't be moved, it will lower the distance and try again
|
||||
// If we want to move on like say a spawn, we can pass send as false
|
||||
void Mob::TryMoveAlong(float distance, float angle, bool send)
|
||||
{
|
||||
angle += GetHeading();
|
||||
angle = FixHeading(angle);
|
||||
|
||||
glm::vec3 tmp_pos;
|
||||
glm::vec3 new_pos = GetPosition();
|
||||
new_pos.x += distance * g_Math.FastSin(angle);
|
||||
new_pos.y += distance * g_Math.FastCos(angle);
|
||||
new_pos.z += GetZOffset();
|
||||
|
||||
if (zone->HasMap()) {
|
||||
auto new_z = zone->zonemap->FindClosestZ(new_pos, nullptr);
|
||||
if (new_z != BEST_Z_INVALID)
|
||||
new_pos.z = new_z;
|
||||
|
||||
if (zone->zonemap->LineIntersectsZone(GetPosition(), new_pos, 0.0f, &tmp_pos))
|
||||
new_pos = tmp_pos;
|
||||
}
|
||||
|
||||
new_pos.z = GetFixedZ(new_pos);
|
||||
Teleport(new_pos);
|
||||
if (send)
|
||||
SendPositionUpdate();
|
||||
}
|
||||
|
||||
int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
|
||||
|
||||
std::string query = StringFormat("SELECT COALESCE(MAX(id), 0) FROM grid WHERE zoneid = %i", zoneid);
|
||||
|
||||
@@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <stdio.h>
|
||||
#include <iomanip>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <process.h>
|
||||
@@ -1813,6 +1814,13 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_UCSServerStatusReply:
|
||||
{
|
||||
auto ucsss = (UCSServerStatus_Struct*)pack->pBuffer;
|
||||
if (zone)
|
||||
zone->SetUCSServerAvailable((ucsss->available != 0), ucsss->timestamp);
|
||||
break;
|
||||
}
|
||||
case ServerOP_CZSetEntityVariableByNPCTypeID:
|
||||
{
|
||||
CZSetEntVarByNPCTypeID_Struct* CZM = (CZSetEntVarByNPCTypeID_Struct*)pack->pBuffer;
|
||||
|
||||
+29
-2
@@ -146,6 +146,8 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
|
||||
UpdateWindowTitle();
|
||||
zone->GetTimeSync();
|
||||
|
||||
zone->RequestUCSServerStatus();
|
||||
|
||||
/* Set Logging */
|
||||
|
||||
LogSys.StartFileLogs(StringFormat("%s_version_%u_inst_id_%u_port_%u", zone->GetShortName(), zone->GetInstanceVersion(), zone->GetInstanceID(), ZoneConfig::get()->ZonePort));
|
||||
@@ -847,6 +849,9 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
GuildBanks = new GuildBankManager;
|
||||
else
|
||||
GuildBanks = nullptr;
|
||||
|
||||
m_ucss_available = false;
|
||||
m_last_ucss_update = 0;
|
||||
}
|
||||
|
||||
Zone::~Zone() {
|
||||
@@ -1863,14 +1868,17 @@ bool ZoneDatabase::GetDecayTimes(npcDecayTimes_Struct* npcCorpseDecayTimes) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Zone::weatherSend()
|
||||
void Zone::weatherSend(Client* client)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_Weather, 8);
|
||||
if(zone_weather>0)
|
||||
outapp->pBuffer[0] = zone_weather-1;
|
||||
if(zone_weather>0)
|
||||
outapp->pBuffer[4] = zone->weather_intensity;
|
||||
entity_list.QueueClients(0, outapp);
|
||||
if (client)
|
||||
client->QueuePacket(outapp);
|
||||
else
|
||||
entity_list.QueueClients(0, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
@@ -2336,3 +2344,22 @@ void Zone::UpdateHotzone()
|
||||
is_hotzone = atoi(row[0]) == 0 ? false: true;
|
||||
}
|
||||
|
||||
void Zone::RequestUCSServerStatus() {
|
||||
auto outapp = new ServerPacket(ServerOP_UCSServerStatusRequest, sizeof(UCSServerStatus_Struct));
|
||||
auto ucsss = (UCSServerStatus_Struct*)outapp->pBuffer;
|
||||
ucsss->available = 0;
|
||||
ucsss->port = Config->ZonePort;
|
||||
ucsss->unused = 0;
|
||||
worldserver.SendPacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
|
||||
if (m_last_ucss_update == update_timestamp && m_ucss_available != ucss_available) {
|
||||
m_ucss_available = false;
|
||||
RequestUCSServerStatus();
|
||||
return;
|
||||
}
|
||||
if (m_last_ucss_update < update_timestamp)
|
||||
m_ucss_available = ucss_available;
|
||||
}
|
||||
|
||||
+8
-1
@@ -224,7 +224,7 @@ public:
|
||||
void SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute);
|
||||
void SetTime(uint8 hour, uint8 minute, bool update_world = true);
|
||||
|
||||
void weatherSend();
|
||||
void weatherSend(Client* client = nullptr);
|
||||
bool CanBind() const { return(can_bind); }
|
||||
bool IsCity() const { return(is_city); }
|
||||
bool CanDoCombat() const { return(can_combat); }
|
||||
@@ -275,6 +275,10 @@ public:
|
||||
inline void ShowZoneGlobalLoot(Client *to) { m_global_loot.ShowZoneGlobalLoot(to); }
|
||||
inline void ShowNPCGlobalLoot(Client *to, NPC *who) { m_global_loot.ShowNPCGlobalLoot(to, who); }
|
||||
|
||||
void RequestUCSServerStatus();
|
||||
void SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp);
|
||||
bool IsUCSServerAvailable() { return m_ucss_available; }
|
||||
|
||||
// random object that provides random values for the zone
|
||||
EQEmu::Random random;
|
||||
|
||||
@@ -355,6 +359,9 @@ private:
|
||||
Timer hotzone_timer;
|
||||
|
||||
GlobalLootManager m_global_loot;
|
||||
|
||||
bool m_ucss_available;
|
||||
uint32 m_last_ucss_update;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+247
-44
@@ -325,62 +325,260 @@ bool ZoneDatabase::logevents(const char* accountname,uint32 accountid,uint8 stat
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneDatabase::RegisterBug(BugReport_Struct* bug_report) {
|
||||
if (!bug_report)
|
||||
return;
|
||||
|
||||
void ZoneDatabase::UpdateBug(BugStruct* bug) {
|
||||
|
||||
uint32 len = strlen(bug->bug);
|
||||
char* bugtext = nullptr;
|
||||
if(len > 0)
|
||||
{
|
||||
bugtext = new char[2*len+1];
|
||||
memset(bugtext, 0, 2*len+1);
|
||||
DoEscapeString(bugtext, bug->bug, len);
|
||||
size_t len = 0;
|
||||
char* name_ = nullptr;
|
||||
char* ui_ = nullptr;
|
||||
char* type_ = nullptr;
|
||||
char* target_ = nullptr;
|
||||
char* bug_ = nullptr;
|
||||
|
||||
len = strlen(bug_report->reporter_name);
|
||||
if (len) {
|
||||
if (len > 63) // check against db column size
|
||||
len = 63;
|
||||
name_ = new char[(2 * len + 1)];
|
||||
memset(name_, 0, (2 * len + 1));
|
||||
DoEscapeString(name_, bug_report->reporter_name, len);
|
||||
}
|
||||
|
||||
len = strlen(bug->ui);
|
||||
char* uitext = nullptr;
|
||||
if(len > 0)
|
||||
{
|
||||
uitext = new char[2*len+1];
|
||||
memset(uitext, 0, 2*len+1);
|
||||
DoEscapeString(uitext, bug->ui, len);
|
||||
len = strlen(bug_report->ui_path);
|
||||
if (len) {
|
||||
if (len > 127)
|
||||
len = 127;
|
||||
ui_ = new char[(2 * len + 1)];
|
||||
memset(ui_, 0, (2 * len + 1));
|
||||
DoEscapeString(ui_, bug_report->ui_path, len);
|
||||
}
|
||||
|
||||
len = strlen(bug->target_name);
|
||||
char* targettext = nullptr;
|
||||
if(len > 0)
|
||||
{
|
||||
targettext = new char[2*len+1];
|
||||
memset(targettext, 0, 2*len+1);
|
||||
DoEscapeString(targettext, bug->target_name, len);
|
||||
len = strlen(bug_report->category_name);
|
||||
if (len) {
|
||||
if (len > 63)
|
||||
len = 63;
|
||||
type_ = new char[(2 * len + 1)];
|
||||
memset(type_, 0, (2 * len + 1));
|
||||
DoEscapeString(type_, bug_report->category_name, len);
|
||||
}
|
||||
|
||||
//x and y are intentionally swapped because eq is inversexy coords
|
||||
std::string query = StringFormat("INSERT INTO bugs (zone, name, ui, x, y, z, type, flag, target, bug, date) "
|
||||
len = strlen(bug_report->target_name);
|
||||
if (len) {
|
||||
if (len > 63)
|
||||
len = 63;
|
||||
target_ = new char[(2 * len + 1)];
|
||||
memset(target_, 0, (2 * len + 1));
|
||||
DoEscapeString(target_, bug_report->target_name, len);
|
||||
}
|
||||
|
||||
len = strlen(bug_report->bug_report);
|
||||
if (len) {
|
||||
if (len > 1023)
|
||||
len = 1023;
|
||||
bug_ = new char[(2 * len + 1)];
|
||||
memset(bug_, 0, (2 * len + 1));
|
||||
DoEscapeString(bug_, bug_report->bug_report, len);
|
||||
}
|
||||
|
||||
//x and y are intentionally swapped because eq is inversexy coords //is this msg out-of-date or are the parameters wrong?
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO `bugs` (`zone`, `name`, `ui`, `x`, `y`, `z`, `type`, `flag`, `target`, `bug`, `date`) "
|
||||
"VALUES('%s', '%s', '%s', '%.2f', '%.2f', '%.2f', '%s', %d, '%s', '%s', CURDATE())",
|
||||
zone->GetShortName(), bug->name, uitext == nullptr ? "": uitext,
|
||||
bug->x, bug->y, bug->z, bug->chartype, bug->type, targettext == nullptr? "Unknown Target": targettext,
|
||||
bugtext==nullptr?"":bugtext);
|
||||
safe_delete_array(bugtext);
|
||||
safe_delete_array(uitext);
|
||||
safe_delete_array(targettext);
|
||||
zone->GetShortName(),
|
||||
(name_ ? name_ : ""),
|
||||
(ui_ ? ui_ : ""),
|
||||
bug_report->pos_x,
|
||||
bug_report->pos_y,
|
||||
bug_report->pos_z,
|
||||
(type_ ? type_ : ""),
|
||||
bug_report->optional_info_mask,
|
||||
(target_ ? target_ : "Unknown Target"),
|
||||
(bug_ ? bug_ : "")
|
||||
);
|
||||
safe_delete_array(name_);
|
||||
safe_delete_array(ui_);
|
||||
safe_delete_array(type_);
|
||||
safe_delete_array(target_);
|
||||
safe_delete_array(bug_);
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug){
|
||||
void ZoneDatabase::RegisterBug(Client* client, BugReport_Struct* bug_report) {
|
||||
if (!client || !bug_report)
|
||||
return;
|
||||
|
||||
uint32 len = strlen(bug->text);
|
||||
auto bugtext = new char[2 * len + 1];
|
||||
memset(bugtext, 0, 2*len+1);
|
||||
DoEscapeString(bugtext, bug->text, len);
|
||||
size_t len = 0;
|
||||
char* category_name_ = nullptr;
|
||||
char* reporter_name_ = nullptr;
|
||||
char* ui_path_ = nullptr;
|
||||
char* target_name_ = nullptr;
|
||||
char* bug_report_ = nullptr;
|
||||
char* system_info_ = nullptr;
|
||||
|
||||
std::string query = StringFormat("INSERT INTO bugs (type, name, bugtext, flag) "
|
||||
"VALUES('%s', '%s', '%s', %i)",
|
||||
"Petition", bug->name, bugtext, 25);
|
||||
safe_delete_array(bugtext);
|
||||
QueryDatabase(query);
|
||||
len = strlen(bug_report->category_name);
|
||||
if (len) {
|
||||
if (len > 63) // check against db column size
|
||||
len = 63;
|
||||
category_name_ = new char[(2 * len + 1)];
|
||||
memset(category_name_, 0, (2 * len + 1));
|
||||
DoEscapeString(category_name_, bug_report->category_name, len);
|
||||
}
|
||||
|
||||
len = strlen(bug_report->reporter_name);
|
||||
if (len) {
|
||||
if (len > 63)
|
||||
len = 63;
|
||||
reporter_name_ = new char[(2 * len + 1)];
|
||||
memset(reporter_name_, 0, (2 * len + 1));
|
||||
DoEscapeString(reporter_name_, bug_report->reporter_name, len);
|
||||
}
|
||||
|
||||
len = strlen(bug_report->ui_path);
|
||||
if (len) {
|
||||
if (len > 127)
|
||||
len = 127;
|
||||
ui_path_ = new char[(2 * len + 1)];
|
||||
memset(ui_path_, 0, (2 * len + 1));
|
||||
DoEscapeString(ui_path_, bug_report->ui_path, len);
|
||||
}
|
||||
|
||||
len = strlen(bug_report->target_name);
|
||||
if (len) {
|
||||
if (len > 63)
|
||||
len = 63;
|
||||
target_name_ = new char[(2 * len + 1)];
|
||||
memset(target_name_, 0, (2 * len + 1));
|
||||
DoEscapeString(target_name_, bug_report->target_name, len);
|
||||
}
|
||||
|
||||
len = strlen(bug_report->bug_report);
|
||||
if (len) {
|
||||
if (len > 1023)
|
||||
len = 1023;
|
||||
bug_report_ = new char[(2 * len + 1)];
|
||||
memset(bug_report_, 0, (2 * len + 1));
|
||||
DoEscapeString(bug_report_, bug_report->bug_report, len);
|
||||
}
|
||||
|
||||
len = strlen(bug_report->system_info);
|
||||
if (len) {
|
||||
if (len > 1023)
|
||||
len = 1023;
|
||||
system_info_ = new char[(2 * len + 1)];
|
||||
memset(system_info_, 0, (2 * len + 1));
|
||||
DoEscapeString(system_info_, bug_report->system_info, len);
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO `bug_reports` "
|
||||
"(`zone`,"
|
||||
" `client_version_id`,"
|
||||
" `client_version_name`,"
|
||||
" `account_id`,"
|
||||
" `character_id`,"
|
||||
" `character_name`,"
|
||||
" `reporter_spoof`,"
|
||||
" `category_id`,"
|
||||
" `category_name`,"
|
||||
" `reporter_name`,"
|
||||
" `ui_path`,"
|
||||
" `pos_x`,"
|
||||
" `pos_y`,"
|
||||
" `pos_z`,"
|
||||
" `heading`,"
|
||||
" `time_played`,"
|
||||
" `target_id`,"
|
||||
" `target_name`,"
|
||||
" `optional_info_mask`,"
|
||||
" `_can_duplicate`,"
|
||||
" `_crash_bug`,"
|
||||
" `_target_info`,"
|
||||
" `_character_flags`,"
|
||||
" `_unknown_value`,"
|
||||
" `bug_report`,"
|
||||
" `system_info`) "
|
||||
"VALUES "
|
||||
"('%s',"
|
||||
" '%u',"
|
||||
" '%s',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%s',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%s',"
|
||||
" '%s',"
|
||||
" '%s',"
|
||||
" '%1.1f',"
|
||||
" '%1.1f',"
|
||||
" '%1.1f',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%s',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%u',"
|
||||
" '%s',"
|
||||
" '%s')",
|
||||
zone->GetShortName(),
|
||||
client->ClientVersion(),
|
||||
EQEmu::versions::ClientVersionName(client->ClientVersion()),
|
||||
client->AccountID(),
|
||||
client->CharacterID(),
|
||||
client->GetName(),
|
||||
(strcmp(client->GetName(), reporter_name_) != 0 ? 1 : 0),
|
||||
bug_report->category_id,
|
||||
(category_name_ ? category_name_ : ""),
|
||||
(reporter_name_ ? reporter_name_ : ""),
|
||||
(ui_path_ ? ui_path_ : ""),
|
||||
bug_report->pos_x,
|
||||
bug_report->pos_y,
|
||||
bug_report->pos_z,
|
||||
bug_report->heading,
|
||||
bug_report->time_played,
|
||||
bug_report->target_id,
|
||||
(target_name_ ? target_name_ : ""),
|
||||
bug_report->optional_info_mask,
|
||||
((bug_report->optional_info_mask & EQEmu::bug::infoCanDuplicate) != 0 ? 1 : 0),
|
||||
((bug_report->optional_info_mask & EQEmu::bug::infoCrashBug) != 0 ? 1 : 0),
|
||||
((bug_report->optional_info_mask & EQEmu::bug::infoTargetInfo) != 0 ? 1 : 0),
|
||||
((bug_report->optional_info_mask & EQEmu::bug::infoCharacterFlags) != 0 ? 1 : 0),
|
||||
((bug_report->optional_info_mask & EQEmu::bug::infoUnknownValue) != 0 ? 1 : 0),
|
||||
(bug_report_ ? bug_report_ : ""),
|
||||
(system_info_ ? system_info_ : "")
|
||||
);
|
||||
safe_delete_array(category_name_);
|
||||
safe_delete_array(reporter_name_);
|
||||
safe_delete_array(ui_path_);
|
||||
safe_delete_array(target_name_);
|
||||
safe_delete_array(bug_report_);
|
||||
safe_delete_array(system_info_);
|
||||
|
||||
auto result = QueryDatabase(query);
|
||||
|
||||
// TODO: Entity dumping [RuleB(Bugs, DumpTargetEntity)]
|
||||
}
|
||||
|
||||
//void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug) {
|
||||
//
|
||||
// uint32 len = strlen(bug->text);
|
||||
// auto bugtext = new char[2 * len + 1];
|
||||
// memset(bugtext, 0, 2 * len + 1);
|
||||
// DoEscapeString(bugtext, bug->text, len);
|
||||
//
|
||||
// std::string query = StringFormat("INSERT INTO bugs (type, name, bugtext, flag) "
|
||||
// "VALUES('%s', '%s', '%s', %i)",
|
||||
// "Petition", bug->name, bugtext, 25);
|
||||
// safe_delete_array(bugtext);
|
||||
// QueryDatabase(query);
|
||||
//}
|
||||
|
||||
bool ZoneDatabase::SetSpecialAttkFlag(uint8 id, const char* flag) {
|
||||
|
||||
std::string query = StringFormat("UPDATE npc_types SET npcspecialattks='%s' WHERE id = %i;", flag, id);
|
||||
@@ -1425,6 +1623,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
if (account_id <= 0)
|
||||
return false;
|
||||
|
||||
std::string mail_key = database.GetMailKey(character_id);
|
||||
|
||||
clock_t t = std::clock(); /* Function timer start */
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `character_data` ("
|
||||
@@ -1521,7 +1721,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
" e_aa_effects, "
|
||||
" e_percent_to_aa, "
|
||||
" e_expended_aa_spent, "
|
||||
" e_last_invsnapshot "
|
||||
" e_last_invsnapshot, "
|
||||
" mailkey "
|
||||
") "
|
||||
"VALUES ("
|
||||
"%u," // id " id, "
|
||||
@@ -1617,7 +1818,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
"%u," // e_aa_effects
|
||||
"%u," // e_percent_to_aa
|
||||
"%u," // e_expended_aa_spent
|
||||
"%u" // e_last_invsnapshot
|
||||
"%u," // e_last_invsnapshot
|
||||
"'%s'" // mailkey mail_key
|
||||
")",
|
||||
character_id, // " id, "
|
||||
account_id, // " account_id, "
|
||||
@@ -1712,7 +1914,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla
|
||||
m_epp->aa_effects,
|
||||
m_epp->perAA,
|
||||
m_epp->expended_aa,
|
||||
m_epp->last_invsnapshot_time
|
||||
m_epp->last_invsnapshot_time,
|
||||
mail_key.c_str()
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterData %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC);
|
||||
|
||||
+3
-2
@@ -442,8 +442,9 @@ public:
|
||||
bool DeleteMerc(uint32 merc_id);
|
||||
|
||||
/* Petitions */
|
||||
void UpdateBug(BugStruct* bug);
|
||||
void UpdateBug(PetitionBug_Struct* bug);
|
||||
void RegisterBug(BugReport_Struct* bug_report); // old method
|
||||
void RegisterBug(Client* client, BugReport_Struct* bug_report); // new method
|
||||
//void UpdateBug(PetitionBug_Struct* bug);
|
||||
void DeletePetitionFromDB(Petition* wpet);
|
||||
void UpdatePetitionToDB(Petition* wpet);
|
||||
void InsertPetitionToDB(Petition* wpet);
|
||||
|
||||
Reference in New Issue
Block a user