예제 #1
0
 void LoadObjectData(ObjectData[] objectData, Dictionary <uint, uint> objectInfo)
 {
     foreach (var data in objectData)
     {
         Cypher.Assert(!objectInfo.ContainsKey(data.entry));
         objectInfo[data.entry] = data.type;
     }
 }
예제 #2
0
 public override void InitSummon()
 {
     base.InitSummon();
     if (!SetCharmedBy(GetOwner(), CharmType.Possess))
     {
         Cypher.Assert(false);
     }
 }
예제 #3
0
 void BindToCaster()
 {
     Cypher.Assert(_caster == null);
     _caster = Global.ObjAccessor.GetUnit(this, GetCasterGUID());
     Cypher.Assert(_caster != null);
     Cypher.Assert(_caster.GetMap() == GetMap());
     _caster._RegisterDynObject(this);
 }
예제 #4
0
        public void SetPartyType(GroupCategory category, GroupType type)
        {
            Cypher.Assert(category < GroupCategory.Max);
            byte value = m_playerData.PartyType;

            value &= (byte)~((byte)0xFF << ((byte)category * 4));
            value |= (byte)((byte)type << ((byte)category * 4));
            SetUpdateFieldValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.PartyType), value);
        }
예제 #5
0
        public void SetPartyType(GroupCategory category, GroupType type)
        {
            Cypher.Assert(category < GroupCategory.Max);
            byte value = GetByteValue(PlayerFields.Bytes3, PlayerFieldOffsets.Bytes3OffsetPartyType);

            value &= (byte)~((byte)0xFF << ((byte)category * 4));
            value |= (byte)((byte)type << ((byte)category * 4));
            SetByteValue(PlayerFields.Bytes3, PlayerFieldOffsets.Bytes3OffsetPartyType, value);
        }
예제 #6
0
 public void Dispose()
 {
     // @Uninstall must be called before this.
     Cypher.Assert(_status == Status.UnInstalling);
     foreach (var pair in Seats)
     {
         Cypher.Assert(pair.Value.IsEmpty());
     }
 }
예제 #7
0
 Node GetGrid(int x, int y)
 {
     Cypher.Assert(x < CELL_NUMBER && y < CELL_NUMBER);
     if (nodes[x][y] == null)
     {
         nodes[x][y] = new Node();
     }
     return(nodes[x][y]);
 }
예제 #8
0
        public virtual void InitStats(uint duration)
        {
            Cypher.Assert(!IsPet());

            m_timer    = duration;
            m_lifetime = duration;

            if (m_type == TempSummonType.ManualDespawn)
            {
                m_type = (duration == 0) ? TempSummonType.DeadDespawn : TempSummonType.TimedDespawn;
            }

            Unit owner = GetSummoner();

            if (owner != null && IsTrigger() && m_spells[0] != 0)
            {
                SetFaction(owner.GetFaction());
                SetLevel(owner.GetLevel());
                if (owner.IsTypeId(TypeId.Player))
                {
                    m_ControlledByPlayer = true;
                }
            }


            if (m_Properties == null)
            {
                return;
            }

            if (owner != null)
            {
                int slot = m_Properties.Slot;
                if (slot > 0)
                {
                    if (!owner.m_SummonSlot[slot].IsEmpty() && owner.m_SummonSlot[slot] != GetGUID())
                    {
                        Creature oldSummon = GetMap().GetCreature(owner.m_SummonSlot[slot]);
                        if (oldSummon != null && oldSummon.IsSummon())
                        {
                            oldSummon.ToTempSummon().UnSummon();
                        }
                    }
                    owner.m_SummonSlot[slot] = GetGUID();
                }
            }

            if (m_Properties.Faction != 0)
            {
                SetFaction(m_Properties.Faction);
            }
            else if (IsVehicle() && owner != null) // properties should be vehicle
            {
                SetFaction(owner.GetFaction());
            }
        }
