Beispiel #1
0
 public bool HasTrafficLight(ushort nodeId, ref NetNode node)
 {
     return(LogicUtil.CheckFlags(
                (uint)node.m_flags,
                (uint)(NetNode.Flags.Created | NetNode.Flags.Deleted | NetNode.Flags.TrafficLights),
                (uint)(NetNode.Flags.Created | NetNode.Flags.TrafficLights)));
 }
Beispiel #2
0
            public override void Execute(object parameter)
            {
                string          text = $"最高速度{vm.CalcUppedSpeed()}km/hにアップすると{LogicUtil.AppendMoneyUnit(vm.CalcSpeedUpCost())}かかります。よろしいですか?";
                ExecuteDelegete exec = new ExecuteDelegete(vm.ExecuteSpeedUp);

                vm.ExecuteWithMoney(text, exec);
            }
 public void TestCheckFlags1()
 {
     Assert.IsTrue(
         LogicUtil.CheckFlags(
             (uint)(NetSegment.Flags.Created | NetSegment.Flags.Deleted),
             (uint)NetSegment.Flags.Created));
 }
        public void OnExecuteSceneCmd(Ticker ticker)
        {
            if (m_logicCmdList == null)
            {
                return;
            }
            uint          currentUpdateTick = 0;
            SceneLogicCmd sceneLogicCmd     = null;

            for (int index = 0; index < m_logicCmdList.Count; ++index)
            {
                sceneLogicCmd = m_logicCmdList[index];
                if (sceneLogicCmd == null)
                {
                    continue;
                }
                if (sceneLogicCmd.LogicUpdateTick >= currentUpdateTick)
                {
                    sceneLogicCmd.ExecuteCmd();
                }
                else
                {
                    m_logicCmdAssistList.Add(sceneLogicCmd);
                }
            }
            LogicUtil.CopyListContent <SceneLogicCmd>(m_logicCmdAssistList, m_logicCmdList);
            m_logicCmdAssistList.Clear();
        }
        /// <summary>
        /// 技能攻击
        /// </summary>
        public void NpcSkillAttack(NPCData attacker, NPCData defender, bool useSkill, Action <object> callback)
        {
            bool isMoveToTarget = false;

            if (LogicConst.BattleType == BattleType.TurnBase)
            {
                isMoveToTarget = attacker.jobType == JobType.Warrior;
            }
            var attackEvent = new NpcSkillAttackEvent();

            attackEvent.attackerid    = attacker.npcid;
            attackEvent.defenderid    = defender.npcid;
            attackEvent.bMoveToTarget = isMoveToTarget;
            attackEvent.bPlaySound    = LogicConst.BattleType == BattleType.TurnBase;
            attackEvent.bUseSkill     = useSkill;

            attackEvent.currHp   = defender.hp;
            attackEvent.maxHp    = defender.hpMax;
            attackEvent.amount   = LogicUtil.Random(-100, 0);
            attackEvent.callback = callback;

            var evData = new GameEventData(GameEventType.Battle, attackEvent);

            evMappingMgr.Add(evData);
            Messenger.Broadcast <GameEventData>(EventNames.EvNpcSkillAttack, evData);
        }
 public void TestCheckFlags2()
 {
     Assert.IsFalse(
         LogicUtil.CheckFlags(
             (uint)(NetSegment.Flags.Created | NetSegment.Flags.Deleted),
             (uint)NetSegment.Flags.Collapsed));
 }
Beispiel #7
0
            public override void Execute(object parameter)
            {
                string          text = $"この路線を増設するには{LogicUtil.AppendMoneyUnit(vm.CalcAddLaneCost())}かかります。よろしいですか?";
                ExecuteDelegete exec = new ExecuteDelegete(vm.ExecuteAddLane);

                vm.ExecuteWithMoney(text, exec);
            }
 public override void InitNpcTeams(List <string> teamDatas)
 {
     turnTeams.Clear();
     foreach (string teamItem in teamDatas)
     {
         var      items    = teamItem.ToList <uint>('-');
         var      teamid   = items[0];
         var      turnNum  = items[1];
         var      maxNum   = items[2];
         TeamData itemData = configMgr.GetTeamData(teamid);
         if (itemData != null)
         {
             for (int i = 0; i < turnNum; i++)
             {
                 TeamData newItem = new TeamData();
                 newItem.id       = itemData.id;
                 newItem.teamNpcs = new List <TeamNpcData>();
                 for (int j = 0; j < maxNum; j++)
                 {
                     int index   = LogicUtil.Random(0, itemData.teamNpcs.Count);
                     var teamNpc = itemData.teamNpcs[index];
                     newItem.teamNpcs.Add(teamNpc);
                 }
                 turnTeams.Enqueue(newItem);
             }
         }
     }
 }
        internal void OnNpcSpawnOK(object param)
        {
            var npcId = param.ToLong();

            Debug.Log("OnNpcSpawnOK:>" + npcId);
            var npcData = npcDataMgr.GetNpcData(npcId);

            if (npcData != null)
            {
                var showTime = LogicUtil.Random(0.2f, 0.5f);
                if (LogicConst.BattleType == BattleType.FreeBattle && npcData.npcType == NpcType.Enemy)
                {
                    showTime = 0;
                }
                battleLogicMgr.NpcShow(npcId, showTime, delegate(object obj)
                {
                    var currData = npcDataMgr.GetNpcData(obj.ToLong());
                    if (npcData != null)
                    {
                        npcData.npcState = NpcState.Ready;
                    }
                    Debug.Log("OnNpcShowOK:>" + obj);
                });
                battleLogicMgr.SetNpcFaceDir(npcId, npcData.faceDir);
            }
        }
        /// <summary>
        /// 出生一组NPC
        /// </summary>
        private void SpawnNpcTeam()
        {
            var currTeam = CurrHandler?.NextTeamData();

            if (currTeam != null)
            {
                List <uint> randomPos = null;
                var         emType    = LogicConst.BattleType == BattleType.FreeBattle ? EmbattleType.BothSides : EmbattleType.Right;
                if (emType == EmbattleType.BothSides)
                {
                    randomPos = new List <uint>();
                    while (randomPos.Count < currTeam.teamNpcs.Count)
                    {
                        var newindex = LogicUtil.Random(0u, 4u);
                        if (!randomPos.Contains(newindex))
                        {
                            randomPos.Add(newindex);
                        }
                    }
                }
                for (var i = 0; i < currTeam.teamNpcs.Count; i++)
                {
                    var newindex = 0;
                    var teamNpc  = currTeam.teamNpcs[i];
                    if (emType == EmbattleType.BothSides)
                    {
                        newindex = (int)randomPos[i] + 1;
                    }
                    else
                    {
                        newindex = i + 1;
                    }
                    var item = embattlePosMgr.GetItem(emType, (uint)newindex);
                    if (item != null)
                    {
                        var npcData = npcDataMgr.NewNpcData(teamNpc.roleid, NpcType.Enemy);
                        npcData.index = (uint)i;
                        npcData.hp    = teamNpc.hp;
                        npcData.hpInc = teamNpc.hpInc;
                        npcData.hpMax = teamNpc.hpMax;

                        npcData.mp    = teamNpc.mp;
                        npcData.mpInc = teamNpc.mpInc;
                        npcData.mpMax = teamNpc.mpMax;

                        npcData.attack   = teamNpc.attack;
                        npcData.defense  = teamNpc.defense;
                        npcData.faceDir  = item.faceDir;
                        npcData.position = item.pos;
                        npcDataMgr.AddNpcData(npcData);

                        npcData.fsm = new NpcFSM();
                        npcData.fsm.Initialize(npcData.npcid);
                        battleLogicMgr.NpcSpawn(npcData, OnNpcSpawnOK);
                    }
                }
            }
        }
