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:
Xackery
2018-03-10 13:59:48 -08:00
96 changed files with 3580 additions and 2398 deletions
+2
View File
@@ -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
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+4 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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)) {
+1
View File
@@ -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
View File
@@ -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();
+1
View File
@@ -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
View File
@@ -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());
}
}
}
+2
View File
@@ -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());
+35
View File
@@ -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;
}
+18
View File
@@ -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
View File
@@ -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)
{
/*
+12
View File
@@ -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)
+2
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -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
View File
@@ -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;
+8
View File
@@ -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
View File
@@ -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;
+2 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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));
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+32
View File
@@ -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);
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);