예제 #9
0
        public Vehicle RemovePassenger(Unit unit)
        {
            if (unit.GetVehicle() != this)
            {
                return(null);
            }

            var seat = GetSeatKeyValuePairForPassenger(unit);

            Cypher.Assert(seat.Value != null);

            Log.outDebug(LogFilter.Vehicle, "Unit {0} exit vehicle entry {1} id {2} dbguid {3} seat {4}",
                         unit.GetName(), _me.GetEntry(), _vehicleInfo.Id, _me.GetGUID().ToString(), seat.Key);

            if (seat.Value.SeatInfo.CanEnterOrExit() && ++UsableSeatNum != 0)
            {
                _me.SetFlag64(UnitFields.NpcFlags, (_me.IsTypeId(TypeId.Player) ? NPCFlags.PlayerVehicle : NPCFlags.SpellClick));
            }

            // Remove UNIT_FLAG_NOT_SELECTABLE if passenger did not have it before entering vehicle
            if (seat.Value.SeatInfo.Flags.HasAnyFlag(VehicleSeatFlags.PassengerNotSelectable) && !seat.Value.Passenger.IsUnselectable)
            {
                unit.RemoveFlag(UnitFields.Flags, UnitFlags.NotSelectable);
            }

            seat.Value.Passenger.Reset();

            if (_me.IsTypeId(TypeId.Unit) && unit.IsTypeId(TypeId.Player) && seat.Value.SeatInfo.Flags.HasAnyFlag(VehicleSeatFlags.CanControl))
            {
                _me.RemoveCharmedBy(unit);
            }

            if (_me.IsInWorld)
            {
                unit.m_movementInfo.ResetTransport();
            }

            // only for flyable vehicles
            if (unit.IsFlying())
            {
                _me.CastSpell(unit, SharedConst.VehicleSpellParachute, true);
            }

            if (_me.IsTypeId(TypeId.Unit) && _me.ToCreature().IsAIEnabled)
            {
                _me.ToCreature().GetAI().PassengerBoarded(unit, seat.Key, false);
            }

            if (GetBase().IsTypeId(TypeId.Unit))
            {
                Global.ScriptMgr.OnRemovePassenger(this, unit);
            }

            unit.SetVehicle(null);
            return(this);
        }
예제 #10
0
        public override void Dispose()
        {
            // make sure all references were properly removed
            Cypher.Assert(_aura == null);
            Cypher.Assert(!_caster);
            Cypher.Assert(!_isViewpoint);
            _removedAura = null;

            base.Dispose();
        }
예제 #11
0
        // Hack to store map because this code is just shit
        public void SetMapFromZone(uint zone)
        {
            AreaTableRecord areaTable = CliDB.AreaTableStorage.LookupByKey(zone);

            Cypher.Assert(areaTable != null);
            Map map = Global.MapMgr.CreateBaseMap(areaTable.ContinentID);

            Cypher.Assert(!map.Instanceable());
            m_map = map;
        }
예제 #12
0
 public Minion(SummonPropertiesRecord properties, Unit owner, bool isWorldObject)
     : base(properties, owner, isWorldObject)
 {
     m_owner = owner;
     Cypher.Assert(m_owner);
     UnitTypeMask |= UnitTypeMask.Minion;
     m_followAngle = SharedConst.PetFollowAngle;
     /// @todo: Find correct way
     InitCharmInfo();
 }
예제 #13
0
 void RemoveAura()
 {
     Cypher.Assert(_aura != null && _removedAura == null);
     _removedAura = _aura;
     _aura        = null;
     if (!_removedAura.IsRemoved())
     {
         _removedAura._Remove(AuraRemoveMode.Default);
     }
 }
예제 #14
0
        void LoadHelper <T>(SortedSet <ulong> guid_set, CellCoord cell, ref uint count, Map map) where T : WorldObject, new()
        {
            foreach (var guid in guid_set)
            {
                T obj = new();
                // Don't spawn at all if there's a respawn time
                if ((obj.IsTypeId(TypeId.Unit) && map.GetCreatureRespawnTime(guid) == 0) || (obj.IsTypeId(TypeId.GameObject) && map.GetGORespawnTime(guid) == 0) || obj.IsTypeId(TypeId.AreaTrigger))
                {
                    //TC_LOG_INFO("misc", "DEBUG: LoadHelper from table: %s for (guid: %u) Loading", table, guid);
                    if (obj.IsTypeId(TypeId.Unit))
                    {
                        CreatureData cdata = Global.ObjectMgr.GetCreatureData(guid);
                        Cypher.Assert(cdata != null, $"Tried to load creature with spawnId {guid}, but no such creature exists.");

                        SpawnGroupTemplateData group = cdata.spawnGroupData;
                        // If creature in manual spawn group, don't spawn here, unless group is already active.
                        if (!group.flags.HasAnyFlag(SpawnGroupFlags.System))
                        {
                            if (!map.IsSpawnGroupActive(group.groupId))
                            {
                                obj.Dispose();
                                continue;
                            }
                        }
                    }
                    else if (obj.IsTypeId(TypeId.GameObject))
                    {
                        // If gameobject in manual spawn group, don't spawn here, unless group is already active.
                        GameObjectData godata = Global.ObjectMgr.GetGameObjectData(guid);
                        Cypher.Assert(godata != null, $"Tried to load gameobject with spawnId {guid}, but no such object exists.");

                        if (!godata.spawnGroupData.flags.HasAnyFlag(SpawnGroupFlags.System))
                        {
                            if (!map.IsSpawnGroupActive(godata.spawnGroupData.groupId))
                            {
                                obj.Dispose();
                                continue;
                            }
                        }
                    }

                    if (!obj.LoadFromDB(guid, map, false, false))
                    {
                        obj.Dispose();
                        continue;
                    }
                    AddObjectHelper(cell, ref count, map, obj);
                }
                else
                {
                    obj.Dispose();
                }
            }
        }
예제 #15
0
        public void Insert(int index, int value)
        {
            Cypher.Assert(index < 0x20);

            _mask |= 1u << index;
            if (_contents.Length <= index)
            {
                Array.Resize(ref _contents, index + 1);
            }
            _contents[index] = value;
        }
예제 #16
0
        GarrisonMap CreateGarrison(uint instanceId, Player owner)
        {
            lock (_mapLock)
            {
                GarrisonMap map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner.GetGUID());
                Cypher.Assert(map.IsGarrison());

                m_InstancedMaps[instanceId] = map;
                return(map);
            }
        }
        public override bool DoUpdate(Player owner, uint diff)
        {
            if (owner == null)
            {
                return(false);
            }

            // skipping the first spline path point because it's our starting point and not a taxi path point
            uint pointId = (uint)(owner.MoveSpline.CurrentPathIdx() <= 0 ? 0 : owner.MoveSpline.CurrentPathIdx() - 1);

            if (pointId > _currentNode && _currentNode < _path.Count - 1)
            {
                bool departureEvent = true;
                do
                {
                    Cypher.Assert(_currentNode < _path.Count, $"Point Id: {pointId}\n{owner.GetDebugInfo()}");

                    DoEventIfAny(owner, _path[_currentNode], departureEvent);
                    while (!_pointsForPathSwitch.Empty() && _pointsForPathSwitch[0].PathIndex <= _currentNode)
                    {
                        _pointsForPathSwitch.RemoveAt(0);
                        owner.m_taxi.NextTaxiDestination();
                        if (!_pointsForPathSwitch.Empty())
                        {
                            owner.UpdateCriteria(CriteriaType.MoneySpentOnTaxis, (uint)_pointsForPathSwitch[0].Cost);
                            owner.ModifyMoney(-_pointsForPathSwitch[0].Cost);
                        }
                    }

                    if (pointId == _currentNode)
                    {
                        break;
                    }

                    if (_currentNode == _preloadTargetNode)
                    {
                        PreloadEndGrid();
                    }

                    _currentNode  += (departureEvent ? 1 : 0);
                    departureEvent = !departureEvent;
                }while (_currentNode < _path.Count - 1);
            }

            if (_currentNode >= (_path.Count - 1))
            {
                AddFlag(MovementGeneratorFlags.InformEnabled);
                return(false);
            }
            return(true);
        }
예제 #18
0
 // Create new link
 public void link(TO toObj, FROM fromObj)
 {
     Cypher.Assert(fromObj != null);                                // fromObj MUST not be NULL
     if (isValid())
     {
         unlink();
     }
     if (toObj != null)
     {
         _RefTo   = toObj;
         _RefFrom = fromObj;
         targetObjectBuildLink();
     }
 }
예제 #19
0
        // Selects proper template overload to call based on passed type
        public uint IsPartOfAPool(SpawnObjectType type, ulong spawnId)
        {
            switch (type)
            {
            case SpawnObjectType.Creature:
                return(IsPartOfAPool <Creature>(spawnId));

            case SpawnObjectType.GameObject:
                return(IsPartOfAPool <GameObject>(spawnId));

            default:
                Cypher.Assert(false, $"Invalid spawn type {type} passed to PoolMgr.IsPartOfPool (with spawnId {spawnId})");
                return(0);
            }
        }
