[Messages] Add GM Status and Invulnerability Messages (#4266)

* [Messages] Add GM Status and Invulnerability Messages

* Update zoning.cpp

* Finalize.

* Update corpse.cpp

* Update message

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
Alex King 2024-05-04 19:07:17 -04:00 committed by GitHub
parent 34c27ebb2a
commit aa0e53f5fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 364 additions and 149 deletions

View File

@ -1355,6 +1355,10 @@ bool SharedTaskManager::CanRequestSharedTask(uint32_t task_id, const SharedTaskR
return false;
}
if (is_gm) {
client_list.SendCharacterMessage(requester->CharID(), Chat::White, "Your GM Flag allows you to bypass shared task minimum player requirements.");
}
// check if party member count is above the maximum
// todo: live creates the shared task but truncates members if it exceeds max (sorted by leader and raid group numbers)
if (task.max_players > 0 && request.members.size() > task.max_players) {

View File

@ -709,23 +709,28 @@ void Client::CompleteConnect()
}
case SE_Levitate:
{
if (!zone->CanLevitate())
{
if (!GetGM())
{
if (!zone->CanLevitate()) {
if (!GetGM()) {
SendAppearancePacket(AppearanceType::FlyMode, 0);
BuffFadeByEffect(SE_Levitate);
Message(Chat::Red, "You can't levitate in this zone.");
break;
}
Message(Chat::White, "Your GM Flag allows you to levitate in this zone.");
}
else {
if (spell.limit_value[x1] == 1) {
SendAppearancePacket(AppearanceType::FlyMode, EQ::constants::GravityBehavior::LevitateWhileRunning, true, true);
}
else {
SendAppearancePacket(AppearanceType::FlyMode, EQ::constants::GravityBehavior::Levitating, true, true);
}
}
SendAppearancePacket(
AppearanceType::FlyMode,
(
spell.limit_value[x1] == 1 ?
EQ::constants::GravityBehavior::LevitateWhileRunning :
EQ::constants::GravityBehavior::Levitating
),
true,
true
);
break;
}
case SE_AddMeleeProc:
@ -2127,8 +2132,19 @@ void Client::Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app)
if (item->MaxCharges != 0)
charges = item->MaxCharges;
if (RuleB(Character, EnableDiscoveredItems) && !GetGM() && !IsDiscovered(item->ID)) {
DiscoverItem(item->ID);
if (RuleB(Character, EnableDiscoveredItems) && !IsDiscovered(item->ID)) {
if (!GetGM()) {
DiscoverItem(item->ID);
} else {
const std::string& item_link = database.CreateItemLink(item->ID);
Message(
Chat::White,
fmt::format(
"Your GM Flag prevents {} from being added to discovered items.",
item_link
).c_str()
);
}
}
EQ::ItemInstance *inst = database.CreateItem(item, charges);
@ -2682,8 +2698,19 @@ void Client::Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app)
RecordPlayerEventLog(PlayerEvent::MERCHANT_PURCHASE, e);
}
if (RuleB(Character, EnableDiscoveredItems) && !GetGM() && !IsDiscovered(item->ID)) {
DiscoverItem(item->ID);
if (RuleB(Character, EnableDiscoveredItems) && !IsDiscovered(item->ID)) {
if (!GetGM()) {
DiscoverItem(item->ID);
} else {
const std::string& item_link = database.CreateItemLink(item->ID);
Message(
Chat::White,
fmt::format(
"Your GM Flag prevents {} from being added to discovered items.",
item_link
).c_str()
);
}
}
EQ::ItemInstance *inst = database.CreateItem(item, charges);
@ -14214,8 +14241,20 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app)
RecordPlayerEventLog(PlayerEvent::MERCHANT_PURCHASE, e);
}
if (RuleB(Character, EnableDiscoveredItems) && !GetGM() && !IsDiscovered(item_id)) {
DiscoverItem(item_id);
if (RuleB(Character, EnableDiscoveredItems) && !IsDiscovered(item_id)) {
if (!GetGM()) {
DiscoverItem(item_id);
} else {
const std::string& item_link = database.CreateItemLink(item_id);
Message(
Chat::White,
fmt::format(
"Your GM Flag prevents {} from being added to discovered items.",
item_link
).c_str()
);
}
}
t1.stop();

View File

@ -1895,31 +1895,45 @@ void Client::DoManaRegen() {
void Client::DoStaminaHungerUpdate()
{
auto outapp = new EQApplicationPacket(OP_Stamina, sizeof(Stamina_Struct));
Stamina_Struct *sta = (Stamina_Struct *)outapp->pBuffer;
auto sta = (Stamina_Struct*) outapp->pBuffer;
LogFood("hunger_level: [{}] thirst_level: [{}] before loss", m_pp.hunger_level, m_pp.thirst_level);
if (zone->GetZoneID() != 151 && !GetGM()) {
int loss = RuleI(Character, FoodLossPerUpdate);
if (GetHorseId() != 0)
loss *= 3;
if (zone->GetZoneID() != Zones::BAZAAR) {
if (!GetGM()) {
int loss = RuleI(Character, FoodLossPerUpdate);
if (GetHorseId() != 0) {
loss *= 3;
}
m_pp.hunger_level = EQ::Clamp(m_pp.hunger_level - loss, 0, 6000);
m_pp.thirst_level = EQ::Clamp(m_pp.thirst_level - loss, 0, 6000);
if (spellbonuses.hunger) {
m_pp.hunger_level = EQ::ClampLower(m_pp.hunger_level, 3500);
m_pp.thirst_level = EQ::ClampLower(m_pp.thirst_level, 3500);
m_pp.hunger_level = EQ::Clamp(m_pp.hunger_level - loss, 0, 6000);
m_pp.thirst_level = EQ::Clamp(m_pp.thirst_level - loss, 0, 6000);
if (spellbonuses.hunger) {
m_pp.hunger_level = EQ::ClampLower(m_pp.hunger_level, 3500);
m_pp.thirst_level = EQ::ClampLower(m_pp.thirst_level, 3500);
}
sta->food = m_pp.hunger_level;
sta->water = m_pp.thirst_level;
} else {
sta->food = 6000;
sta->water = 6000;
Message(Chat::White, "Your GM Flag prevents you from consuming food or water.");
}
sta->food = m_pp.hunger_level;
sta->water = m_pp.thirst_level;
} else {
// No auto food/drink consumption in the Bazaar
sta->food = 6000;
} else { // No auto food/drink consumption in the Bazaar
sta->food = 6000;
sta->water = 6000;
}
LogFood("Current hunger_level: [{}] = ([{}] minutes left) thirst_level: [{}] = ([{}] minutes left) - after loss",
m_pp.hunger_level, m_pp.hunger_level, m_pp.thirst_level, m_pp.thirst_level);
LogFood(
"Current hunger_level: [{}] = ([{}] minutes left) thirst_level: [{}] = ([{}] minutes left) - after loss",
m_pp.hunger_level,
m_pp.hunger_level,
m_pp.thirst_level,
m_pp.thirst_level
);
FastQueuePacket(&outapp);
}

View File

@ -1159,10 +1159,10 @@ void Corpse::MakeLootRequestPackets(Client *c, const EQApplicationPacket *app)
if (c->GetGM()) {
if (c->Admin() >= AccountStatus::GMAdmin) {
m_loot_request_type = LootRequestType::GMAllowed;
}
else {
c->Message(Chat::White, "Your GM Status allows you to loot any items on this corpse.");
} else {
m_loot_request_type = LootRequestType::GMPeek;
c->Message(Chat::White, "Your GM Flag allows you to look at the items on this corpse.");
}
}
else {
@ -1615,14 +1615,21 @@ void Corpse::LootCorpseItem(Client *c, const EQApplicationPacket *app)
// safe to ACK now
c->QueuePacket(app);
if (
!IsPlayerCorpse() &&
RuleB(Character, EnableDiscoveredItems) &&
c &&
!c->GetGM() &&
!c->IsDiscovered(inst->GetItem()->ID)
) {
c->DiscoverItem(inst->GetItem()->ID);
if (!IsPlayerCorpse()) {
if (RuleB(Character, EnableDiscoveredItems) && c && !c->IsDiscovered(inst->GetItem()->ID)) {
if (!c->GetGM()) {
c->DiscoverItem(inst->GetItem()->ID);
} else {
const std::string& item_link = database.CreateItemLink(inst->GetItem()->ID);
c->Message(
Chat::White,
fmt::format(
"Your GM Flag prevents {} from being added to discovered items.",
item_link
).c_str()
);
}
}
}
if (zone->adv_data) {
@ -2287,10 +2294,14 @@ void Corpse::CastRezz(uint16 spell_id, Mob *caster)
// Rez timer has expired, only GMs can rez at this point. (uses rezzable)
if (!IsRezzable()) {
if (caster && caster->IsClient() && !caster->CastToClient()->GetGM()) {
caster->MessageString(Chat::White, REZZ_ALREADY_PENDING);
caster->MessageString(Chat::White, CORPSE_TOO_OLD);
return;
if (caster && caster->IsClient()) {
if (!caster->CastToClient()->GetGM()) {
caster->MessageString(Chat::White, REZZ_ALREADY_PENDING);
caster->MessageString(Chat::White, CORPSE_TOO_OLD);
return;
}
caster->Message(Chat::White, "Your GM Flag allows you to resurrect this corpse.");
}
}
@ -2302,6 +2313,8 @@ void Corpse::CastRezz(uint16 spell_id, Mob *caster)
if (c->GetGM()) {
m_rezzed_experience = m_gm_rezzed_experience;
m_gm_rezzed_experience = 0;
c->Message(Chat::White, "Your GM Flag allows you to resurrect this corpse and return experience.");
}
}
}

View File

@ -286,13 +286,17 @@ void Doors::HandleClick(Client *sender, uint8 trigger)
// enforce flags before they hit zoning process
auto z = GetZone(m_destination_zone_name, 0);
if (z && !z->flag_needed.empty() && Strings::IsNumber(z->flag_needed) && Strings::ToInt(z->flag_needed) == 1) {
if (!sender->GetGM() && !sender->HasZoneFlag(z->zoneidnumber)) {
LogInfo(
"Character [{}] does not have the flag to be in this zone [{}]!",
sender->GetCleanName(),
z->flag_needed
);
sender->MessageString(Chat::LightBlue, DOORS_LOCKED);
if (!sender->HasZoneFlag(z->zoneidnumber)) {
if (!sender->GetGM()) {
LogInfo(
"Character [{}] does not have the flag to be in this zone [{}]!",
sender->GetCleanName(),
z->flag_needed
);
sender->MessageString(Chat::LightBlue, DOORS_LOCKED);
} else {
sender->Message(Chat::White, "Your GM Flag allows you to use this door.");
}
}
}
@ -318,20 +322,40 @@ void Doors::HandleClick(Client *sender, uint8 trigger)
/**
* Guild Doors
*/
if ((GetGuildID() > 0) && !sender->GetGM()) {
if (GetGuildID() > 0) {
std::string guild_name;
char door_message[240];
const bool has_guild_name = guild_mgr.GetGuildNameByID(m_guild_id, guild_name);
if (!sender->GetGM()) {
std::string door_message;
if (guild_mgr.GetGuildNameByID(m_guild_id, guild_name)) {
sprintf(door_message, "Only members of the <%s> guild may enter here", guild_name.c_str());
}
else {
strcpy(door_message, "Door is locked by an unknown guild");
}
if (has_guild_name) {
door_message = fmt::format(
"Only members of the <{}> guild may enter here.",
guild_name
);
} else {
door_message = "Door is locked by an unknown guild.";
}
sender->Message(Chat::LightBlue, door_message);
safe_delete(outapp);
return;
sender->Message(Chat::LightBlue, door_message.c_str());
safe_delete(outapp);
return;
} else {
sender->Message(
Chat::White,
fmt::format(
"Your GM Flag allows you to use this door{}.",
(
has_guild_name ?
fmt::format(
" assigned to the <{}> guild",
guild_name
) :
""
)
).c_str()
);
}
}
/**
@ -515,8 +539,13 @@ void Doors::HandleClick(Client *sender, uint8 trigger)
}
// teleport door
if (((m_open_type == 57) || (m_open_type == 58)) && HasDestinationZone()) {
bool has_key_required = (required_key_item && ((required_key_item == player_key) || sender->GetGM()));
if (EQ::ValueWithin(m_open_type, 57, 58) && HasDestinationZone()) {
bool has_key_required = (required_key_item && required_key_item == player_key);
if (sender->GetGM() && has_key_required) {
has_key_required = false;
sender->Message(Chat::White, "Your GM Flag allows you to open this door without a key.");
}
if (IsDestinationZoneSame() && (!required_key_item)) {
if (!disable_add_to_key_ring) {

View File

@ -1654,6 +1654,10 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap
if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA
Send = clear_target_window;
if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) {
if (c->GetGM()) {
c->Message(Chat::White, "Your GM Flag allows you to always see your targets' buffs.");
}
Send = !clear_target_window;
} else if (c->IsRaidGrouped()) {
Raid *raid = c->GetRaid();

View File

@ -359,5 +359,9 @@ bool ExpeditionRequest::IsPlayerCountValidated()
});
}
if (gm_bypass) {
m_requester->Message(Chat::White, "Your GM Status allows you to bypass expedition minimum and maximum player restrictions.");
}
return requirements_met;
}

View File

@ -642,13 +642,19 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
sender->SendItemPacket(EQ::invslot::slotCursor, m_inst, ItemPacketTrade);
// Could be an undiscovered ground_spawn
if (
m_ground_spawn &&
RuleB(Character, EnableDiscoveredItems) &&
!sender->GetGM() &&
!sender->IsDiscovered(item->ID)
) {
sender->DiscoverItem(item->ID);
if (m_ground_spawn && RuleB(Character, EnableDiscoveredItems) && !sender->IsDiscovered(item->ID)) {
if (!sender->GetGM()) {
sender->DiscoverItem(item->ID);
} else {
const std::string& item_link = database.CreateItemLink(item->ID);
sender->Message(
Chat::White,
fmt::format(
"Your GM Flag prevents {} from being added to discovered items.",
item_link
).c_str()
);
}
}
if (cursor_delete) { // delete the item if it's a duplicate lore. We have to do this because the client expects the item packet

View File

@ -2961,50 +2961,50 @@ bool QuestManager::createBot(const char *name, const char *lastname, uint8 level
auto spawned_bot_count = Bot::SpawnedBotCount(initiator->CharacterID());
if (
bot_spawn_limit >= 0 &&
spawned_bot_count >= bot_spawn_limit &&
!initiator->GetGM()
) {
std::string message;
if (bot_spawn_limit) {
message = fmt::format(
"You cannot have more than {} spawned bot{}.",
bot_spawn_limit,
bot_spawn_limit != 1 ? "s" : ""
);
} else {
message = "You are not currently allowed to spawn any bots.";
}
if (bot_spawn_limit >= 0 && spawned_bot_count >= bot_spawn_limit) {
if (!initiator->GetGM()) {
std::string message;
if (bot_spawn_limit) {
message = fmt::format(
"You cannot have more than {} spawned bot{}.",
bot_spawn_limit,
bot_spawn_limit != 1 ? "s" : ""
);
} else {
message = "You are not currently allowed to spawn any bots.";
}
initiator->Message(Chat::White, message.c_str());
return false;
initiator->Message(Chat::White, message.c_str());
return false;
} else {
initiator->Message(Chat::White, "Your GM Flag allows you to bypass bot spawn limits.");
}
}
auto spawned_bot_count_class = Bot::SpawnedBotCount(initiator->CharacterID(), botclass);
if (
bot_spawn_limit_class >= 0 &&
spawned_bot_count_class >= bot_spawn_limit_class &&
!initiator->GetGM()
) {
std::string message;
if (bot_spawn_limit_class) {
message = fmt::format(
"You cannot have more than {} spawned {} bot{}.",
bot_spawn_limit_class,
GetClassIDName(botclass),
bot_spawn_limit_class != 1 ? "s" : ""
);
} else {
message = fmt::format(
"You are not currently allowed to spawn any {} bots.",
GetClassIDName(botclass)
);
}
if (bot_spawn_limit_class >= 0 && spawned_bot_count_class >= bot_spawn_limit_class) {
if (!initiator->GetGM()) {
std::string message;
if (bot_spawn_limit_class) {
message = fmt::format(
"You cannot have more than {} spawned {} bot{}.",
bot_spawn_limit_class,
GetClassIDName(botclass),
bot_spawn_limit_class != 1 ? "s" : ""
);
} else {
message = fmt::format(
"You are not currently allowed to spawn any {} bots.",
GetClassIDName(botclass)
);
}
initiator->Message(Chat::White, message.c_str());
return false;
initiator->Message(Chat::White, message.c_str());
return false;
} else {
initiator->Message(Chat::White, "Your GM Flag allows you to bypass bot class-based spawn limits.");
}
}
std::string test_name = name;

View File

@ -946,6 +946,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#endif
if (IsClient()) {
if (CastToClient()->GetGM() || RuleB(Character, BindAnywhere)) {
if (CastToClient()->GetGM()) {
Message(Chat::White, "Your GM Flag allows you to bind anywhere.");
}
auto action_packet =
new EQApplicationPacket(OP_Action, sizeof(Action_Struct));
Action_Struct* action = (Action_Struct*) action_packet->pBuffer;

View File

@ -682,16 +682,34 @@ bool Mob::DoCastingChecksZoneRestrictions(bool check_on_casting, int32 spell_id)
If the spell is a initiated from SpellFinished, then check at start of SpellFinished.
*/
bool ignore_if_npc_or_gm = false;
if (!IsClient() || (IsClient() && CastToClient()->GetGM())) {
ignore_if_npc_or_gm = true;
bool bypass_casting_restrictions = false;
if (!IsClient()) {
bypass_casting_restrictions = true;
}
if (IsClient() && CastToClient()->GetGM()) {
bypass_casting_restrictions = true;
Message(
Chat::White,
fmt::format(
"Your GM Flag allows you to bypass zone casting restrictions and cast {} in this zone.",
Saylink::Silent(
fmt::format(
"#castspell {}",
spell_id
),
GetSpellName(spell_id)
)
).c_str()
);
}
/*
Zone ares that prevent blocked spells from being cast.
If on cast iniated then check any mob casting, if on spellfinished only check if is from client.
*/
if ((check_on_casting && !ignore_if_npc_or_gm) || (!check_on_casting && IsClient())) {
if ((check_on_casting && !bypass_casting_restrictions) || (!check_on_casting && IsClient())) {
if (zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) {
if (IsClient()) {
if (!CastToClient()->GetGM()) {
@ -707,6 +725,19 @@ bool Mob::DoCastingChecksZoneRestrictions(bool check_on_casting, int32 spell_id)
LogSpells("Spell casting canceled [{}] : can not cast in this zone location blocked spell.", spell_id);
}
else {
Message(
Chat::White,
fmt::format(
"Your GM Flag allows you to bypass zone blocked spells and cast {} in this zone.",
Saylink::Silent(
fmt::format(
"#castspell {}",
spell_id
),
GetSpellName(spell_id)
)
).c_str()
);
LogSpells("GM Cast Blocked Spell: [{}] (ID [{}])", GetSpellName(spell_id), spell_id);
}
}
@ -716,7 +747,7 @@ bool Mob::DoCastingChecksZoneRestrictions(bool check_on_casting, int32 spell_id)
/*
Zones where you can not use levitate spells.
*/
if (!ignore_if_npc_or_gm && !zone->CanLevitate() && IsEffectInSpell(spell_id, SE_Levitate)) { //check on spellfinished.
if (!bypass_casting_restrictions && !zone->CanLevitate() && IsEffectInSpell(spell_id, SE_Levitate)) { //check on spellfinished.
Message(Chat::Red, "You have entered an area where levitation effects do not function.");
LogSpells("Spell casting canceled [{}] : can not cast levitation in this zone.", spell_id);
return false;
@ -745,11 +776,15 @@ bool Mob::DoCastingChecksZoneRestrictions(bool check_on_casting, int32 spell_id)
/*
Zones where you can not cast out door only spells. This is only checked when casting is completed.
*/
if (!ignore_if_npc_or_gm && spells[spell_id].zone_type == 1 && !zone->CanCastOutdoor()) {
if (IsClient() && !CastToClient()->GetGM()) {
MessageString(Chat::Red, CAST_OUTDOORS);
LogSpells("Spell casting canceled [{}] : can not cast outdoors.", spell_id);
return false;
if (!bypass_casting_restrictions && spells[spell_id].zone_type == 1 && !zone->CanCastOutdoor()) {
if (IsClient()) {
if (!CastToClient()->GetGM()) {
MessageString(Chat::Red, CAST_OUTDOORS);
LogSpells("Spell casting canceled [{}] : can not cast outdoors.", spell_id);
return false;
} else {
Message(Chat::White, "Your GM Flag allows you to cast outdoor spells when indoors.");
}
}
}
}
@ -1066,6 +1101,7 @@ bool Client::CheckFizzle(uint16 spell_id)
{
// GMs don't fizzle
if (GetGM()) {
Message(Chat::White, "Your GM Flag prevents you from fizzling.");
return true;
}
@ -1648,9 +1684,12 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
if(!HasInstrument) { // if the instrument is missing, log it and interrupt the song
LogSpells("Song [{}]: Canceled. Missing required instrument [{}]", spell_id, component);
if(c->GetGM())
c->Message(Chat::White, "Your GM status allows you to finish casting even though you're missing a required instrument.");
else {
if (c->GetGM()) {
c->Message(
Chat::White,
"Your GM Flag allows you to finish casting even though you're missing a required instrument."
);
} else {
InterruptSpell();
return;
}
@ -1686,9 +1725,12 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
} // end reagent loop
if (missingreags) {
if(c->GetGM())
c->Message(Chat::White, "Your GM status allows you to finish casting even though you're missing required components.");
else {
if (c->GetGM()) {
c->Message(
Chat::White,
"Your GM Flag allows you to finish casting even though you're missing required components."
);
} else {
InterruptSpell();
return;
}
@ -4050,6 +4092,24 @@ bool Mob::SpellOnTarget(
(spelltar != this && spelltar->DivineAura()) ||
(spelltar == this && spelltar->DivineAura() && !IsCastNotStandingSpell(spell_id))
) {
if (IsClient()) {
Message(
Chat::White,
fmt::format(
"Your spell {} has failed to land on {} because {} are invulnerable.",
Saylink::Silent(
fmt::format(
"#castspell {}",
spell_id
),
spells[spell_id].name
),
GetTargetDescription(spelltar),
spelltar == this ? "you" : "they"
).c_str()
);
}
LogSpells("Casting spell [{}] on [{}] aborted: they are invulnerable", spell_id, spelltar->GetName());
safe_delete(action_packet);
return false;

View File

@ -123,6 +123,10 @@ bool Client::HasTaskRequestCooldownTimer()
task_request_timer.Disable();
}
if (GetGM()) {
Message(Chat::White, "Your GM Flag prevents you from having a task request cooldown.");
}
return (!GetGM() && task_request_timer.Enabled());
}

View File

@ -1087,7 +1087,17 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
const EQ::ItemData* item = nullptr;
if (((spec->tradeskill==75) || GetGM() || (chance > res)) || zone->random.Roll(aa_chance)) {
if (
(
spec->tradeskill == EQ::skills::SkillRemoveTraps ||
GetGM() ||
(chance > res)
) ||
zone->random.Roll(aa_chance)
) {
if (GetGM()) {
Message(Chat::White, "Your GM Flag gives you a 100% chance to succeed in combining this tradeskill.");
}
success_modifier = 1;

View File

@ -814,6 +814,18 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
((is_pet && (!bagitem->IsQuestItem() || pets_can_take_quest_items) ||
!is_pet)))) {
if (GetGM()) {
const std::string& item_link = database.CreateItemLink(bagitem->ID);
Message(
Chat::White,
fmt::format(
"Your GM Flag allows you to give {} to {}.",
item_link,
GetTargetDescription(tradingWith)
).c_str()
);
}
auto loot_drop_entry = LootdropEntriesRepository::NewNpcEntity();
loot_drop_entry.equip_item = 1;
loot_drop_entry.item_charges = static_cast<int8>(baginst->GetCharges());

View File

@ -92,10 +92,14 @@ bool Trap::Process()
{
if (chkarea_timer.Enabled() && chkarea_timer.Check() && !reset_timer.Enabled())
{
Mob* trigger = entity_list.GetTrapTrigger(this);
if (trigger && !(trigger->IsClient() && trigger->CastToClient()->GetGM()))
{
Trigger(trigger);
Mob* m = entity_list.GetTrapTrigger(this);
const bool is_gm_client = m->IsClient() && m->CastToClient()->GetGM();
if (m && !is_gm_client) {
Trigger(m);
}
if (is_gm_client) {
m->Message(Chat::White, "Your GM Flag prevents you from triggering a trap.");
}
}
else if (reset_timer.Enabled() && reset_timer.Check())
@ -315,6 +319,10 @@ Mob* EntityList::GetTrapTrigger(Trap* trap)
Log(Logs::General, Logs::Traps, "%s is about to trigger trap %d of chance %d. diff: %0.2f maxdist: %0.2f zdiff: %0.2f maxzdiff: %0.2f", cur->GetName(), trap->trap_id, trap->chance, (diff.x*diff.x + diff.y*diff.y), maxdist, diff.z, trap->maxzdiff);
return cur;
}
if (cur->GetGM()) {
cur->Message(Chat::White, "Your GM Flag prevents you from triggering a trap.");
}
}
else
{

View File

@ -373,8 +373,8 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
}
if (content_service.GetCurrentExpansion() >= Expansion::Classic && GetGM()) {
LogInfo("[{}] Bypassing Expansion zone checks because GM status is set", GetCleanName());
Message(Chat::Yellow, "Bypassing Expansion zone checks because GM status is set");
LogInfo("[{}] Bypassing zone expansion checks because GM Flag is set", GetCleanName());
Message(Chat::White, "Your GM Flag allows you to bypass zone expansion checks.");
}
if (zoning_message == ZoningMessage::ZoneSuccess) {
@ -1369,7 +1369,7 @@ bool Client::CanEnterZone(const std::string& zone_short_name, int16 instance_ver
return false;
}
if (GetLevel() < z->min_level) {
if (!GetGM() && GetLevel() < z->min_level) {
LogInfo(
"Character [{}] does not meet minimum level requirement ([{}] < [{}])!",
GetCleanName(),
@ -1379,7 +1379,7 @@ bool Client::CanEnterZone(const std::string& zone_short_name, int16 instance_ver
return false;
}
if (GetLevel() > z->max_level) {
if (!GetGM() && GetLevel() > z->max_level) {
LogInfo(
"Character [{}] does not meet maximum level requirement ([{}] > [{}])!",
GetCleanName(),
@ -1399,15 +1399,19 @@ bool Client::CanEnterZone(const std::string& zone_short_name, int16 instance_ver
return false;
}
if (!z->flag_needed.empty() && Strings::IsNumber(z->flag_needed) && Strings::ToBool(z->flag_needed)) {
if (!GetGM() && !HasZoneFlag(z->zoneidnumber)) {
LogInfo(
"Character [{}] does not have the flag to be in this zone [{}]!",
GetCleanName(),
z->flag_needed
);
return false;
}
if (
!GetGM() &&
!z->flag_needed.empty() &&
Strings::IsNumber(z->flag_needed) &&
Strings::ToBool(z->flag_needed) &&
!HasZoneFlag(z->zoneidnumber)
) {
LogInfo(
"Character [{}] does not have the flag to be in this zone [{}]!",
GetCleanName(),
z->flag_needed
);
return false;
}
return true;