Beispiel #11
0
        public bool CheckVehicleFlags2(ushort vehicleId, Vehicle.Flags2 flagMask, Vehicle.Flags2?expectedResult = default(Vehicle.Flags2?))
        {
            bool ret = false;

            ProcessVehicle(vehicleId, delegate(ushort vId, ref Vehicle vehicle) {
                ret = LogicUtil.CheckFlags((uint)vehicle.m_flags2, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
        public bool CheckNodeFlags(ushort nodeId, NetNode.Flags flagMask, NetNode.Flags?expectedResult = null)
        {
            bool ret = false;

            ProcessNode(nodeId, delegate(ushort nId, ref NetNode node) {
                ret = LogicUtil.CheckFlags((uint)node.m_flags, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
Beispiel #13
0
        public bool CheckCitizenInstanceFlags(ushort citizenInstanceId, CitizenInstance.Flags flagMask, CitizenInstance.Flags?expectedResult = default(CitizenInstance.Flags?))
        {
            bool ret = false;

            ProcessCitizenInstance(citizenInstanceId, delegate(ushort ciId, ref CitizenInstance citizenInstance) {
                ret = LogicUtil.CheckFlags((uint)citizenInstance.m_flags, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
        public bool CheckBuildingFlags(ushort buildingId, Building.Flags flagMask, Building.Flags?expectedResult = default(Building.Flags?))
        {
            bool ret = false;

            ProcessBuilding(buildingId, delegate(ushort bId, ref Building building) {
                ret = LogicUtil.CheckFlags((uint)building.m_flags, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
        public bool CheckUnitFlags(uint unitId, byte flagMask, byte?expectedResult = null)
        {
            bool ret = false;

            ProcessUnit(unitId, delegate(uint uId, ref PathUnit unit) {
                ret = LogicUtil.CheckFlags((uint)unit.m_pathFindFlags, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
        public bool CheckSegmentFlags(ushort segmentId, NetSegment.Flags flagMask, NetSegment.Flags?expectedResult = null)
        {
            bool ret = false;

            ProcessSegment(segmentId, delegate(ushort sId, ref NetSegment segment) {
                ret = LogicUtil.CheckFlags((uint)segment.m_flags, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
Beispiel #17
0
        public bool CheckCitizenFlags(uint citizenId, Citizen.Flags flagMask, Citizen.Flags?expectedResult = default(Citizen.Flags?))
        {
            bool ret = false;

            ProcessCitizen(citizenId, delegate(uint cId, ref Citizen citizen) {
                ret = LogicUtil.CheckFlags((uint)citizen.m_flags, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
        public bool CheckLaneFlags(uint laneId, NetLane.Flags flagMask, NetLane.Flags?expectedResult = null)
        {
            bool ret = false;

            ProcessLane(laneId, delegate(uint lId, ref NetLane lane) {
                ret = LogicUtil.CheckFlags((uint)lane.m_flags, (uint)flagMask, (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
Beispiel #19
0
        /// <summary>
        /// モード設定の1ブロックの文字列から設定を抽出
        /// </summary>
        /// <param name="modeLines"></param>
        private Mode(List <string> modeLines)
        {
            Name    = ApplicationUtil.ExtractModProperty(modeLines, "#mode");
            Year    = int.Parse(ApplicationUtil.ExtractModProperty(modeLines, "year"));
            Money   = long.Parse(ApplicationUtil.ExtractModProperty(modeLines, "money"));
            Message = ApplicationUtil.ExtractModProperty(modeLines, "message").Replace(',', '\n');
            MYear   = int.Parse(ApplicationUtil.ExtractModProperty(modeLines, "myear"));

            DefautltCompositions = ApplicationUtil.ExtractModProperties(modeLines, "car").Select(value =>
            {
                string[] arr     = value.Split(",");
                int ck           = int.Parse(arr[2]);       //編成規格
                bool isLinear    = (ck & 32) > 0;
                bool isDiesel    = (ck & 16) > 0;
                bool isElectric  = (ck & 8) > 0;
                bool isSteam     = (ck & 4) > 0;
                bool isNarrow    = (ck & 1) > 0;
                bool isRegular   = (ck & 2) > 0;
                bool isPendulum  = (ck & 64) > 0;
                bool isFreeGauge = (ck & 128) > 0;

                RailTypeEnum railType = isLinear ? RailTypeEnum.LinearMotor : RailTypeEnum.Iron;

                CarGaugeEnum?carGauge =
                    isLinear ? (CarGaugeEnum?)null :
                    isNarrow ? CarGaugeEnum.Narrow :
                    isRegular ? CarGaugeEnum.Regular :
                    isFreeGauge ? CarGaugeEnum.FreeGauge :
                    throw new ArgumentException("軌間が未定義です");

                PowerEnum powerSource =
                    isLinear ? PowerEnum.LinearMotor :
                    isElectric ? PowerEnum.Electricity :
                    isDiesel ? PowerEnum.Diesel :
                    isSteam ? PowerEnum.Steam :
                    throw new ArgumentException("動力源が未指定です");

                return(new DefautltComposition
                {
                    Name = arr[0],
                    BestSpeed = int.Parse(arr[1]),
                    CarCount = int.Parse(arr[3]),
                    HeldUnits = int.Parse(arr[4]),
                    Price = int.Parse(arr[5]),
                    seat = LogicUtil.ConvertSeatModToInternalId(int.Parse(arr[6])),
                    Gauge = carGauge,
                    Power = powerSource,
                    Tilt = isPendulum ? CarTiltEnum.Pendulum : CarTiltEnum.None,
                    Type = railType
                });
            }).ToList();
        }
Beispiel #20
0
        public bool MayHaveJunctionRestrictions(ushort nodeId)
        {
            NetNode.Flags flags = NetNode.Flags.None;
            Services.NetService.ProcessNode(nodeId, delegate(ushort nId, ref NetNode node) {
                flags = node.m_flags;
                return(true);
            });

            if (LogicUtil.CheckFlags((uint)flags, (uint)(NetNode.Flags.Created | NetNode.Flags.Deleted), (uint)NetNode.Flags.Created))
            {
                return(false);
            }

            return(LogicUtil.CheckFlags((uint)flags, (uint)(NetNode.Flags.Junction | NetNode.Flags.Bend)));
        }
Beispiel #21
0
        public bool CheckVehicleFlags(ushort vehicleId,
                                      Vehicle.Flags flagMask,
                                      Vehicle.Flags?expectedResult = default)
        {
            bool ret = false;

            ProcessVehicle(
                vehicleId,
                (ushort vId, ref Vehicle vehicle) => {
                ret = LogicUtil.CheckFlags(
                    (uint)vehicle.m_flags,
                    (uint)flagMask,
                    (uint?)expectedResult);
                return(true);
            });
            return(ret);
        }
 /// <summary>
 /// 添加测试数据
 /// </summary>
 private void AddTestData()
 {
     uint[] roleids = { 11000 };
     npcDataMgr.ClearNpcData();
     for (int i = 0; i < roleids.Length; i++)
     {
         var npcData = npcDataMgr.NewNpcData(roleids[i], NpcType.Hero);
         npcData.position     = currPos;
         npcData.hp           = npcData.hpMax = 100;
         npcData.mp           = LogicUtil.Random(0, 10);
         npcData.mpMax        = 100;
         npcData.attack       = 10;
         npcData.defense      = 10;
         npcData.mpInc        = 10u;
         npcData.skillConsume = 0;
         npcDataMgr.AddNpcData(npcData);
     }
 }
 /// <summary>
 /// 初始化NPC
 /// </summary>
 public void InitNpcTeams(List <string> teamDatas, Action execOK)
 {
     foreach (string teamItem in teamDatas)
     {
         if (LogicConst.BattleType == BattleType.FreeBattle)
         {
             var      items    = teamItem.ToList <uint>('-');
             var      teamid   = items[0];
             var      turnNum  = items[1];
             var      maxNum   = items[2];
             TeamData itemData = configMgr.GetTeamData(teamid);
             if (itemData != null)
             {
                 for (int i = 0; i < turnNum; i++)
                 {
                     TeamData newItem = new TeamData();
                     newItem.id       = itemData.id;
                     newItem.teamNpcs = new List <TeamNpcData>();
                     for (int j = 0; j < maxNum; j++)
                     {
                         int index   = LogicUtil.Random(0, itemData.teamNpcs.Count);
                         var teamNpc = itemData.teamNpcs[index];
                         newItem.teamNpcs.Add(teamNpc);
                     }
                     turnTeams.Enqueue(newItem);
                 }
             }
         }
         else
         {
             uint     teamid = teamItem.ToUint();
             TeamData item   = configMgr.GetTeamData(teamid);
             if (item != null)
             {
                 turnTeams.Enqueue(item);
             }
         }
     }
     if (execOK != null)
     {
         execOK();
     }
 }
Beispiel #24
0
        private void UpdateExpendSize(string desc)
        {
            if (string.IsNullOrEmpty(desc))
            {
                return;
            }
            if (desc.Length < columnMax)
            {
                mTransform.sizeDelta = new Vector2(defaultSize.x, defaultSize.y);
                return;
            }
            int chinaNum  = 0;
            int letterNum = 0;
            int otherNum  = 0;

            for (int i = 0; i < desc.Length; i += 1)
            {
                if (LogicUtil.IsChinaChar(desc.Substring(i, 1)))
                {
                    chinaNum += 1;
                }
                else if (LogicUtil.IsLetterOrNumber(desc.Substring(i, 1)))
                {
                    letterNum += 1;
                }
                else
                {
                    otherNum += 1;
                }
            }
            int count   = chinaNum + letterNum / 2 + otherNum / 2;
            int maxLine = Mathf.CeilToInt(count / (float)columnMax) - 1;

            if (maxLine < 0)
            {
                maxLine = 1;
            }
            float offY = defaultSize.y + maxLine * charLineHeight;

            mTransform.sizeDelta = new Vector2(defaultSize.x, offY);
        }
        async void OnNpcSkillAttackOK(object o)
        {
            var defenderid = (long)o;
            var defender   = npcDataMgr.GetNpcData(defenderid);

            if (defender != null)
            {
                if (defender.hp <= 0)
                {
                    defender.fsm.ChangeState <FDeathState>();
                }
                else
                {
                    var time = LogicUtil.Random(0.5f, 2f);
                    await new WaitForSeconds(time);
                    NpcSkillAttack();
                    return;
                }
            }
            TryResetNextTurn();
        }
Beispiel #26
0
        private void UpdateExpendSize(string desc, bool tag, int images)
        {
            int chinaNum  = 0;
            int letterNum = 0;
            int otherNum  = 0;

            for (int i = 0; i < desc.Length; i += 1)
            {
                if (LogicUtil.IsChinaChar(desc.Substring(i, 1)))
                {
                    chinaNum += 1;
                }
                else if (LogicUtil.IsLetterOrNumber(desc.Substring(i, 1)))
                {
                    letterNum += 1;
                }
                else
                {
                    otherNum += 1;
                }
            }
            int count   = chinaNum + letterNum / 2 + otherNum / 2;
            int maxLine = Mathf.CeilToInt(count / (float)columnMax) - 1;

            if (maxLine < 1)
            {
                maxLine = 1;
            }
            descLabel.rectTransform.sizeDelta = new Vector2(descLabel.rectTransform.sizeDelta.x, maxLine * charLineHeight);
            imageContent.sizeDelta            = new Vector2(imageContent.sizeDelta.x, images * imageHeight);
            float offY = defaultHeight + maxLine * charLineHeight + images * imageHeight;

            if (tag)
            {
                offY += tagHeight;
            }
            mTransform.DOSizeDelta(new Vector2(mTransform.sizeDelta.x, offY), 0.2f).OnUpdate(() => {
                ViewItem.ParentListView.OnItemSizeChanged(viewItem.ItemIndex);
            });
        }
Beispiel #27
0
        async void OnNpcSkillAttackOK(object o)
        {
            var defenderid = (long)o;
            var defender   = npcDataMgr.GetNpcData(defenderid);

            if (defender != null)
            {
                if (defender.hp <= 0)
                {
                    defender.fsm.RemoveAllStates();
                    defender.fsm = null;
                    npcDataMgr.RemoveNpcData(defenderid);
                    battleLogicMgr.NpcDeath(defenderid);
                }
                else
                {
                    var time = LogicUtil.Random(0.5f, 2f);
                    await new WaitForSeconds(time);
                    NpcSkillAttack();
                    return;
                }
            }
            TryResetNextTurn();
        }
Beispiel #28
0
        public bool IsTrafficLightToggleable(ushort nodeId, ref NetNode node, out UnableReason reason)
        {
            if (TrafficLightSimulationManager.Instance.HasTimedSimulation(nodeId))
            {
                reason = UnableReason.HasTimedLight;
#if DEBUGTTL
                if (GlobalConfig.Instance.Debug.Switches[7] && GlobalConfig.Instance.Debug.NodeId == nodeId)
                {
                    Log._Debug($"Cannot toggle traffic lights at node {nodeId}: Node has a timed traffic light");
                }
#endif
                return(false);
            }

            if (!LogicUtil.CheckFlags((uint)node.m_flags, (uint)(NetNode.Flags.Created | NetNode.Flags.Deleted | NetNode.Flags.Junction), (uint)(NetNode.Flags.Created | NetNode.Flags.Junction)))
            {
                reason = UnableReason.NoJunction;
#if DEBUGTTL
                if (GlobalConfig.Instance.Debug.Switches[7] && GlobalConfig.Instance.Debug.NodeId == nodeId)
                {
                    Log._Debug($"Cannot toggle traffic lights at node {nodeId}: Node is not a junction");
                }
#endif
                return(false);
            }

            int numRoads          = 0;
            int numTrainTracks    = 0;
            int numMonorailTracks = 0;
            int numPedSegments    = 0;
            Services.NetService.IterateNodeSegments(nodeId, delegate(ushort segmentId, ref NetSegment segment) {
                NetInfo info = segment.Info;
                if (info.m_class.m_service == ItemClass.Service.Road)
                {
                    ++numRoads;
                }
                else if ((info.m_vehicleTypes & VehicleInfo.VehicleType.Train) != VehicleInfo.VehicleType.None)
                {
                    ++numTrainTracks;
                }
                else if ((info.m_vehicleTypes & VehicleInfo.VehicleType.Monorail) != VehicleInfo.VehicleType.None)
                {
                    ++numMonorailTracks;
                }
                if (info.m_hasPedestrianLanes)
                {
                    ++numPedSegments;
                }

                return(true);
            });

            if (numRoads >= 2 || numTrainTracks >= 2 || numMonorailTracks >= 2 || numPedSegments != 0)
            {
#if DEBUGTTL
                if (GlobalConfig.Instance.Debug.Switches[7] && GlobalConfig.Instance.Debug.NodeId == nodeId)
                {
                    Log._Debug($"Can toggle traffic lights at node {nodeId}: numRoads={numRoads} numTrainTracks={numTrainTracks} numMonorailTracks={numMonorailTracks} numPedSegments={numPedSegments}");
                }
#endif
                reason = UnableReason.None;
                return(true);
            }

#if DEBUGTTL
            if (GlobalConfig.Instance.Debug.Switches[7] && GlobalConfig.Instance.Debug.NodeId == nodeId)
            {
                Log._Debug($"Cannot toggle traffic lights at node {nodeId}: Insufficient segments. numRoads={numRoads} numTrainTracks={numTrainTracks} numMonorailTracks={numMonorailTracks} numPedSegments={numPedSegments}");
            }
#endif
            reason = UnableReason.InsufficientSegments;
            return(false);
        }
Beispiel #29
0
        public bool CanToggleTrafficLight(ushort nodeId,
                                          bool flag,
                                          ref NetNode node,
                                          out ToggleTrafficLightError reason)
        {
#if DEBUG
            bool logTrafficLights = DebugSwitch.TimedTrafficLights.Get() && DebugSettings.NodeId == nodeId;
#else
            const bool logTrafficLights = false;
#endif
            if (!flag && TrafficLightSimulationManager.Instance.HasTimedSimulation(nodeId))
            {
                reason = ToggleTrafficLightError.HasTimedLight;
                if (logTrafficLights)
                {
                    Log._Debug($"Cannot toggle traffic lights at node {nodeId}: Node has a timed traffic light");
                }

                return(false);
            }

            if (flag && !LogicUtil.CheckFlags(
                    (uint)node.m_flags,
                    (uint)(NetNode.Flags.Created | NetNode.Flags.Deleted | NetNode.Flags.Junction),
                    (uint)(NetNode.Flags.Created | NetNode.Flags.Junction)))
            {
                reason = ToggleTrafficLightError.NoJunction;

                if (logTrafficLights)
                {
                    Log._Debug($"Cannot toggle traffic lights at node {nodeId}: Node is not a junction");
                }

                return(false);
            }

            if (!flag && LogicUtil.CheckFlags(
                    (uint)node.m_flags,
                    (uint)NetNode.Flags.LevelCrossing,
                    (uint)NetNode.Flags.LevelCrossing))
            {
                reason = ToggleTrafficLightError.IsLevelCrossing;

                if (logTrafficLights)
                {
                    Log._Debug($"Cannot toggle traffic lights at node {nodeId}: Node is a level crossing");
                }

                return(false);
            }

            int numRoads          = 0;
            int numTrainTracks    = 0;
            int numMonorailTracks = 0;
            int numPedSegments    = 0;
            Services.NetService.IterateNodeSegments(
                nodeId,
                (ushort segmentId, ref NetSegment segment) => {
                NetInfo info = segment.Info;
                if (info.m_class.m_service == ItemClass.Service.Road)
                {
                    ++numRoads;
                }
                else if ((info.m_vehicleTypes & VehicleInfo.VehicleType.Train) !=
                         VehicleInfo.VehicleType.None)
                {
                    ++numTrainTracks;
                }
                else if ((info.m_vehicleTypes & VehicleInfo.VehicleType.Monorail) !=
                         VehicleInfo.VehicleType.None)
                {
                    ++numMonorailTracks;
                }

                if (info.m_hasPedestrianLanes)
                {
                    ++numPedSegments;
                }

                return(true);
            });

            if (numRoads >= 2 || numTrainTracks >= 2 || numMonorailTracks >= 2 || numPedSegments != 0)
            {
                if (logTrafficLights)
                {
                    Log._DebugFormat(
                        "Can toggle traffic lights at node {0}: numRoads={1} numTrainTracks={2} " +
                        "numMonorailTracks={3} numPedSegments={4}",
                        nodeId, numRoads, numTrainTracks, numMonorailTracks, numPedSegments);
                }

                reason = ToggleTrafficLightError.None;
                return(true);
            }

            if (logTrafficLights)
            {
                Log._DebugFormat(
                    "Cannot toggle traffic lights at node {0}: Insufficient segments. numRoads={1} " +
                    "numTrainTracks={2} numMonorailTracks={3} numPedSegments={4}",
                    nodeId, numRoads, numTrainTracks, numMonorailTracks, numPedSegments);
            }

            reason = ToggleTrafficLightError.InsufficientSegments;
            return(false);
        }