예제 #20
0
        BattlegroundMap CreateBattleground(uint InstanceId, Battleground bg)
        {
            lock (_mapLock)
            {
                Log.outDebug(LogFilter.Maps, "MapInstanced.CreateBattleground: map bg {0} for {1} created.", InstanceId, GetId());

                BattlegroundMap map = new BattlegroundMap(GetId(), (uint)GetGridExpiry(), InstanceId, this, Difficulty.None);
                Cypher.Assert(map.IsBattlegroundOrArena());
                map.SetBG(bg);
                bg.SetBgMap(map);

                m_InstancedMaps[InstanceId] = map;
                return(map);
            }
        }
예제 #21
0
        public bool Initialize(ObjectGuid guid, Player player = null)
        {
            CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(guid);

            if (characterInfo == null)
            {
                return(false);
            }

            if (player)
            {
                Cypher.Assert(player.GetGUID() == guid);

                AccountID     = player.GetSession().GetAccountGUID();
                BnetAccountID = player.GetSession().GetBattlenetAccountGUID();
                Name          = player.GetName();
                RaceID        = player.GetRace();
                Sex           = (Gender)player.GetByteValue(PlayerFields.Bytes3, PlayerFieldOffsets.Bytes3OffsetGender);
                ClassID       = player.GetClass();
                Level         = (byte)player.getLevel();

                DeclinedName names = player.GetDeclinedNames();
                if (names != null)
                {
                    DeclinedNames = names;
                }
            }
            else
            {
                uint accountId     = ObjectManager.GetPlayerAccountIdByGUID(guid);
                uint bnetAccountId = Global.BNetAccountMgr.GetIdByGameAccount(accountId);

                AccountID     = ObjectGuid.Create(HighGuid.WowAccount, accountId);
                BnetAccountID = ObjectGuid.Create(HighGuid.BNetAccount, bnetAccountId);
                Name          = characterInfo.Name;
                RaceID        = characterInfo.RaceID;
                Sex           = characterInfo.Sex;
                ClassID       = characterInfo.ClassID;
                Level         = characterInfo.Level;
            }

            IsDeleted           = characterInfo.IsDeleted;
            GuidActual          = guid;
            VirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress();

            return(true);
        }
예제 #22
0
        public bool Initialize(ObjectGuid guid, Player player = null)
        {
            CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(guid);

            if (characterInfo == null)
            {
                return(false);
            }

            if (player)
            {
                Cypher.Assert(player.GetGUID() == guid);

                AccountID     = player.GetSession().GetAccountGUID();
                BnetAccountID = player.GetSession().GetBattlenetAccountGUID();
                Name          = player.GetName();
                RaceID        = player.GetRace();
                Sex           = player.GetNativeSex();
                ClassID       = player.GetClass();
                Level         = (byte)player.GetLevel();

                DeclinedName names = player.GetDeclinedNames();
                if (names != null)
                {
                    DeclinedNames = names;
                }
            }
            else
            {
                uint accountId     = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(guid);
                uint bnetAccountId = Global.BNetAccountMgr.GetIdByGameAccount(accountId);

                AccountID     = ObjectGuid.Create(HighGuid.WowAccount, accountId);
                BnetAccountID = ObjectGuid.Create(HighGuid.BNetAccount, bnetAccountId);
                Name          = characterInfo.Name;
                RaceID        = characterInfo.RaceId;
                Sex           = characterInfo.Sex;
                ClassID       = characterInfo.ClassId;
                Level         = characterInfo.Level;
            }

            IsDeleted           = characterInfo.IsDeleted;
            GuidActual          = guid;
            VirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress();

            return(true);
        }
