mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Fixed an issue that would cause traps to not function correctly if skill is 0 in the database.
Added undetectable column, to allow content developers to make a trap undetectable and not able to be disarmed. Pets will no longer try to aggro traps its owner triggers. Traps will now use the radius column to determine disarm range, instead of using a hardcoded value which may not be appropriate in all cases. Decreased the scan range for traps to disarm. Fixed some typos, and removed some unused code.
This commit is contained in:
parent
ed98aa45d2
commit
cd748e7d8b
@ -1,3 +1,4 @@
|
||||
alter table `traps` add column `triggered_number` tinyint(4) not null default 0;
|
||||
alter table `traps` add column `group` tinyint(4) not null default 0;
|
||||
alter table `traps` add column `despawn_when_triggered` tinyint(4) not null default 0;
|
||||
alter table `traps` add column `undetectable` tinyint(4) not null default 0;
|
||||
|
||||
@ -2533,6 +2533,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
if (other == this)
|
||||
return;
|
||||
|
||||
if (other->IsTrap())
|
||||
return;
|
||||
|
||||
if (damage < 0) {
|
||||
hate = 1;
|
||||
}
|
||||
@ -3364,7 +3367,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
||||
// pets that have GHold will never automatically add NPCs
|
||||
// pets that have Hold and no Focus will add NPCs if they're engaged
|
||||
// pets that have Hold and Focus will not add NPCs
|
||||
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse() && !pet->IsGHeld())
|
||||
if (pet && !pet->IsFamiliar() && !pet->GetSpecialAbility(IMMUNE_AGGRO) && !pet->IsEngaged() && attacker && attacker != this && !attacker->IsCorpse() && !pet->IsGHeld() && !attacker->IsTrap())
|
||||
{
|
||||
if (!pet->IsHeld()) {
|
||||
Log(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName());
|
||||
|
||||
@ -5329,31 +5329,44 @@ void Client::Handle_OP_DisarmTraps(const EQApplicationPacket *app)
|
||||
|
||||
p_timers.Start(pTimerDisarmTraps, reuse - 1);
|
||||
|
||||
Trap* trap = entity_list.FindNearbyTrap(this, 60);
|
||||
uint8 success = SKILLUP_FAILURE;
|
||||
float curdist = 0;
|
||||
Trap* trap = entity_list.FindNearbyTrap(this, 250, curdist, true);
|
||||
if (trap && trap->detected)
|
||||
{
|
||||
int uskill = GetSkill(EQEmu::skills::SkillDisarmTraps);
|
||||
if ((zone->random.Int(0, 49) + uskill) >= (zone->random.Int(0, 49) + trap->skill))
|
||||
float max_radius = (trap->radius * 2) * (trap->radius * 2); // radius is used to trigger trap, so disarm radius should be a bit bigger.
|
||||
Log(Logs::General, Logs::Traps, "%s is attempting to disarm trap %d. Curdist is %0.2f maxdist is %0.2f", GetName(), trap->trap_id, curdist, max_radius);
|
||||
if (curdist <= max_radius)
|
||||
{
|
||||
Message(MT_Skills, "You disarm a trap.");
|
||||
trap->disarmed = true;
|
||||
Log(Logs::General, Logs::Traps, "Trap %d is disarmed.", trap->trap_id);
|
||||
trap->UpdateTrap();
|
||||
int uskill = GetSkill(EQEmu::skills::SkillDisarmTraps);
|
||||
if ((zone->random.Int(0, 49) + uskill) >= (zone->random.Int(0, 49) + trap->skill))
|
||||
{
|
||||
success = SKILLUP_SUCCESS;
|
||||
Message_StringID(MT_Skills, DISARMED_TRAP);
|
||||
trap->disarmed = true;
|
||||
Log(Logs::General, Logs::Traps, "Trap %d is disarmed.", trap->trap_id);
|
||||
trap->UpdateTrap();
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_StringID(MT_Skills, FAIL_DISARM_DETECTED_TRAP);
|
||||
if (zone->random.Int(0, 99) < 25) {
|
||||
trap->Trigger(this);
|
||||
}
|
||||
}
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillDisarmTraps, nullptr);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (zone->random.Int(0, 99) < 25) {
|
||||
Message(MT_Skills, "You set off the trap while trying to disarm it!");
|
||||
trap->Trigger(this);
|
||||
}
|
||||
else {
|
||||
Message(MT_Skills, "You failed to disarm a trap.");
|
||||
}
|
||||
Message_StringID(MT_Skills, TRAP_TOO_FAR);
|
||||
}
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillDisarmTraps, nullptr);
|
||||
return;
|
||||
}
|
||||
Message(MT_Skills, "You did not find any traps close enough to disarm.");
|
||||
else
|
||||
{
|
||||
Message_StringID(MT_Skills, LDON_SENSE_TRAP2);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -12107,7 +12120,8 @@ void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app)
|
||||
|
||||
p_timers.Start(pTimerSenseTraps, reuse - 1);
|
||||
|
||||
Trap* trap = entity_list.FindNearbyTrap(this, 800);
|
||||
float trap_curdist = 0;
|
||||
Trap* trap = entity_list.FindNearbyTrap(this, 800, trap_curdist);
|
||||
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillSenseTraps, nullptr);
|
||||
|
||||
|
||||
@ -604,6 +604,11 @@ enum { //type arguments to DoAnim
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
SKILLUP_UNKNOWN = 0,
|
||||
SKILLUP_SUCCESS = 1,
|
||||
SKILLUP_FAILURE = 2
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
petFamiliar, //only listens to /pet get lost
|
||||
|
||||
@ -365,7 +365,7 @@ public:
|
||||
//trap stuff
|
||||
Mob* GetTrapTrigger(Trap* trap);
|
||||
void SendAlarm(Trap* trap, Mob* currenttarget, uint8 kos);
|
||||
Trap* FindNearbyTrap(Mob* searcher, float max_dist);
|
||||
Trap* FindNearbyTrap(Mob* searcher, float max_dist, float &curdist, bool detected = false);
|
||||
|
||||
void AddHealAggro(Mob* target, Mob* caster, uint16 hate);
|
||||
Mob* FindDefenseNPC(uint32 npcid);
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#define PROC_TOOLOW 126 //Your will is not sufficient to command this weapon.
|
||||
#define PROC_PETTOOLOW 127 //Your pet's will is not sufficient to command its weapon.
|
||||
#define YOU_FLURRY 128 //You unleash a flurry of attacks.
|
||||
#define FAILED_DISARM_TRAP 129 //You failed to disarm the trap.
|
||||
#define DOORS_LOCKED 130 //It's locked and you're not holding the key.
|
||||
#define DOORS_CANT_PICK 131 //This lock cannot be picked.
|
||||
#define DOORS_INSUFFICIENT_SKILL 132 //You are not sufficiently skilled to pick this lock.
|
||||
@ -98,6 +99,7 @@
|
||||
#define DUP_LORE 290 //Duplicate lore items are not allowed.
|
||||
#define TGB_ON 293 //Target other group buff is *ON*.
|
||||
#define TGB_OFF 294 //Target other group buff is *OFF*.
|
||||
#define DISARMED_TRAP 305 //You have disarmed the trap.
|
||||
#define LDON_SENSE_TRAP1 306 //You do not Sense any traps.
|
||||
#define TRADESKILL_NOCOMBINE 334 //You cannot combine these items in this container type!
|
||||
#define TRADESKILL_FAILED 336 //You lacked the skills to fashion the items together.
|
||||
@ -114,6 +116,8 @@
|
||||
#define MEND_WORSEN 351 //You have worsened your wounds!
|
||||
#define MEND_FAIL 352 //You have failed to mend your wounds.
|
||||
#define LDON_SENSE_TRAP2 367 //You have not detected any traps.
|
||||
#define TRAP_TOO_FAR 368 //You are too far away from that trap to affect it.
|
||||
#define FAIL_DISARM_DETECTED_TRAP 370 //You fail to disarm the detected trap.
|
||||
#define LOOT_LORE_ERROR 371 //You cannot loot this Lore Item. You already have one.
|
||||
#define PICK_LORE 379 //You cannot pick up a lore item you already possess.
|
||||
#define CONSENT_DENIED 390 //You do not have consent to summon that corpse.
|
||||
@ -421,6 +425,7 @@
|
||||
#define SENSE_ANIMAL 12472 //You sense an animal in this direction.
|
||||
#define SENSE_SUMMONED 12473 //You sense a summoned being in this direction.
|
||||
#define SENSE_NOTHING 12474 //You don't sense anything.
|
||||
#define SENSE_TRAP 12475 //You sense a trap in this direction.
|
||||
#define LDON_SENSE_TRAP3 12476 //You don't sense any traps.
|
||||
#define INTERRUPT_SPELL_OTHER 12478 //%1's casting is interrupted!
|
||||
#define YOU_HIT_NONMELEE 12481 //You were hit by non-melee for %1 damage.
|
||||
|
||||
@ -79,6 +79,7 @@ Trap::Trap() :
|
||||
group = 0;
|
||||
despawn_when_triggered = false;
|
||||
charid = 0;
|
||||
undetectable = false;
|
||||
}
|
||||
|
||||
Trap::~Trap()
|
||||
@ -253,7 +254,7 @@ void Trap::Trigger(Mob* trigger)
|
||||
}
|
||||
}
|
||||
|
||||
Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist)
|
||||
Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist, float &trap_curdist, bool detected)
|
||||
{
|
||||
float dist = 999999;
|
||||
Trap* current_trap = nullptr;
|
||||
@ -263,19 +264,29 @@ Trap* EntityList::FindNearbyTrap(Mob* searcher, float max_dist)
|
||||
|
||||
for (auto it = trap_list.begin(); it != trap_list.end(); ++it) {
|
||||
cur = it->second;
|
||||
if(cur->disarmed)
|
||||
if(cur->disarmed || (detected && !cur->detected) || cur->undetectable)
|
||||
continue;
|
||||
|
||||
auto diff = glm::vec3(searcher->GetPosition()) - cur->m_Position;
|
||||
float curdist = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
|
||||
float curdist = diff.x*diff.x + diff.y*diff.y;
|
||||
diff.z = std::abs(diff.z);
|
||||
|
||||
if (curdist < max_dist2 && curdist < dist)
|
||||
if (curdist < max_dist2 && curdist < dist && diff.z <= cur->maxzdiff)
|
||||
{
|
||||
Log(Logs::General, Logs::Traps, "Trap %d is curdist %0.1f", cur->db_id, curdist);
|
||||
dist = curdist;
|
||||
current_trap = cur;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_trap != nullptr)
|
||||
{
|
||||
Log(Logs::General, Logs::Traps, "Trap %d is the closest trap.", current_trap->db_id);
|
||||
trap_curdist = dist;
|
||||
}
|
||||
else
|
||||
trap_curdist = INVALID_INDEX;
|
||||
|
||||
return current_trap;
|
||||
}
|
||||
|
||||
@ -386,7 +397,7 @@ bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
||||
|
||||
std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||
"`group`, triggered_number, despawn_when_triggered FROM traps WHERE zone='%s' AND version=%u", zonename, version);
|
||||
"`group`, triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND version=%u", zonename, version);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
@ -422,7 +433,8 @@ bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) {
|
||||
trap->level = atoi(row[14]);
|
||||
trap->group = grp;
|
||||
trap->triggered_number = atoi(row[16]);
|
||||
trap->despawn_when_triggered = atoi(row[17]);
|
||||
trap->despawn_when_triggered = atobool(row[17]);
|
||||
trap->undetectable = atobool(row[18]);
|
||||
entity_list.AddTrap(trap);
|
||||
trap->CreateHiddenTrigger();
|
||||
Log(Logs::General, Logs::Traps, "Trap %d successfully loaded.", trap->trap_id);
|
||||
@ -469,14 +481,14 @@ bool ZoneDatabase::SetTrapData(Trap* trap, bool repopnow) {
|
||||
{
|
||||
query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||
"triggered_number, despawn_when_triggered FROM traps WHERE zone='%s' AND `group`=%d AND id != %d ORDER BY RAND() LIMIT 1", zone->GetShortName(), trap->group, dbid);
|
||||
"triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND `group`=%d AND id != %d ORDER BY RAND() LIMIT 1", zone->GetShortName(), trap->group, dbid);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We could just use the existing data here, but querying the DB is not expensive, and allows content developers to change traps without rebooting.
|
||||
query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, "
|
||||
"maxzdiff, radius, chance, message, respawn_time, respawn_var, level, "
|
||||
"triggered_number, despawn_when_triggered FROM traps WHERE zone='%s' AND id = %d", zone->GetShortName(), dbid);
|
||||
"triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND id = %d", zone->GetShortName(), dbid);
|
||||
}
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
@ -500,7 +512,8 @@ bool ZoneDatabase::SetTrapData(Trap* trap, bool repopnow) {
|
||||
trap->respawn_var = atoi(row[13]);
|
||||
trap->level = atoi(row[14]);
|
||||
trap->triggered_number = atoi(row[15]);
|
||||
trap->despawn_when_triggered = atoi(row[16]);
|
||||
trap->despawn_when_triggered = atobool(row[16]);
|
||||
trap->undetectable = atobool(row[17]);
|
||||
trap->CreateHiddenTrigger();
|
||||
|
||||
if (repopnow)
|
||||
|
||||
@ -50,7 +50,6 @@ public:
|
||||
void SetHiddenTrigger(NPC* n) { hiddenTrigger = n; }
|
||||
void CreateHiddenTrigger();
|
||||
void DestroyHiddenTrigger() { hiddenTrigger = nullptr; }
|
||||
void SetTrapData();
|
||||
void UpdateTrap(bool respawn = true, bool repopnow = false);
|
||||
//Trap data, leave this unprotected
|
||||
Timer respawn_timer; //Respawn Time when Trap's been disarmed
|
||||
@ -76,6 +75,7 @@ public:
|
||||
uint8 group;
|
||||
bool despawn_when_triggered;
|
||||
uint32 charid; //ID of character that triggered trap. This is cleared when the trap despawns are resets.
|
||||
bool undetectable;
|
||||
|
||||
std::string message;
|
||||
protected:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user