Index: src/common/utils.cpp =================================================================== --- src/common/utils.cpp (revision 3122) +++ src/common/utils.cpp (working copy) @@ -127,6 +127,12 @@ return (radian / (2 * M_PI)) * 256; } +//Amount of rotation needed for A to be facing B head on +uint8 currentAngle(position_t A, position_t B) +{ + uint8 angle = getangle(A,B); + return (angle - A.rotation); +} /************************************************************************ * * Index: src/common/utils.h =================================================================== --- src/common/utils.h (revision 3122) +++ src/common/utils.h (working copy) @@ -38,6 +38,7 @@ float rotationToRadian(uint8 rotation); uint8 radianToRotation(float radian); uint8 getangle(position_t A, position_t B); // А - основная сущность, B - цель сущности (проекция вектора на OX) +uint8 currentAngle(position_t A, position_t B); // А - основная сущность, B - цель сущности (проекция вектора на OX) bool isFaceing(position_t A, position_t B, uint8 coneAngle); // А - основная сущность, B - цель сущности int32 hasBit(uint16 value, uint8* BitArray, uint32 size); // проверяем наличие бита в массиве Index: src/map/ai/ai_mob_dummy.cpp =================================================================== --- src/map/ai/ai_mob_dummy.cpp (revision 3122) +++ src/map/ai/ai_mob_dummy.cpp (working copy) @@ -201,7 +201,7 @@ //Start luautils::OnMobEngaged if (m_PBattleTarget != NULL) { luautils::OnMobEngaged(m_PMob, m_PBattleTarget); - battleutils::MoveIntoRange(m_PMob, m_PBattleTarget, 0); + battleutils::MoveIntoRange(m_PMob, m_PBattleTarget); } @@ -398,8 +398,6 @@ m_ActionType = ACTION_FADE_OUT; m_PMob->loc.zone->PushPacket(m_PMob, CHAR_INRANGE, new CFadeOutPacket(m_PMob)); //if (m_PMob->animationsub == 2) m_PMob->animationsub = 1; - - luautils::OnMobDespawn(m_PMob); } else if (!m_PMob->isDead()) { @@ -428,6 +426,8 @@ m_PMob->PEnmityContainer->Clear(); m_ActionType = m_PMob->m_AllowRespawn ? ACTION_SPAWN : ACTION_NONE; + //DG - Moved here so it is triggered once mob has completed despawn + luautils::OnMobDespawn(m_PMob); } } @@ -537,14 +537,14 @@ ActionAttack(); return; } - battleutils::MoveIntoRange(m_PMob, m_PBattleTarget, 25); + battleutils::MoveIntoRange(m_PMob, m_PBattleTarget); m_PMob->loc.zone->PushPacket(m_PMob,CHAR_INRANGE, new CEntityUpdatePacket(m_PMob, ENTITY_UPDATE)); return; } if(m_PMobSkill->getValidTargets() == TARGET_ENEMY){ //enemy m_PBattleSubTarget = m_PBattleTarget; - battleutils::MoveIntoRange(m_PMob, m_PBattleSubTarget, 25); + battleutils::MoveIntoRange(m_PMob, m_PBattleSubTarget); } else if(m_PMobSkill->getValidTargets() == TARGET_SELF){ //self m_PBattleSubTarget = m_PMob; @@ -1375,7 +1375,7 @@ m_PMob->m_ActionList.push_back(Action); } - battleutils::MoveIntoRange(m_PMob,m_PBattleTarget,25); + battleutils::MoveIntoRange(m_PMob,m_PBattleTarget); m_PMob->loc.zone->PushPacket(m_PMob, CHAR_INRANGE, new CActionPacket(m_PMob)); } //end attack for } @@ -1402,7 +1402,7 @@ m_ActionType = ACTION_MOBABILITY_START; ActionAbilityStart(); } - battleutils::MoveIntoRange(m_PMob, m_PBattleTarget, 25); + battleutils::MoveIntoRange(m_PMob, m_PBattleTarget); } if(m_PMob->m_Type & MOBTYPE_NOTORIOUS && (m_Tick - m_StartBattle) % 3000 <= 400) // launch OnMobFight every 3 sec (not everytime at 0 but 0~400) Index: src/map/ai/ai_pet_dummy.cpp =================================================================== --- src/map/ai/ai_pet_dummy.cpp (revision 3122) +++ src/map/ai/ai_pet_dummy.cpp (working copy) @@ -262,7 +262,7 @@ m_PBattleSubTarget = m_PBattleTarget; } DSP_DEBUG_BREAK_IF(m_PBattleSubTarget == NULL); - battleutils::MoveIntoRange(m_PPet, m_PBattleSubTarget, 25); + battleutils::MoveIntoRange(m_PPet, m_PBattleSubTarget); } Action.ActionTarget = m_PBattleSubTarget; Index: src/map/battleutils.cpp =================================================================== --- src/map/battleutils.cpp (revision 3122) +++ src/map/battleutils.cpp (working copy) @@ -2642,19 +2642,43 @@ ************************************************************************/ -void MoveIntoRange(CBattleEntity* PPursuer, CBattleEntity* PTarget, uint8 angleThreshold) +void MoveIntoRange(CBattleEntity* PPursuer, CBattleEntity* PTarget) { - // if(angle >= angleThreshold){ - // } + uint8 angle = getangle(PPursuer->loc.p, PTarget->loc.p); + uint8 curAngle = currentAngle(PPursuer->loc.p, PTarget->loc.p); - // always change angle for now - uint8 angle = getangle(PPursuer->loc.p, PTarget->loc.p); - PPursuer->loc.p.rotation = angle; + CMobEntity* PMob = (CMobEntity*)PPursuer; - if (distance(PPursuer->loc.p, PTarget->loc.p) > PPursuer->m_ModelSize){ + uint8 fAngleThreshold = PMob->fAngleTol; + uint8 rAngleThreshold = PMob->rAngleTol; - MoveTo(PPursuer, PTarget->loc.p, 2); - } + //If front angle is outside acceptable bounds + if (curAngle >= fAngleThreshold && curAngle <= 254 - fAngleThreshold) + { + //if no rear bounds + if (rAngleThreshold == 0) + { + PPursuer->loc.p.rotation = angle; + } + else + { + //if rear angle is outside acceptable bounds + if (curAngle <= 127 - rAngleThreshold || curAngle >= 127 + rAngleThreshold) + { + PPursuer->loc.p.rotation = angle; + } + } + } + + if (distance(PPursuer->loc.p, PTarget->loc.p) > PPursuer->m_ModelSize) + { + // Turn to face before moving if target is behind mob + if (curAngle >= fAngleThreshold && curAngle <= 254 - fAngleThreshold) + { + PPursuer->loc.p.rotation = angle; + } + MoveTo(PPursuer, PTarget->loc.p, 2); + } } /**************************************************************** Index: src/map/battleutils.h =================================================================== --- src/map/battleutils.h (revision 3122) +++ src/map/battleutils.h (working copy) @@ -141,7 +141,7 @@ uint8 GetEnmityMod(uint8 level, uint8 modType); bool Enfeeble(CBattleEntity* PCaster, CBattleEntity* PDefender, EFFECT Effect); void MoveTo(CBattleEntity* PEntity, position_t pos, uint8 mode); - void MoveIntoRange(CBattleEntity* PPursuer, CBattleEntity* PTarget, uint8 angleThreshold); + void MoveIntoRange(CBattleEntity* PPursuer, CBattleEntity* PTarget); bool isValidSelfTargetWeaponskill(int wsid); bool TryInterruptSpell(CBattleEntity* PAttacker, CBattleEntity* PDefender); float CalculateBaseTP(int delay, int stp); Index: src/map/mobentity.cpp =================================================================== --- src/map/mobentity.cpp (revision 3122) +++ src/map/mobentity.cpp (working copy) @@ -70,6 +70,9 @@ evaRank = 3; linkRadius = 10; + rAngleTol = 0; + fAngleTol = 0; + m_SpecialCoolDown = 0; memset(& m_SpawnPoint, 0, sizeof(m_SpawnPoint)); Index: src/map/mobentity.h =================================================================== --- src/map/mobentity.h (revision 3122) +++ src/map/mobentity.h (working copy) @@ -99,6 +99,8 @@ float HPstat; // HP boost percentage float MPstat; // MP boost percentage uint8 linkRadius; // mobs have different link radiuses + uint8 fAngleTol; // DG - Front angle tolerance + uint8 rAngleTol; // DG - Rear angle tolerance // stat ranks uint8 strRank; Index: src/map/zoneutils.cpp =================================================================== --- src/map/zoneutils.cpp (revision 3122) +++ src/map/zoneutils.cpp (working copy) @@ -253,7 +253,7 @@ Slash, Pierce, H2H, Impact, \ Fire, Ice, Wind, Earth, Lightning, Water, Light, Dark, Element, \ mob_pools.familyid, name_prefix, unknown, animationsub, \ - (mob_family_system.HP / 100), (mob_family_system.MP / 100), hasSpellScript, spellList, ATT, ACC, link_radius \ + (mob_family_system.HP / 100), (mob_family_system.MP / 100), hasSpellScript, spellList, ATT, ACC, link_radius, front_angle, rear_angle \ FROM mob_groups, mob_pools, mob_spawn_points, mob_family_system \ WHERE mob_groups.poolid = mob_pools.poolid \ AND mob_groups.groupid = mob_spawn_points.groupid \ @@ -365,6 +365,10 @@ PMob->HPstat = Sql_GetFloatData(SqlHandle,51); PMob->MPstat = Sql_GetFloatData(SqlHandle,52); + // Setup Angle Tolerances + PMob->fAngleTol = (uint8)Sql_GetIntData(SqlHandle,58); + PMob->rAngleTol = (uint8)Sql_GetIntData(SqlHandle,59); + PMob->PBattleAI = new CAIMobDummy(PMob); if (PMob->m_AllowRespawn = PMob->m_SpawnType == SPAWNTYPE_NORMAL)