mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
WIP for NPC spell push, off by default for now
This commit is contained in:
parent
0d63c8b9ef
commit
ae966e546b
@ -402,6 +402,7 @@ RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spr
|
||||
RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though
|
||||
RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target.
|
||||
RULE_BOOL(Spells, OldRainTargets, false) // use old incorrectly implemented max targets for rains
|
||||
RULE_BOOL(Spells, NPCSpellPush, false) // enable spell push on NPCs
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
|
||||
@ -3622,24 +3622,10 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
|
||||
a->force = 0.0f; // 2013 change that disabled NPC vs NPC push
|
||||
else
|
||||
a->force *= 0.10f; // force against NPCs is divided by 10 I guess? ex bash is 0.3, parsed 0.03 against an NPC
|
||||
}
|
||||
// update NPC stuff
|
||||
if (a->force != 0.0f) {
|
||||
auto new_pos = glm::vec3(
|
||||
m_Position.x + (a->force * g_Math.FastSin(a->hit_heading) + m_Delta.x),
|
||||
m_Position.y + (a->force * g_Math.FastCos(a->hit_heading) + m_Delta.y), m_Position.z);
|
||||
if ((!IsNPC() || position_update_melee_push_timer.Check()) && zone->zonemap &&
|
||||
zone->zonemap->CheckLoS(
|
||||
glm::vec3(m_Position),
|
||||
new_pos)) { // If we have LoS on the new loc it should be reachable.
|
||||
if (IsNPC()) {
|
||||
// Is this adequate?
|
||||
|
||||
Teleport(new_pos);
|
||||
SendPositionUpdate();
|
||||
}
|
||||
} else {
|
||||
a->force = 0.0f; // we couldn't move there, so lets not
|
||||
if (ForcedMovement == 0 && a->force != 0.0f && position_update_melee_push_timer.Check()) {
|
||||
m_Delta.x += a->force * g_Math.FastSin(a->hit_heading);
|
||||
m_Delta.y += a->force * g_Math.FastCos(a->hit_heading);
|
||||
ForcedMovement = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,6 +276,14 @@ bool Map::FindClosestLoS(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outloc) con
|
||||
return imp->rm->raycast((const RmReal*)&myloc, (const RmReal*)&oloc, (RmReal *)&outloc, nullptr, nullptr);
|
||||
}
|
||||
|
||||
// returns true if a collision happens
|
||||
bool Map::DoCollisionCheck(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outnorm, float &distance) const {
|
||||
if(!imp)
|
||||
return false;
|
||||
|
||||
return imp->rm->raycast((const RmReal*)&myloc, (const RmReal*)&oloc, nullptr, (RmReal *)&outnorm, (RmReal *)&distance);
|
||||
}
|
||||
|
||||
inline bool file_exists(const std::string& name) {
|
||||
std::ifstream f(name.c_str());
|
||||
return f.good();
|
||||
|
||||
@ -43,6 +43,7 @@ public:
|
||||
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
|
||||
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
|
||||
bool FindClosestLoS(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outloc) const;
|
||||
bool DoCollisionCheck(glm::vec3 myloc, glm::vec3 oloc, glm::vec3 &outnorm, float &distance) const;
|
||||
|
||||
#ifdef USE_MAP_MMFS
|
||||
bool Load(std::string filename, bool force_mmf_overwrite = false);
|
||||
|
||||
@ -393,6 +393,7 @@ Mob::Mob(const char* in_name,
|
||||
permarooted = (runspeed > 0) ? false : true;
|
||||
|
||||
movetimercompleted = false;
|
||||
ForcedMovement = 0;
|
||||
roamer = false;
|
||||
rooted = false;
|
||||
charmed = false;
|
||||
|
||||
@ -50,6 +50,8 @@ struct AuraRecord;
|
||||
struct NewSpawn_Struct;
|
||||
struct PlayerPositionUpdateServer_Struct;
|
||||
|
||||
const int COLLISION_BOX_SIZE = 4;
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
struct ItemData;
|
||||
@ -1314,6 +1316,9 @@ protected:
|
||||
char lastname[64];
|
||||
|
||||
glm::vec4 m_Delta;
|
||||
// just locs around them to double check, if we do expand collision this should be cached on movement
|
||||
// ideally we should use real models, but this should be quick and work mostly
|
||||
glm::vec4 m_CollisionBox[COLLISION_BOX_SIZE];
|
||||
|
||||
EQEmu::LightSourceProfile m_Light;
|
||||
|
||||
@ -1424,6 +1429,7 @@ protected:
|
||||
std::unique_ptr<Timer> AI_movement_timer;
|
||||
std::unique_ptr<Timer> AI_target_check_timer;
|
||||
bool movetimercompleted;
|
||||
int8 ForcedMovement; // push
|
||||
bool permarooted;
|
||||
std::unique_ptr<Timer> AI_scan_area_timer;
|
||||
std::unique_ptr<Timer> AI_walking_timer;
|
||||
|
||||
@ -29,12 +29,16 @@
|
||||
#include "quest_parser_collection.h"
|
||||
#include "string_ids.h"
|
||||
#include "water_map.h"
|
||||
#include "fastmath.h"
|
||||
|
||||
#include <glm/gtx/projection.hpp>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <math.h>
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern FastMath g_Math;
|
||||
|
||||
extern Zone *zone;
|
||||
|
||||
@ -953,6 +957,68 @@ void Mob::AI_Process() {
|
||||
if (!(AI_think_timer->Check() || attack_timer.Check(false)))
|
||||
return;
|
||||
|
||||
// we are being pushed, we will hijack this movement timer
|
||||
// this also needs to be done before casting to have a chance to interrupt
|
||||
// this flag won't be set if the mob can't be pushed (rooted etc)
|
||||
if (ForcedMovement && AI_movement_timer->Check()) {
|
||||
bool bPassed = true;
|
||||
auto z_off = GetZOffset();
|
||||
glm::vec3 normal;
|
||||
glm::vec3 new_pos = m_Position + m_Delta;
|
||||
new_pos.z += z_off;
|
||||
|
||||
// no zone map = fucked
|
||||
if (zone->HasMap()) {
|
||||
// in front
|
||||
m_CollisionBox[0].x = m_Position.x + 3.0f * g_Math.FastSin(0.0f);
|
||||
m_CollisionBox[0].y = m_Position.y + 3.0f * g_Math.FastCos(0.0f);
|
||||
m_CollisionBox[0].z = m_Position.z + z_off;
|
||||
|
||||
// to right
|
||||
m_CollisionBox[1].x = m_Position.x + 3.0f * g_Math.FastSin(128.0f);
|
||||
m_CollisionBox[1].y = m_Position.y + 3.0f * g_Math.FastCos(128.0f);
|
||||
m_CollisionBox[1].z = m_Position.z + z_off;
|
||||
|
||||
// behind
|
||||
m_CollisionBox[2].x = m_Position.x + 3.0f * g_Math.FastSin(256.0f);
|
||||
m_CollisionBox[2].y = m_Position.y + 3.0f * g_Math.FastCos(256.0f);
|
||||
m_CollisionBox[2].z = m_Position.z + z_off;
|
||||
|
||||
// to left
|
||||
m_CollisionBox[3].x = m_Position.x + 3.0f * g_Math.FastSin(384.0f);
|
||||
m_CollisionBox[3].y = m_Position.y + 3.0f * g_Math.FastCos(384.0f);
|
||||
m_CollisionBox[3].z = m_Position.z + z_off;
|
||||
|
||||
// collision happened, need to move along the wall
|
||||
float distance = 0.0f, shortest = std::numeric_limits<float>::infinity();
|
||||
glm::vec3 tmp_nrm;
|
||||
for (auto &vec : m_CollisionBox) {
|
||||
if (zone->zonemap->DoCollisionCheck(vec, new_pos, tmp_nrm, distance)) {
|
||||
bPassed = false; // lets try with new projection next pass
|
||||
if (distance < shortest) {
|
||||
normal = tmp_nrm;
|
||||
shortest = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bPassed) {
|
||||
ForcedMovement = 0;
|
||||
m_Delta = glm::vec4();
|
||||
Teleport(new_pos);
|
||||
SendPositionUpdate();
|
||||
pLastChange = Timer::GetCurrentTime();
|
||||
} else if (--ForcedMovement) {
|
||||
auto proj = glm::proj(static_cast<glm::vec3>(m_Delta), normal);
|
||||
m_Delta.x -= proj.x;
|
||||
m_Delta.y -= proj.y;
|
||||
m_Delta.z -= proj.z;
|
||||
} else {
|
||||
m_Delta = glm::vec4(); // well, we failed to find a spot to be forced to, lets give up
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCasting())
|
||||
return;
|
||||
|
||||
|
||||
@ -81,6 +81,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
#include "quest_parser_collection.h"
|
||||
#include "string_ids.h"
|
||||
#include "worldserver.h"
|
||||
#include "fastmath.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
@ -104,6 +105,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
extern Zone* zone;
|
||||
extern volatile bool is_zone_loaded;
|
||||
extern WorldServer worldserver;
|
||||
extern FastMath g_Math;
|
||||
|
||||
using EQEmu::CastingSlot;
|
||||
|
||||
@ -3945,6 +3947,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
||||
{
|
||||
spelltar->CastToClient()->SetKnockBackExemption(true);
|
||||
}
|
||||
} else if (RuleB(Spells, NPCSpellPush) && !spelltar->IsRooted() && spelltar->ForcedMovement == 0) {
|
||||
spelltar->m_Delta.x += action->force * g_Math.FastSin(action->hit_heading);
|
||||
spelltar->m_Delta.y += action->force * g_Math.FastCos(action->hit_heading);
|
||||
spelltar->m_Delta.z += action->hit_pitch;
|
||||
spelltar->ForcedMovement = 6;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user