private Dictionary <Vec2i, ChunkStructure> GenerateElementalDungeonEntranceStructures() { Dictionary <Vec2i, ChunkStructure> elDunShells = new Dictionary <Vec2i, ChunkStructure>(); //iterate all counts for (int i = 0; i < 4; i++) { //We make5 attempts to find a valid place for each bandit camp for (int a = 0; a < 5; a++) { //Generate random position and size Vec2i position = GenerationRandom.RandomFromList(GameGenerator.TerrainGenerator.LandChunks); Vec2i size = GenerationRandom.RandomVec2i(1, 3); //Check if position is valid, if (IsPositionValid(position)) { //if valid, we add the structure to ChunkBases and to the dictionary of shells ChunkStructure banditCampShell = new BanditCamp(position, size); for (int x = 0; x < size.x; x++) { for (int z = 0; z < size.z; z++) { GameGenerator.TerrainGenerator.ChunkBases[position.x + x, position.z + z].AddChunkStructure(banditCampShell); } } elDunShells.Add(position, banditCampShell); } } } return(elDunShells); }
/// Get functions for settlement and chunk structures #region ordered_gets /// <summary> /// Searches all settlements to find a random one within 'allowedDistance' regions /// of the defined position. /// </summary> /// <param name="centrePoint"></param> /// <param name="allowedDistance"></param> /// <returns></returns> private Settlement GetRandomSettlement(Vec2i centrePoint, int allowedDistance) { //We first collect all regions close to the required region List <Vec2i> allowedRegions = new List <Vec2i>(); for (int x = -allowedDistance; x <= allowedDistance; x++) { for (int z = -allowedDistance; z <= allowedDistance; z++) { allowedRegions.Add(centrePoint + new Vec2i(x, z)); } } //Keep running loop until a valid settlement is found bool isValid = false; while (!isValid) { //Choose random region Vec2i reg = GenRan.RandomFromList(allowedRegions); //If the selected region contains at least one settlment, randomly select one if (OrderedSettlements.ContainsKey(reg) && OrderedSettlements[reg].Count > 0) { return(GenRan.RandomFromList(OrderedSettlements[reg])); } else { //If no settlements, remove it from the list of allowed regions //to prevent selecting it twice allowedRegions.Remove(reg); } } return(null); }
public Vec2i FindSpace(Kingdom kingdom, int size) { int attempts = 0; while (attempts < 20) { Vec2i v = null; if (kingdom == null) { v = GenerationRandom.RandomFromList(GameGenerator.TerrainGenerator.LandChunks); } else { v = GenerationRandom.RandomFromList(KingdomChunks[kingdom]); } bool canDo = true; //Check point allows settlement within bounds if (v.x - size < 0 || v.x + size > World.WorldSize - 1 || v.z - size < 0 || v.z + size > World.WorldSize - 1) { canDo = false; } else { for (int x = -size; x <= size; x++) { for (int z = -size; z <= size; z++) { int cx = x + v.x; int cz = z + v.z; ChunkBase cb = TerrainGenerator.ChunkBases[cx, cz]; if (cb.Kingdom != kingdom || cb.HasSettlement || !cb.IsLand) { canDo = false; } else if (cb.RiverNode != null || cb.Lake != null) { canDo = false; } /* * else if (TerrainGenerator.ChunkBases[Mathf.Clamp(x + v.x, 0, World.WorldSize - 1), Mathf.Clamp(z + v.z, 0, World.WorldSize - 1)].Kingdom != kingdom) * canDo = false; * else if (TerrainGenerator.ChunkBases[Mathf.Clamp(x + v.x, 0, World.WorldSize - 1), Mathf.Clamp(z + v.z, 0, World.WorldSize - 1)].Settlement != null) * canDo = false; * else if (!TerrainGenerator.ChunkBases[Mathf.Clamp(x + v.x, 0, World.WorldSize - 1), Mathf.Clamp(z + v.z, 0, World.WorldSize - 1)].IsLand) * canDo = false; */ } } } if (canDo) { return(v); } attempts++; } return(null); }
private Vec2i ChooseValidChunk() { Vec2i pos = GenRan.RandomFromList(GameGenerator.TerrainGenerator.LandChunks); while (!IsPositionValid(pos)) { pos = GenRan.RandomFromList(GameGenerator.TerrainGenerator.LandChunks); } return(pos); }
private River GenerateRiver(Vec2i start, Vec2i mainDirection, GenerationRandom genRan) { bool shouldStop = false; River r = new River(); r.SetFirstChunk(start, 5); List <Vec2i> directions = new List <Vec2i>(); directions.Add(mainDirection); directions.Add(mainDirection); directions.Add(mainDirection); directions.Add(mainDirection); directions.AddRange(PerpDir(mainDirection)); Vec2i last = start; while (!shouldStop) { Vec2i next = last + genRan.RandomFromList <Vec2i>(directions); if (r.AddChunk(next, 5)) { last = next; if (next.x < 0 || next.z < 0 || next.x >= World.WorldSize || next.z >= World.WorldSize) { shouldStop = true; } else if (!GameGenerator.TerrainGenerator.ChunkBases[next.x, next.z].IsLand) { shouldStop = true; } } } return(r); }
public GridPoint GetFreeGridPoint(int clearance, int attempts = 5) { if (attempts == -1) { return(null); } attempts--; GridPoint testPoint = GenRan.RandomFromList(FreePoints); for (int x = -clearance; x <= clearance; x++) { for (int z = -clearance; z <= clearance; z++) { Vec2i p = testPoint.GridPos + new Vec2i(x, z); if (GridPlacement.InGridBounds(p)) { GridPoint gp = GameGen.GridPlacement.GridPoints[p.x, p.z]; if (gp == null) { continue; } if (gp.HasNonSettlementStructure) { return(GetFreeGridPoint(clearance, attempts)); } } } } FreePoints.Remove(testPoint); testPoint.HasNonSettlementStructure = true; return(testPoint); }
public Entity ChooseRandomEntity(GenerationRandom ran = null) { Debug.Log(AllEntities.Count); if (ran == null) { return(GameManager.RNG.RandomFromList(AllEntities)); } return(ran.RandomFromList(AllEntities)); }
public SettlementPathNode CreatePathFromNode(SettlementPathNode node, int width, bool extraLength = false, int chosenDirection = -1, int length = -1) { //If no direction is given, choose a null one if (chosenDirection == -1) { List <int> nullDirection = new List <int>(); for (int i = 0; i < 4; i++) { if (node.Connected[i] == null) { nullDirection.Add(i); } } Debug.Log(nullDirection.Count); //Choose a valid direction and find the vector step chosenDirection = GenerationRandom.RandomFromList(nullDirection); } Vec2i step = SettlementPathNode.GetDirection(chosenDirection); //If no length is given or given length is invalid, choose a path length if (length == -1 || !InBounds(node.Position + step * length)) { int attemptLength = length == -1 ? GenerationRandom.RandomInt(40, TileSize) : length; while (!InBounds(node.Position + step * attemptLength)) { attemptLength -= 1; } length = attemptLength; } int halfWidth = width / 2; Vec2i perpDirection = SettlementPathNode.GetPerpendicular(chosenDirection); if (extraLength) { length += halfWidth; } for (int l = 0; l < length; l++) { for (int w = -halfWidth; w <= halfWidth; w++) { Vec2i pos = node.Position + step * l + perpDirection * w; SetTile(pos.x, pos.z, Tile.TEST_BLUE); } } SettlementPathNode endNode = new SettlementPathNode(node.Position + step * length); node.AddConnection(chosenDirection, endNode); endNode.AddConnection(SettlementPathNode.OppositeDirection(chosenDirection), node); return(endNode); }
/// <summary> /// Decides the tile placement in settlement coordinates of all entrances, based on /// the entrance direction data <see cref="Shell.LocationData"/> /// </summary> /// <returns></returns> private Vec2i DecideSettlementEntrance() { List <Vec2i> entrances = new List <Vec2i>(); for (int i = 0; i < 8; i += 2) { int ip1 = (i + 1) % 8; if (Shell.LocationData.EntranceDirections[i] || Shell.LocationData.EntranceDirections[ip1]) { Vec2i side = Vec2i.QUAD_DIR[i / 2]; float xAmount = GenerationRandom.Random(0.8f, 0.95f) * side.x; float zAmount = GenerationRandom.Random(0.8f, 0.95f) * side.z; Vec2i pos = Middle + new Vec2i((int)(xAmount * TileSize / 2), (int)(zAmount * TileSize / 2)); entrances.Add(pos); } } return(GenerationRandom.RandomFromList(entrances)); }
/// <summary> /// Places the dungeon key in a random structure. /// /// </summary> /// <param name="dungeonPos"></param> /// <param name="chunkStructure"></param> /// <param name="endTasks"></param> /// <returns></returns> private Quest GenerateDungeonKeyQuest_RandomStructure(Vec2i dungeonPos, Dungeon dungeon, List <QuestTask> endTasks) { //Find a random chunk structure ChunkStructure ranStruct = GetRandomFreeStructure(dungeonPos, 3); if (ranStruct == null) { throw new System.Exception("We need to fix this"); } //We add the dungeon key to the loot chest of this structure ranStruct.FinalLootChest.GetInventory().AddItem(dungeon.GetKey()); //Add the item finding task endTasks.Add(new QuestTask("Go to " + ranStruct.Name + " and collect the key", QuestTask.QuestTaskType.PICK_UP_ITEM, new object[] { dungeon.GetKey(), ranStruct.WorldMapLocation, (ranStruct.FinalLootChest as WorldObjectData).WorldPosition })); //Quest initiator will be a random entity //Therefore, we choose a random settlement Settlement set = GetRandomSettlement(dungeonPos, 5); //Then take a random npc from it. NPC npc = GameManager.EntityManager.GetEntityFromID(GenRan.RandomFromList(set.SettlementNPCIDs)) as NPC; QuestInitiator questInit = new QuestInitiator(QuestInitiator.InitiationType.TALK_TO_NPC, new object[] { npc, false }); //We now reverse the tasks to get in correct order endTasks.Reverse(); Quest quest = new Quest("Clear dungeon " + questCount, questInit, endTasks.ToArray(), QuestType.clear_dungeon); if (npc.Dialog == null) { NPCDialog dialog = new NPCDialog(npc, "Hello adventurer! How can I help you today?"); NPCDialogNode exitNode = new NPCDialogNode("Don't worry, I'll be on my way", ""); exitNode.IsExitNode = true; dialog.AddNode(exitNode); npc.SetDialog(dialog); } NPCDialogNode startQuestNode = new NPCDialogNode("Have you heard of any quests for an adventurer such as myself?", "I've heard of a dungeon that may be full of sweet shit." + " It's probably locked though, last I heard the key was at " + ranStruct.Name); NPCDialogNode exitNode2 = new NPCDialogNode("Thanks! I'll be on my way", ""); exitNode2.IsExitNode = true; startQuestNode.AddNode(exitNode2); npc.Dialog.AddNode(startQuestNode); startQuestNode.SetOnSelectFunction(() => { GameManager.QuestManager.StartQuest(quest); }); startQuestNode.SetShouldDisplayFunction(() => { if (GameManager.QuestManager.Unstarted.Contains(quest)) { return(true); } return(false); }); NPCDialogNode questRewardNode = new NPCDialogNode("I killed " + dungeon.Boss.Name, "I didn't think it was possible. Here, take this as a reward"); questRewardNode.AddNode(exitNode2); questRewardNode.SetShouldDisplayFunction(() => { return(GameManager.QuestManager.Completed.Contains(quest)); }); questRewardNode.SetOnSelectFunction(() => { Inventory playerInv = GameManager.PlayerManager.Player.Inventory; playerInv.AddItem(new SteelLongSword()); }); npc.Dialog.AddNode(questRewardNode); return(quest); }
private void ClaimChunks(Kingdom[] kings) { int[,] claimedChunkKingdomIDs = new int[World.WorldSize, World.WorldSize]; bool[,] obstruction = new bool[World.WorldSize, World.WorldSize]; for (int x = 0; x < World.WorldSize; x++) { for (int z = 0; z < World.WorldSize; z++) { claimedChunkKingdomIDs[x, z] = -1; if (GameGen.TerGen.ChunkBases[x, z].Biome is ChunkBiome.ocean) { obstruction[x, z] = true; } else if (GameGen.TerGen.ChunkBases[x, z].ChunkFeature is ChunkRiverNode) { obstruction[x, z] = true; } //else if (GameGen.TerGen.EvilDragonMountainPeak.QuickDistance(new Vec2i(x, z)) < 128 * 128) // obstruction[x, z] = true; } } Dictionary <Kingdom, List <Vec2i> > freeBorder = new Dictionary <Kingdom, List <Vec2i> >(); foreach (Kingdom k in kings) { ClaimedChunks.Add(k, new List <Vec2i>(250000)); ClaimedChunks[k].Add(k.CapitalChunk); freeBorder.Add(k, new List <Vec2i>(2000)); freeBorder[k].Add(k.CapitalChunk); } bool shouldRun = true; while (shouldRun) { shouldRun = false; foreach (Kingdom k in kings) { if (freeBorder[k].Count == 0) { continue; } shouldRun = true; //We randomly select a border point and remove it from the list Vec2i curBorder = GenRan.RandomFromList(freeBorder[k]); freeBorder[k].Remove(curBorder); foreach (Vec2i v in Vec2i.QUAD_DIR) { //We iterate all 8 surrounding chunks Vec2i p = curBorder + v; //if there is an obstruction we cannot claim the chunk if (obstruction[p.x, p.z]) { continue; } if (claimedChunkKingdomIDs[p.x, p.z] == -1) { claimedChunkKingdomIDs[p.x, p.z] = k.KingdomID; freeBorder[k].Add(p); ClaimedChunks[k].Add(p); } } } } foreach (Kingdom k in Kingdoms) { k.ClaimedChunks = ClaimedChunks[k]; } for (int x = 0; x < World.WorldSize; x++) { for (int z = 0; z < World.WorldSize; z++) { GameGen.TerGen.ChunkBases[x, z].KingdomID = claimedChunkKingdomIDs[x, z]; } } return; }
/* * private void FromRiverSource(Vec2i source, Vec2i mainDir) * { * * int i = 0; * Vec2i end = null; * Vec2i current = source; * //Ray cast from the source to find the ocean point at this rivers end * while(end == null) * { * i++; * current += mainDir; * if(ChunkBases[current.x, current.z].Biome == ChunkBiome.ocean) * { * end = current; * } * if (i > World.WorldSize) * return; * * } * i = 0; * * Vec2i last = source; * * current = source + mainDir; * bool isDone = false; * * Vector2 lastDir = (end - current).AsVector2().normalized; * Vector2 exactCurrent = current.AsVector2(); * * List<Vec2i> river = new List<Vec2i>(); * * while (!isDone) * { * * * * i++; * // Vector2 currentFlow = FlowField[current.x, current.z]; * * float fx = PerlinNoise(current.x, current.z, 36)*2 - 1; * float fz = PerlinNoise(current.x, current.z, 37)*2 - 1; * Vector2 noiseFlow = new Vector2(fx, fz); * Vector2 flowField = FlowField[current.x, current.z]; * Vector2 targetFlow = (end - current).AsVector2().normalized; * * Vector2 flow = (noiseFlow + 4 * targetFlow + 3 * flowField).normalized; * exactCurrent += flow; * current = Vec2i.FromVector2(exactCurrent); * int check = Mathf.Min(river.Count, 5); * bool isValid = true; * for(int j=0; j< check; j++) * { * if (river[river.Count - j - 1] == current) * isValid = false; * } * if (!isValid) * { * current += mainDir; * exactCurrent = current.AsVector2(); * } * * * if (ChunkBases[current.x, current.z].Biome == ChunkBiome.ocean) * isDone = true; * ChunkBases[current.x, current.z].SetChunkFeature(new ChunkRiverNode()); * river.Add(current); * if (i > 2048) * return; * * } * * * }*/ private void ReverseFlowRiver(Vec2i start, int length, int distSinceFork = 0) { //Give rivers a slight biase towards the middle of the map Vector2 bias = -(new Vector2(World.WorldSize / 2, World.WorldSize / 2) - start.AsVector2()).normalized; Vec2i current = start; Vector2 fullCurrent = current.AsVector2(); Vec2i last = Vec2i.FromVector2(fullCurrent + bias); List <FlowPoint> inputFlowPoints = new List <FlowPoint>(5); for (int i = 0; i < length; i++) { distSinceFork++; inputFlowPoints.Clear(); //if this chunk is a river node already, we have reached the end of this river branch if (ChunkBases[current.x, current.z].ChunkFeature is ChunkRiverNode) { //return; } //Add a river node here ChunkBases[current.x, current.z].SetChunkFeature(new ChunkRiverNode(current)); //We iterate each of the near chunks foreach (Vec2i v in Vec2i.OCT_DIRDIR) { //Coordinate of point of interest Vec2i p = v + current; //If this is the point we just came from, ignore it if (last == p) { continue; } Vector2 vFlow = FlowField[p.x, p.z]; //Find the coordinate that this point flows into Vec2i pointFlowPos = Vec2i.FromVector2(p.AsVector2() + vFlow); //Check if this point flows into our current point if (pointFlowPos == current) { FlowPoint fp = new FlowPoint(); fp.Pos = p; fp.Dir = vFlow; inputFlowPoints.Add(fp); } } //If no points flow here, then the river has reached an end (add lakes?) if (inputFlowPoints.Count == 0) { Debug.Log("zero flow"); Vector2 currentToLast = (current - last).AsVector2(); fullCurrent = fullCurrent - currentToLast; //Debug.Log("zero error..."); //return; } else if (inputFlowPoints.Count == 1) { Debug.Log("single flow"); fullCurrent = fullCurrent - inputFlowPoints[0].Dir; } else { if (distSinceFork < 40) { fullCurrent = fullCurrent - GenRan.RandomFromList(inputFlowPoints).Dir; Debug.Log("No fork - dist"); } else { Debug.Log("fork"); //If we are over 40, then we can create a fork //only 2 forks maximum while (inputFlowPoints.Count > 2) { inputFlowPoints.RemoveAt(GenRan.RandomInt(0, inputFlowPoints.Count)); } ReverseFlowRiver(inputFlowPoints[0].Pos, length - i, 0); ReverseFlowRiver(inputFlowPoints[1].Pos, length - i, 0); Debug.Log("forks"); return; } } last = new Vec2i(current.x, current.z); current = Vec2i.FromVector2(fullCurrent); /* * //We iterate all directions * Vector2 grad = (FlowField[current.x, current.z] + 0.1f * bias).normalized; * fullCurrent = fullCurrent - grad; * current = Vec2i.FromVector2(fullCurrent); */ } }