Fix #318 - added spawn set scared_strong_players [0|1]. NPCs will be afraid if gray con and in aggro range, needs faction to check aggro list
This commit is contained in:
parent
dbf6d0a630
commit
2ea1982355
10 changed files with 115 additions and 17 deletions
1
DB/updates/spawnnpc_update_feb12_2023.sql
Normal file
1
DB/updates/spawnnpc_update_feb12_2023.sql
Normal file
|
@ -0,0 +1 @@
|
|||
alter table spawn_npcs add column scared_by_strong_players tinyint(3) unsigned not null default 0;
|
|
@ -201,6 +201,7 @@ Commands::Commands(){
|
|||
spawn_set_values["race_type"] = SPAWN_SET_RACE_TYPE;
|
||||
spawn_set_values["loot_tier"] = SPAWN_SET_LOOT_TIER;
|
||||
spawn_set_values["loot_drop_type"] = SPAWN_SET_LOOT_DROP_TYPE;
|
||||
spawn_set_values["scared_strong_players"] = SPAWN_SET_SCARED_STRONG_PLAYERS;
|
||||
|
||||
zone_set_values["expansion_id"] = ZONE_SET_VALUE_EXPANSION_ID;
|
||||
zone_set_values["name"] = ZONE_SET_VALUE_NAME;
|
||||
|
@ -898,6 +899,14 @@ bool Commands::SetSpawnCommand(Client* client, Spawn* target, int8 type, const c
|
|||
}
|
||||
break;
|
||||
}
|
||||
case SPAWN_SET_SCARED_STRONG_PLAYERS:{
|
||||
if(target->IsNPC()){
|
||||
sprintf(tmp, "%u", target->IsScaredByStrongPlayers());
|
||||
int32 new_value = atoul(value);
|
||||
target->SetScaredByStrongPlayers(new_value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(temp_value)
|
||||
*temp_value = string(tmp);
|
||||
|
@ -1604,6 +1613,22 @@ bool Commands::SetSpawnCommand(Client* client, Spawn* target, int8 type, const c
|
|||
}
|
||||
break;
|
||||
}
|
||||
case SPAWN_SET_SCARED_STRONG_PLAYERS:{
|
||||
int32 new_value = atoul(value);
|
||||
target->SetScaredByStrongPlayers(new_value);
|
||||
|
||||
if (target->GetDatabaseID() > 0)
|
||||
{
|
||||
char query[256];
|
||||
snprintf(query, 256, "update spawn_npcs set scared_by_strong_players=%u where id=%u", atoul(value), target->GetDatabaseID());
|
||||
if (database.RunQuery(query, strnlen(query, 256)))
|
||||
{
|
||||
if(client)
|
||||
client->Message(CHANNEL_COLOR_RED, "Ran query:%s", query);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -4959,6 +4984,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
|
|||
case SPAWN_SET_RACE_TYPE:
|
||||
case SPAWN_SET_LOOT_TIER:
|
||||
case SPAWN_SET_LOOT_DROP_TYPE:
|
||||
case SPAWN_SET_SCARED_STRONG_PLAYERS:
|
||||
{
|
||||
// not applicable already ran db command
|
||||
break;
|
||||
|
|
|
@ -571,6 +571,7 @@ private:
|
|||
#define SPAWN_SET_RACE_TYPE 103
|
||||
#define SPAWN_SET_LOOT_TIER 104
|
||||
#define SPAWN_SET_LOOT_DROP_TYPE 105
|
||||
#define SPAWN_SET_SCARED_STRONG_PLAYERS 106
|
||||
|
||||
#define ZONE_SET_VALUE_EXPANSION_ID 0
|
||||
#define ZONE_SET_VALUE_NAME 1
|
||||
|
|
|
@ -104,6 +104,7 @@ NPC::NPC(NPC* old_npc){
|
|||
SetLootTier(old_npc->GetLootTier());
|
||||
SetLootDropType(old_npc->GetLootDropType());
|
||||
has_spells = old_npc->HasSpells();
|
||||
SetScaredByStrongPlayers(old_npc->IsScaredByStrongPlayers());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6940,3 +6940,39 @@ void Player::GetSpellBookSlotSort(int32 pattern, int32* i, int8* page_book_count
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Player::IsSpawnInRangeList(int32 spawn_id) {
|
||||
std::shared_lock lock(spawn_aggro_range_mutex);
|
||||
map<int32, bool>::iterator spawn_itr = player_aggro_range_spawns.find(spawn_id);
|
||||
if(spawn_itr != player_aggro_range_spawns.end()) {
|
||||
return spawn_itr->second;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Player::SetSpawnInRangeList(int32 spawn_id, bool in_range) {
|
||||
std::unique_lock lock(spawn_aggro_range_mutex);
|
||||
player_aggro_range_spawns[spawn_id] = in_range;
|
||||
}
|
||||
|
||||
void Player::ProcessSpawnRangeUpdates() {
|
||||
std::unique_lock lock(spawn_aggro_range_mutex);
|
||||
if(GetClient()->GetCurrentZone() == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
map<int32, bool>::iterator spawn_itr;
|
||||
for(spawn_itr = player_aggro_range_spawns.begin(); spawn_itr != player_aggro_range_spawns.end();) {
|
||||
if(spawn_itr->second) {
|
||||
Spawn* spawn = GetClient()->GetCurrentZone()->GetSpawnByID(spawn_itr->first);
|
||||
if(spawn && spawn->IsNPC() && (GetDistance(spawn)) > ((NPC*)spawn)->GetAggroRadius()) {
|
||||
GetClient()->GetCurrentZone()->SendSpawnChanges((NPC*)spawn, GetClient(), true, true);
|
||||
spawn_itr->second = false;
|
||||
spawn_itr = player_aggro_range_spawns.erase(spawn_itr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
spawn_itr++;
|
||||
}
|
||||
}
|
|
@ -973,6 +973,7 @@ public:
|
|||
Mutex vis_mutex;
|
||||
Mutex index_mutex;
|
||||
Mutex spawn_mutex;
|
||||
mutable std::shared_mutex spawn_aggro_range_mutex;
|
||||
|
||||
void SetTempMount(int32 id) { tmp_mount_model = id; }
|
||||
int32 GetTempMount() { return tmp_mount_model; }
|
||||
|
@ -1052,6 +1053,10 @@ public:
|
|||
void SetActiveReward(bool val) { active_reward = val; }
|
||||
bool IsActiveReward() { return active_reward; }
|
||||
|
||||
|
||||
bool IsSpawnInRangeList(int32 spawn_id);
|
||||
void SetSpawnInRangeList(int32 spawn_id, bool in_range);
|
||||
void ProcessSpawnRangeUpdates();
|
||||
Mutex MPlayerQuests;
|
||||
float pos_packet_speed;
|
||||
private:
|
||||
|
@ -1179,6 +1184,7 @@ private:
|
|||
|
||||
map<int32, Spawn*> player_spawn_id_map;
|
||||
map<Spawn*, int32> player_spawn_reverse_id_map;
|
||||
map<int32, bool> player_aggro_range_spawns;
|
||||
|
||||
bool all_spells_locked;
|
||||
Timer lift_cooldown;
|
||||
|
|
|
@ -137,6 +137,7 @@ Spawn::Spawn(){
|
|||
deleted_spawn = false;
|
||||
is_collector = false;
|
||||
trigger_widget_id = 0;
|
||||
scared_by_strong_players = false;
|
||||
}
|
||||
|
||||
Spawn::~Spawn(){
|
||||
|
@ -2354,14 +2355,6 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
|
|||
packet->setDataByName("difficulty", appearance.encounter_level); //6);
|
||||
packet->setDataByName("unknown6", 1);
|
||||
packet->setDataByName("heroic_flag", appearance.heroic_flag);
|
||||
if (IsNPC() && !IsPet())
|
||||
{
|
||||
if(((Entity*)this)->GetInfoStruct()->get_interaction_flag())
|
||||
packet->setDataByName("interaction_flag", ((Entity*)this)->GetInfoStruct()->get_interaction_flag()); //this makes NPCs head turn to look at you (12)
|
||||
else
|
||||
packet->setDataByName("interaction_flag", 12); //turn head since no other value is set
|
||||
}
|
||||
|
||||
packet->setDataByName("class", appearance.adventure_class);
|
||||
|
||||
int16 model_type = appearance.model_type;
|
||||
|
@ -2393,12 +2386,28 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
|
|||
else
|
||||
packet->setDataByName("action_state", appearance.action_state);
|
||||
|
||||
bool scaredOfPlayer = false;
|
||||
|
||||
if(IsCollector() && spawn->GetCollectionList()->HasCollectionsToHandIn())
|
||||
packet->setDataByName("visual_state", 6674);
|
||||
packet->setDataByName("visual_state", VISUAL_STATE_COLLECTION_TURN_IN);
|
||||
else if(!IsRunning() && IsNPC() && IsScaredByStrongPlayers() && spawn->GetArrowColor(GetLevel()) == ARROW_COLOR_GRAY &&
|
||||
(GetDistance(spawn)) <= ((NPC*)this)->GetAggroRadius() && CheckLoS(spawn)) {
|
||||
packet->setDataByName("visual_state", VISUAL_STATE_IDLE_AFRAID);
|
||||
scaredOfPlayer = true;
|
||||
}
|
||||
else if (GetTempVisualState() >= 0)
|
||||
packet->setDataByName("visual_state", GetTempVisualState());
|
||||
else
|
||||
packet->setDataByName("visual_state", appearance.visual_state);
|
||||
|
||||
if (IsNPC() && !IsPet() && !scaredOfPlayer)
|
||||
{
|
||||
if(((Entity*)this)->GetInfoStruct()->get_interaction_flag())
|
||||
packet->setDataByName("interaction_flag", ((Entity*)this)->GetInfoStruct()->get_interaction_flag()); //this makes NPCs head turn to look at you (12)
|
||||
else
|
||||
packet->setDataByName("interaction_flag", 12); //turn head since no other value is set
|
||||
}
|
||||
|
||||
packet->setDataByName("emote_state", appearance.emote_state);
|
||||
packet->setDataByName("mood_state", appearance.mood_state);
|
||||
packet->setDataByName("gender", appearance.gender);
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
#define ENCOUNTER_STATE_OVERMATCHED 4
|
||||
#define ENCOUNTER_STATE_NO_REWARD 5
|
||||
|
||||
#define VISUAL_STATE_COLLECTION_TURN_IN 6674
|
||||
#define VISUAL_STATE_IDLE_AFRAID 17953
|
||||
|
||||
using namespace std;
|
||||
class Spell;
|
||||
class ZoneServer;
|
||||
|
@ -1084,10 +1087,12 @@ public:
|
|||
void FaceTarget(Spawn* target, bool disable_action_state = true);
|
||||
void SetInvulnerable(bool val);
|
||||
bool GetInvulnerable();
|
||||
bool changed;
|
||||
bool position_changed;
|
||||
bool info_changed;
|
||||
bool vis_changed;
|
||||
void SetScaredByStrongPlayers(bool val) { scared_by_strong_players = val; }
|
||||
bool IsScaredByStrongPlayers() { return scared_by_strong_players; }
|
||||
std::atomic<bool> changed;
|
||||
std::atomic<bool> position_changed;
|
||||
std::atomic<bool> info_changed;
|
||||
std::atomic<bool> vis_changed;
|
||||
int16 size;
|
||||
int32 faction_id;
|
||||
int8 oversized_packet; //0xff
|
||||
|
@ -1397,6 +1402,7 @@ private:
|
|||
std::atomic<bool> deleted_spawn;
|
||||
Mutex m_GridMutex;
|
||||
bool is_collector;
|
||||
bool scared_by_strong_players;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -932,7 +932,7 @@ void WorldDatabase::LoadNPCs(ZoneServer* zone){
|
|||
NPC* npc = 0;
|
||||
int32 id = 0;
|
||||
int32 total = 0;
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT,"SELECT npc.spawn_id, s.name, npc.min_level, npc.max_level, npc.enc_level, s.race, s.model_type, npc.class_, npc.gender, s.command_primary, s.command_secondary, s.show_name, npc.min_group_size, npc.max_group_size, npc.hair_type_id, npc.facial_hair_type_id, npc.wing_type_id, npc.chest_type_id, npc.legs_type_id, npc.soga_hair_type_id, npc.soga_facial_hair_type_id, s.attackable, s.show_level, s.targetable, s.show_command_icon, s.display_hand_icon, s.hp, s.power, s.size, s.collision_radius, npc.action_state, s.visual_state, npc.mood_state, npc.initial_state, npc.activity_status, s.faction_id, s.sub_title, s.merchant_id, s.merchant_type, s.size_offset, npc.attack_type, npc.ai_strategy+0, npc.spell_list_id, npc.secondary_spell_list_id, npc.skill_list_id, npc.secondary_skill_list_id, npc.equipment_list_id, npc.str, npc.sta, npc.wis, npc.intel, npc.agi, npc.heat, npc.cold, npc.magic, npc.mental, npc.divine, npc.disease, npc.poison, npc.aggro_radius, npc.cast_percentage, npc.randomize, npc.soga_model_type, npc.heroic_flag, npc.alignment, npc.elemental, npc.arcane, npc.noxious, s.savagery, s.dissonance, npc.hide_hood, npc.emote_state, s.prefix, s.suffix, s.last_name, s.expansion_flag, s.holiday_flag, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, npc.water_type, npc.flying_type, s.loot_tier, s.loot_drop_type\n"
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT,"SELECT npc.spawn_id, s.name, npc.min_level, npc.max_level, npc.enc_level, s.race, s.model_type, npc.class_, npc.gender, s.command_primary, s.command_secondary, s.show_name, npc.min_group_size, npc.max_group_size, npc.hair_type_id, npc.facial_hair_type_id, npc.wing_type_id, npc.chest_type_id, npc.legs_type_id, npc.soga_hair_type_id, npc.soga_facial_hair_type_id, s.attackable, s.show_level, s.targetable, s.show_command_icon, s.display_hand_icon, s.hp, s.power, s.size, s.collision_radius, npc.action_state, s.visual_state, npc.mood_state, npc.initial_state, npc.activity_status, s.faction_id, s.sub_title, s.merchant_id, s.merchant_type, s.size_offset, npc.attack_type, npc.ai_strategy+0, npc.spell_list_id, npc.secondary_spell_list_id, npc.skill_list_id, npc.secondary_skill_list_id, npc.equipment_list_id, npc.str, npc.sta, npc.wis, npc.intel, npc.agi, npc.heat, npc.cold, npc.magic, npc.mental, npc.divine, npc.disease, npc.poison, npc.aggro_radius, npc.cast_percentage, npc.randomize, npc.soga_model_type, npc.heroic_flag, npc.alignment, npc.elemental, npc.arcane, npc.noxious, s.savagery, s.dissonance, npc.hide_hood, npc.emote_state, s.prefix, s.suffix, s.last_name, s.expansion_flag, s.holiday_flag, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, npc.water_type, npc.flying_type, s.loot_tier, s.loot_drop_type, npc.scared_by_strong_players\n"
|
||||
"FROM spawn s\n"
|
||||
"INNER JOIN spawn_npcs npc\n"
|
||||
"ON s.id = npc.spawn_id\n"
|
||||
|
@ -1092,6 +1092,8 @@ void WorldDatabase::LoadNPCs(ZoneServer* zone){
|
|||
|
||||
npc->SetLootDropType(atoul(row[84]));
|
||||
|
||||
npc->SetScaredByStrongPlayers(atoul(row[85]));
|
||||
|
||||
zone->AddNPC(id, npc);
|
||||
total++;
|
||||
LogWrite(NPC__DEBUG, 5, "NPC", "---Loading NPC: '%s' (%u)", npc->appearance.name, id);
|
||||
|
@ -6695,7 +6697,7 @@ bool WorldDatabase::LoadNPC(ZoneServer* zone, int32 spawn_id) {
|
|||
int32 id = 0;
|
||||
DatabaseResult result;
|
||||
|
||||
database_new.Select(&result, "SELECT npc.spawn_id, s.name, npc.min_level, npc.max_level, npc.enc_level, s.race, s.model_type, npc.class_, npc.gender, s.command_primary, s.command_secondary, s.show_name, npc.min_group_size, npc.max_group_size, npc.hair_type_id, npc.facial_hair_type_id, npc.wing_type_id, npc.chest_type_id, npc.legs_type_id, npc.soga_hair_type_id, npc.soga_facial_hair_type_id, s.attackable, s.show_level, s.targetable, s.show_command_icon, s.display_hand_icon, s.hp, s.power, s.size, s.collision_radius, npc.action_state, s.visual_state, npc.mood_state, npc.initial_state, npc.activity_status, s.faction_id, s.sub_title, s.merchant_id, s.merchant_type, s.size_offset, npc.attack_type, npc.ai_strategy+0, npc.spell_list_id, npc.secondary_spell_list_id, npc.skill_list_id, npc.secondary_skill_list_id, npc.equipment_list_id, npc.str, npc.sta, npc.wis, npc.intel, npc.agi, npc.heat, npc.cold, npc.magic, npc.mental, npc.divine, npc.disease, npc.poison, npc.aggro_radius, npc.cast_percentage, npc.randomize, npc.soga_model_type, npc.heroic_flag, npc.alignment, npc.elemental, npc.arcane, npc.noxious, s.savagery, s.dissonance, npc.hide_hood, npc.emote_state, s.prefix, s.suffix, s.last_name, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, s.loot_tier, s.loot_drop_type\n"
|
||||
database_new.Select(&result, "SELECT npc.spawn_id, s.name, npc.min_level, npc.max_level, npc.enc_level, s.race, s.model_type, npc.class_, npc.gender, s.command_primary, s.command_secondary, s.show_name, npc.min_group_size, npc.max_group_size, npc.hair_type_id, npc.facial_hair_type_id, npc.wing_type_id, npc.chest_type_id, npc.legs_type_id, npc.soga_hair_type_id, npc.soga_facial_hair_type_id, s.attackable, s.show_level, s.targetable, s.show_command_icon, s.display_hand_icon, s.hp, s.power, s.size, s.collision_radius, npc.action_state, s.visual_state, npc.mood_state, npc.initial_state, npc.activity_status, s.faction_id, s.sub_title, s.merchant_id, s.merchant_type, s.size_offset, npc.attack_type, npc.ai_strategy+0, npc.spell_list_id, npc.secondary_spell_list_id, npc.skill_list_id, npc.secondary_skill_list_id, npc.equipment_list_id, npc.str, npc.sta, npc.wis, npc.intel, npc.agi, npc.heat, npc.cold, npc.magic, npc.mental, npc.divine, npc.disease, npc.poison, npc.aggro_radius, npc.cast_percentage, npc.randomize, npc.soga_model_type, npc.heroic_flag, npc.alignment, npc.elemental, npc.arcane, npc.noxious, s.savagery, s.dissonance, npc.hide_hood, npc.emote_state, s.prefix, s.suffix, s.last_name, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, s.loot_tier, s.loot_drop_type, npc.scared_by_strong_players\n"
|
||||
"FROM spawn s\n"
|
||||
"INNER JOIN spawn_npcs npc\n"
|
||||
"ON npc.spawn_id = s.id\n"
|
||||
|
@ -6831,6 +6833,8 @@ bool WorldDatabase::LoadNPC(ZoneServer* zone, int32 spawn_id) {
|
|||
|
||||
npc->SetLootDropType(result.GetInt32(80));
|
||||
|
||||
npc->SetScaredByStrongPlayers(result.GetInt32(81));
|
||||
|
||||
zone->AddNPC(id, npc);
|
||||
|
||||
//skipped spells/skills/equipment as it is all loaded, the following rely on a spawn to load
|
||||
|
|
|
@ -926,9 +926,17 @@ bool ZoneServer::CheckNPCAttacks(NPC* npc, Spawn* victim, Client* client){
|
|||
return true;
|
||||
|
||||
if (client) {
|
||||
int8 arrow = 0;
|
||||
if (client->IsReadyForUpdates() && npc->CanSeeInvis(client->GetPlayer()) && client->GetPlayer()->GetFactions()->ShouldAttack(npc->GetFactionID()) && npc->AttackAllowed((Entity*)victim, false)) {
|
||||
if (!npc->EngagedInCombat() && client->GetPlayer()->GetArrowColor(npc->GetLevel()) != ARROW_COLOR_GRAY) {
|
||||
AggroVictim(npc, victim, client);
|
||||
if (!npc->EngagedInCombat()) {
|
||||
if(client->GetPlayer()->GetArrowColor(npc->GetLevel()) != ARROW_COLOR_GRAY) {
|
||||
AggroVictim(npc, victim, client);
|
||||
}
|
||||
else if(npc->IsScaredByStrongPlayers() &&
|
||||
!client->GetPlayer()->IsSpawnInRangeList(npc->GetID())) {
|
||||
SendSpawnChanges(npc, client, true, true);
|
||||
client->GetPlayer()->SetSpawnInRangeList(npc->GetID(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue