- Fix #528 - IMMUNITY_TYPE_STRIKETHROUGH type 10 for AddImmunitySpell and like functions
- Fix #501 - /assist added, /assist on, /assist off, /assist [name], /assist *target* update commands set handler=535 where command='assist'; - Fix #511 - loot tables not properly honoring max drops - Fixed a few crashes / deadlocks with movement - Start of mastery work for #503 -- primary/secondary damage now supports mastery skill
This commit is contained in:
parent
4383e6b20a
commit
c1e8768769
15 changed files with 257 additions and 71 deletions
|
@ -4110,55 +4110,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
}
|
||||
case COMMAND_ATTACK:
|
||||
case COMMAND_AUTO_ATTACK:{
|
||||
int8 type = 1;
|
||||
bool update = false;
|
||||
Player* player = client->GetPlayer();
|
||||
if(!player)
|
||||
break;
|
||||
bool incombat = player->EngagedInCombat();
|
||||
if(sep && sep->arg[0] && sep->IsNumber(0))
|
||||
type = atoi(sep->arg[0]);
|
||||
if(!client->GetPlayer()->Alive()){
|
||||
client->SimpleMessage(CHANNEL_COLOR_RED,"You cannot do that right now.");
|
||||
break;
|
||||
}
|
||||
if(type == 0){
|
||||
if(incombat)
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You stop fighting.");
|
||||
player->StopCombat(type);
|
||||
update = true;
|
||||
}
|
||||
else {
|
||||
if(type == 2){
|
||||
player->InCombat(false);
|
||||
if(incombat && player->GetRangeAttack()){
|
||||
player->StopCombat(type);
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You stop fighting.");
|
||||
update = true;
|
||||
}
|
||||
else{
|
||||
player->SetRangeAttack(true);
|
||||
player->InCombat(true, true);
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You start fighting.");
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
player->InCombat(false, true);
|
||||
player->SetRangeAttack(false);
|
||||
player->InCombat(true);
|
||||
if(!incombat) {
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You start fighting.");
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
/*else
|
||||
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You cannot attack that!");*/
|
||||
}
|
||||
|
||||
if(update) {
|
||||
player->SetCharSheetChanged(true);
|
||||
}
|
||||
Command_AutoAttack(client, sep);
|
||||
break;
|
||||
}
|
||||
case COMMAND_DEPOP:{
|
||||
|
@ -5724,6 +5676,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
case COMMAND_SHARE_QUEST: { Command_ShareQuest(client, sep); break; }
|
||||
case COMMAND_YELL: { Command_Yell(client, sep); break; }
|
||||
case COMMAND_SETAUTOLOOTMODE: { Command_SetAutoLootMode(client, sep); break; }
|
||||
case COMMAND_ASSIST: { Command_Assist(client, sep); break; }
|
||||
default:
|
||||
{
|
||||
LogWrite(COMMAND__WARNING, 0, "Command", "Unhandled command: %s", command->command.data.c_str());
|
||||
|
@ -10970,6 +10923,8 @@ void Commands::Command_WeaponStats(Client* client)
|
|||
if (primary) {
|
||||
client->Message(0, "Name: %s", primary->name.c_str());
|
||||
client->Message(0, "Base Damage: %u - %u", primary->weapon_info->damage_low3, primary->weapon_info->damage_high3);
|
||||
client->Message(0, "Mastery Damage: %u - %u", primary->weapon_info->damage_low2, primary->weapon_info->damage_high2);
|
||||
client->Message(0, "Damage: %u - %u", primary->weapon_info->damage_low1, primary->weapon_info->damage_high1);
|
||||
client->Message(0, "Actual Damage: %u - %u", target ? ((Entity*)target)->GetPrimaryWeaponMinDamage() : player->GetPrimaryWeaponMinDamage(),
|
||||
target ? ((Entity*)target)->GetPrimaryWeaponMaxDamage() : player->GetPrimaryWeaponMaxDamage());
|
||||
client->Message(0, "Actual Delay: %u", target ? ((Entity*)target)->GetPrimaryWeaponDelay() : player->GetPrimaryWeaponDelay());
|
||||
|
@ -10992,6 +10947,8 @@ void Commands::Command_WeaponStats(Client* client)
|
|||
client->SimpleMessage(0, "Secondary:");
|
||||
client->Message(0, "Name: %s", secondary->name.c_str());
|
||||
client->Message(0, "Base Damage: %u - %u", secondary->weapon_info->damage_low3, secondary->weapon_info->damage_high3);
|
||||
client->Message(0, "Mastery Damage: %u - %u", secondary->weapon_info->damage_low2, secondary->weapon_info->damage_high2);
|
||||
client->Message(0, "Damage: %u - %u", secondary->weapon_info->damage_low1, secondary->weapon_info->damage_high1);
|
||||
client->Message(0, "Actual Damage: %u - %u", target ? ((Entity*)target)->GetSecondaryWeaponMinDamage() : player->GetSecondaryWeaponMinDamage(),
|
||||
target ? ((Entity*)target)->GetSecondaryWeaponMaxDamage() : player->GetSecondaryWeaponMaxDamage());
|
||||
client->Message(0, "Actual Delay: %d", target ? ((Entity*)target)->GetSecondaryWeaponDelay() : player->GetSecondaryWeaponDelay() * 0.1);
|
||||
|
@ -11004,6 +10961,8 @@ void Commands::Command_WeaponStats(Client* client)
|
|||
if (ranged) {
|
||||
client->Message(0, "Name: %s", ranged->name.c_str());
|
||||
client->Message(0, "Base Damage: %u - %u", ranged->ranged_info->weapon_info.damage_low3, ranged->ranged_info->weapon_info.damage_high3);
|
||||
client->Message(0, "Mastery Damage: %u - %u", ranged->ranged_info->weapon_info.damage_low2, ranged->ranged_info->weapon_info.damage_high2);
|
||||
client->Message(0, "Damage: %u - %u", ranged->ranged_info->weapon_info.damage_low1, ranged->ranged_info->weapon_info.damage_high1);
|
||||
client->Message(0, "Actual Damage: %u - %u", target ? ((Entity*)target)->GetRangedWeaponMinDamage() : player->GetRangedWeaponMinDamage(),
|
||||
target ? ((Entity*)target)->GetRangedWeaponMaxDamage() : player->GetRangedWeaponMaxDamage());
|
||||
client->Message(0, "Actual Delay: %d", target ? ((Entity*)target)->GetRangeWeaponDelay() : player->GetRangeWeaponDelay() * 0.1);
|
||||
|
@ -12156,3 +12115,101 @@ void Commands::Command_SetAutoLootMode(Client* client, Seperator* sep) {
|
|||
client->SendDefaultGroupOptions();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Command_AutoAttack()
|
||||
Purpose : Attack / Auto Attack
|
||||
Example : /attack, /autoattack type
|
||||
*/
|
||||
void Commands::Command_AutoAttack(Client* client, Seperator* sep) {
|
||||
int8 type = 1;
|
||||
bool update = false;
|
||||
Player* player = client->GetPlayer();
|
||||
if(!player)
|
||||
return;
|
||||
bool incombat = player->EngagedInCombat();
|
||||
if(sep && sep->arg[0] && sep->IsNumber(0))
|
||||
type = atoi(sep->arg[0]);
|
||||
if(!client->GetPlayer()->Alive()){
|
||||
client->SimpleMessage(CHANNEL_COLOR_RED,"You cannot do that right now.");
|
||||
return;
|
||||
}
|
||||
if(type == 0){
|
||||
if(incombat)
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You stop fighting.");
|
||||
player->StopCombat(type);
|
||||
update = true;
|
||||
}
|
||||
else {
|
||||
if(type == 2){
|
||||
player->InCombat(false);
|
||||
if(incombat && player->GetRangeAttack()){
|
||||
player->StopCombat(type);
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You stop fighting.");
|
||||
update = true;
|
||||
}
|
||||
else{
|
||||
player->SetRangeAttack(true);
|
||||
player->InCombat(true, true);
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You start fighting.");
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
player->InCombat(false, true);
|
||||
player->SetRangeAttack(false);
|
||||
player->InCombat(true);
|
||||
if(!incombat) {
|
||||
client->SimpleMessage(CHANNEL_GENERAL_COMBAT, "You start fighting.");
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
/*else
|
||||
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You cannot attack that!");*/
|
||||
}
|
||||
|
||||
if(update) {
|
||||
player->SetCharSheetChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: Command_Assist()
|
||||
Purpose : Assist target
|
||||
Example : /assist [name]
|
||||
* Uses target or character name
|
||||
*/
|
||||
void Commands::Command_Assist(Client* client, Seperator* sep) {
|
||||
Entity* player = (Entity*)client->GetPlayer();
|
||||
Spawn* res = nullptr;
|
||||
if(sep && sep->arg[0]) {
|
||||
if(!stricmp(sep->arg[0], "on")) {
|
||||
database.insertCharacterProperty(client, CHAR_PROPERTY_ASSISTAUTOATTACK, "1");
|
||||
return;
|
||||
}
|
||||
else if(!stricmp(sep->arg[0], "off")) {
|
||||
database.insertCharacterProperty(client, CHAR_PROPERTY_ASSISTAUTOATTACK, "0");
|
||||
return;
|
||||
}
|
||||
Client* otherClient = client->GetPlayer()->GetZone()->GetClientByName(sep->arg[0]);
|
||||
if(otherClient) {
|
||||
res = otherClient->GetPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
if (player->GetTarget()) {
|
||||
res = player->GetTarget(); // selected target other than self only dis-engages that encounter
|
||||
}
|
||||
if(res && res->GetTarget()) {
|
||||
res = res->GetTarget();
|
||||
}
|
||||
|
||||
if(res) {
|
||||
client->TargetSpawn(res);
|
||||
|
||||
if(client->GetPlayer()->GetInfoStruct()->get_assist_auto_attack() && !player->EngagedInCombat()) {
|
||||
Command_AutoAttack(client, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -450,6 +450,8 @@ public:
|
|||
void Command_ShareQuest(Client* client, Seperator* sep);
|
||||
void Command_Yell(Client* client, Seperator* sep);
|
||||
void Command_SetAutoLootMode(Client* client, Seperator* sep);
|
||||
void Command_AutoAttack(Client* client, Seperator* sep);
|
||||
void Command_Assist(Client* client, Seperator* sep);
|
||||
|
||||
// AA Commands
|
||||
void Get_AA_Xml(Client* client, Seperator* sep);
|
||||
|
@ -939,6 +941,7 @@ private:
|
|||
#define COMMAND_SHARE_QUEST 533
|
||||
|
||||
#define COMMAND_SETAUTOLOOTMODE 534
|
||||
#define COMMAND_ASSIST 535
|
||||
|
||||
#define GET_AA_XML 750
|
||||
#define ADD_AA 751
|
||||
|
|
|
@ -363,6 +363,7 @@ void Entity::MapInfoStruct()
|
|||
get_int8_funcs["group_lock_method"] = l::bind(&InfoStruct::get_group_lock_method, &info_struct);
|
||||
get_int8_funcs["group_solo_autolock"] = l::bind(&InfoStruct::get_group_solo_autolock, &info_struct);
|
||||
get_int8_funcs["group_auto_loot_method"] = l::bind(&InfoStruct::get_group_auto_loot_method, &info_struct);
|
||||
get_int8_funcs["assist_auto_attack"] = l::bind(&InfoStruct::get_assist_auto_attack, &info_struct);
|
||||
|
||||
get_string_funcs["action_state"] = l::bind(&InfoStruct::get_action_state, &info_struct);
|
||||
get_string_funcs["combat_action_state"] = l::bind(&InfoStruct::get_combat_action_state, &info_struct);
|
||||
|
@ -564,6 +565,7 @@ void Entity::MapInfoStruct()
|
|||
set_int8_funcs["group_lock_method"] = l::bind(&InfoStruct::set_group_lock_method, &info_struct, l::_1);
|
||||
set_int8_funcs["group_solo_autolock"] = l::bind(&InfoStruct::set_group_solo_autolock, &info_struct, l::_1);
|
||||
set_int8_funcs["group_auto_loot_method"] = l::bind(&InfoStruct::set_group_auto_loot_method, &info_struct, l::_1);
|
||||
set_int8_funcs["assist_auto_attack"] = l::bind(&InfoStruct::set_assist_auto_attack, &info_struct, l::_1);
|
||||
|
||||
set_string_funcs["action_state"] = l::bind(&InfoStruct::set_action_state, &info_struct, l::_1);
|
||||
set_string_funcs["combat_action_state"] = l::bind(&InfoStruct::set_combat_action_state, &info_struct, l::_1);
|
||||
|
@ -762,6 +764,62 @@ void Entity::SetSecondaryLastAttackTime(int32 new_time){
|
|||
GetInfoStruct()->set_secondary_last_attack_time(new_time);
|
||||
}
|
||||
|
||||
void Entity::GetWeaponDamage(Item* item, int32* low_damage, int32* high_damage) {
|
||||
if(!low_damage || !high_damage)
|
||||
return;
|
||||
int32 selected_low_dmg = item->weapon_info->damage_low3;
|
||||
int32 selected_high_dmg = item->weapon_info->damage_high3;
|
||||
|
||||
if(IsPlayer()) {
|
||||
float skillMultiplier = rule_manager.GetGlobalRule(R_Player, LevelMasterySkillMultiplier)->GetFloat();
|
||||
if(skillMultiplier <= 0.0f) {
|
||||
skillMultiplier = 1.0f;
|
||||
}
|
||||
int32 min_level_skill = (int32)((float)item->generic_info.adventure_default_level*skillMultiplier);
|
||||
int32 rec_level_skill = (int32)((float)item->details.recommended_level*skillMultiplier);
|
||||
if(min_level_skill > rec_level_skill) {
|
||||
rec_level_skill = rec_level_skill;
|
||||
}
|
||||
|
||||
Skill* masterySkill = ((Player*)this)->skill_list.GetSkill(item->generic_info.skill_req2);
|
||||
if(masterySkill) {
|
||||
LogWrite(PLAYER__ERROR, 0, "Player", "Item has skill %s %u requirement", masterySkill->name.data.c_str(), item->generic_info.skill_req2);
|
||||
int16 skillID = master_item_list.GetItemStatIDByName(masterySkill->name.data);
|
||||
int32 skill_chance = (int32)CalculateSkillWithBonus((char*)masterySkill->name.data.c_str(), master_item_list.GetItemStatIDByName(masterySkill->name.data), false);
|
||||
if(skill_chance >= min_level_skill && skill_chance < rec_level_skill) {
|
||||
int32 diff_skill = rec_level_skill - skill_chance;
|
||||
if(diff_skill < 1) {
|
||||
selected_low_dmg = item->weapon_info->damage_low2;
|
||||
selected_high_dmg = item->weapon_info->damage_high2;
|
||||
}
|
||||
else {
|
||||
diff_skill += 1;
|
||||
double logResult = log((double)diff_skill) / skillMultiplier;
|
||||
if(logResult > 1.0f) {
|
||||
logResult = .95f;
|
||||
}
|
||||
|
||||
selected_low_dmg = (int32)((double)item->weapon_info->damage_low2 * (1.0 - logResult));
|
||||
if(selected_low_dmg < item->weapon_info->damage_low3) {
|
||||
selected_low_dmg = item->weapon_info->damage_low3;
|
||||
}
|
||||
selected_high_dmg = (int32)((double)item->weapon_info->damage_high2 * (1.0 - logResult));
|
||||
if(selected_high_dmg < item->weapon_info->damage_high3) {
|
||||
selected_high_dmg = item->weapon_info->damage_high3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(skill_chance >= rec_level_skill) {
|
||||
selected_low_dmg = item->weapon_info->damage_low2;
|
||||
selected_high_dmg = item->weapon_info->damage_high2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*low_damage = selected_low_dmg;
|
||||
*high_damage = selected_high_dmg;
|
||||
}
|
||||
|
||||
void Entity::ChangePrimaryWeapon(){
|
||||
if(GetInfoStruct()->get_override_primary_weapon()) {
|
||||
return;
|
||||
|
@ -770,9 +828,12 @@ void Entity::ChangePrimaryWeapon(){
|
|||
int32 str_offset_dmg = GetStrengthDamage();
|
||||
Item* item = equipment_list.GetItem(EQ2_PRIMARY_SLOT);
|
||||
if(item && item->details.item_id > 0 && item->IsWeapon()){
|
||||
int32 selected_low_dmg = item->weapon_info->damage_low3;
|
||||
int32 selected_high_dmg = item->weapon_info->damage_high3;
|
||||
GetWeaponDamage(item, &selected_low_dmg, &selected_high_dmg);
|
||||
GetInfoStruct()->set_primary_weapon_delay(item->weapon_info->delay * 100);
|
||||
GetInfoStruct()->set_primary_weapon_damage_low(item->weapon_info->damage_low3 + str_offset_dmg);
|
||||
GetInfoStruct()->set_primary_weapon_damage_high(item->weapon_info->damage_high3 + str_offset_dmg);
|
||||
GetInfoStruct()->set_primary_weapon_damage_low(selected_low_dmg + str_offset_dmg);
|
||||
GetInfoStruct()->set_primary_weapon_damage_high(selected_high_dmg + str_offset_dmg);
|
||||
GetInfoStruct()->set_primary_weapon_type(item->GetWeaponType());
|
||||
GetInfoStruct()->set_wield_type(item->weapon_info->wield_type);
|
||||
}
|
||||
|
@ -803,9 +864,12 @@ void Entity::ChangeSecondaryWeapon(){
|
|||
|
||||
Item* item = equipment_list.GetItem(EQ2_SECONDARY_SLOT);
|
||||
if(item && item->details.item_id > 0 && item->IsWeapon()){
|
||||
int32 selected_low_dmg = item->weapon_info->damage_low3;
|
||||
int32 selected_high_dmg = item->weapon_info->damage_high3;
|
||||
GetWeaponDamage(item, &selected_low_dmg, &selected_high_dmg);
|
||||
GetInfoStruct()->set_secondary_weapon_delay(item->weapon_info->delay * 100);
|
||||
GetInfoStruct()->set_secondary_weapon_damage_low(item->weapon_info->damage_low3 + str_offset_dmg);
|
||||
GetInfoStruct()->set_secondary_weapon_damage_high(item->weapon_info->damage_high3 + str_offset_dmg);
|
||||
GetInfoStruct()->set_secondary_weapon_damage_low(selected_low_dmg + str_offset_dmg);
|
||||
GetInfoStruct()->set_secondary_weapon_damage_high(selected_high_dmg + str_offset_dmg);
|
||||
GetInfoStruct()->set_secondary_weapon_type(item->GetWeaponType());
|
||||
}
|
||||
else{
|
||||
|
@ -1563,6 +1627,8 @@ void Entity::CalculateBonuses(){
|
|||
|
||||
CalculateApplyWeight();
|
||||
|
||||
UpdateWeapons();
|
||||
|
||||
safe_delete(values);
|
||||
}
|
||||
|
||||
|
|
|
@ -287,6 +287,7 @@ struct InfoStruct{
|
|||
group_lock_method_ = 0;
|
||||
group_solo_autolock_ = 0;
|
||||
group_auto_loot_method_ = 0;
|
||||
assist_auto_attack_ = 0;
|
||||
|
||||
action_state_ = std::string("");
|
||||
}
|
||||
|
@ -697,6 +698,7 @@ struct InfoStruct{
|
|||
int8 get_group_lock_method() { std::lock_guard<std::mutex> lk(classMutex); return group_lock_method_; }
|
||||
int8 get_group_solo_autolock() { std::lock_guard<std::mutex> lk(classMutex); return group_solo_autolock_; }
|
||||
int8 get_group_auto_loot_method() { std::lock_guard<std::mutex> lk(classMutex); return group_auto_loot_method_; }
|
||||
int8 get_assist_auto_attack() { std::lock_guard<std::mutex> lk(classMutex); return assist_auto_attack_; }
|
||||
|
||||
std::string get_action_state() { std::lock_guard<std::mutex> lk(classMutex); return action_state_; }
|
||||
|
||||
|
@ -1003,6 +1005,8 @@ struct InfoStruct{
|
|||
void set_group_solo_autolock(int8 value) { std::lock_guard<std::mutex> lk(classMutex); group_solo_autolock_ = value; }
|
||||
void set_group_auto_loot_method(int8 value) { std::lock_guard<std::mutex> lk(classMutex); group_auto_loot_method_ = value; }
|
||||
|
||||
void set_assist_auto_attack(int8 value) { std::lock_guard<std::mutex> lk(classMutex); assist_auto_attack_ = value; }
|
||||
|
||||
void set_action_state(std::string value) { std::lock_guard<std::mutex> lk(classMutex); action_state_ = value; }
|
||||
|
||||
void set_combat_action_state(std::string value) { std::lock_guard<std::mutex> lk(classMutex); combat_action_state_ = value; }
|
||||
|
@ -1223,6 +1227,8 @@ private:
|
|||
int8 group_solo_autolock_;
|
||||
int8 group_auto_loot_method_;
|
||||
|
||||
int8 assist_auto_attack_;
|
||||
|
||||
std::string action_state_;
|
||||
std::string combat_action_state_;
|
||||
|
||||
|
@ -1323,6 +1329,7 @@ struct ThreatTransfer {
|
|||
#define IMMUNITY_TYPE_AOE 7
|
||||
#define IMMUNITY_TYPE_TAUNT 8
|
||||
#define IMMUNITY_TYPE_RIPOSTE 9
|
||||
#define IMMUNITY_TYPE_STRIKETHROUGH 10
|
||||
|
||||
//class Spell;
|
||||
//class ZoneServer;
|
||||
|
@ -1454,6 +1461,8 @@ public:
|
|||
bool IsDualWield();
|
||||
bool BehindTarget(Spawn* target);
|
||||
bool FlankingTarget(Spawn* target);
|
||||
|
||||
void GetWeaponDamage(Item* item, int32* low_damage, int32* high_damage);
|
||||
void ChangePrimaryWeapon();
|
||||
void ChangeSecondaryWeapon();
|
||||
void ChangeRangedWeapon();
|
||||
|
|
|
@ -849,6 +849,16 @@ ItemStatsValues* MasterItemList::CalculateItemBonuses(Item* item, Entity* entity
|
|||
id = stat->stat_type*multiplier + stat->stat_subtype;
|
||||
}
|
||||
|
||||
if(entity->IsPlayer()) {
|
||||
int32 effective_level = entity->GetInfoStructUInt("effective_level");
|
||||
if(effective_level && effective_level < entity->GetLevel() && item->details.recommended_level > effective_level)
|
||||
{
|
||||
int32 diff = item->details.recommended_level - effective_level;
|
||||
float tmpValue = (float)value;
|
||||
value = (sint32)(float)(tmpValue / (1.0f + ((float)diff * rule_manager.GetGlobalRule(R_Player, MentorItemDecayRate)->GetFloat())));
|
||||
}
|
||||
}
|
||||
|
||||
world.AddBonuses(item, values, id, value, entity);
|
||||
}
|
||||
return values;
|
||||
|
|
|
@ -13335,7 +13335,7 @@ int EQ2Emu_lua_StopMovement(lua_State* state) {
|
|||
return 0;
|
||||
Spawn* spawn = lua_interface->GetSpawn(state);
|
||||
if (spawn) {
|
||||
spawn->StopMovement();
|
||||
spawn->ResetMovement();
|
||||
}
|
||||
lua_interface->ResetFunctionStack(state);
|
||||
return 0;
|
||||
|
|
|
@ -1742,8 +1742,31 @@ bool Player::CanEquipItem(Item* item, int8 slot) {
|
|||
else
|
||||
client->Message(CHANNEL_COLOR_RED, "Your class may not equip %s.", item->CreateItemLink(client->GetVersion()).c_str());
|
||||
}
|
||||
else
|
||||
client->SimpleMessage(0, "You lack the skill required to equip this item.");
|
||||
else {
|
||||
Skill* firstSkill = master_skill_list.GetSkill(item->generic_info.skill_req1);
|
||||
Skill* secondSkill = master_skill_list.GetSkill(item->generic_info.skill_req2);
|
||||
std::string msg("");
|
||||
if(GetClient()->GetAdminStatus() >= 200) {
|
||||
if(firstSkill && !skill_list.HasSkill(item->generic_info.skill_req1)) {
|
||||
msg += "(" + std::string(firstSkill->name.data.c_str());
|
||||
}
|
||||
|
||||
if(secondSkill && !skill_list.HasSkill(item->generic_info.skill_req2)) {
|
||||
if(msg.length() > 0) {
|
||||
msg += ", ";
|
||||
}
|
||||
else {
|
||||
msg = "(";
|
||||
}
|
||||
msg += std::string(secondSkill->name.data.c_str());
|
||||
}
|
||||
|
||||
if(msg.length() > 0) {
|
||||
msg += ") ";
|
||||
}
|
||||
}
|
||||
client->Message(0, "You lack the skill %srequired to equip this item.",msg.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
client->Message(0, "Item %s isn't equipable.", item->name.c_str());
|
||||
|
|
|
@ -226,6 +226,7 @@ void RuleManager::Init()
|
|||
RULE_INIT(R_Player, WeightPercentCap, "0.95"); // cap total impact for being overweight (.95 = 95%)
|
||||
RULE_INIT(R_Player, CoinWeightPerHundred, "100.0"); // coin weight per stone, 100.0 = 100 coins per 1 stone
|
||||
RULE_INIT(R_Player, WeightInflictsSpeed, "1"); // whether weight will inflict speed, 1 = on, 0 = off
|
||||
RULE_INIT(R_Player, LevelMasterySkillMultiplier, "5"); // multiplier for adventure level / recommended level when applying mastery damage to determine if they are in mastery range
|
||||
|
||||
/* PVP */
|
||||
RULE_INIT(R_PVP, AllowPVP, "0");
|
||||
|
|
|
@ -86,6 +86,7 @@ enum RuleType {
|
|||
WeightPercentCap,
|
||||
CoinWeightPerHundred,
|
||||
WeightInflictsSpeed,
|
||||
LevelMasterySkillMultiplier,
|
||||
|
||||
/* PVP */
|
||||
AllowPVP,
|
||||
|
|
|
@ -147,6 +147,7 @@ Spawn::Spawn(){
|
|||
looter_spawn_id = 0;
|
||||
is_loot_complete = false;
|
||||
is_loot_dispensed = false;
|
||||
reset_movement = false;
|
||||
}
|
||||
|
||||
Spawn::~Spawn(){
|
||||
|
@ -2847,6 +2848,10 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
|
|||
}*/
|
||||
return;
|
||||
}
|
||||
if(reset_movement) {
|
||||
ResetMovement();
|
||||
reset_movement = false;
|
||||
}
|
||||
|
||||
if (forceMapCheck && GetZone() != nullptr && GetMap() != nullptr && GetMap()->IsMapLoaded())
|
||||
{
|
||||
|
@ -3113,9 +3118,9 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
|
|||
}*/
|
||||
}
|
||||
|
||||
void Spawn::ResetMovement(bool inFlight){
|
||||
if(!inFlight)
|
||||
void Spawn::ResetMovement(){
|
||||
MMovementLoop.writelock();
|
||||
|
||||
vector<MovementData*>::iterator itr;
|
||||
for(itr = movement_loop.begin(); itr != movement_loop.end(); itr++){
|
||||
safe_delete(*itr);
|
||||
|
@ -3125,10 +3130,9 @@ void Spawn::ResetMovement(bool inFlight){
|
|||
resume_movement = true;
|
||||
ClearRunningLocations();
|
||||
|
||||
if(!inFlight)
|
||||
MMovementLoop.releasewritelock();
|
||||
|
||||
ValidateRunning(true, (inFlight == false));
|
||||
ValidateRunning(true, true);
|
||||
}
|
||||
|
||||
void Spawn::AddMovementLocation(float x, float y, float z, float speed, int16 delay, const char* lua_function, float heading, bool include_heading){
|
||||
|
@ -4541,7 +4545,7 @@ float Spawn::SpawnAngle(Spawn* target, float selfx, float selfz)
|
|||
|
||||
void Spawn::StopMovement()
|
||||
{
|
||||
ResetMovement(true);
|
||||
reset_movement = true;
|
||||
}
|
||||
|
||||
bool Spawn::PauseMovement(int32 period_of_time_ms)
|
||||
|
|
|
@ -1104,7 +1104,7 @@ public:
|
|||
void MoveToLocation(Spawn* spawn, float distance, bool immediate = true, bool isMappedLocation = false);
|
||||
void AddMovementLocation(float x, float y, float z, float speed, int16 delay, const char* lua_function, float heading, bool include_heading = false);
|
||||
void ProcessMovement(bool isSpawnListLocked=false);
|
||||
void ResetMovement(bool inFlight=false);
|
||||
void ResetMovement();
|
||||
bool ValidateRunning(bool lockMovementLocation, bool lockMovementLoop);
|
||||
bool IsRunning();
|
||||
void CalculateRunningLocation(bool stop = false);
|
||||
|
@ -1506,6 +1506,7 @@ private:
|
|||
int32 loot_drop_type;
|
||||
|
||||
std::atomic<bool> deleted_spawn;
|
||||
std::atomic<bool> reset_movement;
|
||||
Mutex m_GridMutex;
|
||||
bool is_collector;
|
||||
bool scared_by_strong_players;
|
||||
|
|
|
@ -2150,6 +2150,11 @@ bool WorldDatabase::loadCharacterProperties(Client* client) {
|
|||
int8 val = atoul(prop_value);
|
||||
client->GetPlayer()->GetInfoStruct()->set_group_lock_method(val);
|
||||
}
|
||||
else if (!stricmp(prop_name, CHAR_PROPERTY_ASSISTAUTOATTACK))
|
||||
{
|
||||
int8 val = atoul(prop_value);
|
||||
client->GetPlayer()->GetInfoStruct()->set_assist_auto_attack(val);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -122,6 +122,8 @@ using namespace std;
|
|||
#define CHAR_PROPERTY_GROUPSOLOAUTOLOCK "group_solo_autolock"
|
||||
#define CHAR_PROPERTY_AUTOLOOTMETHOD "group_auto_loot_method"
|
||||
|
||||
#define CHAR_PROPERTY_ASSISTAUTOATTACK "assist_auto_attack"
|
||||
|
||||
#define DB_TYPE_SPELLEFFECTS 1
|
||||
#define DB_TYPE_MAINTAINEDEFFECTS 2
|
||||
|
||||
|
|
|
@ -726,10 +726,6 @@ void Client::SendCharInfo() {
|
|||
|
||||
SendControlGhost(player->GetIDWithPlayerSpawn(player), 255);
|
||||
|
||||
if (version <= 283) {
|
||||
//le: hack to allow client time to zone in, it gets stuck on Loading UI Resources if we go too fast, need to figure it out. Probably something it doesnt like with ExamineInfo packets
|
||||
Sleep(2000);
|
||||
}
|
||||
//sending bad spawn packet?
|
||||
|
||||
//SendAchievementsList();
|
||||
|
|
|
@ -2773,6 +2773,7 @@ void ZoneServer::AddLoot(NPC* npc, Spawn* killer, GroupLootMethod loot_method, i
|
|||
|
||||
int droplistsize = loot_drops->size();
|
||||
float chancedroptally = 0;
|
||||
bool breakIterMaxLoot = false;
|
||||
chancedrop = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / 100));
|
||||
for (loot_drop_itr = loot_drops->begin(); loot_drop_itr != loot_drops->end(); loot_drop_itr++) {
|
||||
drop = *loot_drop_itr;
|
||||
|
@ -2825,7 +2826,14 @@ void ZoneServer::AddLoot(NPC* npc, Spawn* killer, GroupLootMethod loot_method, i
|
|||
//if(drop->equip_item)
|
||||
|
||||
}
|
||||
if (table->maxlootitems > 0 && count >= table->maxlootitems)
|
||||
// so many items on this table break out and cap it!
|
||||
if (table->maxlootitems > 0 && count >= table->maxlootitems) {
|
||||
breakIterMaxLoot = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// hit our max item drop for this table already, break out of numberchances
|
||||
if(breakIterMaxLoot) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue