public void CreateItems() { WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub); if (wp == null) { DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!"); return; } Hull cargoRoom = Hull.FindHull(wp.WorldPosition); if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } foreach (ItemPrefab prefab in purchasedItems) { Vector2 position = new Vector2( Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20), cargoRoom.Rect.Y - cargoRoom.Rect.Height + prefab.Size.Y / 2); new Item(prefab, position, wp.Submarine); } purchasedItems.Clear(); }
protected Vector2?GetCargoSpawnPosition(ItemPrefab itemPrefab, out Submarine cargoRoomSub) { cargoRoomSub = null; WayPoint cargoSpawnPos = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub, useSyncedRand: true); if (cargoSpawnPos == null) { DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": no waypoints marked as Cargo were found"); return(null); } var cargoRoom = cargoSpawnPos.CurrentHull; if (cargoRoom == null) { DebugConsole.ThrowError($"Couldn't spawn items for mission \"{Name}\": waypoints marked as Cargo must be placed inside a room"); return(null); } cargoRoomSub = cargoRoom.Submarine; return(new Vector2( cargoSpawnPos.Position.X + Rand.Range(-20.0f, 20.0f, Rand.RandSync.Server), cargoRoom.Rect.Y - cargoRoom.Rect.Height + itemPrefab.Size.Y / 2)); }
private void QuickStart() { Submarine selectedSub = null; string subName = GameMain.Config.QuickStartSubmarineName; if (!string.IsNullOrEmpty(subName)) { DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White); selectedSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name.ToLower() == subName.ToLower()); if (selectedSub == null) { DebugConsole.NewMessage($"Cannot find a sub that matches the name \"{subName}\".", Color.Red); } } if (selectedSub == null) { DebugConsole.NewMessage("Loading a random sub.", Color.White); var subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.Shuttle) && !s.HasTag(SubmarineTag.HideInMenus)); selectedSub = subs.ElementAt(Rand.Int(subs.Count())); } var gamesession = new GameSession( selectedSub, "Data/Saves/test.xml", GameModePreset.List.Find(gm => gm.Identifier == "devsandbox"), missionPrefab: null); //(gamesession.GameMode as SinglePlayerCampaign).GenerateMap(ToolBox.RandomSeed(8)); gamesession.StartRound(ToolBox.RandomSeed(8)); GameMain.GameScreen.Select(); string[] jobIdentifiers = new string[] { "captain", "engineer", "mechanic" }; for (int i = 0; i < 3; i++) { var spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); if (spawnPoint == null) { DebugConsole.ThrowError("No spawnpoints found in the selected submarine. Quickstart failed."); GameMain.MainMenuScreen.Select(); return; } var characterInfo = new CharacterInfo( Character.HumanConfigFile, jobPrefab: JobPrefab.List.Find(j => j.Identifier == jobIdentifiers[i])); if (characterInfo.Job == null) { DebugConsole.ThrowError("Failed to find the job \"" + jobIdentifiers[i] + "\"!"); } var newCharacter = Character.Create(Character.HumanConfigFile, spawnPoint.WorldPosition, ToolBox.RandomSeed(8), characterInfo); newCharacter.GiveJobItems(spawnPoint); gamesession.CrewManager.AddCharacter(newCharacter); Character.Controlled = newCharacter; } }
private void LoadItemAsChild(XElement element, Item parent) { string itemName = element.GetAttributeString("name", ""); ItemPrefab itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab; if (itemPrefab == null) { DebugConsole.ThrowError("Couldn't spawn item for cargo mission: item prefab \"" + element.Name.ToString() + "\" not found"); return; } WayPoint cargoSpawnPos = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub, true); if (cargoSpawnPos == null) { DebugConsole.ThrowError("Couldn't spawn items for cargo mission, cargo spawnpoint not found"); return; } var cargoRoom = cargoSpawnPos.CurrentHull; if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } Vector2 position = new Vector2( cargoSpawnPos.Position.X + Rand.Range(-20.0f, 20.0f, Rand.RandSync.Server), cargoRoom.Rect.Y - cargoRoom.Rect.Height + itemPrefab.Size.Y / 2); var item = new Item(itemPrefab, position, cargoRoom.Submarine); item.FindHull(); items.Add(item); if (parent != null) { parent.Combine(item); } foreach (XElement subElement in element.Elements()) { int amount = subElement.GetAttributeInt("amount", 1); for (int i = 0; i < amount; i++) { LoadItemAsChild(subElement, item); } } }
protected Character CreateHuman(HumanPrefab humanPrefab, List <Character> characters, Dictionary <Character, List <Item> > characterItems, Submarine submarine, CharacterTeamType teamType, ISpatialEntity positionToStayIn = null, Rand.RandSync humanPrefabRandSync = Rand.RandSync.Server, bool giveTags = true) { if (positionToStayIn == null) { positionToStayIn = WayPoint.GetRandom(SpawnType.Human, null, submarine); } var characterInfo = humanPrefab.GetCharacterInfo(Rand.RandSync.Server) ?? new CharacterInfo(CharacterPrefab.HumanSpeciesName, npcIdentifier: humanPrefab.Identifier, jobPrefab: humanPrefab.GetJobPrefab(humanPrefabRandSync), randSync: humanPrefabRandSync); characterInfo.TeamID = teamType; Character spawnedCharacter = Character.Create(characterInfo.SpeciesName, positionToStayIn.WorldPosition, ToolBox.RandomSeed(8), characterInfo, createNetworkEvent: false); spawnedCharacter.Prefab = humanPrefab; humanPrefab.InitializeCharacter(spawnedCharacter, positionToStayIn); humanPrefab.GiveItems(spawnedCharacter, submarine, Rand.RandSync.Server, createNetworkEvents: false); characters.Add(spawnedCharacter); characterItems.Add(spawnedCharacter, spawnedCharacter.Inventory.FindAllItems(recursive: true)); return(spawnedCharacter); }
static DebugConsole() { commands.Add(new Command("help", "", (string[] args) => { if (args.Length == 0) { foreach (Command c in commands) { if (string.IsNullOrEmpty(c.help)) { continue; } NewMessage(c.help, Color.Cyan); } } else { var matchingCommand = commands.Find(c => c.names.Any(name => name == args[0])); if (matchingCommand == null) { NewMessage("Command " + args[0] + " not found.", Color.Red); } else { NewMessage(matchingCommand.help, Color.Cyan); } } })); commands.Add(new Command("clientlist", "clientlist: List all the clients connected to the server.", (string[] args) => { if (GameMain.Server == null) { return; } NewMessage("***************", Color.Cyan); foreach (Client c in GameMain.Server.ConnectedClients) { NewMessage("- " + c.ID.ToString() + ": " + c.name + ", " + c.Connection.RemoteEndPoint.Address.ToString(), Color.Cyan); } NewMessage("***************", Color.Cyan); })); commands.Add(new Command("createfilelist", "", (string[] args) => { UpdaterUtil.SaveFileList("filelist.xml"); })); commands.Add(new Command("spawn|spawncharacter", "spawn [creaturename] [near/inside/outside]: Spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine).", (string[] args) => { if (args.Length == 0) { return; } Character spawnedCharacter = null; Vector2 spawnPosition = Vector2.Zero; WayPoint spawnPoint = null; if (args.Length > 1) { switch (args[1].ToLowerInvariant()) { case "inside": spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); break; case "outside": spawnPoint = WayPoint.GetRandom(SpawnType.Enemy); break; case "near": case "close": float closestDist = -1.0f; foreach (WayPoint wp in WayPoint.WayPointList) { if (wp.Submarine != null) { continue; } //don't spawn inside hulls if (Hull.FindHull(wp.WorldPosition, null) != null) { continue; } float dist = Vector2.Distance(wp.WorldPosition, GameMain.GameScreen.Cam.WorldViewCenter); if (closestDist < 0.0f || dist < closestDist) { spawnPoint = wp; closestDist = dist; } } break; case "cursor": spawnPosition = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); break; default: spawnPoint = WayPoint.GetRandom(args[0].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy); break; } } else { spawnPoint = WayPoint.GetRandom(args[0].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy); } if (string.IsNullOrWhiteSpace(args[0])) { return; } if (spawnPoint != null) { spawnPosition = spawnPoint.WorldPosition; } if (args[0].ToLowerInvariant() == "human") { spawnedCharacter = Character.Create(Character.HumanConfigFile, spawnPosition); #if CLIENT if (GameMain.GameSession != null) { SinglePlayerMode mode = GameMain.GameSession.gameMode as SinglePlayerMode; if (mode != null) { Character.Controlled = spawnedCharacter; GameMain.GameSession.CrewManager.AddCharacter(Character.Controlled); GameMain.GameSession.CrewManager.SelectCharacter(null, Character.Controlled); } } #endif } else { spawnedCharacter = Character.Create( "Content/Characters/" + args[0].First().ToString().ToUpper() + args[0].Substring(1) + "/" + args[0].ToLower() + ".xml", spawnPosition); } })); commands.Add(new Command("spawnitem", "spawnitem [itemname] [cursor/inventory]: Spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted.", (string[] args) => { if (args.Length < 1) { return; } Vector2?spawnPos = null; Inventory spawnInventory = null; int extraParams = 0; switch (args.Last()) { case "cursor": extraParams = 1; spawnPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); break; case "inventory": extraParams = 1; spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory; break; default: extraParams = 0; break; } string itemName = string.Join(" ", args.Take(args.Length - extraParams)).ToLowerInvariant(); var itemPrefab = MapEntityPrefab.list.Find(ip => ip.Name.ToLowerInvariant() == itemName) as ItemPrefab; if (itemPrefab == null) { ThrowError("Item \"" + itemName + "\" not found!"); return; } if (spawnPos == null && spawnInventory == null) { var wp = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); spawnPos = wp == null ? Vector2.Zero : wp.WorldPosition; } if (spawnPos != null) { Entity.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos); } else if (spawnInventory != null) { Entity.Spawner.AddToSpawnQueue(itemPrefab, spawnInventory); } })); commands.Add(new Command("disablecrewai", "disablecrewai: Disable the AI of the NPCs in the crew.", (string[] args) => { HumanAIController.DisableCrewAI = true; NewMessage("Crew AI disabled", Color.White); })); commands.Add(new Command("enablecrewai", "enablecrewai: Enable the AI of the NPCs in the crew.", (string[] args) => { HumanAIController.DisableCrewAI = false; NewMessage("Crew AI enabled", Color.White); })); commands.Add(new Command("kick", "kick [name]: Kick a player out of the server.", (string[] args) => { if (GameMain.NetworkMember == null || args.Length == 0) { return; } string playerName = string.Join(" ", args); ShowQuestionPrompt("Reason for kicking \"" + playerName + "\"?", (reason) => { GameMain.NetworkMember.KickPlayer(playerName, reason); }); })); commands.Add(new Command("kickid", "kickid [id]: Kick the player with the specified client ID out of the server.", (string[] args) => { if (GameMain.Server == null || args.Length == 0) { return; } int id = 0; int.TryParse(args[0], out id); var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id); if (client == null) { ThrowError("Client id \"" + id + "\" not found."); return; } ShowQuestionPrompt("Reason for kicking \"" + client.name + "\"?", (reason) => { GameMain.Server.KickPlayer(client.name, reason); }); })); commands.Add(new Command("ban", "ban [name]: Kick and ban the player from the server.", (string[] args) => { if (GameMain.NetworkMember == null || args.Length == 0) { return; } string clientName = string.Join(" ", args); ShowQuestionPrompt("Reason for banning \"" + clientName + "\"?", (reason) => { ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) => { TimeSpan?banDuration = null; if (!string.IsNullOrWhiteSpace(duration)) { TimeSpan parsedBanDuration; if (!TryParseTimeSpan(duration, out parsedBanDuration)) { ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\"."); return; } banDuration = parsedBanDuration; } GameMain.NetworkMember.BanPlayer(clientName, reason, false, banDuration); }); }); })); commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server.", (string[] args) => { if (GameMain.Server == null || args.Length == 0) { return; } int id = 0; int.TryParse(args[0], out id); var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id); if (client == null) { ThrowError("Client id \"" + id + "\" not found."); return; } ShowQuestionPrompt("Reason for banning \"" + client.name + "\"?", (reason) => { ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) => { TimeSpan?banDuration = null; if (!string.IsNullOrWhiteSpace(duration)) { TimeSpan parsedBanDuration; if (!TryParseTimeSpan(duration, out parsedBanDuration)) { ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\"."); return; } banDuration = parsedBanDuration; } GameMain.Server.BanPlayer(client.name, reason, false, banDuration); }); }); })); commands.Add(new Command("banip", "banip [ip]: Ban the IP address from the server.", (string[] args) => { if (GameMain.Server == null || args.Length == 0) { return; } ShowQuestionPrompt("Reason for banning the ip \"" + commands[1] + "\"?", (reason) => { ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) => { TimeSpan?banDuration = null; if (!string.IsNullOrWhiteSpace(duration)) { TimeSpan parsedBanDuration; if (!TryParseTimeSpan(duration, out parsedBanDuration)) { ThrowError("\"" + duration + "\" is not a valid ban duration. Use the format \"[days] d [hours] h\", \"[days] d\" or \"[hours] h\"."); return; } banDuration = parsedBanDuration; } var client = GameMain.Server.ConnectedClients.Find(c => c.Connection.RemoteEndPoint.Address.ToString() == args[0]); if (client == null) { GameMain.Server.BanList.BanPlayer("Unnamed", args[0], reason, banDuration); } else { GameMain.Server.KickClient(client, reason); } }); }); })); commands.Add(new Command("teleportcharacter|teleport", "teleport [character name]: Teleport the specified character to the position of the cursor. If the name parameter is omitted, the controlled character will be teleported.", (string[] args) => { Character tpCharacter = null; if (args.Length == 0) { tpCharacter = Character.Controlled; } else { tpCharacter = FindMatchingCharacter(args, false); } if (tpCharacter == null) { return; } var cam = GameMain.GameScreen.Cam; tpCharacter.AnimController.CurrentHull = null; tpCharacter.Submarine = null; tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition))); tpCharacter.AnimController.FindHull(cam.ScreenToWorld(PlayerInput.MousePosition), true); })); commands.Add(new Command("godmode", "godmode: Toggle submarine godmode. Makes the main submarine invulnerable to damage.", (string[] args) => { if (Submarine.MainSub == null) { return; } Submarine.MainSub.GodMode = !Submarine.MainSub.GodMode; NewMessage(Submarine.MainSub.GodMode ? "Godmode on" : "Godmode off", Color.White); })); commands.Add(new Command("lockx", "lockx: Lock horizontal movement of the main submarine.", (string[] args) => { Submarine.LockX = !Submarine.LockX; })); commands.Add(new Command("locky", "loxky: Lock vertical movement of the main submarine.", (string[] args) => { Submarine.LockY = !Submarine.LockY; })); commands.Add(new Command("dumpids", "", (string[] args) => { try { int count = args.Length == 0 ? 10 : int.Parse(args[0]); Entity.DumpIds(count); } catch (Exception e) { ThrowError("Failed to dump ids", e); } })); commands.Add(new Command("heal", "heal [character name]: Restore the specified character to full health. If the name parameter is omitted, the controlled character will be healed.", (string[] args) => { Character healedCharacter = null; if (args.Length == 0) { healedCharacter = Character.Controlled; } else { healedCharacter = FindMatchingCharacter(args); } if (healedCharacter != null) { healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null); healedCharacter.Oxygen = 100.0f; healedCharacter.Bleeding = 0.0f; healedCharacter.SetStun(0.0f, true); } })); commands.Add(new Command("revive", "revive [character name]: Bring the specified character back from the dead. If the name parameter is omitted, the controlled character will be revived.", (string[] args) => { Character revivedCharacter = null; if (args.Length == 0) { revivedCharacter = Character.Controlled; } else { revivedCharacter = FindMatchingCharacter(args); } if (revivedCharacter == null) { return; } revivedCharacter.Revive(false); if (GameMain.Server != null) { foreach (Client c in GameMain.Server.ConnectedClients) { if (c.Character != revivedCharacter) { continue; } //clients stop controlling the character when it dies, force control back GameMain.Server.SetClientCharacter(c, revivedCharacter); break; } } })); commands.Add(new Command("freeze", "", (string[] args) => { if (Character.Controlled != null) { Character.Controlled.AnimController.Frozen = !Character.Controlled.AnimController.Frozen; } })); commands.Add(new Command("freecamera|freecam", "freecam: Detach the camera from the controlled character.", (string[] args) => { Character.Controlled = null; GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; })); commands.Add(new Command("water|editwater", "water/editwater: Toggle water editing. Allows adding water into rooms by holding the left mouse button and removing it by holding the right mouse button.", (string[] args) => { if (GameMain.Client == null) { Hull.EditWater = !Hull.EditWater; NewMessage(Hull.EditWater ? "Water editing on" : "Water editing off", Color.White); } })); commands.Add(new Command("fire|editfire", "fire/editfire: Allows putting up fires by left clicking.", (string[] args) => { if (GameMain.Client == null) { Hull.EditFire = !Hull.EditFire; NewMessage(Hull.EditFire ? "Fire spawning on" : "Fire spawning off", Color.White); } })); commands.Add(new Command("explosion", "explosion [range] [force] [damage] [structuredamage]: Creates an explosion at the position of the cursor.", (string[] args) => { Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); float range = 500, force = 10, damage = 50, structureDamage = 10; if (args.Length > 0) { float.TryParse(args[0], out range); } if (args.Length > 1) { float.TryParse(args[1], out force); } if (args.Length > 2) { float.TryParse(args[2], out damage); } if (args.Length > 3) { float.TryParse(args[3], out structureDamage); } new Explosion(range, force, damage, structureDamage).Explode(explosionPos); })); commands.Add(new Command("fixitems", "fixitems: Repairs all items and restores them to full condition.", (string[] args) => { foreach (Item it in Item.ItemList) { it.Condition = it.Prefab.Health; } })); commands.Add(new Command("fixhulls|fixwalls", "fixwalls/fixhulls: Fixes all walls.", (string[] args) => { foreach (Structure w in Structure.WallList) { for (int i = 0; i < w.SectionCount; i++) { w.AddDamage(i, -100000.0f); } } })); commands.Add(new Command("power", "power [temperature]: Immediately sets the temperature of the nuclear reactor to the specified value.", (string[] args) => { Item reactorItem = Item.ItemList.Find(i => i.GetComponent <Reactor>() != null); if (reactorItem == null) { return; } float power = 5000.0f; if (args.Length > 0) { float.TryParse(args[0], out power); } var reactor = reactorItem.GetComponent <Reactor>(); reactor.ShutDownTemp = power == 0 ? 0 : 7000.0f; reactor.AutoTemp = true; reactor.Temperature = power; if (GameMain.Server != null) { reactorItem.CreateServerEvent(reactor); } })); commands.Add(new Command("oxygen|air", "oxygen/air: Replenishes the oxygen levels in every room to 100%.", (string[] args) => { foreach (Hull hull in Hull.hullList) { hull.OxygenPercentage = 100.0f; } })); commands.Add(new Command("killmonsters", "killmonsters: Immediately kills all AI-controlled enemies in the level.", (string[] args) => { foreach (Character c in Character.CharacterList) { if (!(c.AIController is EnemyAIController)) { continue; } c.AddDamage(CauseOfDeath.Damage, 10000.0f, null); } })); commands.Add(new Command("netstats", "netstats: Toggles the visibility of the network statistics UI.", (string[] args) => { if (GameMain.Server == null) { return; } GameMain.Server.ShowNetStats = !GameMain.Server.ShowNetStats; })); commands.Add(new Command("setclientcharacter", "setclientcharacter [client name] ; [character name]: Gives the client control of the specified character.", (string[] args) => { if (GameMain.Server == null) { return; } int separatorIndex = Array.IndexOf(args, ";"); if (separatorIndex == -1 || args.Length < 3) { ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\""); return; } string[] argsLeft = args.Take(separatorIndex).ToArray(); string[] argsRight = args.Skip(separatorIndex).ToArray(); string clientName = String.Join(" ", argsLeft); var client = GameMain.Server.ConnectedClients.Find(c => c.name == clientName); if (client == null) { ThrowError("Client \"" + clientName + "\" not found."); } var character = FindMatchingCharacter(argsRight, false); GameMain.Server.SetClientCharacter(client, character); })); #if DEBUG commands.Add(new Command("spamevents", "A debug command that immediately creates entity events for all items, characters and structures.", (string[] args) => { foreach (Item item in Item.ItemList) { for (int i = 0; i < item.components.Count; i++) { if (item.components[i] is IServerSerializable) { GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, i }); } var itemContainer = item.GetComponent <ItemContainer>(); if (itemContainer != null) { GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.InventoryState }); } GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.Status }); item.NeedsPositionUpdate = true; } } foreach (Character c in Character.CharacterList) { GameMain.Server.CreateEntityEvent(c, new object[] { NetEntityEvent.Type.Status }); } foreach (Structure wall in Structure.WallList) { GameMain.Server.CreateEntityEvent(wall); } })); #endif InitProjectSpecific(); commands.Sort((c1, c2) => c1.names[0].CompareTo(c2.names[0])); }
public static void CreateItems(List <PurchasedItem> itemsToSpawn, Submarine sub) { if (itemsToSpawn.Count == 0) { return; } WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, sub); if (wp == null) { DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!"); return; } Hull cargoRoom = Hull.FindHull(wp.WorldPosition); if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } if (sub == Submarine.MainSub) { #if CLIENT new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true), new string[0], type: GUIMessageBox.Type.InGame, iconStyle: "StoreShoppingCrateIcon"); #else foreach (Client client in GameMain.Server.ConnectedClients) { ChatMessage msg = ChatMessage.Create("", TextManager.ContainsTag(cargoRoom.RoomName) ? $"CargoSpawnNotification~[roomname]=§{cargoRoom.RoomName}" : $"CargoSpawnNotification~[roomname]={cargoRoom.RoomName}", ChatMessageType.ServerMessageBoxInGame, null); msg.IconStyle = "StoreShoppingCrateIcon"; GameMain.Server.SendDirectChatMessage(msg, client); } #endif } List <ItemContainer> availableContainers = new List <ItemContainer>(); ItemPrefab containerPrefab = null; foreach (PurchasedItem pi in itemsToSpawn) { Vector2 position = GetCargoPos(cargoRoom, pi.ItemPrefab); for (int i = 0; i < pi.Quantity; i++) { ItemContainer itemContainer = null; if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier)) { itemContainer = availableContainers.Find(ac => ac.Inventory.CanBePut(pi.ItemPrefab) && (ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier || ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()))); if (itemContainer == null) { containerPrefab = ItemPrefab.Prefabs.Find(ep => ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier || (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()))); if (containerPrefab == null) { DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + pi.ItemPrefab.CargoContainerIdentifier + "\"!"); continue; } Item containerItem = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItem.GetComponent <ItemContainer>(); if (itemContainer == null) { DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!"); continue; } availableContainers.Add(itemContainer); #if SERVER if (GameMain.Server != null) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } #endif } } if (itemContainer == null) { //no container, place at the waypoint if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine, onSpawned: itemSpawned); } else { var item = new Item(pi.ItemPrefab, position, wp.Submarine); itemSpawned(item); } continue; } //place in the container if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory, onSpawned: itemSpawned); } else { var item = new Item(pi.ItemPrefab, position, wp.Submarine); itemContainer.Inventory.TryPutItem(item, null); itemSpawned(item); }
public static void CreateItems(List <PurchasedItem> itemsToSpawn) { if (itemsToSpawn.Count == 0) { return; } WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub); if (wp == null) { DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!"); return; } Hull cargoRoom = Hull.FindHull(wp.WorldPosition); if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } #if CLIENT new GUIMessageBox("", TextManager.Get("CargoSpawnNotification").Replace("[roomname]", cargoRoom.DisplayName)); #endif Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>(); ItemPrefab containerPrefab = null; foreach (PurchasedItem pi in itemsToSpawn) { Vector2 position = new Vector2( Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20), cargoRoom.Rect.Y - cargoRoom.Rect.Height + pi.ItemPrefab.Size.Y / 2); ItemContainer itemContainer = null; if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier)) { itemContainer = availableContainers.Keys.ToList().Find(ac => ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier || ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())); if (itemContainer == null) { containerPrefab = MapEntityPrefab.List.Find(ep => ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier || (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()))) as ItemPrefab; if (containerPrefab == null) { DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + containerPrefab.Name + "\"!"); continue; } Item containerItem = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItem.GetComponent <ItemContainer>(); if (itemContainer == null) { DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!"); continue; } availableContainers.Add(itemContainer, itemContainer.Capacity); #if SERVER if (GameMain.Server != null) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } #endif } } for (int i = 0; i < pi.Quantity; i++) { if (itemContainer == null) { //no container, place at the waypoint #if SERVER if (GameMain.Server != null) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine); } else { #endif new Item(pi.ItemPrefab, position, wp.Submarine); #if SERVER } #endif continue; } //if the intial container has been removed due to it running out of space, add a new container //of the same type and begin filling it if (!availableContainers.ContainsKey(itemContainer)) { Item containerItemOverFlow = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItemOverFlow.GetComponent <ItemContainer>(); availableContainers.Add(itemContainer, itemContainer.Capacity); #if SERVER if (GameMain.Server != null) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } #endif } //place in the container #if SERVER if (GameMain.Server != null) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory); } else { #endif var item = new Item(pi.ItemPrefab, position, wp.Submarine); itemContainer.Inventory.TryPutItem(item, null); #if SERVER } #endif //reduce the number of available slots in the container //if there is a container if (availableContainers.ContainsKey(itemContainer)) { availableContainers[itemContainer]--; } if (availableContainers.ContainsKey(itemContainer) && availableContainers[itemContainer] <= 0) { availableContainers.Remove(itemContainer); } } } itemsToSpawn.Clear(); }
private void InitEscort() { characters.Clear(); characterItems.Clear(); WayPoint explicitStayInHullPos = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); Rand.RandSync randSync = Rand.RandSync.Server; if (terroristChance > 0f) { // in terrorist missions, reroll characters each retry to avoid confusion as to who the terrorists are randSync = Rand.RandSync.Unsynced; } //if any of the escortees have a job defined, try to use a spawnpoint designated for that job foreach (XElement element in characterConfig.Elements()) { var humanPrefab = GetHumanPrefabFromElement(element); if (humanPrefab == null || string.IsNullOrEmpty(humanPrefab.Job) || humanPrefab.Job.Equals("any", StringComparison.OrdinalIgnoreCase)) { continue; } var jobPrefab = humanPrefab.GetJobPrefab(); if (jobPrefab != null) { var jobSpecificSpawnPos = WayPoint.GetRandom(SpawnType.Human, jobPrefab, Submarine.MainSub); if (jobSpecificSpawnPos != null) { explicitStayInHullPos = jobSpecificSpawnPos; break; } } } foreach (XElement element in characterConfig.Elements()) { int count = CalculateScalingEscortedCharacterCount(inMission: true); for (int i = 0; i < count; i++) { Character spawnedCharacter = CreateHuman(GetHumanPrefabFromElement(element), characters, characterItems, Submarine.MainSub, CharacterTeamType.FriendlyNPC, explicitStayInHullPos, humanPrefabRandSync: randSync); if (spawnedCharacter.AIController is HumanAIController humanAI) { humanAI.InitMentalStateManager(); } } } if (terroristChance > 0f) { int terroristCount = (int)Math.Ceiling(terroristChance * Rand.Range(0.8f, 1.2f) * characters.Count); terroristCount = Math.Clamp(terroristCount, 1, characters.Count); terroristCharacters.Clear(); characters.GetRange(0, terroristCount).ForEach(c => terroristCharacters.Add(c)); terroristDistanceSquared = Vector2.DistanceSquared(Level.Loaded.StartPosition, Level.Loaded.EndPosition) * Rand.Range(0.35f, 0.65f); #if DEBUG DebugConsole.AddWarning("Terrorists will trigger at range " + Math.Sqrt(terroristDistanceSquared)); foreach (Character character in terroristCharacters) { DebugConsole.AddWarning(character.Name + " is a terrorist."); } #endif } }
private void FindSpawnPosition(bool affectSubImmediately) { if (disallowed) { return; } if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability) { spawnPos = null; Finished(); return; } spawnPos = Vector2.Zero; var availablePositions = GetAvailableSpawnPositions(); var chosenPosition = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false); bool isSubOrWreck = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck; if (affectSubImmediately && !isSubOrWreck && spawnPosType != Level.PositionType.Abyss) { if (availablePositions.None()) { //no suitable position found, disable the event spawnPos = null; Finished(); return; } Submarine refSub = GetReferenceSub(); if (Submarine.MainSubs.Length == 2 && Submarine.MainSubs[1] != null) { refSub = Submarine.MainSubs.GetRandom(Rand.RandSync.Unsynced); } float closestDist = float.PositiveInfinity; //find the closest spawnposition that isn't too close to any of the subs foreach (var position in availablePositions) { Vector2 pos = position.Position.ToVector2(); float dist = Vector2.DistanceSquared(pos, refSub.WorldPosition); foreach (Submarine sub in Submarine.Loaded) { if (sub.Info.Type != SubmarineType.Player && sub != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle) { continue; } float minDistToSub = GetMinDistanceToSub(sub); if (dist < minDistToSub * minDistToSub) { continue; } if (closestDist == float.PositiveInfinity) { closestDist = dist; chosenPosition = position; continue; } //chosen position behind the sub -> override with anything that's closer or to the right if (chosenPosition.Position.X < refSub.WorldPosition.X) { if (dist < closestDist || pos.X > refSub.WorldPosition.X) { closestDist = dist; chosenPosition = position; } } //chosen position ahead of the sub -> only override with a position that's also ahead else if (chosenPosition.Position.X > refSub.WorldPosition.X) { if (dist < closestDist && pos.X > refSub.WorldPosition.X) { closestDist = dist; chosenPosition = position; } } } } //only found a spawnpos that's very far from the sub, pick one that's closer //and wait for the sub to move further before spawning if (closestDist > 15000.0f * 15000.0f) { foreach (var position in availablePositions) { float dist = Vector2.DistanceSquared(position.Position.ToVector2(), refSub.WorldPosition); if (dist < closestDist) { closestDist = dist; chosenPosition = position; } } } } else { if (!isSubOrWreck) { float minDistance = 20000; var refSub = GetReferenceSub(); availablePositions.RemoveAll(p => Vector2.DistanceSquared(refSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance); if (Submarine.MainSubs.Length > 1) { for (int i = 1; i < Submarine.MainSubs.Length; i++) { if (Submarine.MainSubs[i] == null) { continue; } availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSubs[i].WorldPosition, p.Position.ToVector2()) < minDistance * minDistance); } } } if (availablePositions.None()) { //no suitable position found, disable the event spawnPos = null; Finished(); return; } chosenPosition = availablePositions.GetRandom(); } if (chosenPosition.IsValid) { spawnPos = chosenPosition.Position.ToVector2(); if (chosenPosition.Submarine != null || chosenPosition.Ruin != null) { var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false); if (spawnPoint != null) { System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine); System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin); spawnPos = spawnPoint.WorldPosition; } else { //no suitable position found, disable the event spawnPos = null; Finished(); return; } } else if ((chosenPosition.PositionType == Level.PositionType.MainPath || chosenPosition.PositionType == Level.PositionType.SidePath) && offset > 0) { Vector2 dir; var waypoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine == null); var nearestWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, spawnPos.Value)).FirstOrDefault(); if (nearestWaypoint != null) { int currentIndex = waypoints.IndexOf(nearestWaypoint); var nextWaypoint = waypoints[Math.Min(currentIndex + 20, waypoints.Count - 1)]; dir = Vector2.Normalize(nextWaypoint.WorldPosition - nearestWaypoint.WorldPosition); // Ensure that the spawn position is not offset to the left. if (dir.X < 0) { dir.X = 0; } } else { dir = new Vector2(1, Rand.Range(-1, 1)); } Vector2 targetPos = spawnPos.Value + dir * offset; var targetWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, targetPos)).FirstOrDefault(); if (targetWaypoint != null) { spawnPos = targetWaypoint.WorldPosition; } } spawnPending = true; } }
private void LoadItemAsChild(XElement element, Item parent) { ItemPrefab itemPrefab; if (element.Attribute("name") != null) { DebugConsole.ThrowError("Error in cargo mission \"" + Name + "\" - use item identifiers instead of names to configure the items."); string itemName = element.GetAttributeString("name", ""); itemPrefab = MapEntityPrefab.Find(itemName) as ItemPrefab; if (itemPrefab == null) { DebugConsole.ThrowError("Couldn't spawn item for cargo mission: item prefab \"" + itemName + "\" not found"); return; } } else { string itemIdentifier = element.GetAttributeString("identifier", ""); itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab; if (itemPrefab == null) { DebugConsole.ThrowError("Couldn't spawn item for cargo mission: item prefab \"" + itemIdentifier + "\" not found"); return; } } if (itemPrefab == null) { DebugConsole.ThrowError("Couldn't spawn item for cargo mission: item prefab \"" + element.Name.ToString() + "\" not found"); return; } WayPoint cargoSpawnPos = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub, useSyncedRand: true); if (cargoSpawnPos == null) { DebugConsole.ThrowError("Couldn't spawn items for cargo mission, cargo spawnpoint not found"); return; } var cargoRoom = cargoSpawnPos.CurrentHull; if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } Vector2 position = new Vector2( cargoSpawnPos.Position.X + Rand.Range(-20.0f, 20.0f, Rand.RandSync.Server), cargoRoom.Rect.Y - cargoRoom.Rect.Height + itemPrefab.Size.Y / 2); var item = new Item(itemPrefab, position, cargoRoom.Submarine) { SpawnedInOutpost = true }; item.FindHull(); items.Add(item); if (parent != null && parent.GetComponent <ItemContainer>() != null) { parentInventoryIDs.Add(item, parent.ID); parentItemContainerIndices.Add(item, (byte)parent.GetComponentIndex(parent.GetComponent <ItemContainer>())); parent.Combine(item, user: null); } foreach (XElement subElement in element.Elements()) { int amount = subElement.GetAttributeInt("amount", 1); for (int i = 0; i < amount; i++) { LoadItemAsChild(subElement, item); } } }
public MainMenuScreen(GameMain game) { buttonsParent = new GUILayoutGroup(new RectTransform(new Vector2(0.15f, 0.5f), parent: Frame.RectTransform, anchor: Anchor.BottomLeft) { RelativeOffset = new Vector2(0, 0.1f), AbsoluteOffset = new Point(50, 0) }) { Stretch = true, RelativeSpacing = 0.02f }; //debug button for quickly starting a new round #if DEBUG new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform, Anchor.TopCenter, Pivot.BottomCenter) { AbsoluteOffset = new Point(0, -40) }, "Quickstart (dev)", style: "GUIButtonLarge", color: Color.Red) { IgnoreLayoutGroups = true, OnClicked = (tb, userdata) => { Submarine selectedSub = null; string subName = GameMain.Config.QuickStartSubmarineName; if (!string.IsNullOrEmpty(subName)) { DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White); selectedSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name.ToLower() == subName.ToLower()); if (selectedSub == null) { DebugConsole.NewMessage($"Cannot find a sub that matches the name \"{subName}\".", Color.Red); } } if (selectedSub == null) { DebugConsole.NewMessage("Loading a random sub.", Color.White); var subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.Shuttle) && !s.HasTag(SubmarineTag.HideInMenus)); selectedSub = subs.ElementAt(Rand.Int(subs.Count())); } var gamesession = new GameSession( selectedSub, "Data/Saves/test.xml", GameModePreset.List.Find(gm => gm.Identifier == "devsandbox"), missionPrefab: null); //(gamesession.GameMode as SinglePlayerCampaign).GenerateMap(ToolBox.RandomSeed(8)); gamesession.StartRound(ToolBox.RandomSeed(8)); GameMain.GameScreen.Select(); string[] jobIdentifiers = new string[] { "captain", "engineer", "mechanic" }; for (int i = 0; i < 3; i++) { var spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); if (spawnPoint == null) { DebugConsole.ThrowError("No spawnpoints found in the selected submarine. Quickstart failed."); GameMain.MainMenuScreen.Select(); return(true); } var characterInfo = new CharacterInfo( Character.HumanConfigFile, jobPrefab: JobPrefab.List.Find(j => j.Identifier == jobIdentifiers[i])); if (characterInfo.Job == null) { DebugConsole.ThrowError("Failed to find the job \"" + jobIdentifiers[i] + "\"!"); } var newCharacter = Character.Create(Character.HumanConfigFile, spawnPoint.WorldPosition, ToolBox.RandomSeed(8), characterInfo); newCharacter.GiveJobItems(spawnPoint); gamesession.CrewManager.AddCharacter(newCharacter); Character.Controlled = newCharacter; } return(true); } }; #endif var minButtonSize = new Point(120, 20); var maxButtonSize = new Point(240, 40); /*new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("TutorialButton"), style: "GUIButtonLarge") * { * UserData = Tab.Tutorials, * OnClicked = SelectTab, * Enabled = false * };*/ new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("NewGameButton"), style: "GUIButtonLarge") { UserData = Tab.NewGame, OnClicked = SelectTab }; new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("LoadGameButton"), style: "GUIButtonLarge") { UserData = Tab.LoadGame, OnClicked = SelectTab }; new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing joinServerButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("JoinServerButton"), style: "GUIButtonLarge") { OnClicked = JoinServerClicked }; hostServerButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("HostServerButton"), style: "GUIButtonLarge") { UserData = Tab.HostServer, OnClicked = SelectTab }; new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("SubEditorButton"), style: "GUIButtonLarge") { OnClicked = (btn, userdata) => { GameMain.SubEditorScreen.Select(); return(true); } }; new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("CharacterEditorButton"), style: "GUIButtonLarge") { OnClicked = (btn, userdata) => { Submarine.MainSub = null; GameMain.CharacterEditorScreen.Select(); return(true); } }; if (Steam.SteamManager.USE_STEAM) { steamWorkshopButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("SteamWorkshopButton"), style: "GUIButtonLarge") { OnClicked = SteamWorkshopClicked }; } new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), buttonsParent.RectTransform), style: null); //spacing new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("SettingsButton"), style: "GUIButtonLarge") { UserData = Tab.Settings, OnClicked = SelectTab }; new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonsParent.RectTransform), TextManager.Get("QuitButton"), style: "GUIButtonLarge") { OnClicked = QuitClicked }; /* var buttons = GUI.CreateButtons(9, new Vector2(1, 0.04f), buttonsParent.RectTransform, anchor: Anchor.BottomLeft, * minSize: minButtonSize, maxSize: maxButtonSize, relativeSpacing: 0.005f, extraSpacing: i => i % 2 == 0 ? 20 : 0); * buttons.ForEach(b => b.Color *= 0.8f); * SetupButtons(buttons); * buttons.ForEach(b => b.TextBlock.SetTextPos());*/ var relativeSize = new Vector2(0.5f, 0.5f); var minSize = new Point(600, 400); var maxSize = new Point(900, 600); var anchor = Anchor.Center; var pivot = Pivot.Center; menuTabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length + 1]; menuTabs[(int)Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize, Frame.RectTransform, anchor, pivot, minSize, maxSize)); var paddedNewGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.NewGame].RectTransform, Anchor.Center), style: null); menuTabs[(int)Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, Frame.RectTransform, anchor, pivot, minSize, maxSize)); var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center), style: null); campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame) { LoadGame = LoadGame, StartNewGame = StartGame }; var hostServerScale = new Vector2(0.7f, 1.0f); menuTabs[(int)Tab.HostServer] = new GUIFrame(new RectTransform( Vector2.Multiply(relativeSize, hostServerScale), Frame.RectTransform, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale))); CreateHostServerFields(); //---------------------------------------------------------------------- menuTabs[(int)Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, Frame.RectTransform, anchor, pivot, minSize, maxSize)); //PLACEHOLDER var tutorialList = new GUIListBox( new RectTransform(new Vector2(0.95f, 0.85f), menuTabs[(int)Tab.Tutorials].RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) }, false, null, ""); foreach (Tutorial tutorial in Tutorial.Tutorials) { var tutorialText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), tutorialList.Content.RectTransform), tutorial.Name, textAlignment: Alignment.Center, font: GUI.LargeFont) { UserData = tutorial }; } tutorialList.OnSelected += (component, obj) => { TutorialMode.StartTutorial(obj as Tutorial); return(true); }; UpdateTutorialList(); this.game = game; }
public static void ExecuteCommand(string command, GameMain game) { if (string.IsNullOrWhiteSpace(command)) { return; } string[] commands = command.Split(' '); if (!commands[0].ToLowerInvariant().Equals("admin")) { NewMessage(textBox.Text, Color.White); } #if !DEBUG if (GameMain.Client != null && !IsCommandPermitted(commands[0].ToLowerInvariant(), GameMain.Client)) { ThrowError("You're not permitted to use the command \"" + commands[0].ToLowerInvariant() + "\"!"); return; } #endif switch (commands[0].ToLowerInvariant()) { case "help": NewMessage("menu: go to main menu", Color.Cyan); NewMessage("game: enter the \"game screen\"", Color.Cyan); NewMessage("edit: switch to submarine editor", Color.Cyan); NewMessage("edit [submarine name]: load a submarine and switch to submarine editor", Color.Cyan); NewMessage("load [submarine name]: load a submarine", Color.Cyan); NewMessage("save [submarine name]: save the current submarine using the specified name", Color.Cyan); NewMessage(" ", Color.Cyan); NewMessage("spawn [creaturename] [near/inside/outside]: spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine)", Color.Cyan); NewMessage("spawnitem [itemname] [cursor/inventory]: spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted", Color.Cyan); NewMessage(" ", Color.Cyan); NewMessage("lights: disable lighting", Color.Cyan); NewMessage("los: disable the line of sight effect", Color.Cyan); NewMessage("freecam: detach the camera from the controlled character", Color.Cyan); NewMessage("control [character name]: start controlling the specified character", Color.Cyan); NewMessage(" ", Color.Cyan); NewMessage("water: allows adding water into rooms or removing it by holding the left/right mouse buttons", Color.Cyan); NewMessage("fire: allows putting up fires by left clicking", Color.Cyan); NewMessage(" ", Color.Cyan); NewMessage("teleport: teleport the controlled character to the position of the cursor", Color.Cyan); NewMessage("teleport [character name]: teleport the specified character to the position of the cursor", Color.Cyan); NewMessage("heal: restore the controlled character to full health", Color.Cyan); NewMessage("heal [character name]: restore the specified character to full health", Color.Cyan); NewMessage("revive: bring the controlled character back from the dead", Color.Cyan); NewMessage("revive [character name]: bring the specified character back from the dead", Color.Cyan); NewMessage("killmonsters: immediately kills all AI-controlled enemies in the level", Color.Cyan); NewMessage(" ", Color.Cyan); NewMessage("fixwalls: fixes all the walls", Color.Cyan); NewMessage("fixitems: fixes every item/device in the sub", Color.Cyan); NewMessage("oxygen: replenishes the oxygen in every room to 100%", Color.Cyan); NewMessage("power [amount]: immediately sets the temperature of the reactor to the specified value", Color.Cyan); NewMessage(" ", Color.Cyan); NewMessage("kick [name]: kick a player out from the server", Color.Cyan); NewMessage("ban [name]: kick and ban the player from the server", Color.Cyan); NewMessage("banip [IP address]: ban the IP address from the server", Color.Cyan); NewMessage("debugdraw: toggles the \"debug draw mode\"", Color.Cyan); NewMessage("netstats: toggles the visibility of the network statistics panel", Color.Cyan); break; case "createfilelist": UpdaterUtil.SaveFileList("filelist.xml"); break; case "spawn": case "spawncharacter": if (commands.Length == 1) { return; } Character spawnedCharacter = null; Vector2 spawnPosition = Vector2.Zero; WayPoint spawnPoint = null; if (commands.Length > 2) { switch (commands[2].ToLowerInvariant()) { case "inside": spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); break; case "outside": spawnPoint = WayPoint.GetRandom(SpawnType.Enemy); break; case "near": case "close": float closestDist = -1.0f; foreach (WayPoint wp in WayPoint.WayPointList) { if (wp.Submarine != null) { continue; } //don't spawn inside hulls if (Hull.FindHull(wp.WorldPosition, null) != null) { continue; } float dist = Vector2.Distance(wp.WorldPosition, GameMain.GameScreen.Cam.WorldViewCenter); if (closestDist < 0.0f || dist < closestDist) { spawnPoint = wp; closestDist = dist; } } break; case "cursor": spawnPosition = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); break; default: spawnPoint = WayPoint.GetRandom(commands[1].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy); break; } } else { spawnPoint = WayPoint.GetRandom(commands[1].ToLowerInvariant() == "human" ? SpawnType.Human : SpawnType.Enemy); } if (string.IsNullOrWhiteSpace(commands[1])) { return; } if (spawnPoint != null) { spawnPosition = spawnPoint.WorldPosition; } if (commands[1].ToLowerInvariant() == "human") { spawnedCharacter = Character.Create(Character.HumanConfigFile, spawnPosition); if (GameMain.GameSession != null) { SinglePlayerMode mode = GameMain.GameSession.gameMode as SinglePlayerMode; if (mode != null) { Character.Controlled = spawnedCharacter; GameMain.GameSession.CrewManager.AddCharacter(Character.Controlled); GameMain.GameSession.CrewManager.SelectCharacter(null, Character.Controlled); } } } else { spawnedCharacter = Character.Create( "Content/Characters/" + commands[1].First().ToString().ToUpper() + commands[1].Substring(1) + "/" + commands[1].ToLower() + ".xml", spawnPosition); } break; case "spawnitem": if (commands.Length < 2) { return; } Vector2? spawnPos = null; Inventory spawnInventory = null; int extraParams = 0; switch (commands.Last()) { case "cursor": extraParams = 1; spawnPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); break; case "inventory": extraParams = 1; spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory; break; default: extraParams = 0; break; } string itemName = string.Join(" ", commands.Skip(1).Take(commands.Length - extraParams - 1)).ToLowerInvariant(); var itemPrefab = MapEntityPrefab.list.Find(ip => ip.Name.ToLowerInvariant() == itemName) as ItemPrefab; if (itemPrefab == null) { ThrowError("Item \"" + itemName + "\" not found!"); return; } if (spawnPos == null && spawnInventory == null) { var wp = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); spawnPos = wp == null ? Vector2.Zero : wp.WorldPosition; } if (spawnPos != null) { Item.Spawner.AddToSpawnQueue(itemPrefab, (Vector2)spawnPos); } else if (spawnInventory != null) { Item.Spawner.AddToSpawnQueue(itemPrefab, spawnInventory); } break; case "disablecrewai": HumanAIController.DisableCrewAI = !HumanAIController.DisableCrewAI; break; case "enablecrewai": HumanAIController.DisableCrewAI = false; break; /*case "admin": * if (commands.Length < 2) break; * * if (GameMain.Server != null) * { * GameMain.Server.AdminAuthPass = commands[1]; * * } * else if (GameMain.Client != null) * { * GameMain.Client.RequestAdminAuth(commands[1]); * } * break;*/ case "kick": if (GameMain.NetworkMember == null || commands.Length < 2) { break; } GameMain.NetworkMember.KickPlayer(string.Join(" ", commands.Skip(1)), false); break; case "ban": if (GameMain.NetworkMember == null || commands.Length < 2) { break; } GameMain.NetworkMember.KickPlayer(string.Join(" ", commands.Skip(1)), true); break; case "banip": { if (GameMain.Server == null || commands.Length < 2) { break; } var client = GameMain.Server.ConnectedClients.Find(c => c.Connection.RemoteEndPoint.Address.ToString() == commands[1]); if (client == null) { GameMain.Server.BanList.BanPlayer("Unnamed", commands[1]); } else { GameMain.Server.KickClient(client, true); } } break; case "startclient": if (commands.Length == 1) { return; } if (GameMain.Client == null) { GameMain.NetworkMember = new GameClient("Name"); GameMain.Client.ConnectToServer(commands[1]); } break; case "mainmenuscreen": case "mainmenu": case "menu": GameMain.GameSession = null; List <Character> characters = new List <Character>(Character.CharacterList); foreach (Character c in characters) { c.Remove(); } GameMain.MainMenuScreen.Select(); break; case "gamescreen": case "game": GameMain.GameScreen.Select(); break; case "editmapscreen": case "editmap": case "edit": if (commands.Length > 1) { Submarine.Load(string.Join(" ", commands.Skip(1)), true); } GameMain.EditMapScreen.Select(); break; case "test": Submarine.Load("aegir mark ii", true); GameMain.DebugDraw = true; GameMain.LightManager.LosEnabled = false; GameMain.EditMapScreen.Select(); break; case "editcharacter": case "editchar": GameMain.EditCharacterScreen.Select(); break; case "controlcharacter": case "control": { if (commands.Length < 2) { break; } var character = FindMatchingCharacter(commands, true); if (character != null) { Character.Controlled = character; } } break; case "setclientcharacter": { if (GameMain.Server == null) { break; } int separatorIndex = Array.IndexOf(commands, ";"); if (separatorIndex == -1 || commands.Length < 4) { ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\""); break; } string[] commandsLeft = commands.Take(separatorIndex).ToArray(); string[] commandsRight = commands.Skip(separatorIndex).ToArray(); string clientName = String.Join(" ", commandsLeft.Skip(1)); var client = GameMain.Server.ConnectedClients.Find(c => c.name == clientName); if (client == null) { ThrowError("Client \"" + clientName + "\" not found."); } var character = FindMatchingCharacter(commandsRight, false); GameMain.Server.SetClientCharacter(client, character); } break; case "teleportcharacter": case "teleport": var tpCharacter = FindMatchingCharacter(commands, false); if (commands.Length < 2) { tpCharacter = Character.Controlled; } if (tpCharacter != null) { var cam = GameMain.GameScreen.Cam; tpCharacter.AnimController.CurrentHull = null; tpCharacter.Submarine = null; tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition))); tpCharacter.AnimController.FindHull(cam.ScreenToWorld(PlayerInput.MousePosition), true); } break; case "godmode": if (Submarine.MainSub == null) { return; } Submarine.MainSub.GodMode = !Submarine.MainSub.GodMode; break; case "lockx": Submarine.LockX = !Submarine.LockX; break; case "locky": Submarine.LockY = !Submarine.LockY; break; case "dumpids": try { int count = commands.Length < 2 ? 10 : int.Parse(commands[1]); Entity.DumpIds(count); } catch { return; } break; case "heal": Character healedCharacter = null; if (commands.Length == 1) { healedCharacter = Character.Controlled; } else { healedCharacter = FindMatchingCharacter(commands); } if (healedCharacter != null) { healedCharacter.AddDamage(CauseOfDeath.Damage, -healedCharacter.MaxHealth, null); healedCharacter.Oxygen = 100.0f; healedCharacter.Bleeding = 0.0f; healedCharacter.Stun = 0.0f; } break; case "revive": Character revivedCharacter = null; if (commands.Length == 1) { revivedCharacter = Character.Controlled; } else { revivedCharacter = FindMatchingCharacter(commands); } if (revivedCharacter != null) { revivedCharacter.Revive(false); if (GameMain.Server != null) { foreach (Client c in GameMain.Server.ConnectedClients) { if (c.Character != revivedCharacter) { continue; } //clients stop controlling the character when it dies, force control back GameMain.Server.SetClientCharacter(c, revivedCharacter); break; } } } break; case "freeze": if (Character.Controlled != null) { Character.Controlled.AnimController.Frozen = !Character.Controlled.AnimController.Frozen; } break; case "freecamera": case "freecam": Character.Controlled = null; GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; break; case "editwater": case "water": if (GameMain.Client == null) { Hull.EditWater = !Hull.EditWater; } break; case "fire": if (GameMain.Client == null) { Hull.EditFire = !Hull.EditFire; } break; case "fixitems": foreach (Item it in Item.ItemList) { it.Condition = 100.0f; } break; case "fixhull": case "fixwalls": foreach (Structure w in Structure.WallList) { for (int i = 0; i < w.SectionCount; i++) { w.AddDamage(i, -100000.0f); } } break; case "power": Item reactorItem = Item.ItemList.Find(i => i.GetComponent <Reactor>() != null); if (reactorItem == null) { return; } float power = 5000.0f; if (commands.Length > 1) { float.TryParse(commands[1], out power); } var reactor = reactorItem.GetComponent <Reactor>(); reactor.ShutDownTemp = power == 0 ? 0 : 7000.0f; reactor.AutoTemp = true; reactor.Temperature = power; if (GameMain.Server != null) { reactorItem.CreateServerEvent(reactor); } break; case "shake": GameMain.GameScreen.Cam.Shake = 10.0f; break; case "losenabled": case "los": case "drawlos": GameMain.LightManager.LosEnabled = !GameMain.LightManager.LosEnabled; break; case "lighting": case "lightingenabled": case "light": case "lights": GameMain.LightManager.LightingEnabled = !GameMain.LightManager.LightingEnabled; break; case "oxygen": case "air": foreach (Hull hull in Hull.hullList) { hull.OxygenPercentage = 100.0f; } break; case "tutorial": TutorialMode.StartTutorial(Tutorials.TutorialType.TutorialTypes[0]); break; case "editortutorial": GameMain.EditMapScreen.Select(); GameMain.EditMapScreen.StartTutorial(); break; case "lobbyscreen": case "lobby": GameMain.LobbyScreen.Select(); break; case "savemap": case "savesub": case "save": if (commands.Length < 2) { break; } if (GameMain.EditMapScreen.CharacterMode) { GameMain.EditMapScreen.ToggleCharacterMode(); } string fileName = string.Join(" ", commands.Skip(1)); if (fileName.Contains("../")) { DebugConsole.ThrowError("Illegal symbols in filename (../)"); return; } if (Submarine.SaveCurrent(System.IO.Path.Combine(Submarine.SavePath, fileName + ".sub"))) { NewMessage("Sub saved", Color.Green); //Submarine.Loaded.First().CheckForErrors(); } break; case "loadmap": case "loadsub": case "load": if (commands.Length < 2) { break; } Submarine.Load(string.Join(" ", commands.Skip(1)), true); break; case "cleansub": for (int i = MapEntity.mapEntityList.Count - 1; i >= 0; i--) { MapEntity me = MapEntity.mapEntityList[i]; if (me.SimPosition.Length() > 2000.0f) { DebugConsole.NewMessage("Removed " + me.Name + " (simposition " + me.SimPosition + ")", Color.Orange); MapEntity.mapEntityList.RemoveAt(i); } else if (me.MoveWithLevel) { DebugConsole.NewMessage("Removed " + me.Name + " (MoveWithLevel==true)", Color.Orange); MapEntity.mapEntityList.RemoveAt(i); } else if (me is Item) { Item item = me as Item; var wire = item.GetComponent <Wire>(); if (wire == null) { continue; } if (wire.GetNodes().Count > 0 && !wire.Connections.Any(c => c != null)) { wire.Item.Drop(null); DebugConsole.NewMessage("Dropped wire (ID: " + wire.Item.ID + ") - attached on wall but no connections found", Color.Orange); } } } break; case "messagebox": if (commands.Length < 3) { break; } new GUIMessageBox(commands[1], commands[2]); break; case "debugdraw": GameMain.DebugDraw = !GameMain.DebugDraw; break; case "disablehud": case "hud": GUI.DisableHUD = !GUI.DisableHUD; GameMain.Instance.IsMouseVisible = !GameMain.Instance.IsMouseVisible; break; case "followsub": Camera.FollowSub = !Camera.FollowSub; break; case "drawaitargets": case "showaitargets": AITarget.ShowAITargets = !AITarget.ShowAITargets; break; case "killmonsters": foreach (Character c in Character.CharacterList) { if (!(c.AIController is EnemyAIController)) { continue; } c.AddDamage(CauseOfDeath.Damage, 10000.0f, null); } break; case "netstats": if (GameMain.Server == null) { return; } GameMain.Server.ShowNetStats = !GameMain.Server.ShowNetStats; break; #if DEBUG case "spamevents": foreach (Item item in Item.ItemList) { for (int i = 0; i < item.components.Count; i++) { if (item.components[i] is IServerSerializable) { GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, i }); } var itemContainer = item.GetComponent <ItemContainer>(); if (itemContainer != null) { GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.InventoryState }); } GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.Status }); item.NeedsPositionUpdate = true; } } foreach (Character c in Character.CharacterList) { GameMain.Server.CreateEntityEvent(c, new object[] { NetEntityEvent.Type.Status }); } foreach (Structure wall in Structure.WallList) { GameMain.Server.CreateEntityEvent(wall); } break; case "spamchatmessages": int msgCount = 1000; if (commands.Length > 1) { int.TryParse(commands[1], out msgCount); } int msgLength = 50; if (commands.Length > 2) { int.TryParse(commands[2], out msgLength); } for (int i = 0; i < msgCount; i++) { if (GameMain.Server != null) { GameMain.Server.SendChatMessage(ToolBox.RandomSeed(msgLength), ChatMessageType.Default); } else { GameMain.Client.SendChatMessage(ToolBox.RandomSeed(msgLength)); } } break; #endif case "cleanbuild": GameMain.Config.MusicVolume = 0.5f; GameMain.Config.SoundVolume = 0.5f; DebugConsole.NewMessage("Music and sound volume set to 0.5", Color.Green); GameMain.Config.GraphicsWidth = 0; GameMain.Config.GraphicsHeight = 0; GameMain.Config.WindowMode = WindowMode.Fullscreen; DebugConsole.NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green); DebugConsole.NewMessage("Fullscreen enabled", Color.Green); GameSettings.VerboseLogging = false; if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster") { DebugConsole.ThrowError("MasterServerUrl \"" + GameMain.Config.MasterServerUrl + "\"!"); } GameMain.Config.Save("config.xml"); var saveFiles = System.IO.Directory.GetFiles(SaveUtil.SaveFolder); foreach (string saveFile in saveFiles) { System.IO.File.Delete(saveFile); DebugConsole.NewMessage("Deleted " + saveFile, Color.Green); } if (System.IO.Directory.Exists(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp"))) { System.IO.Directory.Delete(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp"), true); DebugConsole.NewMessage("Deleted temp save folder", Color.Green); } if (System.IO.Directory.Exists(ServerLog.SavePath)) { var logFiles = System.IO.Directory.GetFiles(ServerLog.SavePath); foreach (string logFile in logFiles) { System.IO.File.Delete(logFile); DebugConsole.NewMessage("Deleted " + logFile, Color.Green); } } if (System.IO.File.Exists("filelist.xml")) { System.IO.File.Delete("filelist.xml"); DebugConsole.NewMessage("Deleted filelist", Color.Green); } if (System.IO.File.Exists("Submarines/TutorialSub.sub")) { System.IO.File.Delete("Submarines/TutorialSub.sub"); DebugConsole.NewMessage("Deleted TutorialSub from the submarine folder", Color.Green); } if (System.IO.File.Exists(GameServer.SettingsFile)) { System.IO.File.Delete(GameServer.SettingsFile); DebugConsole.NewMessage("Deleted server settings", Color.Green); } if (System.IO.File.Exists(GameServer.ClientPermissionsFile)) { System.IO.File.Delete(GameServer.ClientPermissionsFile); DebugConsole.NewMessage("Deleted client permission file", Color.Green); } if (System.IO.File.Exists("crashreport.txt")) { System.IO.File.Delete("crashreport.txt"); DebugConsole.NewMessage("Deleted crashreport.txt", Color.Green); } if (!System.IO.File.Exists("Content/Map/TutorialSub.sub")) { DebugConsole.ThrowError("TutorialSub.sub not found!"); } break; default: NewMessage("Command not found", Color.Red); break; } }
private void FindSpawnPosition(bool affectSubImmediately) { if (disallowed) { return; } spawnPos = Vector2.Zero; var availablePositions = GetAvailableSpawnPositions(); var chosenPosition = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false); var removedPositions = new List <Level.InterestingPosition>(); foreach (var position in availablePositions) { if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability) { removedPositions.Add(position); if (prefab.AllowOnlyOnce) { Level.Loaded.UsedPositions.Add(position); } } } removedPositions.ForEach(p => availablePositions.Remove(p)); bool isSubOrWreck = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck; if (affectSubImmediately && !isSubOrWreck) { if (availablePositions.None()) { //no suitable position found, disable the event Finished(); return; } float closestDist = float.PositiveInfinity; //find the closest spawnposition that isn't too close to any of the subs foreach (var position in availablePositions) { Vector2 pos = position.Position.ToVector2(); float dist = Vector2.DistanceSquared(pos, Submarine.MainSub.WorldPosition); foreach (Submarine sub in Submarine.Loaded) { if (sub.Info.Type != SubmarineInfo.SubmarineType.Player) { continue; } float minDistToSub = GetMinDistanceToSub(sub); if (dist > minDistToSub * minDistToSub && dist < closestDist) { closestDist = dist; chosenPosition = position; } } } //only found a spawnpos that's very far from the sub, pick one that's closer //and wait for the sub to move further before spawning if (closestDist > 15000.0f * 15000.0f) { foreach (var position in availablePositions) { float dist = Vector2.DistanceSquared(position.Position.ToVector2(), Submarine.MainSub.WorldPosition); if (dist < closestDist) { closestDist = dist; chosenPosition = position; } } } } else { if (!isSubOrWreck) { float minDistance = 20000; availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance); } if (availablePositions.None()) { //no suitable position found, disable the event Finished(); return; } chosenPosition = availablePositions.GetRandom(); } if (chosenPosition.IsValid) { spawnPos = chosenPosition.Position.ToVector2(); if (chosenPosition.Submarine != null || chosenPosition.Ruin != null) { var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false); if (spawnPoint != null) { System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine); System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin); spawnPos = spawnPoint.WorldPosition; } } spawnPending = true; if (prefab.AllowOnlyOnce) { Level.Loaded.UsedPositions.Add(chosenPosition); } } }
public static void CreateItems(List <PurchasedItem> itemsToSpawn) { if (itemsToSpawn.Count == 0) { return; } WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub); if (wp == null) { DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!"); return; } Hull cargoRoom = Hull.FindHull(wp.WorldPosition); if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } #if CLIENT new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true), new string[0], type: GUIMessageBox.Type.InGame, iconStyle: "StoreShoppingCrateIcon"); #else foreach (Client client in GameMain.Server.ConnectedClients) { ChatMessage msg = ChatMessage.Create("", $"CargoSpawnNotification~[roomname]=§{cargoRoom.RoomName}", ChatMessageType.ServerMessageBoxInGame, null); msg.IconStyle = "StoreShoppingCrateIcon"; GameMain.Server.SendDirectChatMessage(msg, client); } #endif Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>(); ItemPrefab containerPrefab = null; foreach (PurchasedItem pi in itemsToSpawn) { float floorPos = cargoRoom.Rect.Y - cargoRoom.Rect.Height; Vector2 position = new Vector2( cargoRoom.Rect.Width > 40 ? Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20) : cargoRoom.Rect.Center.X, floorPos); //check where the actual floor structure is in case the bottom of the hull extends below it if (Submarine.PickBody( ConvertUnits.ToSimUnits(new Vector2(position.X, cargoRoom.Rect.Y - cargoRoom.Rect.Height / 2)), ConvertUnits.ToSimUnits(position), collisionCategory: Physics.CollisionWall) != null) { float floorStructurePos = ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition.Y); if (floorStructurePos > floorPos) { floorPos = floorStructurePos; } } position.Y = floorPos + pi.ItemPrefab.Size.Y / 2; ItemContainer itemContainer = null; if (!string.IsNullOrEmpty(pi.ItemPrefab.CargoContainerIdentifier)) { itemContainer = availableContainers.Keys.ToList().Find(ac => ac.Item.Prefab.Identifier == pi.ItemPrefab.CargoContainerIdentifier || ac.Item.Prefab.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant())); if (itemContainer == null) { containerPrefab = ItemPrefab.Prefabs.Find(ep => ep.Identifier == pi.ItemPrefab.CargoContainerIdentifier || (ep.Tags != null && ep.Tags.Contains(pi.ItemPrefab.CargoContainerIdentifier.ToLowerInvariant()))); if (containerPrefab == null) { DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + pi.ItemPrefab.CargoContainerIdentifier + "\"!"); continue; } Item containerItem = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItem.GetComponent <ItemContainer>(); if (itemContainer == null) { DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!"); continue; } availableContainers.Add(itemContainer, itemContainer.Capacity); #if SERVER if (GameMain.Server != null) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } #endif } } for (int i = 0; i < pi.Quantity; i++) { if (itemContainer == null) { //no container, place at the waypoint if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, position, wp.Submarine, onSpawned: itemSpawned); } else { var item = new Item(pi.ItemPrefab, position, wp.Submarine); itemSpawned(item); } continue; } //if the intial container has been removed due to it running out of space, add a new container //of the same type and begin filling it if (!availableContainers.ContainsKey(itemContainer)) { Item containerItemOverFlow = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItemOverFlow.GetComponent <ItemContainer>(); availableContainers.Add(itemContainer, itemContainer.Capacity); #if SERVER if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } #endif } //place in the container if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { Entity.Spawner.AddToSpawnQueue(pi.ItemPrefab, itemContainer.Inventory, onSpawned: itemSpawned); } else { var item = new Item(pi.ItemPrefab, position, wp.Submarine); itemContainer.Inventory.TryPutItem(item, null); itemSpawned(item); }
private void FindSpawnPosition(bool affectSubImmediately) { if (disallowed) { return; } spawnPos = Vector2.Zero; var availablePositions = GetAvailableSpawnPositions(); var chosenPosition = new Level.InterestingPosition(Point.Zero, Level.PositionType.MainPath, isValid: false); var removedPositions = new List <Level.InterestingPosition>(); foreach (var position in availablePositions) { if (Rand.Value(Rand.RandSync.Server) > prefab.SpawnProbability) { removedPositions.Add(position); } } removedPositions.ForEach(p => availablePositions.Remove(p)); bool isSubOrWreck = spawnPosType == Level.PositionType.Ruin || spawnPosType == Level.PositionType.Wreck; if (affectSubImmediately && !isSubOrWreck) { if (availablePositions.None()) { //no suitable position found, disable the event Finished(); return; } float closestDist = float.PositiveInfinity; //find the closest spawnposition that isn't too close to any of the subs foreach (var position in availablePositions) { Vector2 pos = position.Position.ToVector2(); float dist = Vector2.DistanceSquared(pos, Submarine.MainSub.WorldPosition); foreach (Submarine sub in Submarine.Loaded) { if (sub.Info.Type != SubmarineInfo.SubmarineType.Player) { continue; } float minDistToSub = GetMinDistanceToSub(sub); if (dist > minDistToSub * minDistToSub && dist < closestDist) { closestDist = dist; chosenPosition = position; } } } //only found a spawnpos that's very far from the sub, pick one that's closer //and wait for the sub to move further before spawning if (closestDist > 15000.0f * 15000.0f) { foreach (var position in availablePositions) { float dist = Vector2.DistanceSquared(position.Position.ToVector2(), Submarine.MainSub.WorldPosition); if (dist < closestDist) { closestDist = dist; chosenPosition = position; } } } } else { if (!isSubOrWreck) { float minDistance = 20000; availablePositions.RemoveAll(p => Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, p.Position.ToVector2()) < minDistance * minDistance); } if (availablePositions.None()) { //no suitable position found, disable the event Finished(); return; } chosenPosition = availablePositions.GetRandom(); } if (chosenPosition.IsValid) { spawnPos = chosenPosition.Position.ToVector2(); if (chosenPosition.Submarine != null || chosenPosition.Ruin != null) { var spawnPoint = WayPoint.GetRandom(SpawnType.Enemy, sub: chosenPosition.Submarine, ruin: chosenPosition.Ruin, useSyncedRand: false); if (spawnPoint != null) { System.Diagnostics.Debug.Assert(spawnPoint.Submarine == chosenPosition.Submarine); System.Diagnostics.Debug.Assert(spawnPoint.ParentRuin == chosenPosition.Ruin); spawnPos = spawnPoint.WorldPosition; } } else if (chosenPosition.PositionType == Level.PositionType.MainPath && offset > 0) { Vector2 dir; var waypoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine == null); var nearestWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, spawnPos.Value)).FirstOrDefault(); if (nearestWaypoint != null) { int currentIndex = waypoints.IndexOf(nearestWaypoint); var nextWaypoint = waypoints[Math.Min(currentIndex + 20, waypoints.Count - 1)]; dir = Vector2.Normalize(nextWaypoint.WorldPosition - nearestWaypoint.WorldPosition); } else { dir = new Vector2(1, Rand.Range(-1, 1)); } Vector2 targetPos = spawnPos.Value + dir * offset; var targetWaypoint = waypoints.OrderBy(wp => Vector2.DistanceSquared(wp.WorldPosition, targetPos)).FirstOrDefault(); if (targetWaypoint != null) { spawnPos = targetWaypoint.WorldPosition; } } spawnPending = true; } }
public static void CreateItems(List <ItemPrefab> itemsToSpawn) { WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub); if (wp == null) { DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!"); return; } Hull cargoRoom = Hull.FindHull(wp.WorldPosition); if (cargoRoom == null) { DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!"); return; } Dictionary <ItemContainer, int> availableContainers = new Dictionary <ItemContainer, int>(); foreach (ItemPrefab prefab in itemsToSpawn) { Vector2 position = new Vector2( Rand.Range(cargoRoom.Rect.X + 20, cargoRoom.Rect.Right - 20), cargoRoom.Rect.Y - cargoRoom.Rect.Height + prefab.Size.Y / 2); ItemContainer itemContainer = null; if (!string.IsNullOrEmpty(prefab.CargoContainerName)) { itemContainer = availableContainers.Keys.ToList().Find(ac => ac.Item.Prefab.NameMatches(prefab.CargoContainerName) || ac.Item.Prefab.Tags.Contains(prefab.CargoContainerName.ToLowerInvariant())); if (itemContainer == null) { var containerPrefab = MapEntityPrefab.List.Find(ep => ep.NameMatches(prefab.CargoContainerName) || (ep.Tags != null && ep.Tags.Contains(prefab.CargoContainerName.ToLowerInvariant()))) as ItemPrefab; if (containerPrefab == null) { DebugConsole.ThrowError("Cargo spawning failed - could not find the item prefab for container \"" + containerPrefab.Name + "\"!"); continue; } Item containerItem = new Item(containerPrefab, position, wp.Submarine); itemContainer = containerItem.GetComponent <ItemContainer>(); if (itemContainer == null) { DebugConsole.ThrowError("Cargo spawning failed - container \"" + containerItem.Name + "\" does not have an ItemContainer component!"); continue; } availableContainers.Add(itemContainer, itemContainer.Capacity); if (GameMain.Server != null) { Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false); } } } if (itemContainer == null) { //no container, place at the waypoint if (GameMain.Server != null) { Entity.Spawner.AddToSpawnQueue(prefab, position, wp.Submarine); } else { new Item(prefab, position, wp.Submarine); } } else { //place in the container if (GameMain.Server != null) { Entity.Spawner.AddToSpawnQueue(prefab, itemContainer.Inventory); } else { var item = new Item(prefab, position, wp.Submarine); itemContainer.Inventory.TryPutItem(item, null); } //reduce the number of available slots in the container availableContainers[itemContainer]--; if (availableContainers[itemContainer] <= 0) { availableContainers.Remove(itemContainer); } } } itemsToSpawn.Clear(); }