public MapPlayers(Ruleset rules, int playerCount) { var firstFaction = rules.Actors["world"].TraitInfos<FactionInfo>() .First(f => f.Selectable).InternalName; Players = new Dictionary<string, PlayerReference> { { "Neutral", new PlayerReference { Name = "Neutral", Faction = firstFaction, OwnsWorld = true, NonCombatant = true } }, { "Creeps", new PlayerReference { Name = "Creeps", Faction = firstFaction, NonCombatant = true, Enemies = Exts.MakeArray(playerCount, i => "Multi{0}".F(i)) } } }; for (var index = 0; index < playerCount; index++) { var p = new PlayerReference { Name = "Multi{0}".F(index), Faction = "Random", Playable = true, Enemies = new[] { "Creeps" } }; Players.Add(p.Name, p); } }
public void FixOpenAreas(Ruleset rules) { var r = new Random(); var tileset = rules.TileSets[Tileset]; for (var j = Bounds.Top; j < Bounds.Bottom; j++) { for (var i = Bounds.Left; i < Bounds.Right; i++) { var type = MapTiles.Value[new MPos(i, j)].Type; var index = MapTiles.Value[new MPos(i, j)].Index; if (!tileset.Templates.ContainsKey(type)) { Console.WriteLine("Unknown Tile ID {0}".F(type)); continue; } var template = tileset.Templates[type]; if (!template.PickAny) continue; index = (byte)r.Next(0, template.TilesCount); MapTiles.Value[new MPos(i, j)] = new TerrainTile(type, index); } } }
// Returns true if played successfully public bool PlayPredefined(Ruleset ruleset, Player p, Actor voicedActor, string type, string definition, string variant, bool relative, WPos pos, float volumeModifier, bool attenuateVolume) { if (ruleset == null) throw new ArgumentNullException("ruleset"); if (definition == null) return false; if (ruleset.Voices == null || ruleset.Notifications == null) return false; var rules = (voicedActor != null) ? ruleset.Voices[type] : ruleset.Notifications[type]; if (rules == null) return false; var id = voicedActor != null ? voicedActor.ActorID : 0; string clip; var suffix = rules.DefaultVariant; var prefix = rules.DefaultPrefix; if (voicedActor != null) { if (!rules.VoicePools.Value.ContainsKey(definition)) throw new InvalidOperationException("Can't find {0} in voice pool.".F(definition)); clip = rules.VoicePools.Value[definition].GetNext(); } else { if (!rules.NotificationsPools.Value.ContainsKey(definition)) throw new InvalidOperationException("Can't find {0} in notification pool.".F(definition)); clip = rules.NotificationsPools.Value[definition].GetNext(); } if (string.IsNullOrEmpty(clip)) return false; if (variant != null) { if (rules.Variants.ContainsKey(variant) && !rules.DisableVariants.Contains(definition)) suffix = rules.Variants[variant][id % rules.Variants[variant].Length]; if (rules.Prefixes.ContainsKey(variant) && !rules.DisablePrefixes.Contains(definition)) prefix = rules.Prefixes[variant][id % rules.Prefixes[variant].Length]; } var name = prefix + clip + suffix; if (!string.IsNullOrEmpty(name) && (p == null || p == p.World.LocalPlayer)) { var sound = soundEngine.Play2D(sounds[name], false, relative, pos, InternalSoundVolume * volumeModifier, attenuateVolume); if (id != 0) { if (currentSounds.ContainsKey(id)) soundEngine.StopSound(currentSounds[id]); currentSounds[id] = sound; } } return true; }
public NewMapLogic(Action onExit, Action<string> onSelect, Ruleset modRules, Widget widget, World world) { panel = widget; panel.Get<ButtonWidget>("CANCEL_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; var tilesetDropDown = panel.Get<DropDownButtonWidget>("TILESET"); var tilesets = modRules.TileSets.Select(t => t.Key).ToList(); Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, () => tilesetDropDown.Text == option, () => { tilesetDropDown.Text = option; }); item.Get<LabelWidget>("LABEL").GetText = () => option; return item; }; tilesetDropDown.Text = tilesets.First(); tilesetDropDown.OnClick = () => tilesetDropDown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 210, tilesets, setupItem); var widthTextField = panel.Get<TextFieldWidget>("WIDTH"); var heightTextField = panel.Get<TextFieldWidget>("HEIGHT"); panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = () => { var tileset = modRules.TileSets[tilesetDropDown.Text]; var map = Map.FromTileset(tileset); int width, height; int.TryParse(widthTextField.Text, out width); int.TryParse(heightTextField.Text, out height); // Require at least a 2x2 playable area so that the // ground is visible through the edge shroud width = Math.Max(2, width); height = Math.Max(2, height); map.Resize(width + 2, height + tileset.MaxGroundHeight + 2); map.ResizeCordon(1, 1, width + 1, height + tileset.MaxGroundHeight + 1); map.PlayerDefinitions = new MapPlayers(map.Rules, map.SpawnPoints.Value.Length).ToMiniYaml(); map.FixOpenAreas(modRules); var userMapFolder = Game.ModData.Manifest.MapFolders.First(f => f.Value == "User").Key; // Ignore optional flag if (userMapFolder.StartsWith("~")) userMapFolder = userMapFolder.Substring(1); var mapDir = Platform.ResolvePath(userMapFolder); Directory.CreateDirectory(mapDir); var tempLocation = Path.Combine(mapDir, "temp") + ".oramap"; map.Save(tempLocation); // TODO: load it right away and save later properly var newMap = new Map(tempLocation); Game.ModData.MapCache[newMap.Uid].UpdateFromMap(newMap, MapClassification.User); ConnectionLogic.Connect(System.Net.IPAddress.Loopback.ToString(), Game.CreateLocalServer(newMap.Uid), "", () => { Game.LoadEditor(newMap.Uid); }, () => { Game.CloseServer(); onExit(); }); onSelect(newMap.Uid); }; }
public NewMapLogic(Action onExit, Action<string> onSelect, Ruleset modRules, Widget widget, World world) { panel = widget; panel.Get<ButtonWidget>("CANCEL_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; var tilesetDropDown = panel.Get<DropDownButtonWidget>("TILESET"); var tilesets = modRules.TileSets.Select(t => t.Key).ToList(); Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, () => tilesetDropDown.Text == option, () => { tilesetDropDown.Text = option; }); item.Get<LabelWidget>("LABEL").GetText = () => option; return item; }; tilesetDropDown.Text = tilesets.First(); tilesetDropDown.OnClick = () => tilesetDropDown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 210, tilesets, setupItem); var widthTextField = panel.Get<TextFieldWidget>("WIDTH"); var heightTextField = panel.Get<TextFieldWidget>("HEIGHT"); panel.Get<ButtonWidget>("CREATE_BUTTON").OnClick = () => { int width, height; int.TryParse(widthTextField.Text, out width); int.TryParse(heightTextField.Text, out height); // Require at least a 2x2 playable area so that the // ground is visible through the edge shroud width = Math.Max(2, width); height = Math.Max(2, height); var maxTerrainHeight = Game.ModData.Manifest.MaximumTerrainHeight; var tileset = modRules.TileSets[tilesetDropDown.Text]; var map = new Map(tileset, width + 2, height + maxTerrainHeight + 2); var tl = new MPos(1, 1); var br = new MPos(width, height + maxTerrainHeight); map.SetBounds(tl, br); map.PlayerDefinitions = new MapPlayers(map.Rules, map.SpawnPoints.Value.Length).ToMiniYaml(); map.FixOpenAreas(modRules); Action<string> afterSave = uid => { // HACK: Work around a synced-code change check. // It's not clear why this is needed here, but not in the other places that load maps. Game.RunAfterTick(() => { ConnectionLogic.Connect(System.Net.IPAddress.Loopback.ToString(), Game.CreateLocalServer(uid), "", () => Game.LoadEditor(uid), () => { Game.CloseServer(); onExit(); }); }); Ui.CloseWindow(); onSelect(uid); }; Ui.OpenWindow("SAVE_MAP_PANEL", new WidgetArgs() { { "onSave", afterSave }, { "onExit", () => { Ui.CloseWindow(); onExit(); } }, { "map", map }, { "playerDefinitions", map.PlayerDefinitions }, { "actorDefinitions", map.ActorDefinitions } }); }; }
public bool PlayNotification(Ruleset rules, Player player, string type, string notification, string variant) { if (rules == null) throw new ArgumentNullException("rules"); if (type == null || notification == null) return false; return PlayPredefined(rules, player, null, type.ToLowerInvariant(), notification, variant, true, WPos.Zero, 1f, false); }
public ModData(Manifest mod, InstalledMods mods, bool useLoadScreen = false) { Languages = new string[0]; // Take a local copy of the manifest Manifest = new Manifest(mod.Id, mod.Package); ObjectCreator = new ObjectCreator(Manifest, mods); PackageLoaders = ObjectCreator.GetLoaders <IPackageLoader>(Manifest.PackageFormats, "package"); ModFiles = new FS(mod.Id, mods, PackageLoaders); ModFiles.LoadFromManifest(Manifest); Manifest.LoadCustomData(ObjectCreator); if (useLoadScreen) { LoadScreen = ObjectCreator.CreateObject <ILoadScreen>(Manifest.LoadScreen.Value); LoadScreen.Init(this, Manifest.LoadScreen.ToDictionary(my => my.Value)); LoadScreen.Display(); } WidgetLoader = new WidgetLoader(this); MapCache = new MapCache(this); SoundLoaders = ObjectCreator.GetLoaders <ISoundLoader>(Manifest.SoundFormats, "sound"); SpriteLoaders = ObjectCreator.GetLoaders <ISpriteLoader>(Manifest.SpriteFormats, "sprite"); VideoLoaders = ObjectCreator.GetLoaders <IVideoLoader>(Manifest.VideoFormats, "video"); var terrainFormat = Manifest.Get <TerrainFormat>(); var terrainLoader = ObjectCreator.FindType(terrainFormat.Type + "Loader"); var terrainCtor = terrainLoader?.GetConstructor(new[] { typeof(ModData) }); if (terrainLoader == null || !terrainLoader.GetInterfaces().Contains(typeof(ITerrainLoader)) || terrainCtor == null) { throw new InvalidOperationException("Unable to find a terrain loader for type '{0}'.".F(terrainFormat.Type)); } TerrainLoader = (ITerrainLoader)terrainCtor.Invoke(new[] { this }); var sequenceFormat = Manifest.Get <SpriteSequenceFormat>(); var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader"); var sequenceCtor = sequenceLoader != null?sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null; if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || sequenceCtor == null) { throw new InvalidOperationException("Unable to find a sequence loader for type '{0}'.".F(sequenceFormat.Type)); } SpriteSequenceLoader = (ISpriteSequenceLoader)sequenceCtor.Invoke(new[] { this }); var modelFormat = Manifest.Get <ModelSequenceFormat>(); var modelLoader = ObjectCreator.FindType(modelFormat.Type + "Loader"); var modelCtor = modelLoader != null?modelLoader.GetConstructor(new[] { typeof(ModData) }) : null; if (modelLoader == null || !modelLoader.GetInterfaces().Contains(typeof(IModelSequenceLoader)) || modelCtor == null) { throw new InvalidOperationException("Unable to find a model loader for type '{0}'.".F(modelFormat.Type)); } ModelSequenceLoader = (IModelSequenceLoader)modelCtor.Invoke(new[] { this }); ModelSequenceLoader.OnMissingModelError = s => Log.Write("debug", s); Hotkeys = new HotkeyManager(ModFiles, Game.Settings.Keys, Manifest); defaultRules = Exts.Lazy(() => Ruleset.LoadDefaults(this)); defaultTerrainInfo = Exts.Lazy(() => { var items = new Dictionary <string, ITerrainInfo>(); foreach (var file in Manifest.TileSets) { var t = TerrainLoader.ParseTerrain(DefaultFileSystem, file); items.Add(t.Id, t); } return((IReadOnlyDictionary <string, ITerrainInfo>)(new ReadOnlyDictionary <string, ITerrainInfo>(items))); }); defaultSequences = Exts.Lazy(() => { var items = DefaultTerrainInfo.ToDictionary(t => t.Key, t => new SequenceProvider(DefaultFileSystem, this, t.Key, null)); return((IReadOnlyDictionary <string, SequenceProvider>)(new ReadOnlyDictionary <string, SequenceProvider>(items))); }); initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; }
// Returns true if played successfully public bool PlayPredefined(SoundType soundType, Ruleset ruleset, Player p, Actor voicedActor, string type, string definition, string variant, bool relative, WPos pos, float volumeModifier, bool attenuateVolume) { if (ruleset == null) { throw new ArgumentNullException("ruleset"); } if (definition == null || (DisableWorldSounds && soundType == SoundType.World)) { return(false); } if (ruleset.Voices == null || ruleset.Notifications == null) { return(false); } var rules = (voicedActor != null) ? ruleset.Voices[type] : ruleset.Notifications[type]; if (rules == null) { return(false); } var id = voicedActor != null ? voicedActor.ActorID : 0; string clip; var suffix = rules.DefaultVariant; var prefix = rules.DefaultPrefix; if (voicedActor != null) { if (!rules.VoicePools.Value.ContainsKey(definition)) { throw new InvalidOperationException("Can't find {0} in voice pool.".F(definition)); } clip = rules.VoicePools.Value[definition].GetNext(); } else { if (!rules.NotificationsPools.Value.ContainsKey(definition)) { throw new InvalidOperationException("Can't find {0} in notification pool.".F(definition)); } clip = rules.NotificationsPools.Value[definition].GetNext(); } if (string.IsNullOrEmpty(clip)) { return(false); } if (variant != null) { if (rules.Variants.ContainsKey(variant) && !rules.DisableVariants.Contains(definition)) { suffix = rules.Variants[variant][id % rules.Variants[variant].Length]; } if (rules.Prefixes.ContainsKey(variant) && !rules.DisablePrefixes.Contains(definition)) { prefix = rules.Prefixes[variant][id % rules.Prefixes[variant].Length]; } } var name = prefix + clip + suffix; if (!string.IsNullOrEmpty(name) && (p == null || p == p.World.LocalPlayer)) { var sound = soundEngine.Play2D(sounds[name], false, relative, pos, InternalSoundVolume * volumeModifier, attenuateVolume); if (id != 0) { if (currentSounds.ContainsKey(id)) { soundEngine.StopSound(currentSounds[id]); } currentSounds[id] = sound; } } return(true); }
public static Ruleset Load(ModData modData, IReadOnlyFileSystem fileSystem, string tileSet, MiniYaml mapRules, MiniYaml mapWeapons, MiniYaml mapVoices, MiniYaml mapNotifications, MiniYaml mapMusic, MiniYaml mapSequences, MiniYaml mapModelSequences) { var m = modData.Manifest; var dr = modData.DefaultRules; Ruleset ruleset = null; Action f = () => { var actors = MergeOrDefault("Rules", fileSystem, m.Rules, mapRules, dr.Actors, k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value), filterNode: n => n.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal)); var weapons = MergeOrDefault("Weapons", fileSystem, m.Weapons, mapWeapons, dr.Weapons, k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); var voices = MergeOrDefault("Voices", fileSystem, m.Voices, mapVoices, dr.Voices, k => new SoundInfo(k.Value)); var notifications = MergeOrDefault("Notifications", fileSystem, m.Notifications, mapNotifications, dr.Notifications, k => new SoundInfo(k.Value)); var music = MergeOrDefault("Music", fileSystem, m.Music, mapMusic, dr.Music, k => new MusicInfo(k.Key, k.Value)); // TODO: Add support for merging custom terrain modifications var terrainInfo = modData.DefaultTerrainInfo[tileSet]; // TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object var sequences = mapSequences == null ? modData.DefaultSequences[tileSet] : new SequenceProvider(fileSystem, modData, tileSet, mapSequences); var modelSequences = dr.ModelSequences; if (mapModelSequences != null) { modelSequences = MergeOrDefault("ModelSequences", fileSystem, m.ModelSequences, mapModelSequences, dr.ModelSequences, k => k); } ruleset = new Ruleset(actors, weapons, voices, notifications, music, terrainInfo, sequences, modelSequences); }; if (modData.IsOnMainThread) { modData.HandleLoadingProgress(); var loader = new Task(f); loader.Start(); // Animate the loadscreen while we wait while (!loader.Wait(40)) { modData.HandleLoadingProgress(); } } else { f(); } return(ruleset); }
public void UpdateRemoteSearch(MapStatus status, MiniYaml yaml, Action <MapPreview> parseMetadata = null) { var newData = innerData.Clone(); newData.Status = status; newData.Class = MapClassification.Remote; if (status == MapStatus.DownloadAvailable) { try { var r = FieldLoader.Load <RemoteMapData>(yaml); // Map download has been disabled server side if (!r.downloading) { newData.Status = MapStatus.Unavailable; return; } newData.Title = r.title; newData.Categories = r.categories; newData.Author = r.author; newData.PlayerCount = r.players; newData.Bounds = r.bounds; newData.TileSet = r.tileset; var spawns = new CPos[r.spawnpoints.Length / 2]; for (var j = 0; j < r.spawnpoints.Length; j += 2) { spawns[j / 2] = new CPos(r.spawnpoints[j], r.spawnpoints[j + 1]); } newData.SpawnPoints = spawns; newData.GridType = r.map_grid_type; try { newData.Preview = new Bitmap(new MemoryStream(Convert.FromBase64String(r.minimap))); } catch (Exception e) { Log.Write("debug", "Failed parsing mapserver minimap response: {0}", e); newData.Preview = null; } var playersString = Encoding.UTF8.GetString(Convert.FromBase64String(r.players_block)); newData.Players = new MapPlayers(MiniYaml.FromString(playersString)); newData.SetRulesetGenerator(modData, () => { var rulesString = Encoding.UTF8.GetString(Convert.FromBase64String(r.rules)); var rulesYaml = new MiniYaml("", MiniYaml.FromString(rulesString)).ToDictionary(); var ruleDefinitions = LoadRuleSection(rulesYaml, "Rules"); var weaponDefinitions = LoadRuleSection(rulesYaml, "Weapons"); var voiceDefinitions = LoadRuleSection(rulesYaml, "Voices"); var musicDefinitions = LoadRuleSection(rulesYaml, "Music"); var notificationDefinitions = LoadRuleSection(rulesYaml, "Notifications"); var sequenceDefinitions = LoadRuleSection(rulesYaml, "Sequences"); var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); return(Pair.New(rules, flagged)); }); } catch (Exception e) { Log.Write("debug", "Failed parsing mapserver response: {0}", e); } // Commit updated data before running the callbacks innerData = newData; if (innerData.Preview != null) { cache.CacheMinimap(this); } if (parseMetadata != null) { parseMetadata(this); } } // Update the status and class unconditionally innerData = newData; }
public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType) { Dictionary <string, MiniYaml> yaml; using (var yamlStream = p.GetStream("map.yaml")) { if (yamlStream == null) { throw new FileNotFoundException("Required file map.yaml not present in this map"); } yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, "map.yaml")).ToDictionary(); } Package = p; parentPackage = parent; var newData = innerData.Clone(); newData.GridType = gridType; newData.Class = classification; MiniYaml temp; if (yaml.TryGetValue("MapFormat", out temp)) { var format = FieldLoader.GetValue <int>("MapFormat", temp.Value); if (format != Map.SupportedMapFormat) { throw new InvalidDataException("Map format {0} is not supported.".F(format)); } } if (yaml.TryGetValue("Title", out temp)) { newData.Title = temp.Value; } if (yaml.TryGetValue("Categories", out temp)) { newData.Categories = FieldLoader.GetValue <string[]>("Categories", temp.Value); } if (yaml.TryGetValue("Tileset", out temp)) { newData.TileSet = temp.Value; } if (yaml.TryGetValue("Author", out temp)) { newData.Author = temp.Value; } if (yaml.TryGetValue("Bounds", out temp)) { newData.Bounds = FieldLoader.GetValue <Rectangle>("Bounds", temp.Value); } if (yaml.TryGetValue("Visibility", out temp)) { newData.Visibility = FieldLoader.GetValue <MapVisibility>("Visibility", temp.Value); } string requiresMod = string.Empty; if (yaml.TryGetValue("RequiresMod", out temp)) { requiresMod = temp.Value; } newData.Status = mapCompatibility == null || mapCompatibility.Contains(requiresMod) ? MapStatus.Available : MapStatus.Unavailable; try { // Actor definitions may change if the map format changes MiniYaml actorDefinitions; if (yaml.TryGetValue("Actors", out actorDefinitions)) { var spawns = new List <CPos>(); foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); spawns.Add(s.InitDict.Get <LocationInit>().Value(null)); } newData.SpawnPoints = spawns.ToArray(); } else { newData.SpawnPoints = new CPos[0]; } } catch (Exception) { newData.SpawnPoints = new CPos[0]; newData.Status = MapStatus.Unavailable; } try { // Player definitions may change if the map format changes MiniYaml playerDefinitions; if (yaml.TryGetValue("Players", out playerDefinitions)) { newData.Players = new MapPlayers(playerDefinitions.Nodes); newData.PlayerCount = newData.Players.Players.Count(x => x.Value.Playable); } } catch (Exception) { newData.Status = MapStatus.Unavailable; } newData.SetRulesetGenerator(modData, () => { var ruleDefinitions = LoadRuleSection(yaml, "Rules"); var weaponDefinitions = LoadRuleSection(yaml, "Weapons"); var voiceDefinitions = LoadRuleSection(yaml, "Voices"); var musicDefinitions = LoadRuleSection(yaml, "Music"); var notificationDefinitions = LoadRuleSection(yaml, "Notifications"); var sequenceDefinitions = LoadRuleSection(yaml, "Sequences"); var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); return(Pair.New(rules, flagged)); }); if (p.Contains("map.png")) { using (var dataStream = p.GetStream("map.png")) newData.Preview = new Bitmap(dataStream); } // Assign the new data atomically innerData = newData; }