Merge remote-tracking branch 'upstream/master' into spa395fix2

This commit is contained in:
KayenEQ
2021-10-01 14:28:45 -04:00
55 changed files with 6196 additions and 5682 deletions
+6 -5
View File
@@ -2701,8 +2701,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
}
}
if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0))
TryTriggerOnValueAmount(false, false, false, true);
if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0)) {
TryTriggerOnCastRequirement();
}
if (IsClient() && !IsAIControlled())
return;
@@ -3343,7 +3344,7 @@ int32 Mob::ReduceAllDamage(int32 damage)
if (GetMana() >= mana_reduced) {
damage -= mana_reduced;
SetMana(GetMana() - mana_reduced);
TryTriggerOnValueAmount(false, true);
TryTriggerOnCastRequirement();
}
}
@@ -3356,7 +3357,7 @@ int32 Mob::ReduceAllDamage(int32 damage)
if (IsClient() && CastToClient()->GetEndurance() >= endurance_drain) {
damage -= damage_reduced;
CastToClient()->SetEndurance(CastToClient()->GetEndurance() - endurance_drain);
TryTriggerOnValueAmount(false, false, true);
TryTriggerOnCastRequirement();
}
}
@@ -3646,7 +3647,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
TryDeathSave();
}
TryTriggerOnValueAmount(true);
TryTriggerOnCastRequirement();
//fade mez if we are mezzed
if (IsMezzed() && attacker) {
+18 -4
View File
@@ -1256,8 +1256,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_MitigateDamageShield: {
if (base1 < 0)
//AA that increase mitigation are set to negative.
if (base1 < 0) {
base1 = base1 * (-1);
}
newbon->DSMitigationOffHand += base1;
break;
@@ -2663,8 +2666,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_MitigateDamageShield:
{
if (effect_value < 0)
effect_value = effect_value*-1;
/*
Bard songs have identical negative base value and positive max
The effect for the songs should increase mitigation. There are
spells that do decrease the mitigation with just negative base values.
To be consistent all values that increase mitigation will be set to positives
*/
if (max > 0 && effect_value < 0) {
effect_value = max;
}
new_bonus->DSMitigationOffHand += effect_value;
break;
@@ -3198,7 +3208,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_TriggerOnReqTarget:
case SE_TriggerOnReqCaster:
new_bonus->TriggerOnValueAmount = true;
new_bonus->TriggerOnCastRequirement = true;
break;
case SE_DivineAura:
@@ -3661,6 +3671,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
new_bonus->ZoneSuspendMinion = effect_value;
break;
case SE_CompleteHeal:
new_bonus->CompleteHealBuffBlocker = true;
break;
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) {
+10 -6
View File
@@ -9191,7 +9191,7 @@ void Client::SetDisplayMobInfoWindow(bool display_mob_info_window)
bool Client::IsDevToolsEnabled() const
{
return dev_tools_enabled && RuleB(World, EnableDevTools);
return dev_tools_enabled && GetGM() && RuleB(World, EnableDevTools);
}
void Client::SetDevToolsEnabled(bool in_dev_tools_enabled)
@@ -9481,12 +9481,16 @@ void Client::SendCrossZoneMessage(
}
else if (!character_name.empty() && !message.empty())
{
uint32_t pack_size = sizeof(CZMessagePlayer_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_CZMessagePlayer, pack_size);
auto buf = reinterpret_cast<CZMessagePlayer_Struct*>(pack->pBuffer);
uint32_t pack_size = sizeof(CZMessage_Struct);
auto pack = std::make_unique<ServerPacket>(ServerOP_CZMessage, pack_size);
auto buf = reinterpret_cast<CZMessage_Struct*>(pack->pBuffer);
uint8 update_type = CZUpdateType_Character;
int update_identifier = 0;
buf->update_type = update_type;
buf->update_identifier = update_identifier;
buf->type = chat_type;
strn0cpy(buf->character_name, character_name.c_str(), sizeof(buf->character_name));
strn0cpy(buf->message, message.c_str(), sizeof(buf->message));
strn0cpy(buf->client_name, character_name.c_str(), sizeof(buf->client_name));
worldserver.SendPacket(pack.get());
}
@@ -9519,7 +9523,7 @@ void Client::SendCrossZoneMessageString(
auto buf = reinterpret_cast<CZClientMessageString_Struct*>(pack->pBuffer);
buf->string_id = string_id;
buf->chat_type = chat_type;
strn0cpy(buf->character_name, character_name.c_str(), sizeof(buf->character_name));
strn0cpy(buf->client_name, character_name.c_str(), sizeof(buf->client_name));
buf->args_size = args_size;
memcpy(buf->args, argument_buffer.buffer(), argument_buffer.size());
+4 -2
View File
@@ -203,8 +203,10 @@ enum eInnateSkill {
InnateDisabled = 255
};
const std::string DIAWIND_RESPONSE_KEY = "diawind_npcresponse";
const uint32 POPUPID_DIAWIND = 999;
const std::string DIAWIND_RESPONSE_ONE_KEY = "diawind_npc_response_one";
const std::string DIAWIND_RESPONSE_TWO_KEY = "diawind_npc_response_two";
const uint32 POPUPID_DIAWIND_ONE = 99999;
const uint32 POPUPID_DIAWIND_TWO = 100000;
const uint32 POPUPID_UPDATE_SHOWSTATSWINDOW = 1000000;
struct ClientReward
+16 -5
View File
@@ -11155,9 +11155,18 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app)
return;
break;
case POPUPID_DIAWIND:
if (EntityVariableExists(DIAWIND_RESPONSE_KEY.c_str())) {
response = GetEntityVariable(DIAWIND_RESPONSE_KEY.c_str());
case POPUPID_DIAWIND_ONE:
if (EntityVariableExists(DIAWIND_RESPONSE_ONE_KEY.c_str())) {
response = GetEntityVariable(DIAWIND_RESPONSE_ONE_KEY.c_str());
if (!response.empty()) {
ChannelMessageReceived(8, 0, 100, response.c_str());
}
}
break;
case POPUPID_DIAWIND_TWO:
if (EntityVariableExists(DIAWIND_RESPONSE_TWO_KEY.c_str())) {
response = GetEntityVariable(DIAWIND_RESPONSE_TWO_KEY.c_str());
if (!response.empty()) {
ChannelMessageReceived(8, 0, 100, response.c_str());
}
@@ -12189,7 +12198,8 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app)
tr.name,
tr.trivial,
SUM(tre.componentcount),
tr.tradeskill
tr.tradeskill,
tr.must_learn
FROM
tradeskill_recipe AS tr
LEFT JOIN tradeskill_recipe_entries AS tre ON tr.id = tre.recipe_id
@@ -12289,7 +12299,8 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app)
tr.name,
tr.trivial,
SUM(tre.componentcount),
tr.tradeskill
tr.tradeskill,
tr.must_learn
FROM
tradeskill_recipe AS tr
LEFT JOIN tradeskill_recipe_entries AS tre ON tr.id = tre.recipe_id
+3 -1
View File
@@ -183,6 +183,8 @@ bool Client::Process() {
SetDynamicZoneMemberStatus(DynamicZoneMemberStatus::Offline);
parse->EventPlayer(EVENT_DISCONNECT, this, "", 0);
return false; //delete client
}
@@ -1864,7 +1866,7 @@ void Client::DoEnduranceUpkeep() {
if(upkeep_sum != 0){
SetEndurance(GetEndurance() - upkeep_sum);
TryTriggerOnValueAmount(false, false, true);
TryTriggerOnCastRequirement();
}
if (!has_effect)
+796 -639
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -554,6 +554,7 @@ struct StatBonuses {
int32 ItemEnduranceRegenCap; // modify endurance regen cap
int32 WeaponStance[WEAPON_STANCE_TYPE_MAX +1];// base = trigger spell id, base2 = 0 is 2h, 1 is shield, 2 is dual wield, [0]spid 2h, [1]spid shield, [2]spid DW
bool ZoneSuspendMinion; // base 1 allows suspended minions to zone
bool CompleteHealBuffBlocker; // Use in SPA 101 to prevent recast of complete heal from this effect till blocker buff is removed.
// AAs
uint16 SecondaryForte; // allow a second skill to be specialized with a cap of this value.
@@ -602,7 +603,7 @@ struct StatBonuses {
int32 FinishingBlow[2]; // Chance to do a finishing blow for specified damage amount.
uint32 FinishingBlowLvl[2]; // Sets max level an NPC can be affected by FB. (base1 = lv, base2= ???)
int32 ShieldEquipDmgMod; // Increases weapon's base damage by base1 % when shield is equipped (indirectly increasing hate)
bool TriggerOnValueAmount; // Triggers off various different conditions, bool to check if client has effect.
bool TriggerOnCastRequirement; // Triggers off various different conditions defined as emum SpellRestrictions
int8 StunBashChance; // chance to stun with bash.
int8 IncreaseChanceMemwipe; // increases chance to memory wipe
int8 CriticalMend; // chance critical monk mend
+125 -11
View File
@@ -11,7 +11,8 @@ void DialogueWindow::Render(Client *c, std::string markdown)
}
// zero this out
c->SetEntityVariable(DIAWIND_RESPONSE_KEY.c_str(), "");
c->SetEntityVariable(DIAWIND_RESPONSE_ONE_KEY.c_str(), "");
c->SetEntityVariable(DIAWIND_RESPONSE_TWO_KEY.c_str(), "");
// simple find and replace for the markdown
find_replace(output, "~", "</c>");
@@ -32,10 +33,10 @@ void DialogueWindow::Render(Client *c, std::string markdown)
// mysterious voice
bool render_mysterious_voice = false;
if (markdown.find("mysterious") != std::string::npos) {
if (markdown.find("{mysterious}") != std::string::npos) {
render_mysterious_voice = true;
LogDiaWind("Client [{}] Rendering mysterious voice", c->GetCleanName());
find_replace(output, "mysterious", "");
find_replace(output, "{mysterious}", "");
}
// noquotes
@@ -98,10 +99,10 @@ void DialogueWindow::Render(Client *c, std::string markdown)
}
}
uint32 popup_id = POPUPID_DIAWIND;
uint32 negative_id = 0;
char *button_name_0 = nullptr;
char *button_name_1 = nullptr;
uint32 popup_id = POPUPID_DIAWIND_ONE;
uint32 negative_id = POPUPID_DIAWIND_TWO;
std::string button_one_name;
std::string button_two_name;
uint32 sound_controls = 0;
// window type
@@ -171,6 +172,96 @@ void DialogueWindow::Render(Client *c, std::string markdown)
}
}
// secondresponseid
std::string secondresponseid;
if (markdown.find("secondresponseid") != std::string::npos) {
LogDiaWind("Client [{}] Rendering secondresponseid option", c->GetCleanName());
auto first_split = split_string(output, "secondresponseid:");
if (!first_split.empty()) {
auto second_split = split_string(first_split[1], " ");
if (!second_split.empty()) {
secondresponseid = second_split[0];
LogDiaWindDetail("Client [{}] Rendering secondresponseid option secondresponseid [{}]", c->GetCleanName(), secondresponseid);
}
if (first_split[1].length() == 1) {
secondresponseid = first_split[1];
LogDiaWindDetail(
"Client [{}] Rendering secondresponseid (end) option secondresponseid [{}]",
c->GetCleanName(),
secondresponseid
);
}
find_replace(output, fmt::format("secondresponseid:{}", secondresponseid), "");
if (!secondresponseid.empty()) {
negative_id = (StringIsNumber(secondresponseid) ? std::atoi(secondresponseid.c_str()) : 0);
}
}
}
// Buttons Text
std::string button_one;
std::string button_two;
if (
markdown.find("button_one") != std::string::npos &&
markdown.find("button_two") != std::string::npos
) {
LogDiaWind("Client [{}] Rendering button_one option.", c->GetCleanName());
auto one_first_split = split_string(output, "button_one:");
if (!one_first_split.empty()) {
auto one_second_split = split_string(one_first_split[1], " ");
if (!one_second_split.empty()) {
button_one = one_second_split[0];
LogDiaWindDetail("Client [{}] Rendering button_one option button_one [{}]", c->GetCleanName(), button_one);
}
if (one_first_split[1].length() == 1) {
button_one = one_first_split[1];
LogDiaWindDetail(
"Client [{}] Rendering button_one (end) option button_one [{}]",
c->GetCleanName(),
button_one
);
}
find_replace(output, fmt::format("button_one:{}", button_one), "");
if (!button_one.empty()) {
button_one_name = button_one.c_str();
}
}
LogDiaWind("Client [{}] Rendering button_two option.", c->GetCleanName());
auto two_first_split = split_string(output, "button_two:");
if (!two_first_split.empty()) {
auto two_second_split = split_string(two_first_split[1], " ");
if (!two_second_split.empty()) {
button_two = two_second_split[0];
LogDiaWindDetail("Client [{}] Rendering button_two option button_two [{}]", c->GetCleanName(), button_two);
}
if (two_first_split[1].length() == 1) {
button_two = two_first_split[1];
LogDiaWindDetail(
"Client [{}] Rendering button_two (end) option button_two [{}]",
c->GetCleanName(),
button_two
);
}
find_replace(output, fmt::format("button_two:{}", button_two), "");
if (!button_two.empty()) {
button_two_name = button_two.c_str();
}
}
}
// bracket responses
std::vector<std::string> responses;
std::vector<std::string> bracket_responses;
@@ -209,13 +300,25 @@ void DialogueWindow::Render(Client *c, std::string markdown)
}
}
// Placed here to allow silent message or other message to override default for custom values.
if (!button_one_name.empty() && !button_two_name.empty()) {
c->SetEntityVariable(
DIAWIND_RESPONSE_ONE_KEY.c_str(),
button_one_name.c_str()
);
c->SetEntityVariable(
DIAWIND_RESPONSE_TWO_KEY.c_str(),
button_two_name.c_str()
);
}
// handle silent prompts from the [> silent syntax
std::string silent_message;
if (responses.empty() && markdown.find('[') != std::string::npos && markdown.find('>') != std::string::npos) {
silent_message = get_between(output, "[", ">");
// temporary and used during the response
c->SetEntityVariable(DIAWIND_RESPONSE_KEY.c_str(), silent_message.c_str());
c->SetEntityVariable(DIAWIND_RESPONSE_ONE_KEY.c_str(), silent_message.c_str());
// pop the silent message off
find_replace(output, fmt::format("[{}>", silent_message), "");
@@ -225,7 +328,7 @@ void DialogueWindow::Render(Client *c, std::string markdown)
silent_message = responses[0];
// temporary and used during the response
c->SetEntityVariable(DIAWIND_RESPONSE_KEY.c_str(), silent_message.c_str());
c->SetEntityVariable(DIAWIND_RESPONSE_ONE_KEY.c_str(), silent_message.c_str());
// pop the silent message off
find_replace(output, fmt::format("[{}]", silent_message), "");
@@ -282,6 +385,17 @@ void DialogueWindow::Render(Client *c, std::string markdown)
);
}
if (!button_one_name.empty() && !button_two_name.empty()) {
click_response = fmt::format(
"<c \"#F07F00\">Click [{}] to respond with [{}]...<br>"
"Click [{}] to respond with [{}]...</c>",
button_one_name,
button_one_name,
button_two_name,
button_two_name
);
}
// post processing of color markdowns
// {spring_green_1} = <c "#5EFB6E">
if (markdown.find('{') != std::string::npos && markdown.find('}') != std::string::npos) {
@@ -325,8 +439,8 @@ void DialogueWindow::Render(Client *c, std::string markdown)
negative_id,
window_type,
window_expire_seconds,
button_name_0,
button_name_1,
button_one_name.c_str(),
button_two_name.c_str(),
sound_controls
);
+6
View File
@@ -122,6 +122,7 @@ const char *QuestEventSubroutines[_LargestEventID] = {
"EVENT_BOT_COMMAND",
"EVENT_WARP",
"EVENT_TEST_BUFF",
"EVENT_COMBINE",
"EVENT_CONSIDER",
"EVENT_CONSIDER_CORPSE"
};
@@ -1657,6 +1658,11 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_COMBINE: {
ExportVar(package_name.c_str(), "container_slot", std::stoi(data));
break;
}
default: {
break;
}
+2357 -1579
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -90,6 +90,7 @@ typedef enum {
EVENT_BOT_COMMAND,
EVENT_WARP,
EVENT_TEST_BUFF,
EVENT_COMBINE,
EVENT_CONSIDER,
EVENT_CONSIDER_CORPSE,
_LargestEventID
+22 -18
View File
@@ -129,7 +129,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
std::vector<std::string> move_h_options_negative;
std::vector<std::string> set_size_options_positive;
std::vector<std::string> set_size_options_negative;
for (const auto &move_option : move_options) {
for (const auto &move_option : move_options) {
if (move_option == move_x_action) {
move_x_options_positive.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
@@ -165,7 +165,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#door edit {} -.25", move_option),
false,
"-.25"
".25"
)
);
}
@@ -190,7 +190,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
}
for (int move_index = -15; move_index <= 0; move_index += 5) {
int value = (move_index == 0 ? 1 : move_index);
int value = (move_index == 0 ? -1 : move_index);
move_y_options_negative.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#door edit {} {}", move_option, value),
@@ -204,7 +204,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#door edit {} -.25", move_option),
false,
"-.25"
".25"
)
);
}
@@ -229,7 +229,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
}
for (int move_index = -15; move_index <= 0; move_index += 5) {
int value = (move_index == 0 ? 1 : move_index);
int value = (move_index == 0 ? -1 : move_index);
move_z_options_negative.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#door edit {} {}", move_option, value),
@@ -243,7 +243,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#door edit {} -.25", move_option),
false,
"-.25"
".25"
)
);
}
@@ -260,7 +260,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
}
for (int move_index = -50; move_index <= 0; move_index += 5) {
int value = (move_index == 0 ? 1 : move_index);
int value = (move_index == 0 ? -1 : move_index);
move_h_options_negative.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#door edit {} {}", move_option, value),
@@ -283,7 +283,7 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
}
for (int move_index = -100; move_index <= 0; move_index += 10) {
int value = (move_index == 0 ? 1 : move_index);
int value = (move_index == 0 ? -1 : move_index);
set_size_options_negative.emplace_back(
EQ::SayLinkEngine::GenerateQuestSaylink(
fmt::format("#door edit {} {}", move_option, value),
@@ -297,26 +297,30 @@ void DoorManipulation::CommandHandler(Client *c, const Seperator *sep)
// we're passing a move action here
if (!arg3.empty() && StringIsNumber(arg3)) {
int x_move = 0;
int y_move = 0;
int z_move = 0;
int h_move = 0;
int set_size = 0;
float x_move = 0.0f;
float y_move = 0.0f;
float z_move = 0.0f;
float h_move = 0.0f;
float set_size = 0.0f;
if (arg2 == move_x_action) {
x_move = std::atoi(arg3.c_str());
x_move = std::atof(arg3.c_str());
}
if (arg2 == move_y_action) {
y_move = std::atoi(arg3.c_str());
y_move = std::atof(arg3.c_str());
}
if (arg2 == move_z_action) {
z_move = std::atoi(arg3.c_str());
z_move = std::atof(arg3.c_str());
}
if (arg2 == move_h_action) {
h_move = std::atoi(arg3.c_str());
h_move = std::atof(arg3.c_str());
}
if (arg2 == set_size_action) {
set_size = std::atoi(arg3.c_str());
set_size = std::atof(arg3.c_str());
}
door->SetLocation(
+1383 -700
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -133,6 +133,7 @@ const char *LuaEvents[_LargestEventID] = {
"event_bot_command",
"event_warp",
"event_test_buff",
"event_combine",
"event_consider",
"event_consider_corpse"
};
@@ -222,6 +223,7 @@ LuaParser::LuaParser() {
PlayerArgumentDispatch[EVENT_COMBINE_VALIDATE] = handle_player_combine_validate;
PlayerArgumentDispatch[EVENT_BOT_COMMAND] = handle_player_bot_command;
PlayerArgumentDispatch[EVENT_WARP] = handle_player_warp;
PlayerArgumentDispatch[EVENT_COMBINE] = handle_player_quest_combine;
PlayerArgumentDispatch[EVENT_CONSIDER] = handle_player_consider;
PlayerArgumentDispatch[EVENT_CONSIDER_CORPSE] = handle_player_consider_corpse;
+5
View File
@@ -573,6 +573,11 @@ void handle_player_warp(QuestInterface* parse, lua_State* L, Client* client, std
lua_setfield(L, -2, "from_z");
}
void handle_player_quest_combine(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector<EQ::Any>* extra_pointers) {
lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "container_slot");
}
void handle_player_consider(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector<EQ::Any>* extra_pointers) {
lua_pushinteger(L, std::stoi(data));
lua_setfield(L, -2, "entity_id");
+2
View File
@@ -105,6 +105,8 @@ void handle_player_bot_command(QuestInterface *parse, lua_State* L, Client* clie
std::vector<EQ::Any> *extra_pointers);
void handle_player_warp(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQ::Any>* extra_pointers);
void handle_player_quest_combine(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQ::Any>* extra_pointers);
void handle_player_consider(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<EQ::Any>* extra_pointers);
void handle_player_consider_corpse(QuestInterface* parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
+1 -1
View File
@@ -987,7 +987,7 @@ int32 Lua_StatBonuses::GetShieldEquipDmgMod() const {
bool Lua_StatBonuses::GetTriggerOnValueAmount() const {
Lua_Safe_Call_Bool();
return self->TriggerOnValueAmount;
return self->TriggerOnCastRequirement;
}
int8 Lua_StatBonuses::GetStunBashChance() const {
+18 -73
View File
@@ -2838,10 +2838,17 @@ bool Mob::HateSummon() {
if(summon_level == 1) {
entity_list.MessageClose(this, true, 500, Chat::Say, "%s says 'You will not evade me, %s!' ", GetCleanName(), target->GetCleanName() );
auto new_pos = m_Position;
float angle = new_pos.w - target->GetHeading();
new_pos.w = target->GetHeading();
// probably should be like half melee range, but we can't get melee range nicely because reasons :)
new_pos = target->TryMoveAlong(new_pos, 5.0f, angle);
if (target->IsClient())
target->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), m_Position.x, m_Position.y, m_Position.z, target->GetHeading(), 0, SummonPC);
target->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), new_pos.x, new_pos.y, new_pos.z, new_pos.w, 0, SummonPC);
else
target->GMMove(m_Position.x, m_Position.y, m_Position.z, target->GetHeading());
target->GMMove(new_pos.x, new_pos.y, new_pos.z, new_pos.w);
return true;
} else if(summon_level == 2) {
@@ -3602,81 +3609,20 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect)
return false;
}
void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsPet)
void Mob::TryTriggerOnCastRequirement()
{
/*
At present time there is no obvious difference between ReqTarget and ReqCaster
ReqTarget is typically used in spells cast on a target where the trigger occurs on that target.
ReqCaster is typically self only spells where the triggers on self.
Regardless both trigger on the owner of the buff.
*/
/*
Base2 Range: 1004 = Below < 80% HP
Base2 Range: 500-520 = Below (base2 - 500)*5 HP
Base2 Range: 521 = Below (?) Mana UKNOWN - Will assume its 20% unless proven otherwise
Base2 Range: 522 = Below (40%) Endurance
Base2 Range: 523 = Below (40%) Mana
Base2 Range: 220-? = Number of pets on hatelist to trigger (base2 - 220) (Set at 30 pets max for now)
38311 = < 10% mana;
*/
if (!spellbonuses.TriggerOnValueAmount)
return;
if (spellbonuses.TriggerOnValueAmount){
if (spellbonuses.TriggerOnCastRequirement) {
int buff_count = GetMaxTotalSlots();
for(int e = 0; e < buff_count; e++){
uint32 spell_id = buffs[e].spellid;
if (IsValidSpell(spell_id)){
for(int i = 0; i < EFFECT_COUNT; i++){
for (int e = 0; e < buff_count; e++) {
int spell_id = buffs[e].spellid;
if (IsValidSpell(spell_id)) {
for (int i = 0; i < EFFECT_COUNT; i++) {
if ((spells[spell_id].effectid[i] == SE_TriggerOnReqTarget) || (spells[spell_id].effectid[i] == SE_TriggerOnReqCaster)) {
int base2 = spells[spell_id].base2[i];
bool use_spell = false;
if (IsHP){
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5)
use_spell = true;
else if (base2 == 1004 && GetHPRatio() < 80)
use_spell = true;
}
else if (IsMana){
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40))
use_spell = true;
else if (base2 == 38311 && GetManaRatio() < 10)
use_spell = true;
}
else if (IsEndur){
if (base2 == 522 && GetEndurancePercent() < 40){
use_spell = true;
}
}
else if (IsPet){
int count = hate_list.GetSummonedPetCountOnHateList(this);
if ((base2 >= 220 && base2 <= 250) && count >= (base2 - 220)){
use_spell = true;
}
}
if (use_spell){
if (PassCastRestriction(spells[spell_id].base2[i])) {
SpellFinished(spells[spell_id].base[i], this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff);
if(!TryFadeEffect(e))
if (!TryFadeEffect(e)) {
BuffFadeBySlot(e);
}
}
}
}
@@ -3685,7 +3631,6 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
}
}
//Twincast Focus effects should stack across different types (Spell, AA - when implemented ect)
void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id)
{
+5 -1
View File
@@ -623,6 +623,7 @@ public:
void Teleport(const glm::vec3 &pos);
void Teleport(const glm::vec4 &pos);
void TryMoveAlong(float distance, float angle, bool send = true);
glm::vec4 TryMoveAlong(const glm::vec4 &start, float distance, float angle);
void ProcessForcedMovement();
inline void IncDeltaX(float in) { m_Delta.x += in; }
inline void IncDeltaY(float in) { m_Delta.y += in; }
@@ -796,7 +797,7 @@ public:
void TryTriggerOnCastFocusEffect(focusType type, uint16 spell_id);
bool TryTriggerOnCastProc(uint16 focusspellid, uint16 spell_id, uint16 proc_spellid);
bool TrySpellTrigger(Mob *target, uint32 spell_id, int effect);
void TryTriggerOnValueAmount(bool IsHP = false, bool IsMana = false, bool IsEndur = false, bool IsPet = false);
void TryTriggerOnCastRequirement();
void TryTwincast(Mob *caster, Mob *target, uint32 spell_id);
void TrySympatheticProc(Mob *target, uint32 spell_id);
bool TryFadeEffect(int slot);
@@ -844,6 +845,8 @@ public:
bool CanFocusUseRandomEffectivenessByType(focusType type);
int GetFocusRandomEffectivenessValue(int focus_base, int focus_base2, bool best_focus = 0);
int GetHealRate() const { return itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate; }
int GetMemoryBlurChance(int base_chance);
bool TryDoubleMeleeRoundEffect();
bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; }
@@ -1532,6 +1535,7 @@ protected:
bool endur_upkeep;
bool degenerating_effects; // true if we have a buff that needs to be recalced every tick
bool spawned_in_water;
public:
bool GetWasSpawnedInWater() const;
+2 -2
View File
@@ -4016,7 +4016,7 @@ XS(XS_Client_Freeze);
XS(XS_Client_Freeze) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client:Freeze(THIS)");
Perl_croak(aTHX_ "Usage: Client::Freeze(THIS)");
{
Client *THIS;
VALIDATE_THIS_IS_CLIENT;
@@ -4029,7 +4029,7 @@ XS(XS_Client_UnFreeze);
XS(XS_Client_UnFreeze) {
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Client:UnFreeze(THIS)");
Perl_croak(aTHX_ "Usage: Client::UnFreeze(THIS)");
{
Client *THIS;
VALIDATE_THIS_IS_CLIENT;
+1 -1
View File
@@ -304,7 +304,7 @@ XS(XS_Raid_GetClientByIndex); /* prototype to pass -Wmissing-prototypes */
XS(XS_Raid_GetClientByIndex) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Raid::GetClientByIndex(THIS, uint16 raid_indez)"); // @categories Raid
Perl_croak(aTHX_ "Usage: Raid::GetClientByIndex(THIS, uint16 raid_index)"); // @categories Raid
{
Raid *THIS;
Client *RETVAL;
+203 -886
View File
File diff suppressed because it is too large Load Diff
+16 -81
View File
@@ -290,87 +290,22 @@ public:
static std::string GetZoneLongName(std::string zone_short_name);
static std::string GetZoneLongNameByID(uint32 zone_id);
static std::string GetZoneShortName(uint32 zone_id);
void CrossZoneAssignTaskByCharID(int character_id, uint32 task_id, bool enforce_level_requirement = false);
void CrossZoneAssignTaskByGroupID(int group_id, uint32 task_id, bool enforce_level_requirement = false);
void CrossZoneAssignTaskByRaidID(int raid_id, uint32 task_id, bool enforce_level_requirement = false);
void CrossZoneAssignTaskByGuildID(int guild_id, uint32 task_id, bool enforce_level_requirement = false);
void CrossZoneCastSpellByCharID(int character_id, uint32 spell_id);
void CrossZoneCastSpellByGroupID(int group_id, uint32 spell_id);
void CrossZoneCastSpellByRaidID(int raid_id, uint32 spell_id);
void CrossZoneCastSpellByGuildID(int guild_id, uint32 spell_id);
void CrossZoneDisableTaskByCharID(int character_id, uint32 task_id);
void CrossZoneDisableTaskByGroupID(int group_id, uint32 task_id);
void CrossZoneDisableTaskByRaidID(int raid_id, uint32 task_id);
void CrossZoneDisableTaskByGuildID(int guild_id, uint32 task_id);
void CrossZoneEnableTaskByCharID(int character_id, uint32 task_id);
void CrossZoneEnableTaskByGroupID(int group_id, uint32 task_id);
void CrossZoneEnableTaskByRaidID(int raid_id, uint32 task_id);
void CrossZoneEnableTaskByGuildID(int guild_id, uint32 task_id);
void CrossZoneFailTaskByCharID(int character_id, uint32 task_id);
void CrossZoneFailTaskByGroupID(int group_id, uint32 task_id);
void CrossZoneFailTaskByRaidID(int raid_id, uint32 task_id);
void CrossZoneFailTaskByGuildID(int guild_id, uint32 task_id);
void CrossZoneLDoNUpdate(uint8 type, uint8 subtype, int identifier, uint32 theme_id, int points = 1);
void CrossZoneMarqueeByCharID(int character_id, uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, const char *message);
void CrossZoneMarqueeByGroupID(int group_id, uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, const char *message);
void CrossZoneMarqueeByRaidID(int raid_id, uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, const char *message);
void CrossZoneMarqueeByGuildID(int guild_id, uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, const char *message);
void CrossZoneMessagePlayerByName(uint32 type, const char *character_name, const char *message);
void CrossZoneMessagePlayerByGroupID(uint32 type, int group_id, const char *message);
void CrossZoneMessagePlayerByRaidID(uint32 type, int raid_id, const char *message);
void CrossZoneMessagePlayerByGuildID(uint32 type, int guild_id, const char *message);
void CrossZoneMovePlayerByCharID(int character_id, const char *zone_short_name);
void CrossZoneMovePlayerByGroupID(int group_id, const char *zone_short_name);
void CrossZoneMovePlayerByRaidID(int raid_id, const char *zone_short_name);
void CrossZoneMovePlayerByGuildID(int guild_id, const char *zone_short_name);
void CrossZoneMoveInstanceByCharID(int character_id, uint16 instance_id);
void CrossZoneMoveInstanceByGroupID(int group_id, uint16 instance_id);
void CrossZoneMoveInstanceByRaidID(int raid_id, uint16 instance_id);
void CrossZoneMoveInstanceByGuildID(int guild_id, uint16 instance_id);
void CrossZoneRemoveSpellByCharID(int character_id, uint32 spell_id);
void CrossZoneRemoveSpellByGroupID(int group_id, uint32 spell_id);
void CrossZoneRemoveSpellByRaidID(int raid_id, uint32 spell_id);
void CrossZoneRemoveSpellByGuildID(int guild_id, uint32 spell_id);
void CrossZoneRemoveTaskByCharID(int character_id, uint32 task_id);
void CrossZoneRemoveTaskByGroupID(int group_id, uint32 task_id);
void CrossZoneRemoveTaskByRaidID(int raid_id, uint32 task_id);
void CrossZoneRemoveTaskByGuildID(int guild_id, uint32 task_id);
void CrossZoneResetActivityByCharID(int character_id, uint32 task_id, int activity_id);
void CrossZoneResetActivityByGroupID(int group_id, uint32 task_id, int activity_id);
void CrossZoneResetActivityByRaidID(int raid_id, uint32 task_id, int activity_id);
void CrossZoneResetActivityByGuildID(int guild_id, uint32 task_id, int activity_id);
void CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, const char *variable_name, const char *variable_value);
void CrossZoneSetEntityVariableByClientName(const char *character_name, const char *variable_name, const char *variable_value);
void CrossZoneSetEntityVariableByGroupID(int group_id, const char *variable_name, const char *variable_value);
void CrossZoneSetEntityVariableByRaidID(int raid_id, const char *variable_name, const char *variable_value);
void CrossZoneSetEntityVariableByGuildID(int guild_id, const char *variable_name, const char *variable_value);
void CrossZoneSignalPlayerByCharID(int charid, uint32 signal);
void CrossZoneSignalPlayerByGroupID(int group_id, uint32 signal);
void CrossZoneSignalPlayerByRaidID(int raid_id, uint32 signal);
void CrossZoneSignalPlayerByGuildID(int guild_id, uint32 signal);
void CrossZoneSignalNPCByNPCTypeID(uint32 npctype_id, uint32 signal);
void CrossZoneSignalPlayerByName(const char *character_name, uint32 signal);
void CrossZoneUpdateActivityByCharID(int character_id, uint32 task_id, int activity_id, int activity_count = 1);
void CrossZoneUpdateActivityByGroupID(int group_id, uint32 task_id, int activity_id, int activity_count = 1);
void CrossZoneUpdateActivityByRaidID(int raid_id, uint32 task_id, int activity_id, int activity_count = 1);
void CrossZoneUpdateActivityByGuildID(int guild_id, uint32 task_id, int activity_id, int activity_count = 1);
void WorldWideAssignTask(uint32 task_id, bool enforce_level_requirement = false, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideCastSpell(uint32 spell_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideDisableTask(uint32 task_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideEnableTask(uint32 task_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideFailTask(uint32 task_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideMarquee(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, const char *message, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideMessage(uint32 type, const char *message, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideMove(const char *zone_short_name, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideMoveInstance(uint16 instance_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideRemoveSpell(uint32 spell_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideRemoveTask(uint32 task_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideResetActivity(uint32 task_id, int activity_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideSetEntityVariableClient(const char *variable_name, const char *variable_value, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideSetEntityVariableNPC(const char *variable_name, const char *variable_value);
void WorldWideSignalClient(uint32 signal, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideSignalNPC(uint32 signal);
void WorldWideUpdateActivity(uint32 task_id, int activity_id, int activity_count = 1, uint8 min_status = 0, uint8 max_status = 0);
void CrossZoneLDoNUpdate(uint8 update_type, uint8 update_subtype, int update_identifier, uint32 theme_id, int points = 1, const char* client_name = "");
void CrossZoneMarquee(uint8 update_type, int update_identifier, uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, const char* message, const char* client_name = "");
void CrossZoneMessage(uint8 update_type, int update_identifier, uint32 type, const char* message, const char* client_name = "");
void CrossZoneMove(uint8 update_type, uint8 update_subtype, int update_identifier, const char* zone_short_name, uint16 instance_id, const char* client_name = "");
void CrossZoneSetEntityVariable(uint8 update_type, int update_identifier, const char* variable_name, const char* variable_value, const char* client_name = "");
void CrossZoneSignal(uint8 update_type, int update_identifier, uint32 signal, const char* client_name = "");
void CrossZoneSpell(uint8 update_type, uint8 update_subtype, int update_identifier, uint32 spell_id, const char* client_name = "");
void CrossZoneTaskUpdate(uint8 update_type, uint8 update_subtype, int update_identifier, uint32 task_identifier, int task_subidentifier = -1, int update_count = 1, bool enforce_level_requirement = false, const char* client_name = "");
void WorldWideLDoNUpdate(uint8 update_type, uint32 theme_id, int points = 1, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideMarquee(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, const char* message, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideMessage(uint32 type, const char* message, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideMove(uint8 update_type, const char* zone_short_name, uint16 instance_id = 0, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideSetEntityVariable(uint8 update_type, const char* variable_name, const char* variable_value, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideSignal(uint8 update_type, uint32 signal, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideSpell(uint8 update_type, uint32 spell_id, uint8 min_status = 0, uint8 max_status = 0);
void WorldWideTaskUpdate(uint8 update_type, uint32 task_identifier, int task_subidentifier = -1, int update_count = 1, bool enforce_level_requirement = false, uint8 min_status = 0, uint8 max_status = 0);
bool EnableRecipe(uint32 recipe_id);
bool DisableRecipe(uint32 recipe_id);
void ClearNPCTypeCache(int npctype_id);
+93 -61
View File
@@ -63,6 +63,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
if (spell.disallow_sit && IsBuffSpell(spell_id) && IsClient() && (CastToClient()->IsSitting() || CastToClient()->GetHorseId() != 0))
return false;
bool CanMemoryBlurFromMez = true;
if (IsMezzed()) { //Check for special memory blur behavior when on mez, this needs to be before buff override.
CanMemoryBlurFromMez = false;
}
bool c_override = false;
if (caster && caster->IsClient() && GetCastedSpellInvSlot() > 0) {
const EQ::ItemInstance *inst = caster->CastToClient()->GetInv().GetItem(GetCastedSpellInvSlot());
@@ -343,31 +348,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Complete Heal");
#endif
//make sure they are not allready affected by this...
//I think that is the point of making this a buff.
//this is in the wrong spot, it should be in the immune
//section so the buff timer does not get refreshed!
int i;
bool inuse = false;
int buff_count = GetMaxTotalSlots();
for(i = 0; i < buff_count; i++) {
if(buffs[i].spellid == spell_id && i != buffslot) {
Message(0, "You must wait before you can be affected by this spell again.");
inuse = true;
break;
}
}
if(inuse)
break;
int32 val = 0;
val = 7500 * effect_value;
if (caster)
int val = 7500 * effect_value;
if (caster) {
val = caster->GetActSpellHealing(spell_id, val, this);
if (val > 0)
}
if (val > 0) {
HealDamage(val, caster);
}
break;
}
@@ -387,7 +374,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
caster->SetMana(caster->GetMana() + std::abs(effect_value));
if (effect_value < 0)
TryTriggerOnValueAmount(false, true);
TryTriggerOnCastRequirement();
#ifdef SPELL_EFFECT_SPAM
if (caster)
caster->Message(Chat::White, "You have gained %+i mana!", effect_value);
@@ -403,7 +390,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
SetMana(GetMana() + effect_value);
if (effect_value < 0)
TryTriggerOnValueAmount(false, true);
TryTriggerOnCastRequirement();
}
break;
@@ -600,7 +587,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
snprintf(effect_desc, _EDLEN, "Invisibility to Animals");
#endif
invisible_animals = true;
SetInvisible(0);
break;
}
@@ -611,7 +597,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
snprintf(effect_desc, _EDLEN, "Invisibility to Undead");
#endif
invisible_undead = true;
SetInvisible(0);
break;
}
case SE_SeeInvis:
@@ -1136,13 +1121,23 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
case SE_Purify:
{
//Attempt to remove all Deterimental buffs.
int buff_count = GetMaxTotalSlots();
for(int slot = 0; slot < buff_count; slot++) {
if (buffs[slot].spellid != SPELL_UNKNOWN &&
IsDetrimentalSpell(buffs[slot].spellid) && spells[buffs[slot].spellid].dispel_flag == 0)
{
if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){
//Attempt to remove up to base amount of detrimental effects (excluding charm, fear, resurrection, and revival sickness).
int purify_count = spells[spell_id].base[i];
if (purify_count > GetMaxTotalSlots()) {
purify_count = GetMaxTotalSlots();
}
for(int slot = 0; slot < purify_count; slot++) {
if (IsValidSpell(buffs[slot].spellid) && IsDetrimentalSpell(buffs[slot].spellid)){
if (!IsEffectInSpell(buffs[slot].spellid, SE_Charm) &&
!IsEffectInSpell(buffs[slot].spellid, SE_Fear) &&
buffs[slot].spellid != SPELL_RESURRECTION_SICKNESS &&
buffs[slot].spellid != SPELL_RESURRECTION_SICKNESS2 &&
buffs[slot].spellid != SPELL_RESURRECTION_SICKNESS3 &&
buffs[slot].spellid != SPELL_RESURRECTION_SICKNESS4 &&
buffs[slot].spellid != SPELL_REVIVAL_SICKNESS)
{
BuffFadeBySlot(slot);
}
}
@@ -1531,16 +1526,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Memory Blur: %d", effect_value);
#endif
int wipechance = spells[spell_id].base[i];
int bonus = 0;
if (caster){
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
caster->itembonuses.IncreaseChanceMemwipe +
caster->aabonuses.IncreaseChanceMemwipe;
//Memory blur component of Mez spells is not checked again if Mez is recast on a target that is already mezed
if (!CanMemoryBlurFromMez && IsEffectInSpell(spell_id, SE_Mez)) {
break;
}
int wipechance = 0;
if (caster) {
wipechance = caster->GetMemoryBlurChance(effect_value);
}
wipechance += wipechance*bonus/100;
if(zone->random.Roll(wipechance))
{
@@ -2458,8 +2453,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#endif
if(IsClient()) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + effect_value);
if (effect_value < 0)
TryTriggerOnValueAmount(false, false, true);
if (effect_value < 0) {
TryTriggerOnCastRequirement();
}
}
break;
}
@@ -2470,10 +2466,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
snprintf(effect_desc, _EDLEN, "Current Endurance Once: %+i", effect_value);
#endif
if(IsClient()) {
if (IsClient()) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + effect_value);
if (effect_value < 0)
TryTriggerOnValueAmount(false, false, true);
if (effect_value < 0) {
TryTriggerOnCastRequirement();
}
}
break;
}
@@ -2652,7 +2649,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
int32 mana_to_use = GetMana() - spell.base[i];
if(mana_to_use > -1) {
SetMana(GetMana() - spell.base[i]);
TryTriggerOnValueAmount(false, true);
TryTriggerOnCastRequirement();
// we take full dmg(-10 to make the damage the right sign)
mana_damage = spell.base[i] / -10 * spell.base2[i];
Damage(caster, mana_damage, spell_id, spell.skill, false, i, true);
@@ -2672,7 +2669,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
int32 end_to_use = CastToClient()->GetEndurance() - spell.base[i];
if(end_to_use > -1) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() - spell.base[i]);
TryTriggerOnValueAmount(false, false, true);
TryTriggerOnCastRequirement();
// we take full dmg(-10 to make the damage the right sign)
end_damage = spell.base[i] / -10 * spell.base2[i];
Damage(caster, end_damage, spell_id, spell.skill, false, i, true);
@@ -2754,7 +2751,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
else {
dmg = ratio*max_mana/10;
caster->SetMana(caster->GetMana() - max_mana);
TryTriggerOnValueAmount(false, true);
TryTriggerOnCastRequirement();
}
if(IsDetrimentalSpell(spell_id)) {
@@ -3858,19 +3855,15 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
}
case SE_WipeHateList: {
if (IsMezSpell(buff.spellid))
if (IsMezSpell(buff.spellid)) {
break;
int wipechance = spells[buff.spellid].base[i];
int bonus = 0;
if (caster) {
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
caster->itembonuses.IncreaseChanceMemwipe +
caster->aabonuses.IncreaseChanceMemwipe;
}
wipechance += wipechance * bonus / 100;
int wipechance = 0;
if (caster) {
wipechance = caster->GetMemoryBlurChance(effect_value);
}
if (zone->random.Roll(wipechance)) {
if (IsAIControlled()) {
@@ -8528,3 +8521,42 @@ int Mob::GetFocusRandomEffectivenessValue(int focus_base, int focus_base2, bool
return zone->random.Int(focus_base, focus_base2);
}
int Mob::GetMemoryBlurChance(int base_chance)
{
/*
Memory Blur mechanic for SPA 62
Chance formula is effect chance + charisma modifer + caster level modifier
Effect chance is base value of spell
Charisma modifier is CHA/10 = %, with MAX of 15% (thus 150 cha gives you max bonus)
Caster level modifier. +100% if caster < level 17 which scales down to 25% at > 53. **
(Yes the above gets worse as you level. Behavior was confirmed on live.)
Memory blur is applied to mez on initial cast using same formula. However, recasting on a target that
is already mezed will not give a chance to memory blur. The blur is not checked on buff ticks.
SPA 242 SE_IncreaseChanceMemwipe modifies the final chance after all bonuses are applied.
This is also applied to memory blur from mez spells.
this = caster
*/
int cha_mod = int(GetCHA() / 10);
cha_mod = std::min(cha_mod, 15);
int lvl_mod = 0;
if (GetLevel() < 17) {
lvl_mod = 100;
}
else if (GetLevel() > 53) {
lvl_mod = 25;
}
else {
lvl_mod = 100 + ((GetLevel() - 16)*-2);//Derived from above range of values.**
}
int chance = cha_mod + lvl_mod + base_chance;
int chance_mod = spellbonuses.IncreaseChanceMemwipe + itembonuses.IncreaseChanceMemwipe + aabonuses.IncreaseChanceMemwipe;
chance += chance * chance_mod / 100;
return chance;
}
+9 -4
View File
@@ -383,7 +383,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
GetName()
);
TryTriggerOnValueAmount(false, true);
TryTriggerOnCastRequirement();
return(false);
}
@@ -2467,7 +2467,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
LogSpells("Spell [{}]: consuming [{}] mana", spell_id, mana_used);
if (!DoHPToManaCovert(mana_used)) {
SetMana(GetMana() - mana_used);
TryTriggerOnValueAmount(false, true);
TryTriggerOnCastRequirement();
}
}
// one may want to check if this is a disc or not, but we actually don't, there are non disc stuff that have end cost
@@ -2478,7 +2478,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui
if (mgb)
end_cost *= 2;
SetEndurance(GetEndurance() - EQ::ClampUpper(end_cost, GetEndurance()));
TryTriggerOnValueAmount(false, false, true);
TryTriggerOnCastRequirement();
}
if (mgb)
SetMGB(false);
@@ -2931,6 +2931,11 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
LogSpells("Check Stacking on old [{}] ([{}]) @ lvl [{}] (by [{}]) vs. new [{}] ([{}]) @ lvl [{}] (by [{}])", sp1.name, spellid1, caster_level1, (caster1==nullptr)?"Nobody":caster1->GetName(), sp2.name, spellid2, caster_level2, (caster2==nullptr)?"Nobody":caster2->GetName());
if (spellbonuses.CompleteHealBuffBlocker && IsEffectInSpell(spellid2, SE_CompleteHeal)) {
Message(0, "You must wait before you can be affected by this spell again.");
return -1;
}
if (spellid1 == spellid2 ) {
if (!IsStackableDot(spellid1) && !IsEffectInSpell(spellid1, SE_ManaBurn)) { // mana burn spells we need to use the stacking command blocks live actually checks those first, we should probably rework to that too
if (caster_level1 > caster_level2) { // cur buff higher level than new
@@ -3401,7 +3406,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
buffs[emptyslot].focusproclimit_procamt = 0;
buffs[emptyslot].instrument_mod = caster ? caster->GetInstrumentMod(spell_id) : 10;
if (level_override > 0) {
if (level_override > 0 || buffs[emptyslot].numhits > 0) {
buffs[emptyslot].UpdateClient = true;
} else {
if (buffs[emptyslot].ticsremaining > (1 + CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration)))
+25 -8
View File
@@ -375,6 +375,14 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
}
DBTradeskillRecipe_Struct spec;
if (parse->EventPlayer(EVENT_COMBINE, user, std::to_string(in_combine->container_slot), 0) == 1) {
auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0);
user->QueuePacket(outapp);
safe_delete(outapp);
return;
}
if (!content_db.GetTradeRecipe(container, c_type, some_id, user->CharacterID(), &spec)) {
LogTradeskillsDetail("[HandleCombine] Check 2");
@@ -774,7 +782,7 @@ void Client::SendTradeskillSearchResults(
for (auto row = results.begin(); row != results.end(); ++row) {
if (row == nullptr || row[0] == nullptr || row[1] == nullptr || row[2] == nullptr || row[3] == nullptr ||
row[5] == nullptr) {
row[4] == nullptr || row[5] == nullptr) {
continue;
}
@@ -782,27 +790,36 @@ void Client::SendTradeskillSearchResults(
const char *name = row[1];
uint32 trivial = (uint32) atoi(row[2]);
uint32 comp_count = (uint32) atoi(row[3]);
uint32 tradeskill = (uint16) atoi(row[5]);
uint32 tradeskill = (uint16) atoi(row[4]);
uint32 must_learn = (uint16) atoi(row[5]);
// Skip the recipes that exceed the threshold in skill difference
// Recipes that have either been made before or were
// explicitly learned are excempt from that limit
auto character_learned_recipe = CharacterRecipeListRepository::GetRecipe(
character_learned_recipe_list,
recipe_id
);
if (RuleB(Skills, UseLimitTradeskillSearchSkillDiff) &&
((int32) trivial - (int32) GetSkill((EQ::skills::SkillType) tradeskill)) >
RuleI(Skills, MaxTradeskillSearchSkillDiff)) {
LogTradeskills("Checking limit recipe_id [{}] name [{}]", recipe_id, name);
auto character_learned_recipe = CharacterRecipeListRepository::GetRecipe(
character_learned_recipe_list,
recipe_id
);
if (character_learned_recipe.made_count == 0) {
continue;
}
}
//Skip recipes that must be learned
if ((must_learn & 0xf) && !character_learned_recipe.recipe_id) {
continue;
}
auto outapp = new EQApplicationPacket(OP_RecipeReply, sizeof(RecipeReply_Struct));
RecipeReply_Struct *reply = (RecipeReply_Struct *) outapp->pBuffer;
@@ -1481,7 +1498,7 @@ bool ZoneDatabase::GetTradeRecipe(
recipe_id
);
if (character_learned_recipe.made_count > 0) {
if (character_learned_recipe.recipe_id) { //If this exists we learned it
LogTradeskills("[GetTradeRecipe] made_count [{}]", character_learned_recipe.made_count);
spec->has_learnt = true;
+26
View File
@@ -935,6 +935,32 @@ void Mob::TryMoveAlong(float distance, float angle, bool send)
Teleport(new_pos);
}
// like above, but takes a starting position and returns a new location instead of actually moving
glm::vec4 Mob::TryMoveAlong(const glm::vec4 &start, float distance, float angle)
{
angle += start.w;
angle = FixHeading(angle);
glm::vec3 tmp_pos;
glm::vec3 new_pos = start;
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(start, new_pos, 0.0f, &tmp_pos))
new_pos = tmp_pos;
}
new_pos.z = GetFixedZ(new_pos);
return {new_pos.x, new_pos.y, new_pos.z, start.w};
}
int ZoneDatabase::GetHighestGrid(uint32 zoneid) {
std::string query = StringFormat("SELECT COALESCE(MAX(id), 0) FROM grid WHERE zoneid = %i", zoneid);
+741 -849
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -153,7 +153,6 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
LogInfo("Zone Bootup: [{}] ([{}]: [{}])", zonename, iZoneID, iInstanceID);
parse->Init();
UpdateWindowTitle(nullptr);
zone->GetTimeSync();
zone->RequestUCSServerStatus();
@@ -1818,7 +1817,8 @@ void Zone::Repop(uint32 delay)
void Zone::GetTimeSync()
{
if (worldserver.Connected() && !zone_has_current_time) {
if (!zone_has_current_time) {
LogInfo("Requesting world time");
auto pack = new ServerPacket(ServerOP_GetWorldTime, 1);
worldserver.SendPacket(pack);
safe_delete(pack);
+5 -1
View File
@@ -167,7 +167,9 @@ bool ZoneDatabase::GetZoneCFG(
"fast_regen_endurance, " // 59
"npc_max_aggro_dist, " // 60
"max_movement_update_range, " // 61
"underworld_teleport_index " // 62
"underworld_teleport_index, " // 62
"lava_damage, " // 63
"min_lava_damage " // 64
"FROM zone WHERE zoneidnumber = %i AND version = %i %s",
zoneid,
instance_id,
@@ -220,6 +222,8 @@ bool ZoneDatabase::GetZoneCFG(
zone_data->FastRegenEndurance = atoi(row[59]);
zone_data->NPCAggroMaxDist = atoi(row[60]);
zone_data->underworld_teleport_index = atoi(row[62]);
zone_data->LavaDamage = atoi(row[63]);
zone_data->MinLavaDamage = atoi(row[64]);
int bindable = 0;
bindable = atoi(row[31]);