using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class RoomSpawner : MonoBehaviour
{
[Header("Prefabs")]
[SerializeField] private GameObject corridorPrefab;
[SerializeField] private GameObject startRoom;
[SerializeField] private List<GameObject> spawnableRooms;
[SerializeField] private List<GameObject> bossRooms;
[Header("Spawn parameters")]
[SerializeField] private int numberOfRooms;
[SerializeField] private Vector2 roomoffset;
[Tooltip("The rooms spawned are being counted. This parameter asks after how many rooms can there be a chance for the boss room to spawn.")]
[SerializeField] private int bossRoomNumber;
//[SerializeField]
//[Tooltip("If adaptative it's true, it will add the offset to room size.If offset it's 0 they will just generate based on their size, this may overlap.")]
private bool adaptative = false;
private GameObject[,] rooms;
private RoomInformation[,] roomsInfos;
private System.Random random;
private void Awake()
{
random = new System.Random();
rooms = new GameObject[numberOfRooms * 2 + 1, numberOfRooms * 2 + 1];
roomsInfos = new RoomInformation[numberOfRooms * 2 + 1, numberOfRooms * 2 + 1];
GameObject currentRoom = Instantiate(startRoom);
Vector2 coords = new Vector2(numberOfRooms, numberOfRooms);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
currentRoom.name = "StartRoom";
RoomInformation ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
roomsInfos[(int)coords.x, (int)coords.y] = ri;
int nor = 0;
float bossRoom = (float)random.NextDouble() * (numberOfRooms - bossRoomNumber);
float bossRoomRegister = bossRoom;
bool spawnedBoss = false;
bool wantsToSpawnBoss = false;
while (true)
{
GameObject toSpawn = spawnableRooms[Random.Range(0, spawnableRooms.Count)];
int o = UnityEngine.Random.Range(1, 4);
if (nor >= numberOfRooms && spawnedBoss) break;
if (nor >= bossRoomNumber && !spawnedBoss)
{
if (bossRoom <= 0)
{
toSpawn = bossRooms[Random.Range(0, bossRooms.Count)];
wantsToSpawnBoss = true;
}
bossRoom--;
}
if (adaptative)
{
switch (o)
{
case 0:
if (rooms[(int)coords.x + 1, (int)coords.y] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x + ri.dimensions.x + roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x + 1, coords.y);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
roomsInfos[(int)coords.x, (int)coords.y] = ri;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
case 1:
if (rooms[(int)coords.x, (int)coords.y + 1] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y + ri.dimensions.y + roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x, coords.y + 1);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
roomsInfos[(int)coords.x, (int)coords.y] = ri;
rooms[(int)coords.x, (int)coords.y] = currentRoom;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
case 2:
if (rooms[(int)coords.x, (int)coords.y - 1] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y - ri.dimensions.y - roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x, coords.y - 1);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
roomsInfos[(int)coords.x, (int)coords.y] = ri;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
case 3:
if (rooms[(int)coords.x - 1, (int)coords.y] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x - ri.dimensions.x - roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x - 1, coords.y);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
roomsInfos[(int)coords.x, (int)coords.y] = ri;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
}
}
else
{
switch (o)
{
case 0:
if (rooms[(int)coords.x + 1, (int)coords.y] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x + roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x + 1, coords.y);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
roomsInfos[(int)coords.x, (int)coords.y] = ri;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
case 1:
if (rooms[(int)coords.x, (int)coords.y + 1] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y + roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x, coords.y + 1);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
roomsInfos[(int)coords.x, (int)coords.y] = ri;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
case 2:
if (rooms[(int)coords.x, (int)coords.y - 1] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x, currentRoom.transform.position.y - roomoffset.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x, coords.y - 1);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
roomsInfos[(int)coords.x, (int)coords.y] = ri;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
case 3:
if (rooms[(int)coords.x - 1, (int)coords.y] == null)
{
currentRoom = Instantiate(toSpawn, new Vector3(currentRoom.transform.position.x - roomoffset.x, currentRoom.transform.position.y, currentRoom.transform.position.z), Quaternion.identity);
coords = new Vector2(coords.x - 1, coords.y);
ri = currentRoom.GetComponent<IRoomCreationHandler>().InstantiateRoom(coords);
rooms[(int)coords.x, (int)coords.y] = currentRoom;
roomsInfos[(int)coords.x, (int)coords.y] = ri;
nor++;
if (wantsToSpawnBoss) spawnedBoss = true;
}
break;
}
}
}
}
public List<string> WhereCanIOpen(Vector2 myCoords)
{
List<string> list = new List<string>();
if (rooms[(int)myCoords.x + 1, (int)myCoords.y] != null)
{
list.Add("wallR");
CreateBridge(myCoords, 0);
}
if (rooms[(int)myCoords.x - 1, (int)myCoords.y] != null)
{
list.Add("wallL");
CreateBridge(myCoords, 1);
}
if (rooms[(int)myCoords.x, (int)myCoords.y + 1] != null)
{
list.Add("roof");
CreateBridge(myCoords, 2);
}
if (rooms[(int)myCoords.x, (int)myCoords.y - 1] != null)
{
list.Add("floor");
CreateBridge(myCoords, 3);
}
return list;
}
public void CreateBridge(Vector2 coords, int dir)
{
GameObject[] exi = new GameObject[2];
switch (dir)
{
case 0:
exi = GetExits(coords, coords + new Vector2(1, 0), "wallR", "wallL");
if (exi[0] == null || exi[1] == null) break;
if (exi[0].transform.position.y >= exi[1].transform.position.y)
{
SpawnHorizontalCorridor(exi[0], exi[1]);
}
else
{
SpawnHorizontalCorridor(exi[1], exi[0]);
}
break;
case 1:
exi = GetExits(coords, coords + new Vector2(-1, 0), "wallL", "wallR");
if (exi[0] == null || exi[1] == null) break;
if (exi[0].transform.position.y >= exi[1].transform.position.y)
{
SpawnHorizontalCorridor(exi[0], exi[1]);
}
else
{
SpawnHorizontalCorridor(exi[1], exi[0]);
}
break;
case 2:
exi = GetExits(coords, coords + new Vector2(0, 1), "roof", "floor");
if (exi[0] == null || exi[1] == null) break;
if (exi[0].transform.position.x >= exi[1].transform.position.x)
{
SpawnVerticalCorridor(exi[1], exi[0]);
}
else
{
SpawnVerticalCorridor(exi[0], exi[1]);
}
break;
case 3:
exi = GetExits(coords, coords + new Vector2(0, -1), "floor", "roof");
if (exi[0] == null || exi[1] == null) break;
if (exi[0].transform.position.x >= exi[1].transform.position.x)
{
SpawnVerticalCorridor(exi[1], exi[0]);
}
else
{
SpawnVerticalCorridor(exi[0], exi[1]);
}
break;
}
}
void SpawnHorizontalCorridor(GameObject upper, GameObject bottom)
{
//Upper part spawn
Vector3 c = new Vector3((upper.transform.position.x + bottom.transform.position.x) / 2 + upper.transform.localScale.x / 2,
upper.transform.position.y + upper.transform.localScale.y / 2 + corridorPrefab.transform.localScale.y / 2, upper.transform.position.z);
GameObject t = Instantiate(corridorPrefab, c, Quaternion.identity);
t.transform.localScale = new Vector3(Mathf.Abs(upper.transform.position.x - bottom.transform.position.x), 1, 1);
//Bottom spawn
c = new Vector3((upper.transform.position.x + bottom.transform.position.x) / 2 + upper.transform.localScale.x / 2,
bottom.transform.position.y - bottom.transform.localScale.y / 2 - corridorPrefab.transform.localScale.y / 2, bottom.transform.position.z);
t = Instantiate(corridorPrefab, c, Quaternion.identity);
t.transform.localScale = new Vector3(Mathf.Abs(upper.transform.position.x - bottom.transform.position.x), 1, 1);
}
void SpawnVerticalCorridor(GameObject left, GameObject right)
{
//Left spawn
Vector3 c = new Vector3(left.transform.position.x - left.transform.localScale.x/2 - corridorPrefab.transform.localScale.x/2,
(left.transform.position.y + right.transform.position.y)/2, left.transform.position.z);
GameObject t = Instantiate(corridorPrefab, c, Quaternion.identity);
t.transform.localScale = new Vector3(1, Mathf.Abs(left.transform.position.y - right.transform.position.y), 1);
t.name = "Left";
//Right spawn
c = new Vector3(right.transform.position.x + right.transform.localScale.x / 2 + corridorPrefab.transform.localScale.x / 2,
(left.transform.position.y + right.transform.position.y) / 2, right.transform.position.z);
t = Instantiate(corridorPrefab, c, Quaternion.identity);
t.transform.localScale = new Vector3(1, Mathf.Abs(left.transform.position.y - right.transform.position.y), 1);
t.name = "Right";
}
GameObject[] GetExits(Vector2 coords1, Vector2 coords2, string f, string s)
{
GameObject[] ret = new GameObject[2];
foreach (ExitScript g in roomsInfos[(int)coords1.x, (int)coords1.y].exits)
{
if (g != null)
{
if (g.transform.parent.name == f)
{
ret[0] = g.gameObject;
}
}
}
foreach (ExitScript g in roomsInfos[(int)coords2.x, (int)coords2.y].exits)
{
if (g != null)
{
if (g.transform.parent.name == s)
{
ret[1] = g.gameObject;
}
}
}
return ret;
}
}