예제 #23
0
        InstanceMap CreateInstance(uint InstanceId, InstanceSave save, Difficulty difficulty, int teamId)
        {
            lock (_mapLock)
            {
                // make sure we have a valid map id
                MapRecord entry = CliDB.MapStorage.LookupByKey(GetId());
                if (entry == null)
                {
                    Log.outError(LogFilter.Maps, "CreateInstance: no record for map {0}", GetId());
                    Cypher.Assert(false);
                }
                InstanceTemplate iTemplate = Global.ObjectMgr.GetInstanceTemplate(GetId());
                if (iTemplate == null)
                {
                    Log.outError(LogFilter.Maps, "CreateInstance: no instance template for map {0}", GetId());
                    Cypher.Assert(false);
                }

                // some instances only have one difficulty
                Global.DB2Mgr.GetDownscaledMapDifficultyData(GetId(), ref difficulty);

                Log.outDebug(LogFilter.Maps, "MapInstanced.CreateInstance: {0} map instance {1} for {2} created with difficulty {3}", save != null ? "" : "new ", InstanceId, GetId(), difficulty);

                InstanceMap map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this);
                Cypher.Assert(map.IsDungeon());

                map.LoadRespawnTimes();
                map.LoadCorpseData();

                bool load_data = save != null;
                map.CreateInstanceData(load_data);
                InstanceScenario instanceScenario = Global.ScenarioMgr.CreateInstanceScenario(map, teamId);
                if (instanceScenario != null)
                {
                    map.SetInstanceScenario(instanceScenario);
                }

                if (WorldConfig.GetBoolValue(WorldCfg.InstancemapLoadGrids))
                {
                    map.LoadAllCells();
                }

                m_InstancedMaps[InstanceId] = map;
                return(map);
            }
        }
예제 #24
0
        public static bool IsValidProcess(Unit hatedUnit, Unit hatingUnit, SpellInfo threatSpell = null)
        {
            //function deals with adding threat and adding players and pets into ThreatList
            //mobs, NPCs, guards have ThreatList and HateOfflineList
            //players and pets have only InHateListOf
            //HateOfflineList is used co contain unattackable victims (in-flight, in-water, GM etc.)

            if (hatedUnit == null || hatingUnit == null)
            {
                return(false);
            }

            // not to self
            if (hatedUnit == hatingUnit)
            {
                return(false);
            }

            // not to GM
            if (hatedUnit.IsTypeId(TypeId.Player) && hatedUnit.ToPlayer().IsGameMaster())
            {
                return(false);
            }

            // not to dead and not for dead
            if (!hatedUnit.IsAlive() || !hatingUnit.IsAlive())
            {
                return(false);
            }

            // not in same map or phase
            if (!hatedUnit.IsInMap(hatingUnit) || !hatedUnit.IsInPhase(hatingUnit))
            {
                return(false);
            }

            // spell not causing threat
            if (threatSpell != null && threatSpell.HasAttribute(SpellAttr1.NoThreat))
            {
                return(false);
            }

            Cypher.Assert(hatingUnit.IsTypeId(TypeId.Unit));

            return(true);
        }
예제 #25
0
        public bool getObjectHitPos(Vector3 startPos, Vector3 endPos, ref Vector3 resultHitPos, float modifyDist, PhaseShift phaseShift)
        {
            bool  result  = false;
            float maxDist = (endPos - startPos).magnitude();

            // valid map coords should *never ever* produce float overflow, but this would produce NaNs too
            Cypher.Assert(maxDist < float.MaxValue);
            // prevent NaN values which can cause BIH intersection to enter infinite loop
            if (maxDist < 1e-10f)
            {
                resultHitPos = endPos;
                return(false);
            }
            Vector3 dir  = (endPos - startPos) / maxDist;             // direction with length of 1
            Ray     ray  = new Ray(startPos, dir);
            float   dist = maxDist;

            if (getIntersectionTime(ray, endPos, phaseShift, dist))
            {
                resultHitPos = startPos + dir * dist;
                if (modifyDist < 0)
                {
                    if ((resultHitPos - startPos).magnitude() > -modifyDist)
                    {
                        resultHitPos += dir * modifyDist;
                    }
                    else
                    {
                        resultHitPos = startPos;
                    }
                }
                else
                {
                    resultHitPos += dir * modifyDist;
                }

                result = true;
            }
            else
            {
                resultHitPos = endPos;
                result       = false;
            }
            return(result);
        }
