934 lines
51 KiB
C#
934 lines
51 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.AI;
|
|
using Unity.AI.Navigation;
|
|
|
|
public static class LaboratoryLevelGenerator
|
|
{
|
|
private const float WALL_HEIGHT = 4.5f;
|
|
private const float WALL_THICKNESS = 0.35f;
|
|
|
|
// Outer Perimeter: 100m x 100m (-50 to +50 in X and Z)
|
|
private const float MIN_COORD = -50f;
|
|
private const float MAX_COORD = 50f;
|
|
|
|
[MenuItem("Tools/Generate Full Laboratory Location")]
|
|
public static void Generate()
|
|
{
|
|
Debug.Log("<color=cyan>=== GENERATING EXPANDED COMPLEX LABORATORY LOCATION (100x100m) ===</color>");
|
|
|
|
// 1. Remove previous Laboratory_Complex or old maze if present
|
|
var oldLab = GameObject.Find("Laboratory_Complex");
|
|
if (oldLab != null)
|
|
{
|
|
Undo.DestroyObjectImmediate(oldLab);
|
|
}
|
|
|
|
var oldMaze = GameObject.Find("Maze");
|
|
if (oldMaze != null)
|
|
{
|
|
oldMaze.SetActive(false);
|
|
}
|
|
|
|
// Disable or cleanup old planes
|
|
for (int i = 0; i <= 6; i++)
|
|
{
|
|
string pName = i == 0 ? "Plane" : $"Plane ({i})";
|
|
var pl = GameObject.Find(pName);
|
|
if (pl != null)
|
|
{
|
|
pl.SetActive(false);
|
|
}
|
|
}
|
|
|
|
// Load assets and materials
|
|
Material echoMat = AssetDatabase.LoadAssetAtPath<Material>("Assets/EchoCloudMat.mat");
|
|
if (echoMat == null)
|
|
{
|
|
echoMat = AssetDatabase.LoadAssetAtPath<Material>("Assets/EchoMat.mat");
|
|
}
|
|
|
|
GameObject tablePrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/table with drawers.prefab");
|
|
GameObject shelfShowcasePrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/shelf showcase.prefab");
|
|
GameObject shelf2Prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/shelf (2).prefab");
|
|
GameObject rackPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/rack.prefab");
|
|
GameObject chairPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/chair.prefab");
|
|
GameObject pillarPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/pillar.prefab");
|
|
GameObject boxPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/Box.prefab");
|
|
GameObject beakerPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/Beaker.prefab");
|
|
GameObject flaskPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/Erlenmeyer_flask.prefab");
|
|
GameObject testTubePrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/Glass_Lab_test_tube.prefab");
|
|
GameObject instPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/analytical_lab_instruments.prefab");
|
|
GameObject tapPrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/3D Laboratory Environment with Appratus/Prefabs/tap.prefab");
|
|
|
|
// Root object
|
|
GameObject labRoot = new GameObject("Laboratory_Complex");
|
|
Undo.RegisterCreatedObjectUndo(labRoot, "Create Laboratory_Complex");
|
|
|
|
GameObject floorsParent = new GameObject("Floors");
|
|
floorsParent.transform.SetParent(labRoot.transform);
|
|
|
|
GameObject wallsParent = new GameObject("Walls");
|
|
wallsParent.transform.SetParent(labRoot.transform);
|
|
|
|
GameObject roomsParent = new GameObject("Rooms_Props");
|
|
roomsParent.transform.SetParent(labRoot.transform);
|
|
|
|
GameObject lightsParent = new GameObject("Atmospheric_Lighting");
|
|
lightsParent.transform.SetParent(labRoot.transform);
|
|
|
|
GameObject pickupsParent = new GameObject("Throwable_Distractions");
|
|
pickupsParent.transform.SetParent(labRoot.transform);
|
|
|
|
// 2. Build Floor Grid (100m x 100m, from -50 to +50 in X and Z)
|
|
CreateFloorGrid(floorsParent.transform, echoMat, MIN_COORD, MAX_COORD, MIN_COORD, MAX_COORD);
|
|
|
|
// 3. Build Perimeter Exterior Walls (100m perimeter)
|
|
CreateWall(wallsParent.transform, echoMat, new Vector3(0, WALL_HEIGHT / 2f, MIN_COORD), new Vector3(100f, WALL_HEIGHT, WALL_THICKNESS), "Wall_Perimeter_South");
|
|
CreateWall(wallsParent.transform, echoMat, new Vector3(0, WALL_HEIGHT / 2f, MAX_COORD), new Vector3(100f, WALL_HEIGHT, WALL_THICKNESS), "Wall_Perimeter_North");
|
|
CreateWall(wallsParent.transform, echoMat, new Vector3(MIN_COORD, WALL_HEIGHT / 2f, 0), new Vector3(WALL_THICKNESS, WALL_HEIGHT, 100f), "Wall_Perimeter_West");
|
|
CreateWall(wallsParent.transform, echoMat, new Vector3(MAX_COORD, WALL_HEIGHT / 2f, 0), new Vector3(WALL_THICKNESS, WALL_HEIGHT, 100f), "Wall_Perimeter_East");
|
|
|
|
// 4. Build Major Facility Wings & Rooms:
|
|
|
|
// --- SECTOR A: Entrance & Decontamination Airlock (X: -8 to 8, Z: -50 to -38) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, -8f, 8f, -50f, -38f,
|
|
southDoor: null,
|
|
northDoor: new Vector2(-2.2f, 2.2f), // Main airlock door to South Concourse
|
|
westDoor: null,
|
|
eastDoor: null,
|
|
roomName: "Decontamination_Airlock");
|
|
|
|
// --- SECTOR B: Cryogenics & Specimen Archive (Southwest, X: -48 to -26, Z: -48 to -26) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, -48f, -26f, -48f, -26f,
|
|
southDoor: null,
|
|
northDoor: new Vector2(-39f, -35f), // to West Mid Lab
|
|
westDoor: null,
|
|
eastDoor: new Vector2(-39f, -35f), // to South Concourse
|
|
roomName: "Cryogenics_Vault");
|
|
|
|
// --- SECTOR C: High-Security Armory & CCTV (Southeast, X: 26 to 48, Z: -48 to -26) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, 26f, 48f, -48f, -26f,
|
|
southDoor: null,
|
|
northDoor: new Vector2(35f, 39f), // to East Mid Medical
|
|
westDoor: new Vector2(-39f, -35f), // to South Concourse
|
|
eastDoor: null,
|
|
roomName: "Security_Armory");
|
|
|
|
// --- SECTOR D: Biochemistry Research Wing (West Mid, X: -48 to -24, Z: -22 to 2) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, -48f, -24f, -22f, 2f,
|
|
southDoor: new Vector2(-39f, -35f), // to Cryo corridor
|
|
northDoor: new Vector2(-39f, -35f), // to Quarantine Wing
|
|
westDoor: null,
|
|
eastDoor: new Vector2(-12f, -8f), // to Maintenance Pipe Slalom
|
|
roomName: "Biochem_Research");
|
|
|
|
// --- SECTOR E: Surgical Theatre & ICU (East Mid, X: 24 to 48, Z: -22 to 2) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, 24f, 48f, -22f, 2f,
|
|
southDoor: new Vector2(35f, 39f), // to Armory corridor
|
|
northDoor: new Vector2(35f, 39f), // to Genetics Lab
|
|
westDoor: new Vector2(-12f, -8f), // to East Slalom corridor
|
|
eastDoor: null,
|
|
roomName: "Surgical_ICU");
|
|
|
|
// --- SECTOR F: Quarantine Cellblock & Solitary Isolation (TIGHT / LABYRINTH, X: -48 to -22, Z: 6 to 26) ---
|
|
// Narrow cramped corridors with individual solitary confinement cells
|
|
BuildRoomWalls(wallsParent.transform, echoMat, -48f, -22f, 6f, 26f,
|
|
southDoor: new Vector2(-39f, -35f), // from Biochem
|
|
northDoor: new Vector2(-39f, -35f), // to Chemical Silo
|
|
westDoor: null,
|
|
eastDoor: new Vector2(14f, 18f), // to Grand Atrium West Entrance
|
|
roomName: "Quarantine_Wing");
|
|
|
|
// --- SECTOR G: Genetics & Cybernetics Laboratory (East North, X: 22 to 48, Z: 6 to 26) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, 22f, 48f, 6f, 26f,
|
|
southDoor: new Vector2(35f, 39f), // from Surgical
|
|
northDoor: new Vector2(35f, 39f), // to Substation
|
|
westDoor: new Vector2(14f, 18f), // to Grand Atrium East Entrance
|
|
eastDoor: null,
|
|
roomName: "Genetics_Cybernetics");
|
|
|
|
// --- SECTOR H: Chemical Silos & Toxic Waste (Northwest, X: -48 to -26, Z: 28 to 48) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, -48f, -26f, 28f, 48f,
|
|
southDoor: new Vector2(-39f, -35f), // from Quarantine
|
|
northDoor: new Vector2(-39f, -35f), // to North Maintenance Conduit
|
|
westDoor: null,
|
|
eastDoor: new Vector2(36f, 40f), // to Reactor Hall
|
|
roomName: "Chemical_Silos");
|
|
|
|
// --- SECTOR I: Auxiliary Power Substation & Battery Banks (Northeast, X: 26 to 48, Z: 28 to 48) ---
|
|
BuildRoomWalls(wallsParent.transform, echoMat, 26f, 48f, 28f, 48f,
|
|
southDoor: new Vector2(35f, 39f), // from Genetics
|
|
northDoor: new Vector2(35f, 39f), // to North Maintenance Conduit
|
|
westDoor: new Vector2(36f, 40f), // to Reactor Hall
|
|
eastDoor: null,
|
|
roomName: "Power_Substation");
|
|
|
|
// --- SECTOR J: GRAND CENTRAL ATRIUM & BIO-DOME (VERY SPACIOUS! X: -18 to 18, Z: -6 to 24) ---
|
|
// Huge 36m x 30m open amphitheatre / bio-dome
|
|
BuildRoomWalls(wallsParent.transform, echoMat, -18f, 18f, -6f, 24f,
|
|
southDoor: new Vector2(-4f, 4f), // Grand 8m South Portal to Concourse
|
|
northDoor: new Vector2(-4f, 4f), // Grand 8m North Portal to Reactor Core
|
|
westDoor: new Vector2(7f, 11f), // West Portal to Maintenance/Quarantine
|
|
eastDoor: new Vector2(7f, 11f), // East Portal to Medical/Genetics
|
|
roomName: "Grand_Atrium");
|
|
|
|
// --- SECTOR K: SUB-REACTOR & TURBINE POWER PLANT (VERY SPACIOUS! X: -22 to 22, Z: 28 to 48) ---
|
|
// Huge 44m x 20m industrial turbine hall
|
|
BuildRoomWalls(wallsParent.transform, echoMat, -22f, 22f, 28f, 48f,
|
|
southDoor: new Vector2(-4f, 4f), // Direct entrance from Atrium
|
|
northDoor: new Vector2(-2.5f, 2.5f),// Service door to North Maintenance Conduit
|
|
westDoor: new Vector2(36f, 40f), // to Chemical Silos
|
|
eastDoor: new Vector2(36f, 40f), // to Power Substation
|
|
roomName: "Reactor_Turbine_Hall");
|
|
|
|
// 5. Build Complex Corridors, Tight Crawlways, and Slalom Alley
|
|
BuildComplexCorridors(wallsParent.transform, echoMat);
|
|
|
|
// 6. Build Quarantine Cellblock Interior (Cramped cells with narrow 1.3m doors)
|
|
BuildQuarantineCells(wallsParent.transform, echoMat);
|
|
|
|
// 7. Populate Rooms & Halls with Furniture, Machinery, Obstacles and Distractions
|
|
PopulateAirlock(roomsParent.transform, pillarPrefab, rackPrefab, chairPrefab);
|
|
PopulateGrandAtrium(roomsParent.transform, pillarPrefab, tablePrefab, instPrefab, boxPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateReactorHall(roomsParent.transform, pillarPrefab, boxPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateSouthConcourse(roomsParent.transform, pillarPrefab, chairPrefab, boxPrefab, pickupsParent.transform);
|
|
PopulateBiochem(roomsParent.transform, tablePrefab, shelfShowcasePrefab, shelf2Prefab, tapPrefab, instPrefab, beakerPrefab, flaskPrefab, testTubePrefab, pickupsParent.transform);
|
|
PopulateSurgical(roomsParent.transform, tablePrefab, shelfShowcasePrefab, chairPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateQuarantineProps(roomsParent.transform, boxPrefab, rackPrefab, chairPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateGenetics(roomsParent.transform, tablePrefab, shelfShowcasePrefab, instPrefab, chairPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateCryo(roomsParent.transform, rackPrefab, shelf2Prefab, boxPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateArmory(roomsParent.transform, rackPrefab, tablePrefab, instPrefab, boxPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateChemicalSilos(roomsParent.transform, pillarPrefab, boxPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateSubstation(roomsParent.transform, pillarPrefab, boxPrefab, beakerPrefab, pickupsParent.transform);
|
|
PopulateSlalomAlleyProps(roomsParent.transform, boxPrefab, rackPrefab);
|
|
|
|
// 8. Atmospheric Lighting setup across all sectors
|
|
CreateLighting(lightsParent.transform);
|
|
|
|
// 9. Reconfigure Player Position in Starting Airlock
|
|
GameObject player = GameObject.Find("Player");
|
|
if (player == null) player = GameObject.FindWithTag("Player");
|
|
if (player == null) player = Object.FindAnyObjectByType<PlayerHealth>()?.gameObject;
|
|
if (player == null) player = GameObject.Find("Capsule");
|
|
|
|
if (player != null)
|
|
{
|
|
var cc = player.GetComponent<CharacterController>();
|
|
if (cc != null) cc.enabled = false;
|
|
player.transform.position = new Vector3(0f, 1.05f, -44f);
|
|
player.transform.rotation = Quaternion.Euler(0f, 0f, 0f);
|
|
if (cc != null) cc.enabled = true;
|
|
Debug.Log("<color=green>Positioned Player in Starting Airlock (0, 1.05, -44).</color>");
|
|
|
|
var cam = Camera.main;
|
|
if (cam != null)
|
|
{
|
|
cam.transform.position = new Vector3(0f, 2.5f, -48f);
|
|
cam.transform.rotation = Quaternion.Euler(12f, 0f, 0f);
|
|
}
|
|
}
|
|
|
|
// 10. Reconfigure Enemy (BlindMutantAI) & Comprehensive 32+ Point Patrol Route
|
|
GameObject enemy = GameObject.Find("enemy");
|
|
if (enemy == null) enemy = Object.FindAnyObjectByType<BlindMutantAI>()?.gameObject;
|
|
SetupPatrolWaypoints(labRoot.transform, enemy);
|
|
|
|
// Apply EchoCloudMat to all generated props and objects under labRoot
|
|
if (echoMat != null)
|
|
{
|
|
foreach (var r in labRoot.GetComponentsInChildren<Renderer>(true))
|
|
{
|
|
var mats = new Material[r.sharedMaterials.Length];
|
|
for (int i = 0; i < mats.Length; i++) mats[i] = echoMat;
|
|
r.sharedMaterials = mats;
|
|
}
|
|
}
|
|
|
|
// 11. Re-bake NavMesh Surface for entire 100x100m facility
|
|
var navMeshSurface = Object.FindAnyObjectByType<NavMeshSurface>();
|
|
if (navMeshSurface != null)
|
|
{
|
|
navMeshSurface.transform.position = Vector3.zero;
|
|
navMeshSurface.collectObjects = CollectObjects.All;
|
|
navMeshSurface.BuildNavMesh();
|
|
Debug.Log("<color=green>NavMesh successfully baked for the 100x100m complex facility!</color>");
|
|
}
|
|
|
|
// 12. Populate All Sectors and Rooms with Mutants (Roamers, Heavy Swarms, and Room Guards)
|
|
MutantPopulationSetup.Populate();
|
|
|
|
// Mark scene dirty
|
|
EditorUtility.SetDirty(labRoot);
|
|
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
|
|
Debug.Log("<color=green>=== EXPANDED LABORATORY COMPLEX GENERATION COMPLETE! ===</color>");
|
|
}
|
|
|
|
private static void CreateFloorGrid(Transform parent, Material mat, float minX, float maxX, float minZ, float maxZ)
|
|
{
|
|
// 16 large floor slabs (4x4 grid) for crisp rendering and solid physics
|
|
int divisions = 4;
|
|
float stepX = (maxX - minX) / divisions;
|
|
float stepZ = (maxZ - minZ) / divisions;
|
|
|
|
for (int ix = 0; ix < divisions; ix++)
|
|
{
|
|
for (int iz = 0; iz < divisions; iz++)
|
|
{
|
|
float x0 = minX + ix * stepX;
|
|
float x1 = x0 + stepX;
|
|
float z0 = minZ + iz * stepZ;
|
|
float z1 = z0 + stepZ;
|
|
|
|
var floorGo = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
floorGo.name = $"Floor_Chunk_{ix}_{iz}";
|
|
floorGo.transform.SetParent(parent);
|
|
floorGo.transform.position = new Vector3((x0 + x1) / 2f, -0.25f, (z0 + z1) / 2f);
|
|
floorGo.transform.localScale = new Vector3(stepX, 0.5f, stepZ);
|
|
if (mat != null) floorGo.GetComponent<Renderer>().sharedMaterial = mat;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void BuildRoomWalls(Transform parent, Material mat, float minX, float maxX, float minZ, float maxZ,
|
|
Vector2? southDoor, Vector2? northDoor, Vector2? westDoor, Vector2? eastDoor, string roomName)
|
|
{
|
|
GameObject roomWalls = new GameObject($"Walls_{roomName}");
|
|
roomWalls.transform.SetParent(parent);
|
|
|
|
// South Wall (along X at Z = minZ)
|
|
CreateWallWithDoor(roomWalls.transform, mat, minX, maxX, minZ, true, southDoor, $"{roomName}_South");
|
|
|
|
// North Wall (along X at Z = maxZ)
|
|
CreateWallWithDoor(roomWalls.transform, mat, minX, maxX, maxZ, true, northDoor, $"{roomName}_North");
|
|
|
|
// West Wall (along Z at X = minX)
|
|
CreateWallWithDoor(roomWalls.transform, mat, minZ, maxZ, minX, false, westDoor, $"{roomName}_West");
|
|
|
|
// East Wall (along Z at X = maxX)
|
|
CreateWallWithDoor(roomWalls.transform, mat, minZ, maxZ, maxX, false, eastDoor, $"{roomName}_East");
|
|
}
|
|
|
|
private static void CreateWallWithDoor(Transform parent, Material mat, float startCoord, float endCoord, float fixedCoord,
|
|
bool isHorizontal, Vector2? doorRange, string wallName)
|
|
{
|
|
if (startCoord > endCoord)
|
|
{
|
|
float t = startCoord; startCoord = endCoord; endCoord = t;
|
|
}
|
|
|
|
if (!doorRange.HasValue)
|
|
{
|
|
float length = endCoord - startCoord;
|
|
float mid = (startCoord + endCoord) / 2f;
|
|
Vector3 pos = isHorizontal ? new Vector3(mid, WALL_HEIGHT / 2f, fixedCoord) : new Vector3(fixedCoord, WALL_HEIGHT / 2f, mid);
|
|
Vector3 scale = isHorizontal ? new Vector3(length, WALL_HEIGHT, WALL_THICKNESS) : new Vector3(WALL_THICKNESS, WALL_HEIGHT, length);
|
|
CreateWall(parent, mat, pos, scale, wallName);
|
|
return;
|
|
}
|
|
|
|
float dMin = Mathf.Clamp(doorRange.Value.x, startCoord, endCoord);
|
|
float dMax = Mathf.Clamp(doorRange.Value.y, startCoord, endCoord);
|
|
|
|
// Left / Start section
|
|
if (dMin > startCoord + 0.2f)
|
|
{
|
|
float len1 = dMin - startCoord;
|
|
float mid1 = (startCoord + dMin) / 2f;
|
|
Vector3 pos1 = isHorizontal ? new Vector3(mid1, WALL_HEIGHT / 2f, fixedCoord) : new Vector3(fixedCoord, WALL_HEIGHT / 2f, mid1);
|
|
Vector3 scale1 = isHorizontal ? new Vector3(len1, WALL_HEIGHT, WALL_THICKNESS) : new Vector3(WALL_THICKNESS, WALL_HEIGHT, len1);
|
|
CreateWall(parent, mat, pos1, scale1, $"{wallName}_PartA");
|
|
}
|
|
|
|
// Right / End section
|
|
if (endCoord > dMax + 0.2f)
|
|
{
|
|
float len2 = endCoord - dMax;
|
|
float mid2 = (dMax + endCoord) / 2f;
|
|
Vector3 pos2 = isHorizontal ? new Vector3(mid2, WALL_HEIGHT / 2f, fixedCoord) : new Vector3(fixedCoord, WALL_HEIGHT / 2f, mid2);
|
|
Vector3 scale2 = isHorizontal ? new Vector3(len2, WALL_HEIGHT, WALL_THICKNESS) : new Vector3(WALL_THICKNESS, WALL_HEIGHT, len2);
|
|
CreateWall(parent, mat, pos2, scale2, $"{wallName}_PartB");
|
|
}
|
|
|
|
// Over-door Lintel (bulkhead arch)
|
|
float doorLen = dMax - dMin;
|
|
float doorMid = (dMin + dMax) / 2f;
|
|
float lintelHeight = WALL_HEIGHT - 2.6f;
|
|
float lintelPosY = 2.6f + (lintelHeight / 2f);
|
|
Vector3 lintelPos = isHorizontal ? new Vector3(doorMid, lintelPosY, fixedCoord) : new Vector3(fixedCoord, lintelPosY, doorMid);
|
|
Vector3 lintelScale = isHorizontal ? new Vector3(doorLen, lintelHeight, WALL_THICKNESS) : new Vector3(WALL_THICKNESS, lintelHeight, doorLen);
|
|
CreateWall(parent, mat, lintelPos, lintelScale, $"{wallName}_Lintel");
|
|
}
|
|
|
|
private static GameObject CreateWall(Transform parent, Material mat, Vector3 pos, Vector3 scale, string name)
|
|
{
|
|
var wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
wall.name = name;
|
|
wall.transform.SetParent(parent);
|
|
wall.transform.position = pos;
|
|
wall.transform.localScale = scale;
|
|
if (mat != null) wall.GetComponent<Renderer>().sharedMaterial = mat;
|
|
return wall;
|
|
}
|
|
|
|
private static void BuildComplexCorridors(Transform parent, Material mat)
|
|
{
|
|
GameObject corrGo = new GameObject("Corridors_Complex_Layout");
|
|
corrGo.transform.SetParent(parent);
|
|
|
|
// 1. GRAND SOUTH CONCOURSE (Z: -36 to -24, X: -26 to 26)
|
|
// High, wide passage with central architectural dividers
|
|
CreateWall(corrGo.transform, mat, new Vector3(-12f, WALL_HEIGHT / 2f, -30f), new Vector3(2.5f, WALL_HEIGHT, 4f), "Concourse_Pillar_West");
|
|
CreateWall(corrGo.transform, mat, new Vector3(12f, WALL_HEIGHT / 2f, -30f), new Vector3(2.5f, WALL_HEIGHT, 4f), "Concourse_Pillar_East");
|
|
|
|
// 2. WEST TIGHT MAINTENANCE SLALOM (CRAMPED / DIFFICULT CHOKEPOINT)
|
|
// Flanking the Grand Atrium between X: -24 and -18, Z: -22 to 24.
|
|
// Narrow 1.6m wide corridor with alternating zigzag baffles:
|
|
CreateWall(corrGo.transform, mat, new Vector3(-20f, WALL_HEIGHT / 2f, -18f), new Vector3(WALL_THICKNESS, WALL_HEIGHT, 8f), "Slalom_W_Wall1");
|
|
CreateWall(corrGo.transform, mat, new Vector3(-22.5f, WALL_HEIGHT / 2f, -14f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_W_Baffle1"); // forces jog east
|
|
CreateWall(corrGo.transform, mat, new Vector3(-19.5f, WALL_HEIGHT / 2f, -8f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_W_Baffle2"); // forces jog west
|
|
CreateWall(corrGo.transform, mat, new Vector3(-22.5f, WALL_HEIGHT / 2f, 0f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_W_Baffle3");
|
|
CreateWall(corrGo.transform, mat, new Vector3(-19.5f, WALL_HEIGHT / 2f, 8f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_W_Baffle4");
|
|
CreateWall(corrGo.transform, mat, new Vector3(-22.5f, WALL_HEIGHT / 2f, 16f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_W_Baffle5");
|
|
|
|
// 3. EAST TIGHT CABLE-TRUNK SLALOM (CRAMPED / DIFFICULT CHOKEPOINT)
|
|
// Flanking the Grand Atrium between X: 18 and 24, Z: -22 to 24.
|
|
CreateWall(corrGo.transform, mat, new Vector3(20f, WALL_HEIGHT / 2f, -18f), new Vector3(WALL_THICKNESS, WALL_HEIGHT, 8f), "Slalom_E_Wall1");
|
|
CreateWall(corrGo.transform, mat, new Vector3(22.5f, WALL_HEIGHT / 2f, -14f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_E_Baffle1");
|
|
CreateWall(corrGo.transform, mat, new Vector3(19.5f, WALL_HEIGHT / 2f, -8f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_E_Baffle2");
|
|
CreateWall(corrGo.transform, mat, new Vector3(22.5f, WALL_HEIGHT / 2f, 0f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_E_Baffle3");
|
|
CreateWall(corrGo.transform, mat, new Vector3(19.5f, WALL_HEIGHT / 2f, 8f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_E_Baffle4");
|
|
CreateWall(corrGo.transform, mat, new Vector3(22.5f, WALL_HEIGHT / 2f, 16f), new Vector3(3.2f, WALL_HEIGHT, WALL_THICKNESS), "Slalom_E_Baffle5");
|
|
|
|
// 4. NORTH MAINTENANCE BYPASS CONDUIT (LONG NARROW RUNWAY, Z: 46 to 49)
|
|
// Spans from X: -48 to +48 along the north perimeter, letting players bypass the loud reactor
|
|
CreateWallWithDoor(corrGo.transform, mat, -48f, -24f, 46f, true, new Vector2(-39f, -35f), "NorthBypass_WestGuide");
|
|
CreateWallWithDoor(corrGo.transform, mat, -20f, 20f, 46f, true, new Vector2(-2.5f, 2.5f), "NorthBypass_MidGuide");
|
|
CreateWallWithDoor(corrGo.transform, mat, 24f, 48f, 46f, true, new Vector2(35f, 39f), "NorthBypass_EastGuide");
|
|
|
|
// Inter-conduit chokepoint baffles
|
|
CreateWall(corrGo.transform, mat, new Vector3(-12f, WALL_HEIGHT / 2f, 47.5f), new Vector3(WALL_THICKNESS, WALL_HEIGHT, 2.5f), "Bypass_Baffle_W");
|
|
CreateWall(corrGo.transform, mat, new Vector3(12f, WALL_HEIGHT / 2f, 47.5f), new Vector3(WALL_THICKNESS, WALL_HEIGHT, 2.5f), "Bypass_Baffle_E");
|
|
}
|
|
|
|
private static void BuildQuarantineCells(Transform parent, Material mat)
|
|
{
|
|
// Quarantine Sector is located X: -48 to -22, Z: 6 to 26
|
|
// We build a central cell corridor along X = -35 (from Z = 6 to 26)
|
|
// With 6 individual high-security isolation cubicles
|
|
GameObject qGo = new GameObject("Quarantine_Cell_Partitions");
|
|
qGo.transform.SetParent(parent);
|
|
|
|
// West corridor wall (at X = -37) with doors into cells 1, 2, 3
|
|
CreateWallWithDoor(qGo.transform, mat, 6f, 12f, -37f, false, new Vector2(8f, 10f), "Cell_Door_1");
|
|
CreateWallWithDoor(qGo.transform, mat, 13f, 19f, -37f, false, new Vector2(15f, 17f), "Cell_Door_2");
|
|
CreateWallWithDoor(qGo.transform, mat, 20f, 26f, -37f, false, new Vector2(22f, 24f), "Cell_Door_3");
|
|
|
|
// Cell dividers on West side (Z = 12.5 and Z = 19.5, X from -48 to -37)
|
|
CreateWall(qGo.transform, mat, new Vector3(-42.5f, WALL_HEIGHT / 2f, 12.5f), new Vector3(11f, WALL_HEIGHT, WALL_THICKNESS), "Cell_Divider_W1");
|
|
CreateWall(qGo.transform, mat, new Vector3(-42.5f, WALL_HEIGHT / 2f, 19.5f), new Vector3(11f, WALL_HEIGHT, WALL_THICKNESS), "Cell_Divider_W2");
|
|
|
|
// East corridor wall (at X = -33) with doors into cells 4, 5, 6
|
|
CreateWallWithDoor(qGo.transform, mat, 6f, 12f, -33f, false, new Vector2(8f, 10f), "Cell_Door_4");
|
|
CreateWallWithDoor(qGo.transform, mat, 13f, 19f, -33f, false, new Vector2(15f, 17f), "Cell_Door_5");
|
|
CreateWallWithDoor(qGo.transform, mat, 20f, 26f, -33f, false, new Vector2(22f, 24f), "Cell_Door_6");
|
|
|
|
// Cell dividers on East side (Z = 12.5 and Z = 19.5, X from -33 to -22)
|
|
CreateWall(qGo.transform, mat, new Vector3(-27.5f, WALL_HEIGHT / 2f, 12.5f), new Vector3(11f, WALL_HEIGHT, WALL_THICKNESS), "Cell_Divider_E1");
|
|
CreateWall(qGo.transform, mat, new Vector3(-27.5f, WALL_HEIGHT / 2f, 19.5f), new Vector3(11f, WALL_HEIGHT, WALL_THICKNESS), "Cell_Divider_E2");
|
|
}
|
|
|
|
private static void PopulateAirlock(Transform parent, GameObject pillarPrefab, GameObject rackPrefab, GameObject chairPrefab)
|
|
{
|
|
GameObject room = new GameObject("Airlock_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
// Decon arch frames
|
|
SpawnProp(pillarPrefab, room.transform, new Vector3(-3f, 0f, -42f), Quaternion.identity);
|
|
SpawnProp(pillarPrefab, room.transform, new Vector3(3f, 0f, -42f), Quaternion.identity);
|
|
|
|
// Lockers and benches
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(-6.5f, 0f, -46f), Quaternion.Euler(0f, 90f, 0f));
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(-6.5f, 0f, -44f), Quaternion.Euler(0f, 90f, 0f));
|
|
SpawnProp(chairPrefab, room.transform, new Vector3(6.5f, 0f, -46f), Quaternion.Euler(0f, -90f, 0f));
|
|
SpawnProp(chairPrefab, room.transform, new Vector3(6.5f, 0f, -44f), Quaternion.Euler(0f, -90f, 0f));
|
|
}
|
|
|
|
private static void PopulateGrandAtrium(Transform parent, GameObject pillarPrefab, GameObject tablePrefab, GameObject instPrefab,
|
|
GameObject boxPrefab, GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("GrandAtrium_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
// 8 Grand architectural colonnades ringing the open 36x30m atrium
|
|
Vector3[] pillarPos = new Vector3[]
|
|
{
|
|
new Vector3(-12f, 0f, 0f),
|
|
new Vector3(-12f, 0f, 18f),
|
|
new Vector3(12f, 0f, 0f),
|
|
new Vector3(12f, 0f, 18f),
|
|
new Vector3(-6f, 0f, -3f),
|
|
new Vector3(6f, 0f, -3f),
|
|
new Vector3(-6f, 0f, 21f),
|
|
new Vector3(6f, 0f, 21f)
|
|
};
|
|
|
|
foreach (var pos in pillarPos)
|
|
{
|
|
SpawnProp(pillarPrefab, room.transform, pos, Quaternion.identity);
|
|
}
|
|
|
|
// Massive Central Mutant Observation Specimen Vat (Radius 4.5m)
|
|
var coreCylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
coreCylinder.name = "Grand_Mutant_Cryo_Vat";
|
|
coreCylinder.transform.SetParent(room.transform);
|
|
coreCylinder.transform.position = new Vector3(0f, 2.25f, 9f);
|
|
coreCylinder.transform.localScale = new Vector3(7f, 2.25f, 7f);
|
|
|
|
// Observation Control Desks
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(-5f, 0f, 4f), Quaternion.Euler(0f, 45f, 0f));
|
|
SpawnProp(instPrefab, room.transform, new Vector3(-5f, 1.07f, 4f), Quaternion.Euler(0f, 45f, 0f));
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(5f, 0f, 4f), Quaternion.Euler(0f, -45f, 0f));
|
|
SpawnProp(instPrefab, room.transform, new Vector3(5f, 1.07f, 4f), Quaternion.Euler(0f, -45f, 0f));
|
|
|
|
// Cover Crates around perimeter
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-14f, 0f, 9f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-14f, 1.08f, 9f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(14f, 0f, 9f), Quaternion.identity);
|
|
|
|
// Distraction Throwables in Grand Atrium
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(-4.8f, 1.15f, 4.2f), "Throwable_Beaker_Atrium_W");
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(4.8f, 1.15f, 4.2f), "Throwable_Beaker_Atrium_E");
|
|
}
|
|
|
|
private static void PopulateReactorHall(Transform parent, GameObject pillarPrefab, GameObject boxPrefab, GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("ReactorHall_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
// Two massive industrial reactor turbine housings
|
|
var turbine1 = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
turbine1.name = "Reactor_Turbine_Alpha";
|
|
turbine1.transform.SetParent(room.transform);
|
|
turbine1.transform.position = new Vector3(-10f, 2.5f, 38f);
|
|
turbine1.transform.localScale = new Vector3(6f, 2.5f, 6f);
|
|
|
|
var turbine2 = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
turbine2.name = "Reactor_Turbine_Beta";
|
|
turbine2.transform.SetParent(room.transform);
|
|
turbine2.transform.position = new Vector3(10f, 2.5f, 38f);
|
|
turbine2.transform.localScale = new Vector3(6f, 2.5f, 6f);
|
|
|
|
// High Voltage Pillars
|
|
SpawnProp(pillarPrefab, room.transform, new Vector3(-18f, 0f, 32f), Quaternion.identity);
|
|
SpawnProp(pillarPrefab, room.transform, new Vector3(-18f, 0f, 44f), Quaternion.identity);
|
|
SpawnProp(pillarPrefab, room.transform, new Vector3(18f, 0f, 32f), Quaternion.identity);
|
|
SpawnProp(pillarPrefab, room.transform, new Vector3(18f, 0f, 44f), Quaternion.identity);
|
|
|
|
// Stacks of heavy shielded crates for stealth cover
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(0f, 0f, 34f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(0f, 1.08f, 34f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(0f, 0f, 42f), Quaternion.identity);
|
|
|
|
// Throwable Beaker
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(0f, 1.15f, 34f), "Throwable_Beaker_Reactor_Core");
|
|
}
|
|
|
|
private static void PopulateSouthConcourse(Transform parent, GameObject pillarPrefab, GameObject chairPrefab, GameObject boxPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject concourse = new GameObject("SouthConcourse_Props");
|
|
concourse.transform.SetParent(parent);
|
|
|
|
// Architectural rest benches
|
|
SpawnProp(chairPrefab, concourse.transform, new Vector3(-6f, 0f, -32f), Quaternion.identity);
|
|
SpawnProp(chairPrefab, concourse.transform, new Vector3(6f, 0f, -32f), Quaternion.identity);
|
|
SpawnProp(chairPrefab, concourse.transform, new Vector3(-18f, 0f, -32f), Quaternion.identity);
|
|
SpawnProp(chairPrefab, concourse.transform, new Vector3(18f, 0f, -32f), Quaternion.identity);
|
|
|
|
// Crates for cover
|
|
SpawnProp(boxPrefab, concourse.transform, new Vector3(-8f, 0f, -28f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, concourse.transform, new Vector3(8f, 0f, -28f), Quaternion.identity);
|
|
}
|
|
|
|
private static void PopulateBiochem(Transform parent, GameObject tablePrefab, GameObject showcasePrefab, GameObject shelfPrefab,
|
|
GameObject tapPrefab, GameObject instPrefab, GameObject beakerPrefab, GameObject flaskPrefab, GameObject tubePrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("BiochemLab_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
// Lab Island 1
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(-40f, 0f, -14f), Quaternion.identity);
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(-36f, 0f, -14f), Quaternion.identity);
|
|
SpawnProp(instPrefab, room.transform, new Vector3(-40f, 1.07f, -14f), Quaternion.identity);
|
|
SpawnProp(tapPrefab, room.transform, new Vector3(-36f, 1.07f, -14f), Quaternion.identity);
|
|
|
|
// Lab Island 2
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(-40f, 0f, -6f), Quaternion.identity);
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(-36f, 0f, -6f), Quaternion.identity);
|
|
SpawnProp(tubePrefab, room.transform, new Vector3(-39.5f, 1.07f, -6f), Quaternion.identity);
|
|
SpawnProp(flaskPrefab, room.transform, new Vector3(-36.5f, 1.07f, -6f), Quaternion.identity);
|
|
|
|
// Shelves
|
|
SpawnProp(showcasePrefab, room.transform, new Vector3(-46f, 0f, -18f), Quaternion.Euler(0f, 90f, 0f));
|
|
SpawnProp(showcasePrefab, room.transform, new Vector3(-46f, 0f, -2f), Quaternion.Euler(0f, 90f, 0f));
|
|
|
|
// Throwables
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(-35.5f, 1.15f, -14f), "Throwable_Beaker_Biochem1");
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(-40.5f, 1.15f, -6f), "Throwable_Beaker_Biochem2");
|
|
}
|
|
|
|
private static void PopulateSurgical(Transform parent, GameObject tablePrefab, GameObject showcasePrefab, GameObject chairPrefab,
|
|
GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("Surgical_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
// Operating Tables
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(34f, 0f, -14f), Quaternion.identity);
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(40f, 0f, -14f), Quaternion.identity);
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(37f, 0f, -6f), Quaternion.identity);
|
|
|
|
// Chairs
|
|
SpawnProp(chairPrefab, room.transform, new Vector3(34f, 0f, -12.5f), Quaternion.Euler(0f, 180f, 0f));
|
|
SpawnProp(chairPrefab, room.transform, new Vector3(40f, 0f, -12.5f), Quaternion.Euler(0f, 180f, 0f));
|
|
|
|
// Medical Cabinets
|
|
SpawnProp(showcasePrefab, room.transform, new Vector3(46f, 0f, -10f), Quaternion.Euler(0f, -90f, 0f));
|
|
|
|
// Throwable
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(37f, 1.15f, -6f), "Throwable_Beaker_Surgical");
|
|
}
|
|
|
|
private static void PopulateQuarantineProps(Transform parent, GameObject boxPrefab, GameObject rackPrefab, GameObject chairPrefab,
|
|
GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("Quarantine_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
// Clutter in cells (broken chairs, overturned cots, boxes)
|
|
SpawnProp(chairPrefab, room.transform, new Vector3(-43f, 0f, 9f), Quaternion.Euler(0f, 45f, 0f));
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-44f, 0f, 16f), Quaternion.Euler(0f, 25f, 0f));
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-27f, 0f, 9f), Quaternion.identity);
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(-26f, 0f, 23f), Quaternion.Euler(0f, 90f, 0f));
|
|
|
|
// Distraction beaker hidden in isolation cell
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(-43f, 0.5f, 23f), "Throwable_Beaker_Quarantine");
|
|
}
|
|
|
|
private static void PopulateGenetics(Transform parent, GameObject tablePrefab, GameObject showcasePrefab, GameObject instPrefab,
|
|
GameObject chairPrefab, GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("Genetics_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(34f, 0f, 14f), Quaternion.identity);
|
|
SpawnProp(instPrefab, room.transform, new Vector3(34f, 1.07f, 14f), Quaternion.identity);
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(40f, 0f, 14f), Quaternion.identity);
|
|
SpawnProp(instPrefab, room.transform, new Vector3(40f, 1.07f, 14f), Quaternion.identity);
|
|
|
|
SpawnProp(showcasePrefab, room.transform, new Vector3(46f, 0f, 18f), Quaternion.Euler(0f, -90f, 0f));
|
|
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(40f, 1.15f, 14f), "Throwable_Beaker_Genetics");
|
|
}
|
|
|
|
private static void PopulateCryo(Transform parent, GameObject rackPrefab, GameObject shelfPrefab, GameObject boxPrefab,
|
|
GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("Cryo_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
// Aisles of cryogenic specimen racks
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
float x = -44f + i * 6f;
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(x, 0f, -44f), Quaternion.identity);
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(x, 0f, -38f), Quaternion.identity);
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(x, 0f, -32f), Quaternion.identity);
|
|
}
|
|
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-29f, 0f, -30f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-29f, 1.08f, -30f), Quaternion.identity);
|
|
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(-38f, 1.15f, -38f), "Throwable_Beaker_Cryo");
|
|
}
|
|
|
|
private static void PopulateArmory(Transform parent, GameObject rackPrefab, GameObject tablePrefab, GameObject instPrefab,
|
|
GameObject boxPrefab, GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("Armory_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
SpawnProp(tablePrefab, room.transform, new Vector3(36f, 0f, -35f), Quaternion.identity);
|
|
SpawnProp(instPrefab, room.transform, new Vector3(36f, 1.07f, -35f), Quaternion.identity);
|
|
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(44f, 0f, -44f), Quaternion.identity);
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(44f, 0f, -38f), Quaternion.identity);
|
|
SpawnProp(rackPrefab, room.transform, new Vector3(44f, 0f, -32f), Quaternion.identity);
|
|
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(30f, 0f, -30f), Quaternion.identity);
|
|
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(36f, 1.15f, -35f), "Throwable_Beaker_Armory");
|
|
}
|
|
|
|
private static void PopulateChemicalSilos(Transform parent, GameObject pillarPrefab, GameObject boxPrefab, GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("ChemicalSilos_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
var silo1 = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
silo1.name = "Toxic_Silo_Alpha";
|
|
silo1.transform.SetParent(room.transform);
|
|
silo1.transform.position = new Vector3(-37f, 2.5f, 38f);
|
|
silo1.transform.localScale = new Vector3(5.5f, 2.5f, 5.5f);
|
|
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-44f, 0f, 32f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-44f, 1.08f, 32f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(-30f, 0f, 44f), Quaternion.identity);
|
|
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(-44f, 1.15f, 32f), "Throwable_Beaker_Silo");
|
|
}
|
|
|
|
private static void PopulateSubstation(Transform parent, GameObject pillarPrefab, GameObject boxPrefab, GameObject beakerPrefab, Transform pickupsParent)
|
|
{
|
|
GameObject room = new GameObject("Substation_Props");
|
|
room.transform.SetParent(parent);
|
|
|
|
var cap1 = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
cap1.name = "Substation_Transformer";
|
|
cap1.transform.SetParent(room.transform);
|
|
cap1.transform.position = new Vector3(37f, 2.5f, 38f);
|
|
cap1.transform.localScale = new Vector3(5.5f, 2.5f, 5.5f);
|
|
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(44f, 0f, 32f), Quaternion.identity);
|
|
SpawnProp(boxPrefab, room.transform, new Vector3(30f, 0f, 44f), Quaternion.identity);
|
|
|
|
SpawnThrowableBeaker(beakerPrefab, pickupsParent, new Vector3(44f, 1.15f, 32f), "Throwable_Beaker_Substation");
|
|
}
|
|
|
|
private static void PopulateSlalomAlleyProps(Transform parent, GameObject boxPrefab, GameObject rackPrefab)
|
|
{
|
|
GameObject props = new GameObject("Slalom_Chokepoint_Props");
|
|
props.transform.SetParent(parent);
|
|
|
|
// Obstacles placed right at the slalom bends to tighten passage
|
|
SpawnProp(boxPrefab, props.transform, new Vector3(-21f, 0f, -11f), Quaternion.Euler(0f, 45f, 0f));
|
|
SpawnProp(boxPrefab, props.transform, new Vector3(-21f, 0f, 5f), Quaternion.Euler(0f, 25f, 0f));
|
|
SpawnProp(rackPrefab, props.transform, new Vector3(21f, 0f, -11f), Quaternion.Euler(0f, 90f, 0f));
|
|
SpawnProp(rackPrefab, props.transform, new Vector3(21f, 0f, 5f), Quaternion.Euler(0f, 90f, 0f));
|
|
}
|
|
|
|
private static void SpawnProp(GameObject prefab, Transform parent, Vector3 pos, Quaternion rot)
|
|
{
|
|
if (prefab == null) return;
|
|
GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab, parent);
|
|
if (instance != null)
|
|
{
|
|
instance.transform.position = pos;
|
|
instance.transform.rotation = rot;
|
|
}
|
|
}
|
|
|
|
private static void SpawnThrowableBeaker(GameObject beakerPrefab, Transform parent, Vector3 pos, string name)
|
|
{
|
|
GameObject beaker;
|
|
if (beakerPrefab != null)
|
|
{
|
|
beaker = (GameObject)PrefabUtility.InstantiatePrefab(beakerPrefab, parent);
|
|
}
|
|
else
|
|
{
|
|
beaker = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
|
|
beaker.transform.localScale = new Vector3(0.3f, 0.5f, 0.3f);
|
|
}
|
|
|
|
beaker.name = name;
|
|
beaker.transform.position = pos;
|
|
|
|
var col = beaker.GetComponent<Collider>();
|
|
if (col == null)
|
|
{
|
|
col = beaker.AddComponent<CapsuleCollider>();
|
|
}
|
|
|
|
var rb = beaker.GetComponent<Rigidbody>();
|
|
if (rb == null)
|
|
{
|
|
rb = beaker.AddComponent<Rigidbody>();
|
|
}
|
|
rb.mass = 1.0f;
|
|
rb.collisionDetectionMode = CollisionDetectionMode.Continuous;
|
|
|
|
var wave = beaker.GetComponent<ImpactWave>();
|
|
if (wave == null)
|
|
{
|
|
wave = beaker.AddComponent<ImpactWave>();
|
|
}
|
|
wave.soundRadius = 22f;
|
|
wave.minImpactForce = 1.5f;
|
|
|
|
var pulsePrefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/EchoPulse.prefab");
|
|
if (pulsePrefab != null)
|
|
{
|
|
wave.wavePrefab = pulsePrefab;
|
|
}
|
|
}
|
|
|
|
private static void CreateLighting(Transform parent)
|
|
{
|
|
// Entrance Airlock - Warning Red
|
|
CreatePointLight(parent, "Light_Decon_Red", new Vector3(0f, 3.8f, -44f), new Color(1f, 0.2f, 0.15f), 2.5f, 14f);
|
|
|
|
// Grand South Concourse - Warm Bronze
|
|
CreatePointLight(parent, "Light_Concourse_Mid", new Vector3(0f, 4f, -30f), new Color(1f, 0.75f, 0.4f), 2.2f, 20f);
|
|
CreatePointLight(parent, "Light_Concourse_West", new Vector3(-18f, 4f, -30f), new Color(1f, 0.75f, 0.4f), 1.8f, 18f);
|
|
CreatePointLight(parent, "Light_Concourse_East", new Vector3(18f, 4f, -30f), new Color(1f, 0.75f, 0.4f), 1.8f, 18f);
|
|
|
|
// Grand Central Atrium - Bio-Luminescent Emerald & Cyan
|
|
CreatePointLight(parent, "Light_Atrium_Core", new Vector3(0f, 4.2f, 9f), new Color(0.15f, 1f, 0.8f), 3.5f, 32f);
|
|
CreatePointLight(parent, "Light_Atrium_South", new Vector3(0f, 4.2f, 0f), new Color(0.2f, 0.9f, 0.8f), 2.0f, 22f);
|
|
CreatePointLight(parent, "Light_Atrium_North", new Vector3(0f, 4.2f, 18f), new Color(0.2f, 0.9f, 0.8f), 2.0f, 22f);
|
|
|
|
// Sub-Reactor Hall - Warning Amber & Industrial High-Voltage
|
|
CreatePointLight(parent, "Light_Reactor_Turbine_W", new Vector3(-10f, 4.2f, 38f), new Color(1f, 0.55f, 0.1f), 3.0f, 26f);
|
|
CreatePointLight(parent, "Light_Reactor_Turbine_E", new Vector3(10f, 4.2f, 38f), new Color(1f, 0.55f, 0.1f), 3.0f, 26f);
|
|
CreatePointLight(parent, "Light_Reactor_Core", new Vector3(0f, 4.2f, 38f), new Color(0.3f, 0.85f, 1f), 2.5f, 24f);
|
|
|
|
// Quarantine Wing - Claustrophobic Flickering Crimson
|
|
CreatePointLight(parent, "Light_Quarantine_1", new Vector3(-35f, 3.8f, 9f), new Color(1f, 0.1f, 0.1f), 2.0f, 16f);
|
|
CreatePointLight(parent, "Light_Quarantine_2", new Vector3(-35f, 3.8f, 23f), new Color(1f, 0.1f, 0.1f), 2.0f, 16f);
|
|
|
|
// Biochem Lab - Toxic Mint Green
|
|
CreatePointLight(parent, "Light_Biochem", new Vector3(-37f, 3.8f, -10f), new Color(0.3f, 0.95f, 0.5f), 2.2f, 22f);
|
|
|
|
// Surgical ICU - Cold Clinical White
|
|
CreatePointLight(parent, "Light_Surgical", new Vector3(37f, 3.8f, -10f), new Color(0.85f, 0.95f, 1f), 2.2f, 22f);
|
|
|
|
// Genetics Lab - Electric Violet
|
|
CreatePointLight(parent, "Light_Genetics", new Vector3(37f, 3.8f, 16f), new Color(0.6f, 0.35f, 1f), 2.0f, 22f);
|
|
|
|
// Cryo Vault - Deep Glacier Cyan
|
|
CreatePointLight(parent, "Light_Cryo", new Vector3(-37f, 3.8f, -37f), new Color(0.2f, 0.65f, 1f), 2.0f, 22f);
|
|
|
|
// Armory - Surveillance Amber
|
|
CreatePointLight(parent, "Light_Armory", new Vector3(37f, 3.8f, -37f), new Color(1f, 0.65f, 0.2f), 2.0f, 22f);
|
|
|
|
// Silos & Substation
|
|
CreatePointLight(parent, "Light_Silos", new Vector3(-37f, 3.8f, 38f), new Color(0.8f, 0.9f, 0.2f), 2.0f, 22f);
|
|
CreatePointLight(parent, "Light_Substation", new Vector3(37f, 3.8f, 38f), new Color(0.4f, 0.7f, 1f), 2.0f, 22f);
|
|
|
|
// North Bypass Runways
|
|
CreatePointLight(parent, "Light_Bypass_W", new Vector3(-25f, 3.2f, 47.5f), new Color(1f, 0.7f, 0.3f), 1.4f, 14f);
|
|
CreatePointLight(parent, "Light_Bypass_Mid", new Vector3(0f, 3.2f, 47.5f), new Color(1f, 0.7f, 0.3f), 1.4f, 14f);
|
|
CreatePointLight(parent, "Light_Bypass_E", new Vector3(25f, 3.2f, 47.5f), new Color(1f, 0.7f, 0.3f), 1.4f, 14f);
|
|
}
|
|
|
|
private static void CreatePointLight(Transform parent, string name, Vector3 pos, Color color, float intensity, float range)
|
|
{
|
|
GameObject lightGo = new GameObject(name);
|
|
lightGo.transform.SetParent(parent);
|
|
lightGo.transform.position = pos;
|
|
var light = lightGo.AddComponent<Light>();
|
|
light.type = LightType.Point;
|
|
light.color = color;
|
|
light.intensity = intensity;
|
|
light.range = range;
|
|
light.shadows = LightShadows.Soft;
|
|
}
|
|
|
|
private static void SetupPatrolWaypoints(Transform parent, GameObject enemy)
|
|
{
|
|
var oldPatrol = GameObject.Find("PatrolWaypoints");
|
|
if (oldPatrol != null)
|
|
{
|
|
Undo.DestroyObjectImmediate(oldPatrol);
|
|
}
|
|
|
|
// Clean any old 1..15 in scene
|
|
for (int i = 0; i <= 20; i++)
|
|
{
|
|
string oldName = i == 0 ? "1" : $"1 ({i})";
|
|
var oldGo = GameObject.Find(oldName);
|
|
if (oldGo != null)
|
|
{
|
|
oldGo.SetActive(false);
|
|
}
|
|
}
|
|
|
|
GameObject patrolParent = new GameObject("PatrolWaypoints");
|
|
patrolParent.transform.SetParent(parent);
|
|
|
|
// 32 Waypoints looping smoothly through ALL wings and sectors of the 100x100m facility!
|
|
Vector3[] waypoints = new Vector3[]
|
|
{
|
|
// South Concourse & Cryo
|
|
new Vector3(0f, 0f, -30f), // WP0: Concourse Center
|
|
new Vector3(-18f, 0f, -30f), // WP1: Concourse West
|
|
new Vector3(-37f, 0f, -37f), // WP2: Cryogenics Vault
|
|
new Vector3(-37f, 0f, -24f), // WP3: Cryo North Gate
|
|
// Biochem & West Slalom
|
|
new Vector3(-37f, 0f, -14f), // WP4: Biochem Lab South
|
|
new Vector3(-37f, 0f, -4f), // WP5: Biochem Lab North
|
|
new Vector3(-21f, 0f, -4f), // WP6: West Slalom Entry
|
|
new Vector3(-21f, 0f, 6f), // WP7: West Slalom Mid
|
|
// Quarantine Cellblock (Labyrinth)
|
|
new Vector3(-35f, 0f, 8f), // WP8: Quarantine Cell Corridor South
|
|
new Vector3(-43f, 0f, 9f), // WP9: Isolation Cell 1
|
|
new Vector3(-35f, 0f, 16f), // WP10: Quarantine Cell Corridor Mid
|
|
new Vector3(-27f, 0f, 16f), // WP11: Isolation Cell 5
|
|
new Vector3(-35f, 0f, 23f), // WP12: Quarantine Cell Corridor North
|
|
// Chemical Silos & North Bypass
|
|
new Vector3(-37f, 0f, 38f), // WP13: Chemical Silos
|
|
new Vector3(-37f, 0f, 47.5f), // WP14: North Bypass West
|
|
new Vector3(-15f, 0f, 47.5f), // WP15: North Bypass Mid-West
|
|
// Reactor Turbine Hall (Very Spacious)
|
|
new Vector3(-10f, 0f, 38f), // WP16: Reactor Turbine Alpha
|
|
new Vector3(0f, 0f, 38f), // WP17: Reactor Core Platform
|
|
new Vector3(10f, 0f, 38f), // WP18: Reactor Turbine Beta
|
|
// Substation & East North Bypass
|
|
new Vector3(25f, 0f, 47.5f), // WP19: North Bypass East
|
|
new Vector3(37f, 0f, 38f), // WP20: Power Substation
|
|
// Genetics & Cybernetics
|
|
new Vector3(37f, 0f, 22f), // WP21: Genetics Lab North
|
|
new Vector3(37f, 0f, 10f), // WP22: Genetics Lab South
|
|
// Grand Atrium (Very Spacious)
|
|
new Vector3(12f, 0f, 9f), // WP23: Grand Atrium East Colonnade
|
|
new Vector3(0f, 0f, 18f), // WP24: Grand Atrium North Observation
|
|
new Vector3(-12f, 0f, 9f), // WP25: Grand Atrium West Colonnade
|
|
new Vector3(0f, 0f, 0f), // WP26: Grand Atrium South Portal
|
|
// East Slalom & Surgical ICU
|
|
new Vector3(21f, 0f, 0f), // WP27: East Slalom Corridor
|
|
new Vector3(37f, 0f, -4f), // WP28: Surgical ICU North
|
|
new Vector3(37f, 0f, -14f), // WP29: Surgical ICU South
|
|
// Security Armory & Return to Concourse
|
|
new Vector3(37f, 0f, -37f), // WP30: Security Armory
|
|
new Vector3(18f, 0f, -30f) // WP31: Concourse East
|
|
};
|
|
|
|
Transform[] transforms = new Transform[waypoints.Length];
|
|
for (int i = 0; i < waypoints.Length; i++)
|
|
{
|
|
var wpGo = new GameObject($"Waypoint_{i}");
|
|
wpGo.transform.SetParent(patrolParent.transform);
|
|
wpGo.transform.position = waypoints[i];
|
|
transforms[i] = wpGo.transform;
|
|
}
|
|
|
|
if (enemy != null)
|
|
{
|
|
// Position enemy in South Concourse right outside the starting airlock
|
|
enemy.transform.position = new Vector3(0f, 0.08f, -28f);
|
|
enemy.transform.rotation = Quaternion.Euler(0f, 90f, 0f);
|
|
var ai = enemy.GetComponent<BlindMutantAI>();
|
|
if (ai != null)
|
|
{
|
|
Undo.RecordObject(ai, "Setup Patrol Points");
|
|
ai.patrolPoints = transforms;
|
|
EditorUtility.SetDirty(ai);
|
|
EditorUtility.SetDirty(enemy);
|
|
Debug.Log($"<color=green>Configured {transforms.Length} patrol points for SkinnyOrc BlindMutantAI in South Concourse (0, 0.08, -28)!</color>");
|
|
}
|
|
}
|
|
}
|
|
}
|