Player/Target Radius added to distance checks

Radius is now built into the GetDistance formula, it also is based on f32/32.0f per recommendations of peak (Thx peak!)

Added combat range as a rule: rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat()

Fixes #53
This commit is contained in:
Image 2020-03-22 09:45:40 -04:00
parent 442868f80a
commit 04498a2490
11 changed files with 113 additions and 47 deletions

View file

@ -2,6 +2,9 @@
#include "../Combat.h"
#include "../Spells.h"
#include "../../common/Log.h"
#include "../Rules/Rules.h"
extern RuleManager rule_manager;
BotBrain::BotBrain(Bot* body) : Brain(body) {
Body = body;
@ -46,11 +49,9 @@ void BotBrain::Think() {
// Get distance from the owner
float distance = GetBody()->GetDistance(target);
distance -= target->appearance.pos.collision_radius / 10;
distance -= GetBody()->appearance.pos.collision_radius / 10;
// If out of melee range then move closer
if (distance > MAX_COMBAT_RANGE)
if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser(target);
}

View file

@ -170,7 +170,7 @@ bool Entity::AttackAllowed(Entity* target, float distance, bool range_attack) {
}
}
else if (distance != 0) {
if(distance >= MAX_COMBAT_RANGE) {
if(distance >= rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat()) {
LogWrite(COMBAT__DEBUG, 3, "AttackAllowed", "Failed to attack: distance is beyond melee range");
return false;
}
@ -1151,8 +1151,6 @@ void Player::ProcessCombat() {
float distance = 0;
distance = GetDistance(combat_target);
distance -= combat_target->appearance.pos.collision_radius / 10;
distance -= appearance.pos.collision_radius / 10;
// Check to see if we are doing ranged auto attacks if not check to see if we are in melee range
if (GetRangeAttack()) {
@ -1185,7 +1183,7 @@ void Player::ProcessCombat() {
}
}
}
else if(distance <= MAX_COMBAT_RANGE) {
else if(distance <= rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat()) {
// We are doing melee auto attacks and are within range
// Check to see if we can attack the target

View file

@ -27,7 +27,8 @@
#define COMBAT_NORMAL_FIGHTER 0
#define COMBAT_ADD_FIGHTER 1
#define COMBAT_REMOVE_FIGHTER 2
#define MAX_COMBAT_RANGE 3
// replace with rule rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat()
//#define MAX_COMBAT_RANGE 3
class ZoneServer;
class SpellProcess;

View file

@ -864,8 +864,6 @@ int EQ2Emu_lua_SpellHeal(lua_State* state) {
luaspell->resisted = false;
if (target) {
float distance = caster->GetDistance(target, true);
distance -= caster->appearance.pos.collision_radius / 10;
distance -= target->appearance.pos.collision_radius / 10;
if (((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs))
success = true;
}
@ -876,8 +874,6 @@ int EQ2Emu_lua_SpellHeal(lua_State* state) {
for (int32 i = 0; i < luaspell->targets.size(); i++) {
if ((target = zone->GetSpawnByID(luaspell->targets[i]))) {
float distance = caster->GetDistance(target, true);
distance -= caster->appearance.pos.collision_radius / 10;
distance -= target->appearance.pos.collision_radius / 10;
((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs);
}
}
@ -1230,8 +1226,6 @@ int EQ2Emu_lua_SpellDamage(lua_State* state) {
race_match = true; // if the race_req.size = 0 then there is no race requirement and the race_match will be true
if (race_match == true) {
float distance = caster->GetDistance(target, true);
distance -= caster->appearance.pos.collision_radius / 10;
distance -= target->appearance.pos.collision_radius / 10;
((Entity*)caster)->SpellAttack(target, distance, luaspell, type, min_damage, max_damage, crit_mod, no_calcs);
}
}
@ -1253,8 +1247,6 @@ int EQ2Emu_lua_SpellDamage(lua_State* state) {
race_match = true; // if the race_req.size = 0 then there is no race requirement and the race_match will be true
if (race_match == true) {
float distance = caster->GetDistance(target, true);
distance -= caster->appearance.pos.collision_radius / 10;
distance -= target->appearance.pos.collision_radius / 10;
if (((Entity*)caster)->SpellAttack(target, distance, luaspell, type, min_damage, max_damage, crit_mod, no_calcs))
success = true;
}
@ -2322,11 +2314,7 @@ int EQ2Emu_lua_GetDistance(lua_State* state) {
Spawn* spawn2 = lua_interface->GetSpawn(state, 2);
bool include_radius = lua_interface->GetInt8Value(state, 3) == 1;
if (spawn && spawn2) {
float distance = spawn->GetDistance(spawn2);
if (include_radius) {
distance -= spawn->appearance.pos.collision_radius / 10;
distance -= spawn2->appearance.pos.collision_radius / 10;
}
float distance = spawn->GetDistance(spawn2, false, include_radius);
lua_interface->SetFloatValue(state, distance);
return 1;

View file

@ -25,6 +25,9 @@
#include "../common/Log.h"
#include "LuaInterface.h"
#include "World.h"
#include "Rules/Rules.h"
extern RuleManager rule_manager;
extern LuaInterface* lua_interface;
extern World world;
@ -101,8 +104,6 @@ void Brain::Think() {
// Still within max chase distance lets to the combat stuff now
float distance = m_body->GetDistance(target);
distance -= target->appearance.pos.collision_radius / 10;
distance -= m_body->appearance.pos.collision_radius / 10;
if(!m_body->IsCasting() && (!HasRecovered() || !ProcessSpell(target, distance))) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s is attempting melee on %s.", m_body->GetName(), target->GetName());
@ -328,7 +329,7 @@ bool Brain::CheckBuffs() {
}
void Brain::ProcessMelee(Entity* target, float distance) {
if(distance > MAX_COMBAT_RANGE)
if(distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser(target);
else {
if (target) {
@ -479,11 +480,9 @@ void CombatPetBrain::Think() {
// Get distance from the owner
float distance = GetBody()->GetDistance(target);
distance -= target->appearance.pos.collision_radius / 10;
distance -= GetBody()->appearance.pos.collision_radius / 10;
// If out of melee range then move closer
if (distance > MAX_COMBAT_RANGE)
if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser(target);
}
@ -513,11 +512,9 @@ void NonCombatPetBrain::Think() {
// Get distance from the owner
float distance = GetBody()->GetDistance(target);
distance -= target->appearance.pos.collision_radius / 10;
distance -= GetBody()->appearance.pos.collision_radius / 10;
// If out of melee range then move closer
if (distance > MAX_COMBAT_RANGE)
if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser(target);
}
@ -591,8 +588,6 @@ void DumbFirePetBrain::Think() {
}
float distance = GetBody()->GetDistance(target);
distance -= target->appearance.pos.collision_radius / 10;
distance -= GetBody()->appearance.pos.collision_radius / 10;
if(!GetBody()->IsCasting() && (!HasRecovered() || !ProcessSpell(target, distance))) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s is attempting melee on %s.", GetBody()->GetName(), target->GetName());

View file

@ -207,6 +207,8 @@ RuleManager::RuleManager() {
RULE_INIT(R_PVP, LevelRange, "4");
RULE_INIT(R_PVP, InvisPlayerDiscoveryRange, "20"); // value > 0 sets radius inner to see, = 0 means always seen, -1 = never seen
/* COMBAT */
RULE_INIT(R_Combat, MaxCombatRange, "4.0");
/* SPAWN */
RULE_INIT(R_Spawn, SpeedMultiplier, "300"); // note: this value was 1280 until 6/1/2009, then was 600 til Sep 2009, when it became 300...?
RULE_INIT(R_Spawn, SpeedRatio, "0"); // was 1280/7.5 and 600/7.5 until it became 300.

View file

@ -33,6 +33,7 @@ enum RuleCategory {
R_Guild,
R_Player,
R_PVP,
R_Combat,
R_Spawn,
R_UI,
R_World,
@ -74,6 +75,9 @@ enum RuleType {
LevelRange,
InvisPlayerDiscoveryRange,
/* COMBAT */
MaxCombatRange,
/* SPAWN */
SpeedMultiplier,
SpeedRatio,

View file

@ -22,6 +22,7 @@
#include "../common/timer.h"
#include <time.h>
#include <math.h>
#include <emmintrin.h>
#include "Entity.h"
#include "Widget.h"
#include "Sign.h"
@ -1078,20 +1079,64 @@ float Spawn::GetDistance(float x1, float y1, float z1, float x2, float y2, float
return sqrt(x1*x1 + y1*y1 + z1*z1);
}
float Spawn::GetDistance(float x, float y, float z, bool ignore_y){
if(ignore_y)
return GetDistance(x, y, z, GetX(), y, GetZ());
float Spawn::GetDistance(float x, float y, float z, float radius, bool ignore_y) {
if (ignore_y)
return GetDistance(x, y, z, GetX(), y, GetZ()) - radius;
else
return GetDistance(x, y, z, GetX(), GetY(), GetZ());
return GetDistance(x, y, z, GetX(), GetY(), GetZ()) - radius;
}
float Spawn::GetDistance(Spawn* spawn, bool ignore_y){
float Spawn::GetDistance(float x, float y, float z, bool ignore_y) {
return GetDistance(x, y, z, 0.0f, ignore_y);
}
float Spawn::GetDistance(Spawn* spawn, bool ignore_y, bool includeRadius){
float ret = 0;
if(spawn)
ret = GetDistance(spawn->GetX(), spawn->GetY(), spawn->GetZ(), ignore_y);
if (spawn)
{
float radius = 0.0f;
if (includeRadius)
radius = CalculateRadius(spawn);
ret = GetDistance(spawn->GetX(), spawn->GetY(), spawn->GetZ(), radius, ignore_y);
}
// maybe distance against ourselves, in that case we want to nullify the radius check
if (ret < 0)
ret = 0.0f;
return ret;
}
float Spawn::GetDistance(Spawn* spawn, float x1, float y1, float z1, bool includeRadius) {
float ret = 0;
if (spawn)
{
float radius = 0.0f;
if (includeRadius)
radius = CalculateRadius(spawn);
ret = GetDistance(x1, y1, z1, spawn->GetX(), spawn->GetY(), spawn->GetZ()) - radius;
}
// maybe distance against ourselves, in that case we want to nullify the radius check
if (ret < 0)
ret = 0.0f;
return ret;
}
float Spawn::CalculateRadius(Spawn* target)
{
float srcRadius = short_to_float(appearance.pos.collision_radius);
if (target)
{
float targRadius = short_to_float(target->appearance.pos.collision_radius);
return (targRadius / 32.0f) + (srcRadius / 32.0f);
}
else
return (srcRadius / 32.0f);
}
int32 Spawn::GetRespawnTime(){
return respawn;
}
@ -1841,19 +1886,19 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
SetSpeed(speed);
}
MovementLocation* loc = GetCurrentRunningLocation();
if (GetDistance(followTarget, true) <= MAX_COMBAT_RANGE || (loc && loc->x == GetX() && loc->y == GetY() && loc->z == GetZ())) {
if ((GetDistance(followTarget, true) <= rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat()) || (loc && loc->x == GetX() && loc->y == GetY() && loc->z == GetZ())) {
ClearRunningLocations();
CalculateRunningLocation(true);
}
else if (loc) {
float distance = GetDistance(loc->x, loc->y, loc->z, followTarget->GetX(), followTarget->GetY(), followTarget->GetZ());
if (distance > MAX_COMBAT_RANGE) {
MoveToLocation(followTarget, MAX_COMBAT_RANGE);
float distance = GetDistance(followTarget, loc->x, loc->y, loc->z);
if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat()) {
MoveToLocation(followTarget, rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat());
CalculateRunningLocation();
}
}
else {
MoveToLocation(followTarget, MAX_COMBAT_RANGE);
MoveToLocation(followTarget, rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat());
CalculateRunningLocation();
}
}

View file

@ -590,9 +590,13 @@ public:
int32 GetID(){
return id;
}
float GetDistance(Spawn* spawn, bool ignore_y = false);
float GetDistance(float x, float y, float z, bool ignore_y = false);
float GetDistance(float x1, float y1, float z1, float x2, float y2, float z2);
float GetDistance(float x, float y, float z, float radius, bool ignore_y = false);
float GetDistance(float x, float y, float z, bool ignore_y = false);
float GetDistance(Spawn* spawn, bool ignore_y = false, bool includeRadius=true);
float GetDistance(Spawn* spawn, float x1, float y1, float z1, bool includeRadius=true);
float CalculateRadius(Spawn* target);
int8 GetEncounterLevel(){
return appearance.encounter_level;
}

View file

@ -922,4 +922,27 @@ strlcpy(char *dst, const char *src, size_t size) {
}
return(s - src - 1);
}
}
float short_to_float(const ushort x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
const uint32 e = (x & 0x7C00) >> 10; // exponent
const uint32 m = (x & 0x03FF) << 13; // mantissa
const uint32 v = as_uint((float)m) >> 23; // evil log2 bit hack to count leading zeros in denormalized format
return as_float((x & 0x8000) << 16 | (e != 0) * ((e + 112) << 23 | m) | ((e == 0) & (m != 0)) * ((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000))); // sign : normalized : denormalized
}
uint32 float_to_int(const float x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
const uint32 b = as_uint(x) + 0x00001000; // round-to-nearest-even: add last bit after truncated mantissa
const uint32 e = (b & 0x7F800000) >> 23; // exponent
const uint32 m = b & 0x007FFFFF; // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
return (b & 0x80000000) >> 16 | (e > 112)* ((((e - 112) << 10) & 0x7C00) | m >> 13) | ((e < 113) & (e > 101))* ((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143) * 0x7FFF; // sign : normalized : denormalized : saturate
}
uint32 as_uint(const float x) {
return *(uint32*)&x;
}
float as_float(const uint32 x) {
return *(float*)&x;
}

View file

@ -80,6 +80,11 @@ int16 GetOpcodeVersion(int16 version);
void SleepMS(int32 milliseconds);
size_t strlcpy(char *dst, const char *src, size_t size);
float short_to_float(const ushort x);
uint32 float_to_int(const float x);
uint32 as_uint(const float x);
float as_float(const uint32 x);
bool INIReadBool(FILE *f, const char *section, const char *property, bool *out);
bool INIReadInt(FILE *f, const char *section, const char *property, int *out);