public static void AD_CastingSkill(ActionDisplay actionDisplay, IMap map, Entity source, Entity target) { // The maximum life the effects will have. This way, if the entity gets stuck with IsCastingSkill set to true, // the effects will at least go away eventually. Make sure that this is not greater than the longest possible // time to cast a skill. const int maxEffectLife = 1000 * 20; var drawableMap = map as IDrawableMap; var sourceAsCharacter = source as Character; var castingEffects = new List <ITemporaryMapEffect>(); // Make sure we have a valid source if (sourceAsCharacter == null) { const string errmsg = "AD_CastingSkill requires a Character as the source, but the source ({0}) is type `{1}`."; if (log.IsErrorEnabled) { log.ErrorFormat(errmsg, source, source.GetType()); } Debug.Fail(string.Format(errmsg, source, source.GetType())); return; } // Play the sound PlaySoundSimple(actionDisplay, source); // Check if we can properly display the effect if (drawableMap != null) { // Show the graphic going from the source to target if (actionDisplay.GrhIndex != GrhIndex.Invalid) { var gd = GrhInfo.GetData(actionDisplay.GrhIndex); if (gd != null) { // Make the effect loop indefinitely var grh = new Grh(gd, AnimType.Loop, TickCount.Now); var effect = new MapGrhEffectTimed(grh, source.Center, maxEffectLife) { MapRenderLayer = MapRenderLayer.SpriteForeground }; drawableMap.AddTemporaryMapEffect(effect); castingEffects.Add(effect); } } // Show the particle effect var pe = ParticleEffectManager.Instance.TryCreateEffect(actionDisplay.ParticleEffect); if (pe != null) { // Effect that just takes place on the caster pe.Position = source.Center; pe.Life = maxEffectLife; var effect = new TemporaryMapParticleEffect(pe) { MapRenderLayer = MapRenderLayer.SpriteForeground }; drawableMap.AddTemporaryMapEffect(effect); castingEffects.Add(effect); } } // Make sure we have at least one valid effect. If not, there is nothing more to do. if (castingEffects.Count <= 0) { return; } // Add the list of effects to our local dictionary lock (_activeCastingSkillEffectsSync) { // Make sure they don't already have effects in the dictionary RemoveFromActiveCastingSkillEffects(sourceAsCharacter); // Add to the dictionary _activeCastingSkillEffects.Add(sourceAsCharacter, castingEffects); } // Attach the listener for the IsCastingSkill sourceAsCharacter.IsCastingSkillChanged += AD_CastingSkill_Character_IsCastingSkillChanged; // If the source already finished casting the skill, destroy them now since we probably missed the event if (!sourceAsCharacter.IsCastingSkill) { RemoveFromActiveCastingSkillEffects(sourceAsCharacter); } }
public ItemEntity(GrhIndex graphicIndex, byte amount, TickCount currentTime) : base(Vector2.Zero, Vector2.Zero) { Amount = amount; _grh = new Grh(GrhInfo.GetData(graphicIndex), AnimType.Loop, currentTime); }
public static void AD_SkillCasted(ActionDisplay actionDisplay, IMap map, Entity source, Entity target) { var drawableMap = map as IDrawableMap; // Play the sound PlaySoundSimple(actionDisplay, source); // Check if we can properly display the effect if (drawableMap != null && source != null) { if (actionDisplay.GrhIndex != GrhIndex.Invalid) { if (target != null && target != source) { // Show the graphic going from the source to target var gd = GrhInfo.GetData(actionDisplay.GrhIndex); if (gd != null) { var grh = new Grh(gd, AnimType.Loop, TickCount.Now); var effect = new MapGrhEffectSeekPosition(grh, source.Center, target.Center, 750f) { MapRenderLayer = MapRenderLayer.SpriteForeground }; drawableMap.AddTemporaryMapEffect(effect); } } else { // Show the graphic at the source var gd = GrhInfo.GetData(actionDisplay.GrhIndex); if (gd != null) { var grh = new Grh(gd, AnimType.Loop, TickCount.Now); var effect = new MapGrhEffectLoopOnce(grh, source.Center) { MapRenderLayer = MapRenderLayer.SpriteForeground }; drawableMap.AddTemporaryMapEffect(effect); } } } // Show the particle effect var pe = ParticleEffectManager.Instance.TryCreateEffect(actionDisplay.ParticleEffect); if (pe != null) { pe.Position = source.Center; ITemporaryMapEffect effect; if (target != null && target != source) { // Effect that seeks out the position of the target effect = new TemporaryMapParticleEffectSeekPosition(pe, target.Center, 250f) { MapRenderLayer = MapRenderLayer.SpriteForeground }; } else { // Effect that takes place at the source effect = new TemporaryMapParticleEffect(pe) { MapRenderLayer = MapRenderLayer.SpriteForeground }; } // Add the effect to the map if (effect != null) { drawableMap.AddTemporaryMapEffect(effect); } } } }
/// <summary> /// Gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="grhIndex">The <see cref="GrhIndex"/> to get the <see cref="Image"/> for.</param> /// <returns>The <see cref="Image"/> for the <paramref name="grhIndex"/>.</returns> public Image GetImage(GrhIndex grhIndex) { var gd = GrhInfo.GetData(grhIndex); return(GetImage(gd)); }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="grhIndex">The <see cref="GrhIndex"/> to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void GetImageAsync(GrhIndex grhIndex, GrhImageListAsyncCallback callback, object userState) { var gd = GrhInfo.GetData(grhIndex); GetImageAsync(gd, callback, userState); }
void btnAccept_Click(object sender, EventArgs e) { var gdStationary = _gd as StationaryGrhData; var gdAnimated = _gd as AnimatedGrhData; // Validate the category and title, making sure its unique if (!ValidateCategorization(true)) { return; } if (radioAnimated.Checked) { // Generate the frames var framesText = txtFrames.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); var frames = new GrhIndex[framesText.Length]; for (var i = 0; i < framesText.Length; i++) { // First check if it was entered as by the index if (!Parser.Current.TryParse(framesText[i], out frames[i])) { // Support it being entered by category var lastPeriod = framesText[i].LastIndexOf('.'); var category = framesText[i].Substring(0, lastPeriod); var title = framesText[i].Substring(lastPeriod + 1); var tempGD = GrhInfo.GetData(category, title); if (tempGD != null) { frames[i] = tempGD.GrhIndex; } } } // Check that all the frames are valid foreach (var frame in frames) { if (GrhInfo.GetData(frame) == null) { MessageBox.Show("GrhIndex [" + frame + "] does not exist! Aborting save..."); return; } } } // Validate the strings GrhIndex newIndex; if (Parser.Current.TryParse(txtIndex.Text, out newIndex)) { if (newIndex != _gd.GrhIndex) { if ( MessageBox.Show("Are you sure you wish to change the index? Changes will not be reflected on maps!", "Change GrhIndex", MessageBoxButtons.YesNo) == DialogResult.No) { return; } if (GrhInfo.GetData(newIndex) != null) { MessageBox.Show("Index already in use"); return; } } } else { MessageBox.Show("Invalid index specified"); return; } // Get the categorization var categorization = new SpriteCategorization(txtCategory.GetSanitizedText(), txtTitle.Text); // Set the information if (radioStationary.Checked) { if (gdStationary == null) { MessageBox.Show("For some reason, could not cast the GrhData to StationaryGrhData..."); return; } // Stationary var cm = gdStationary.ContentManager; var x = Parser.Current.ParseInt(txtX.Text); var y = Parser.Current.ParseInt(txtY.Text); var w = Parser.Current.ParseInt(txtW.Text); var h = Parser.Current.ParseInt(txtH.Text); var textureName = txtTexture.GetSanitizedText(); var autoSize = chkAutoSize.Checked; // Validate the texture try { cm.LoadImage("Grh" + DirSep + textureName, ContentLevel.Map); } catch (Exception ex) { MessageBox.Show("Unable to load texture [" + textureName + "]! Aborting save..." + Environment.NewLine + ex); return; } gdStationary.ChangeTexture(textureName, new Rectangle(x, y, w, h)); _gd.SetCategorization(categorization); gdStationary.AutomaticSize = autoSize; } else { // Animated if (gdAnimated == null) { MessageBox.Show("For some reason, could not cast the GrhData to AnimatedGrhData..."); return; } var speed = Parser.Current.ParseFloat(txtSpeed.Text); gdAnimated.SetSpeed(speed); } // Set the MapGrhWalls _mapGrhWalls[_gd] = BoundWalls.ToList(); // Write Enabled = false; GrhInfo.Save(ContentPaths.Dev); Enabled = true; WasCanceled = false; DialogResult = DialogResult.OK; }
/// <summary> /// Updates the sizes of the <see cref="StationaryGrhData"/>s where <see cref="StationaryGrhData.AutomaticSize"/> is set and /// the cached size is invalid. /// </summary> public virtual void UpdateSizes() { // Loop through all StationaryGrhDatas foreach (var gd in GrhInfo.GrhDatas.OfType <StationaryGrhData>()) { // Check that AutomaticSize is set if (!gd.AutomaticSize) { continue; } // Make sure the asset exists in the dev path var devTexturePath = TryGetAbsoluteFilePath(gd, ContentPaths.Dev); if (devTexturePath == null) { continue; } // Get the size of the file from the Dev path since we will be needing it later var realFileSize = GetFileSize(devTexturePath); // Check if the GrhData is in the cache CacheItemInfo cacheItem; if (_cache.TryGetValue(gd.GrhIndex, out cacheItem)) { Debug.Assert(gd.GrhIndex == cacheItem.GrhIndex); // The GrhData was in the cache, so check that the cache information is still valid if (gd.Width == cacheItem.Width && gd.Height == cacheItem.Height && gd.TextureName == cacheItem.AssetName && realFileSize == cacheItem.FileSize) { // All of the cached values match the values in the GrhData, so assume its up-to-date and move to the next continue; } } // Make sure the asset exists in the build path var buildTexturePath = TryGetAbsoluteFilePath(gd, ContentPaths.Build); if (buildTexturePath == null) { continue; } // The GrhData was not in the cache or the cache contains outdated values, so find the real size by grabbing it directly // from the GrhData's texture var realSize = new Vector2(gd.Texture.Width, gd.Texture.Height); // To avoid using too much memory, we will dispose of the texture after we are done. Since the textures are lazy-loaded and // automatically reload, this will not do any harm. We may end up disposing a few textures that were actually being used // right now, but that is not a big deal. gd.Texture.Dispose(); // Set the new size gd.UpdateAutomaticSize(realSize); // Update the cache var addToCache = false; if (cacheItem == null) { cacheItem = new CacheItemInfo(); addToCache = true; } cacheItem.AssetName = gd.TextureName; cacheItem.Width = (int)realSize.X; cacheItem.Height = (int)realSize.Y; cacheItem.GrhIndex = gd.GrhIndex; cacheItem.FileSize = realFileSize; // Since the CacheItemInfo is an object, we only need to add it to the dictionary if it didn't already exist in it if (addToCache) { _cache.Add(cacheItem.GrhIndex, cacheItem); } } // Be sure to remove any cache items for GrhDatas that no longer exist just to make sure they don't cause any problems // later (and to help remove some storage overhead) var toRemove = new Stack <GrhIndex>(); foreach (var cacheItem in _cache) { if (GrhInfo.GetData(cacheItem.Key) == null) { toRemove.Push(cacheItem.Key); } } while (toRemove.Count > 0) { var removeGrhIndex = toRemove.Pop(); _cache.Remove(removeGrhIndex); } // Save the cache and the GrhDatas Save(); GrhInfo.Save(ContentPaths.Dev); }
/// <summary> /// Updates a GrhData's information in the tree /// </summary> /// <param name="grhIndex">Index of the GrhData to update</param> public void UpdateGrhData(GrhIndex grhIndex) { UpdateGrhData(GrhInfo.GetData(grhIndex)); }
/// <summary> /// Initializes a new instance of the <see cref="DemoGame"/> class. /// </summary> public DemoGame() : base( new Point((int)GameData.ScreenSize.X, (int)GameData.ScreenSize.Y), new Point((int)GameData.ScreenSize.X, (int)GameData.ScreenSize.Y), GameMessageCollection.CurrentLanguage.GetMessage(GameMessage.GameTitle)) { ThreadAsserts.IsMainThread(); EngineSettingsInitializer.Initialize(); // Create the screen manager var skinManager = new SkinManager("Default"); _screenManager = new ScreenManager(this, skinManager, "Font/Arial", 24); // Initialize the socket manager ClientSockets.Initialize(ScreenManager); _sockets = ClientSockets.Instance; // Read the GrhInfo LoadGrhInfo(); var lightGD = GrhInfo.GetData("Effect", "light"); _screenManager.DrawingManager.LightManager.DefaultSprite = new Grh(lightGD); // Set up our custom chat bubbles ChatBubble.CreateChatBubbleInstance = CreateChatBubbleInstanceHandler; // Get our title song var titleSong = ScreenManager.AudioManager.MusicManager.MusicInfos.ElementAt(0); // Create the screens new OptionsScreen(ScreenManager) { ScreenMusic = titleSong };; new GameplayScreen(ScreenManager); new MainMenuScreen(ScreenManager) { ScreenMusic = titleSong }; new LoginScreen(ScreenManager) { ScreenMusic = titleSong };; new CharacterSelectionScreen(ScreenManager) { ScreenMusic = titleSong };; new CreateCharacterScreen(ScreenManager) { ScreenMusic = titleSong };; new NewAccountScreen(ScreenManager) { ScreenMusic = titleSong };; ScreenManager.ConsoleScreen = new ConsoleScreen(ScreenManager); ScreenManager.SetScreen <MainMenuScreen>(); ShowMouseCursor = true; KeyPressed -= DemoGame_KeyPressed; KeyPressed += DemoGame_KeyPressed; var clientSettings = ClientSettings.Default; // Apply some of the initial settings ScreenManager.AudioManager.SoundManager.Volume = clientSettings.Audio_SoundVolume; ScreenManager.AudioManager.MusicManager.Volume = clientSettings.Audio_MusicVolume; UseVerticalSync = clientSettings.Graphics_VSync; IsFullscreen = clientSettings.Graphics_Fullscreen; // Listen for changes to the settings clientSettings.PropertyChanged -= Default_PropertyChanged; clientSettings.PropertyChanged += Default_PropertyChanged; }
/// <summary> /// Updates all of the automaticly added GrhDatas. /// </summary> /// <param name="cm"><see cref="IContentManager"/> to use for new GrhDatas.</param> /// <param name="rootGrhDir">Root Grh texture directory.</param> /// <param name="added">The GrhDatas that were added (empty if none were added).</param> /// <param name="deleted">The GrhDatas that were deleted (empty if none were added).</param> /// <param name="grhDataFileTags">The file tags for the corresponding GrhDatas.</param> /// <returns> /// IEnumerable of all of the new GrhDatas created. /// </returns> public static void Update(IContentManager cm, string rootGrhDir, out GrhData[] added, out GrhData[] deleted, out Dictionary <GrhData, GrhData.FileTags> grhDataFileTags) { if (!rootGrhDir.EndsWith("\\") && !rootGrhDir.EndsWith("/")) { rootGrhDir += "/"; } // Clear the temporary content to make sure we have plenty of working memory cm.Unload(ContentLevel.Temporary, true); // Get the relative file path for all files up-front (only do this once since it doesn't scale well) var relFilePaths = Directory.GetFiles(rootGrhDir, "*", SearchOption.AllDirectories) .Select(x => x.Replace('\\', '/').Substring(rootGrhDir.Length)) .ToArray(); // Also grab the existing GrhDatas var existingGrhDatas = GrhInfo.GrhDatas.ToDictionary(x => x.Categorization.ToString(), x => x); // Go through each file and do the adds grhDataFileTags = new Dictionary <GrhData, GrhData.FileTags>(); HashSet <GrhData> addedGrhDatas = new HashSet <GrhData>(); HashSet <GrhData> deletedGrhDatas = new HashSet <GrhData>(); HashSet <GrhData> grhDatasToDelete = new HashSet <GrhData>(existingGrhDatas.Values); HashSet <string> checkedAnimationRelDirs = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var relFilePath in relFilePaths) { // Before doing anything else, ensure it is a valid file type to handle string fileExtension = Path.GetExtension(relFilePath); if (!_graphicFileSuffixes.Contains(fileExtension, StringComparer.OrdinalIgnoreCase)) { continue; } string absFilePath = rootGrhDir + relFilePath; // Grab some stuff based on the file path string absDir = Path.GetDirectoryName(absFilePath); if (rootGrhDir.Length >= absDir.Length) { continue; } string relDir = absDir.Substring(rootGrhDir.Length); string parentDirName = absDir.Substring(Path.GetDirectoryName(absDir).Length + 1); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(relFilePath); bool isAnimationFrame = parentDirName.StartsWith("_"); if (!isAnimationFrame) { // ** Stationary ** var fileTags = GrhData.FileTags.Create(fileNameWithoutExtension); // Build the categorization info string category = relDir.Replace("/", SpriteCategorization.Delimiter).Replace("\\", SpriteCategorization.Delimiter); SpriteCategorization cat = new SpriteCategorization(category, fileTags.Title); // Get existing GrhIndex?grhIndex = null; GrhData grhData; if (existingGrhDatas.TryGetValue(cat.ToString(), out grhData)) { grhDatasToDelete.Remove(grhData); } // If already exists as animated, delete first if (grhData != null && (grhData is AnimatedGrhData || grhData is AutomaticAnimatedGrhData)) { grhIndex = grhData.GrhIndex; // We will re-use this GrhIndex GrhInfo.Delete(grhData); deletedGrhDatas.Add(grhData); grhData = null; } // Add new string texturePath = "/" + relFilePath.Substring(0, relFilePath.Length - Path.GetExtension(absFilePath).Length); if (grhData == null) { grhData = GrhInfo.CreateGrhData(cm, cat, texturePath, grhIndex); addedGrhDatas.Add(grhData); } else { // Make sure the texture is correct string currTextureName = "/" + ((StationaryGrhData)grhData).TextureName.ToString().TrimStart('/', '\\'); if (currTextureName != texturePath) { ((StationaryGrhData)grhData).ChangeTexture(texturePath); } } // Ensure set to auto-size StationaryGrhData stationaryGrhData = (StationaryGrhData)grhData; if (!stationaryGrhData.AutomaticSize) { stationaryGrhData.AutomaticSize = true; } // Add to GrhDataFileTags if (grhDataFileTags.ContainsKey(grhData)) { throw new GrhDataException(grhData, string.Format("Found more than one stationary GrhData with the categorization: `{0}`." + " Make sure that you do not have multiple image files in /DevContent/ in the same folder with the same name but different extensions (e.g. Sprite.png and Sprite.jpg).", grhData.Categorization)); } grhDataFileTags.Add(grhData, fileTags); } else { // ** Animated ** // Make sure we only handle each animation once (since this will get called for each frame since we're looping over the files) if (!checkedAnimationRelDirs.Add(relDir)) { continue; } var fileTags = GrhData.FileTags.Create(parentDirName.Substring(1)); // Remove the _ prefix from directory name // Build the categorization string category = Path.GetDirectoryName(absDir).Substring(rootGrhDir.Length) .Replace("/", SpriteCategorization.Delimiter).Replace("\\", SpriteCategorization.Delimiter); SpriteCategorization cat = new SpriteCategorization(category, fileTags.Title); // Get existing GrhIndex?grhIndex = null; GrhData grhData; if (existingGrhDatas.TryGetValue(cat.ToString(), out grhData)) { grhDatasToDelete.Remove(grhData); // If already exists as stationary, delete first if (grhData is StationaryGrhData) { grhIndex = grhData.GrhIndex; // We will re-use this GrhIndex GrhInfo.Delete(grhData); deletedGrhDatas.Add(grhData); grhData = null; } } // Add new if (grhData == null) { grhData = GrhInfo.CreateAutomaticAnimatedGrhData(cm, cat, grhIndex); addedGrhDatas.Add(grhData); } // Add to GrhDataFileTags if (grhDataFileTags.ContainsKey(grhData)) { throw new GrhDataException(grhData, string.Format("Found more than one animated GrhData with the categorization: `{0}`." + " Make sure that you do not have multiple sub-folders in /DevContent/ in the same folder with the same name but different folder tags (e.g. /_Sprite[s100]/ and /_Sprite[s200]/).", grhData.Categorization)); } grhDataFileTags.Add(grhData, fileTags); } } // Now check if there are any GrhDatas to be deleted by taking existing GrhDatas, getting their relative path, and // see if that exists in our relative path list we built earlier against the file system foreach (var toDelete in grhDatasToDelete) { GrhInfo.Delete(toDelete); deletedGrhDatas.Add(toDelete); } if (log.IsInfoEnabled) { log.WarnFormat("Automatic GrhData creation update resulted in `{0}` new GrhData(s) and `{1}` deleted GrhData(s).", addedGrhDatas.Count, deletedGrhDatas.Count); } added = addedGrhDatas.ToArray(); deleted = deletedGrhDatas.ToArray(); }
/// <summary> /// Gets the <see cref="ISprite"/> for the skin with the given <see cref="SpriteTitle"/>. /// </summary> /// <param name="subCategory">The sprite sub-category under the skin.</param> /// <param name="spriteTitle">The title of the <see cref="ISprite"/> to get.</param> /// <returns>The <see cref="ISprite"/> for the skin with the given <see cref="SpriteTitle"/>, /// or null if no <see cref="ISprite"/> could be created with the given categorization information.</returns> public ISprite GetSprite(SpriteCategory subCategory, SpriteTitle spriteTitle) { var key = string.Empty; if (subCategory != null && subCategory.ToString().Length > 0) { key += subCategory; } if (spriteTitle != null) { key += "." + spriteTitle; } // Check for the sprite in the cache ISprite sprite; if (_spriteCache.TryGetValue(key, out sprite)) { return(sprite); } // Check for the sprite in the current skin var fullSC = GetSpriteCategory(CurrentSkin, subCategory); var grhData = GrhInfo.GetData(fullSC, spriteTitle); // The sprite was not found in the current category, so check the default category only if the current category // is not the default category if (grhData == null && !IsCurrentSkinDefault) { fullSC = GetSpriteCategory(DefaultSkin, subCategory); grhData = GrhInfo.GetData(fullSC, spriteTitle); } // If the grhData is not null, create the sprite, otherwise have the sprite be null if (grhData == null) { sprite = null; } else { sprite = new Grh(grhData); } // Add the sprite to the cache, even if it is null try { if (sprite != null) { _spriteCache.Add(key, sprite); } } catch (ArgumentException ex) { const string errmsg = "Key `{0}` already exists. Multi-threading conflict? This should never happen, but its likely not critical. Exception: {1}"; if (log.IsWarnEnabled) { log.WarnFormat(errmsg, key, ex); } Debug.Fail(string.Format(errmsg, key, ex)); } // Return the sprite return(sprite); }
/// <summary> /// Adds the <see cref="GrhData"/>. /// </summary> /// <param name="cm">The <see cref="IContentManager"/> to use.</param> /// <returns> /// The <see cref="GrhData"/> that was added. /// </returns> public GrhData Add(IContentManager cm) { return(GrhInfo.CreateAutomaticAnimatedGrhData(cm, _categorization)); }