IEnumerator NextTurnWithDelay(int oldTurn) { bool ready; /* 페이즈 1: 일반 피격 애니메이션 재생 */ if (oldTurn == 0) { // 플레이어의 턴이 끝남 foreach (Character e in enemies) { e.DamagedAnimation(); } } else if (oldTurn == 1) { // 적들의 턴이 끝남 player.DamagedAnimation(); } while (true) { ready = true; foreach (Character e in enemies) { if (e.Alive && e.Mover.IsMoving) { ready = false; break; } } if (player.Alive && player.Mover.IsMoving) { ready = false; } if (ready) { break; } else { yield return(null); } } /* 페이즈 2: 무기 특수 효과(흡수) 대미지 애니메이션 처리 */ if (oldTurn == 0) { // 흡수 효과의 회복 처리 if (player.EquippedWeapon.drainedPercent > 0f && player.attackSum > 0) { player.Drained(); } player.attackSum = 0; } else if (oldTurn == 1) { // 적들의 턴이 끝남 foreach (Character e in enemies) { // 흡수 효과의 회복 처리 if (e.EquippedWeapon.drainedPercent > 0f && e.attackSum > 0) { e.Drained(); } e.attackSum = 0; } } while (true) { ready = true; foreach (Character e in enemies) { if (e.Alive && e.Mover.IsMoving) { ready = false; break; } } if (player.Alive && player.Mover.IsMoving) { ready = false; } if (ready) { break; } else { yield return(null); } } /* 페이즈 3: 무기 특수 효과(중독, 돌풍) 대미지 애니메이션 처리 */ if (oldTurn == 0) { // 플레이어의 턴이 끝남 foreach (Character e in enemies) { // 돌풍 효과의 대미지 처리 if (e.gustDamage > 0) { e.Gusted(); } } // 중독 효과의 대미지 처리 if (player.poisonDamage > 0) { player.Poisoned(); } } else if (oldTurn == 1) { // 적들의 턴이 끝남 foreach (Character e in enemies) { // 중독 효과의 대미지 처리 if (e.poisonDamage > 0) { e.Poisoned(); } } } while (true) { ready = true; foreach (Character e in enemies) { if (e.Alive && e.Mover.IsMoving) { ready = false; break; } } if (player.Alive && player.Mover.IsMoving) { ready = false; } if (ready) { break; } else { yield return(null); } } /* 페이즈 4: 방어구 특수 효과(반사, 재생) 대미지 애니메이션 처리 */ if (oldTurn == 0) { foreach (Character e in enemies) { e.armor.InvokeArmorEffects(e); // 턴을 넘길 때의 각 적의 현재 체력을 기억 e.oldHealth = e.currentHealth; } player.Reflected(); foreach (Character e in enemies) { e.Regenerated(); } // 턴을 넘길 때의 플레이어의 현재 체력을 기억 player.oldHealth = player.currentHealth; player.trueOldHealth = player.currentHealth; } else if (oldTurn == 1) { player.armor.InvokeArmorEffects(player); foreach (Character e in enemies) { e.Reflected(); // 턴을 넘길 때의 각 적의 현재 체력을 기억 e.oldHealth = e.currentHealth; e.trueOldHealth = e.currentHealth; } player.Regenerated(); player.oldHealth = player.currentHealth; } while (true) { ready = true; foreach (Character e in enemies) { if (e.Alive && e.Mover.IsMoving) { ready = false; break; } } if (player.Alive && player.Mover.IsMoving) { ready = false; } if (ready) { break; } else { yield return(null); } } /* 페이즈 5: 제한 턴 초과에 의한 대미지 애니메이션 처리 */ if (oldTurn == 0) { if (RemainedTurn == 0) { player.Damaged(player.MaxHealth, new Vector3(0f, 0f, 0f), true); player.DamagedAnimation(); // 턴을 넘길 때의 플레이어의 현재 체력을 기억 player.oldHealth = player.currentHealth; player.trueOldHealth = player.currentHealth; } } else if (oldTurn == 1) { } while (true) { ready = true; if (player.Alive && player.Mover.IsMoving) { ready = false; } if (ready) { break; } else { yield return(null); } } // 사망 여부 확인 player.DeathCheck(); foreach (Character e in enemies) { e.DeathCheck(); } /* 페이즈 6: 탈바꿈 애니메이션 처리 */ if (oldTurn == 0) { } else if (oldTurn == 1) { foreach (Character e in enemies) { e.armor.InvokeActiveArmorEffects(e); // 턴을 넘길 때의 각 적의 현재 체력을 기억 e.oldHealth = e.currentHealth; e.trueOldHealth = e.currentHealth; } player.oldHealth = player.currentHealth; } while (true) { ready = true; foreach (Character e in enemies) { if (e.Alive && e.Mover.IsMoving) { ready = false; break; } } if (player.Alive && player.Mover.IsMoving) { ready = false; } if (ready) { break; } else { yield return(null); } } monsterNumberText.text = MonsterNumber.ToString(); if (MonsterNumber == 0) { monsterNumberText.color = ColorManager.cm.monsterNumberColors[0]; if (!monsterEliminated) { monsterEliminated = true; Canvas.GetComponent <UIInfo>().notiPanel.GetComponent <NotiUI>().SetNotiText("All monsters were eliminated."); } } else { monsterNumberText.color = ColorManager.cm.monsterNumberColors[1]; } turn = (oldTurn + 1) % 2; if (turn == 1) { TurnNumber++; } }
public void StartThreadingScan() { MonsterInfoScanRef = new ThreadStart(ScanMonsterInfo); MonsterInfoScan = new Thread(MonsterInfoScanRef) { Name = $"Scanner_Monster.{MonsterNumber}" }; Debugger.Warn(GStrings.GetLocalizationByXPath("/Console/String[@ID='MESSAGE_MONSTER_SCANNER_INITIALIZED']").Replace("{MonsterNumber}", MonsterNumber.ToString())); MonsterInfoScan.Start(); }
private void Initialize(string mapName = null) { MapEntityInfo mei = null; GameObject g = GameObject.Find("MapEntityInfo"); if (g != null) { mei = g.GetComponent <MapEntityInfo>(); if (mei != null) { map = mei.map; enemies = mei.enemies; interactables = mei.interactables; } } bool mapAutoGeneration = false; if (mapName != null) { map.mapName = mapName; mapAutoGeneration = true; MapInfo mi = MapManager.mm.FindMapInfo(mapName, mapLevel); map.GetComponent <AudioSource>().clip = Resources.Load("Audios/" + StringManager.ToPascalCase(mi.backgroundMusic), typeof(AudioClip)) as AudioClip; map.GetComponent <AudioSource>().Play(); monsterNumberMark.SetActive(true); monsterNumberText.gameObject.SetActive(true); turnLimit = mi.turnLimit; turnNumber = 0; if (turnLimit >= 0) { Canvas.GetComponent <UIInfo>().turnLimitMark.SetActive(true); Canvas.GetComponent <UIInfo>().turnLimitText.gameObject.SetActive(true); Canvas.GetComponent <UIInfo>().turnLimitText.text = RemainedTurn.ToString(); int ind = Canvas.GetComponent <UIInfo>().turnLimitSprites.Count - 1; if (turnLimit == 0) { ind = 0; } Canvas.GetComponent <UIInfo>().turnLimitMark.GetComponent <Image>().sprite = Canvas.GetComponent <UIInfo>().turnLimitSprites[ind]; Canvas.GetComponent <UIInfo>().turnLimitMark.GetComponent <Image>().color = Canvas.GetComponent <UIInfo>().turnLimitColors[ind]; Canvas.GetComponent <UIInfo>().turnLimitText.color = Canvas.GetComponent <UIInfo>().turnLimitColors[ind]; } else { Canvas.GetComponent <UIInfo>().turnLimitMark.SetActive(false); Canvas.GetComponent <UIInfo>().turnLimitText.gameObject.SetActive(false); } } else { monsterNumberMark.SetActive(false); monsterNumberText.gameObject.SetActive(false); turnNumber = 0; turnLimit = -1; Canvas.GetComponent <UIInfo>().turnLimitMark.SetActive(false); Canvas.GetComponent <UIInfo>().turnLimitText.gameObject.SetActive(false); } hasShopVisited = false; StringManager.sm.RefreshTexts(); map.Initialize(mapAutoGeneration); AvailableTile availableTile = new AvailableTile(map.MapSize, map.BottomLeft); // 맵의 각 타일 위에 새 개체를 놓을 수 있는지 확인 for (int i = (int)map.BottomLeft.x; i <= (int)map.TopRight.x; i++) { for (int j = (int)map.BottomLeft.y; j <= (int)map.TopRight.y; j++) { // 밟을 수 없는 타일 확인 if (map.GetTypeOfTile(i, j) != 0) { availableTile.Set(i, j); } } } // 플레이어 시작 위치 지정 int randomQuadrant = Random.Range(1, 5); Vector2Int v = map.GetACornerPosition(randomQuadrant); if (!mapAutoGeneration && SceneManager.GetActiveScene().name.Equals("Tutorial")) { player.GetComponent <Transform>().position = new Vector3(0f, 0f, -1f); map.AddItemOnTile(100, new Vector3(21f, 1f, -1f)); map.AddItemOnTile(101, new Vector3(21f, 0f, -1f)); map.AddItemOnTile(102, new Vector3(20f, 0f, -1f)); map.AddItemOnTile(103, new Vector3(20f, 1f, -1f)); } else if (!mapAutoGeneration && SceneManager.GetActiveScene().name.Equals("Town")) { player.GetComponent <Transform>().position = new Vector3(2f, 2f, -1f); if (isTutorialSkipped) { map.AddItemOnTile(100, new Vector3(2f, 1f, -1f)); map.AddItemOnTile(101, new Vector3(2f, 3f, -1f)); map.AddItemOnTile(102, new Vector3(1f, 2f, -1f)); map.AddItemOnTile(103, new Vector3(3f, 2f, -1f)); isTutorialSkipped = false; } } else { player.GetComponent <Transform>().position = new Vector3(v.x, v.y, player.GetComponent <Transform>().position.z); } map.SetEntityOnTile(player, player.GetComponent <Transform>().position); availableTile.Set(v.x, v.y); #region MapEntityInfo에 따라 씬에 미리 배치되어 있는 개체 등록 foreach (Interactable i in mei.interactables) { map.SetEntityOnTile(i, i.GetComponent <Transform>().position); availableTile.Set(i.GetComponent <Transform>().position); } // TODO 시작 시에 존재하는 모든 적의 충돌 판정 크기가 타일 1개 크기라고 가정 // 또한, 다른 개체와 같은 타일에 겹쳐 있는 상태로 시작하는 적이 없다고 가정 // 그리고 맵의 범위를 벗어난 위치에 있거나 벗어난 위치를 순찰 체크포인트로 갖는 적이 없다고 가정 foreach (Character c in mei.enemies) { map.SetEntityOnTile(c, c.GetComponent <Transform>().position); c.statusUI = UIObject.GetComponent <UIInfo>().enemyStatusUI; availableTile.Set(c.GetComponent <Transform>().position); foreach (Vector3 cp in ((EnemyMover)c.Mover).checkpoints) { availableTile.Set(cp); } } #endregion #region 맵 정보(MapInfo)에 따라 개체 생성 후 등록 if (mapName != null) { MapInfo mi = MapManager.mm.FindMapInfo(mapName, mapLevel); if (mi != null) { foreach (int id in mi.interactablesID) { Interactable i = GetComponent <InteractableManager>().GetInteractable(id); if (i != null) { int quadrant = 0; int maxLoop = 100; bool canCreate = true; for (int j = 0; j < maxLoop; j++) { if (id == 0) { for (int k = 0; k < maxLoop; k++) { quadrant = Random.Range(1, 5); if (quadrant != randomQuadrant) { break; } if (k == maxLoop - 1) { Debug.LogWarning("Exceed max loop limit!"); } } //v = map.GetACornerPosition((randomQuadrant + 2) % 4); v = map.GetACornerPosition(quadrant); if (map.GetEntityOnTile(v.x, v.y) == null && map.GetTypeOfTile(v.x, v.y) == 0) { break; } } else { v = new Vector2Int(Random.Range(Mathf.RoundToInt(map.BottomLeft.x), Mathf.RoundToInt(map.TopRight.x)), Random.Range(Mathf.RoundToInt(map.BottomLeft.y), Mathf.RoundToInt(map.TopRight.y))); if (map.GetEntityOnTile(v.x, v.y) == null && map.GetTypeOfTile(v.x, v.y) == 0) { break; } } if (j == maxLoop - 1) { Debug.LogWarning("Exceed max loop limit!"); canCreate = false; } } if (!canCreate) { continue; } // TODO 생성 위치 바꾸기 g = Instantiate(i.gameObject, new Vector3(v.x, v.y, -1f), Quaternion.identity); interactables.Add(g.GetComponent <Interactable>()); map.SetEntityOnTile(g.GetComponent <Interactable>(), g.GetComponent <Transform>().position); availableTile.Set(v.x, v.y); } } // TODO 맵 정보에 의해 생성되는 모든 적의 충돌 판정 크기가 타일 1개 크기라고 가정 // 또한, 다른 개체와 같은 타일에 겹쳐 있는 상태로 시작하는 적이 없다고 가정 foreach (int id in mi.enemiesID) { EnemyInfo ei = EnemyManager.em.FindEnemyInfo(id); if (ei != null) { // 생성 위치 정하기 int x = 0, y = 0, x2 = 0, y2 = 0, maxLoop = 100; bool canCreate = true; for (int j = 0; j < maxLoop; j++) { // 우선 가능한 위치 중에서 랜덤으로 생성하고, 후에 스폰 가능한 위치인지 확인 x = Random.Range(Mathf.RoundToInt(map.BottomLeft.x), Mathf.RoundToInt(map.TopRight.x)); y = Random.Range(Mathf.RoundToInt(map.BottomLeft.y), Mathf.RoundToInt(map.TopRight.y)); if (map.GetEntityOnTile(x, y) == null && map.GetTypeOfTile(x, y) == 0 && availableTile.Get(x, y) && VectorUtility.ChebyshevDistance(new Vector3(x, y, 0f), player.GetComponent <Transform>().position) > 3) { bool b = true; foreach (Interactable i in interactables) { if (VectorUtility.ChebyshevDistance(new Vector3(x, y, 0f), i.GetComponent <Transform>().position) <= 2) { b = false; break; } } if (b) { // 순찰 경로 지정 if (ei.type == EnemyInfo.Type.Normal || (mapLevel >= 64 && ei.type == EnemyInfo.Type.Elite)) { int distance = 4; bool b2 = true; for (int k = 0; k < maxLoop; k++) { // 자신 근처의 위치 중에서, 순찰 경로 안에 스폰 불가능 위치가 하나도 존재하지 않은 위치로 결정 // 순찰 경로의 체크포인트가 하나만 존재함을 가정 x2 = Random.Range(Mathf.Clamp(x - distance, 0, map.MapSize.x - 1), Mathf.Clamp(x + distance, 0, map.MapSize.x - 1)); y2 = Random.Range(Mathf.Clamp(y - distance, 0, map.MapSize.y - 1), Mathf.Clamp(y + distance, 0, map.MapSize.y - 1)); if (map.GetEntityOnTile(x2, y2) == null && map.GetTypeOfTile(x2, y2) == 0 && !(x2 == x && y2 == y)) { bool b3 = true; for (int l = Mathf.Min(x, x2); l <= Mathf.Max(x, x2); l++) { if (!availableTile.Get(l, Mathf.Min(y, y2)) || !availableTile.Get(l, Mathf.Max(y, y2))) { b3 = false; break; } } for (int l = Mathf.Min(y, y2); l <= Mathf.Max(y, y2); l++) { if (!availableTile.Get(Mathf.Min(x, x2), l) || !availableTile.Get(Mathf.Max(x, x2), l)) { b3 = false; break; } } if (b3) { break; } } if (k == maxLoop - 1) { //Debug.LogWarning("Exceed max loop limit!"); b2 = false; } } if (b2) { break; } } else { break; } } } if (j == maxLoop - 1) { Debug.LogWarning("Exceed max loop limit!"); canCreate = false; } } if (!canCreate) { continue; } g = Instantiate(EnemyManager.em.monsterPrefab, new Vector3(x, y, -1f), Quaternion.identity); Character c = g.GetComponent <Character>(); c.name = ei.name; c.level = mapLevel; //Debug.Log("GM creates an enemy. (call first)"); enemies.Add(c); map.SetEntityOnTile(c, g.GetComponent <Transform>().position); c.statusUI = UIObject.GetComponent <UIInfo>().enemyStatusUI; availableTile.Set(x, y); c.GetComponent <EnemyMover>().checkpoints = new List <Vector3>(); if (ei.type == EnemyInfo.Type.Normal || (mapLevel >= 64 && ei.type == EnemyInfo.Type.Elite)) { c.GetComponent <EnemyMover>().checkpoints.Add(new Vector3(x2, y2, -1f)); availableTile.Set(x2, y2); for (int l = Mathf.Min(x, x2); l <= Mathf.Max(x, x2); l++) { availableTile.Set(l, y); availableTile.Set(l, y2); } for (int l = Mathf.Min(y, y2); l <= Mathf.Max(y, y2); l++) { availableTile.Set(x, l); availableTile.Set(x2, l); } } } } } } #endregion monsterNumberText.text = MonsterNumber.ToString(); if (MonsterNumber == 0) { monsterNumberText.color = ColorManager.cm.monsterNumberColors[0]; } else { monsterNumberText.color = ColorManager.cm.monsterNumberColors[1]; } if (mapAutoGeneration) { monsterEliminated = false; } else { monsterEliminated = true; } }