예제 #26
0
        public override void MovementInform(MovementGeneratorType moveType, uint Id)
        {
            // no action allowed if there is no escort
            if (!HasEscortState(EscortState.Escorting))
            {
                return;
            }

            //Combat start position reached, continue waypoint movement
            if (moveType == MovementGeneratorType.Point)
            {
                if (_pauseTimer == 0)
                {
                    _pauseTimer = 2000;
                }

                if (Id == EscortPointIds.LastPoint)
                {
                    Log.outDebug(LogFilter.Scripts, "EscortAI.MovementInform has returned to original position before combat");

                    me.SetWalk(!_running);
                    RemoveEscortState(EscortState.Returning);
                }
                else if (Id == EscortPointIds.Home)
                {
                    Log.outDebug(LogFilter.Scripts, "EscortAI.MovementInform: returned to home location and restarting waypoint path");
                    _started = false;
                }
            }
            else if (moveType == MovementGeneratorType.Waypoint)
            {
                Cypher.Assert(Id < _path.nodes.Count, $"EscortAI.MovementInform: referenced movement id ({Id}) points to non-existing node in loaded path");
                WaypointNode waypoint = _path.nodes[(int)Id];

                Log.outDebug(LogFilter.Scripts, $"EscortAI.MovementInform: waypoint node {waypoint.id} reached");

                // last point
                if (Id == _path.nodes.Count - 1)
                {
                    _started    = false;
                    _ended      = true;
                    _pauseTimer = 1000;
                }
            }
        }
        void SendSplineFor(Unit me, int index, uint toNext)
        {
            Cypher.Assert(index < _chainSize);
            Log.outDebug(LogFilter.Movement, "{0}: Sending spline for {1}.", me.GetGUID().ToString(), index);

            SplineChainLink thisLink       = _chain[index];
            uint            actualDuration = SendPathSpline(me, new Span <Vector3>(thisLink.Points.ToArray()));

            if (actualDuration != thisLink.ExpectedDuration)
            {
                Log.outDebug(LogFilter.Movement, "{0}: Sent spline for {1}, duration is {2} ms. Expected was {3} ms (delta {4} ms). Adjusting.", me.GetGUID().ToString(), index, actualDuration, thisLink.ExpectedDuration, actualDuration - thisLink.ExpectedDuration);
                toNext = (uint)(actualDuration / thisLink.ExpectedDuration * toNext);
            }
            else
            {
                Log.outDebug(LogFilter.Movement, "{0}: Sent spline for {1}, duration is {2} ms.", me.GetGUID().ToString(), index, actualDuration);
            }
        }
        uint SendPathSpline(Unit me, Span <Vector3> wp)
        {
            int numWp = wp.Length;

            Cypher.Assert(numWp > 1, "Every path must have source & destination");
            MoveSplineInit init = new MoveSplineInit(me);

            if (numWp > 2)
            {
                init.MovebyPath(wp.ToArray());
            }
            else
            {
                init.MoveTo(wp[1], false, true);
            }
            init.SetWalk(_walk);
            return((uint)init.Launch());
        }
예제 #29
0
        public override bool GetResetPosition(Unit owner, out float x, out float y, out float z)
        {
            x = y = z = 0;

            // prevent a crash at empty waypoint path.
            if (_path == null || _path.nodes.Empty())
            {
                return(false);
            }

            Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator::GetResetPosition: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
            WaypointNode waypoint = _path.nodes.ElementAt(_currentNode);

            x = waypoint.x;
            y = waypoint.y;
            z = waypoint.z;
            return(true);
        }
예제 #30
0
        public bool GetObjectHitPos(Vector3 pPos1, Vector3 pPos2, out Vector3 pResultHitPos, float pModifyDist)
        {
            bool  result;
            float maxDist = (pPos2 - pPos1).magnitude();

            // valid map coords should *never ever* produce float overflow, but this would produce NaNs too
            Cypher.Assert(maxDist < float.MaxValue);
            // prevent NaN values which can cause BIH intersection to enter infinite loop
            if (maxDist < 1e-10f)
            {
                pResultHitPos = pPos2;
                return(false);
            }
            Vector3 dir  = (pPos2 - pPos1) / maxDist;             // direction with length of 1
            Ray     ray  = new Ray(pPos1, dir);
            float   dist = maxDist;

            if (GetIntersectionTime(ray, ref dist, false, ModelIgnoreFlags.Nothing))
            {
                pResultHitPos = pPos1 + dir * dist;
                if (pModifyDist < 0)
                {
                    if ((pResultHitPos - pPos1).magnitude() > -pModifyDist)
                    {
                        pResultHitPos += dir * pModifyDist;
                    }
                    else
                    {
                        pResultHitPos = pPos1;
                    }
                }
                else
                {
                    pResultHitPos += dir * pModifyDist;
                }
                result = true;
            }
            else
            {
                pResultHitPos = pPos2;
                result        = false;
            }
            return(result);
        }