/// <summary> /// Displays the icon in the system tray. /// </summary> public void SetIcon(System.IO.MemoryStream icon, string petName, string aboutAuthor, string aboutTitle, string aboutVersion, string aboutInfo) { bool success = true; try { ni.Icon = new Icon(icon, 32, 32); ContextMenus.UpdateIcon(ni.Icon, petName, aboutAuthor, aboutTitle, aboutVersion, aboutInfo); ni.Text = petName + " Desktop Pet"; } catch (Exception) { success = false; } if (!success) { try { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "Animation ICON is invalid (icon converter is on the webpage)"); ni.Icon = new Icon(Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location), 32, 32); ContextMenus.UpdateIcon(ni.Icon, petName, aboutAuthor, aboutTitle, aboutVersion, aboutInfo); } catch (Exception) { } // probably thread error. } }
/// <summary> /// Update the values of the animation.<br /> /// If "random" was used, on each start of a new animation this will change so the expression must be evaluated again.<br /> /// Total steps are also calculated, so it has a better performance by playing it. /// </summary> /// <param name="id">ID of the Animation.</param> private void UpdateAnimationValues(int id) { bool bUpdated = false; TAnimation ani = SheepAnimations[id]; if (ani.Sequence.Repeat.IsDynamic) { // Calculate the total steps, based on the repeat values. ani.Sequence.TotalSteps = ani.Sequence.CalculateTotalSteps(); bUpdated = true; } if (ani.Start.Interval.IsDynamic || ani.Start.X.IsDynamic || ani.Start.Y.IsDynamic) { ani.Start.Interval.Value = ani.Start.Interval.GetValue(); ani.Start.X.Value = ani.Start.X.GetValue(); ani.Start.Y.Value = ani.Start.Y.GetValue(); bUpdated = true; } if (ani.End.Interval.IsDynamic || ani.End.X.IsDynamic || ani.End.Y.IsDynamic) { ani.End.Interval.Value = ani.End.Interval.GetValue(); ani.End.X.Value = ani.End.X.GetValue(); ani.End.Y.Value = ani.End.Y.GetValue(); bUpdated = true; } // If a value was changed, overwrite the old structure with the new one. if (bUpdated) { SheepAnimations[id] = ani; } StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "new animation: " + ani.Name + " (" + ani.ID + ")"); }
/// <summary> /// Parse a value, converting keys like screenW, imageH, random,... to integers. /// </summary> /// <remarks> /// See <a href="https://msdn.microsoft.com/en-us/library/9za5w1xw(v=vs.100).aspx">https://msdn.microsoft.com/en-us/library/9za5w1xw(v=vs.100).aspx</a> /// for more information of what you can write as sText (expression to compute). /// </remarks> /// <param name="sText">The text to parse and convert.</param> /// <returns>The integer value from the parsed text expression.</returns> public int parseValue(string sText) { int iRet = 0; DataTable dt = new DataTable(); Random rand = new Random(); sText = sText.Replace("screenW", Screen.PrimaryScreen.Bounds.Width.ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("screenH", Screen.PrimaryScreen.Bounds.Height.ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("areaW", Screen.PrimaryScreen.WorkingArea.Width.ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("areaH", Screen.PrimaryScreen.WorkingArea.Height.ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageW", (FullImage.Width / AnimationXML.Image.TilesX).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageH", (FullImage.Height / AnimationXML.Image.TilesY).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageX", (parentX).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageY", (parentY).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("random", rand.Next(0, 100).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("randS", iRandomSpawn.ToString(CultureInfo.InvariantCulture)); var v = dt.Compute(sText, ""); double dv; if (double.TryParse(v.ToString(), out dv)) { iRet = (int)dv; } else { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "Unable to parse integer: " + sText); } return(iRet); }
/// <summary> /// Pet allows dropping other files. If you drop a XML animation file, the mouse icon will change. /// </summary> /// <param name="sender">Caller object.</param> /// <param name="e">Mouse event values.</param> private void Form2_DragEnter(object sender, DragEventArgs e) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "dragging file..."); if (e.Data.GetDataPresent(DataFormats.FileDrop)) { e.Effect = DragDropEffects.Copy; } }
/// <summary> /// Add another Child to the Child dictionary. Childs are defined in the XML. /// <seealso cref="AddAnimation(int, string)"/> /// <seealso cref="AddSpawn(int, int)"/> /// </summary> /// <param name="ID">Child unique ID.</param> /// <returns></returns> public TChild AddChild(int ID) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "adding child: ani." + ID.ToString()); if (!SheepChild.ContainsKey(ID)) // does not contains childs { SheepChild.Add(ID, new List <TChild>(1)); } SheepChild[ID].Add(new TChild()); return(SheepChild[ID].Last()); }
/// <summary> /// Pet allows dropping other files. If a XML file was dropped, this one will be loaded. /// </summary> /// <param name="sender">Caller object.</param> /// <param name="e">Dragging event values.</param> private void Form2_DragDrop(object sender, DragEventArgs e) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "files dragged:"); string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); foreach (string file in files) { Program.Mainthread.LoadNewXMLFromString(File.ReadAllText(file)); break; // Currently only 1 file, in future maybe more animations at the same time } }
/// <summary> /// Set the next animation, once the last one was finished. /// </summary> /// <param name="list">List of animations that can be executed.</param> /// <param name="where">Where the pet is "walking"</param> /// <returns>ID of the next animation to play. -1 if there is no animation.</returns> private int SetNextGeneralAnimation(List <TNextAnimation> list, TNextAnimation.TOnly where) { int iDefaultID = -1; if (list.Count > 0) // Find the next animation only if there is at least 1 animation in the list { int iVal; int iSum = 0; int iRandMax = 0; foreach (TNextAnimation anim in list) { if (anim.only != TNextAnimation.TOnly.NONE && (anim.only & where) == 0) { continue; } iRandMax += anim.Probability; } iVal = rand.Next(0, iRandMax); foreach (TNextAnimation anim in list) { if (anim.only != TNextAnimation.TOnly.NONE && (anim.only & where) == 0) { continue; } iSum += anim.Probability; if (iSum >= iVal) { iDefaultID = anim.ID; break; } } // If an animation was found, re-calculate the values (if there are some Random values, they must be evaluated again) if (iDefaultID > 0) { UpdateAnimationValues(iDefaultID); if (SheepSound.ContainsKey(iDefaultID)) { if (rand.Next(0, 100) < SheepSound[iDefaultID].Probability) { SheepSound[iDefaultID].Play(SheepSound[iDefaultID].Loop); } } } return(iDefaultID); } else { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "no next animation found"); return(-1); // a new spawn is requested } }
/// <summary> /// Event handler to check XML validity. /// </summary> /// <param name="sender">Caller as object.</param> /// <param name="e">Validation event values.</param> static void ValidationEventHandler(object sender, ValidationEventArgs e) { switch (e.Severity) { case XmlSeverityType.Error: StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "XSD validation: " + e.Message); break; case XmlSeverityType.Warning: StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "XSD validation: " + e.Message); break; } }
/// <summary> /// Add another animation to the animations dictionary. Animations are defined in the XML. /// <seealso cref="AddSpawn(int, int)"/> /// <seealso cref="AddChild(int)"/> /// </summary> /// <param name="ID">Animation unique ID</param> /// <param name="name">Animation name</param> /// <returns>Structure item (so it is possible to fill all values)</returns> public TAnimation AddAnimation(int ID, string name) { try { SheepAnimations.Add(ID, new TAnimation(name, ID)); StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "adding animation: " + name); } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "unable to add animation: " + ex.Message); } return(SheepAnimations[ID]); }
/// <summary> /// Parse a value, converting keys like screenW, imageH, random,... to integers. /// </summary> /// <remarks> /// See <a href="https://msdn.microsoft.com/en-us/library/9za5w1xw(v=vs.100).aspx">https://msdn.microsoft.com/en-us/library/9za5w1xw(v=vs.100).aspx</a> /// for more information of what you can write as sText (expression to compute). /// </remarks> /// <param name="parsingText">The text to parse and convert.</param> /// <param name="debugInfo">Debug text to show if this function fails.</param> /// <param name="screenIndex">If set, the xml will be parsed with the screen dimension.</param> /// <returns>The integer value from the parsed text expression.</returns> public int ParseValue(string parsingText, string debugInfo, int screenIndex = -1) { int iRet = 0; DataTable dt = new DataTable(); Random rand = new Random(); // When adding a child, it is important to place the child on the other side of the parent, if the parent is flipped. if (parentFlipped) { if (parsingText.IndexOf("-imageW") >= 0) { parsingText = parsingText.Replace("-imageW", "+imageW"); } else { parsingText = parsingText.Replace("imageW", "(-imageW)"); } } var screen = Screen.PrimaryScreen; if (screenIndex >= 0) { screen = Screen.AllScreens[screenIndex]; } parsingText = parsingText.Replace("screenW", screen.Bounds.Width.ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("screenH", screen.Bounds.Height.ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("areaW", screen.WorkingArea.Width.ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("areaH", (screen.WorkingArea.Height + screen.WorkingArea.Y).ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("imageW", spriteWidth.ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("imageH", spriteHeight.ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("imageX", (parentX).ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("imageY", (parentY).ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("random", rand.Next(0, 100).ToString(CultureInfo.InvariantCulture)); parsingText = parsingText.Replace("randS", iRandomSpawn.ToString(CultureInfo.InvariantCulture)); var v = dt.Compute(parsingText, ""); double dv; if (double.TryParse(v.ToString(), out dv)) { iRet = (int)dv; } else { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "Unable to parse integer: " + parsingText + " - " + debugInfo); } return(iRet); }
/// <summary> /// Open the option dialog, to show some options like reset XML animation or load animation from the webpage. /// </summary> public static void OpenOptionDialog() { FormOptions formoptions = new FormOptions(); switch (formoptions.ShowDialog()) { case DialogResult.Retry: StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "restoring default XML"); MyData.SetIcon(""); MyData.SetImages(""); MyData.SetXml("", ""); break; } }
/// <summary> /// Parse a value, converting keys like screenW, imageH, random,... to integers. /// </summary> /// <remarks> /// See <a href="https://msdn.microsoft.com/en-us/library/9za5w1xw(v=vs.100).aspx">https://msdn.microsoft.com/en-us/library/9za5w1xw(v=vs.100).aspx</a> /// for more information of what you can write as sText (expression to compute). /// </remarks> /// <param name="sText">The text to parse and convert.</param> /// <returns>The integer value from the parsed text expression.</returns> public int parseValue(string sText) { int iRet = 0; DataTable dt = new DataTable(); Random rand = new Random(); // When adding a child, it is important to place the child on the other side of the parent, if the parent is flipped. if (parentFlipped) { if (sText.IndexOf("-imageW") >= 0) { sText = sText.Replace("-imageW", "+imageW"); } else { sText = sText.Replace("imageW", "(-imageW)"); } } sText = sText.Replace("screenW", Screen.PrimaryScreen.Bounds.Width.ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("screenH", Screen.PrimaryScreen.Bounds.Height.ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("areaW", Screen.PrimaryScreen.WorkingArea.Width.ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("areaH", (Screen.PrimaryScreen.WorkingArea.Height + Screen.PrimaryScreen.WorkingArea.Y).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageW", (FullImage.Width / AnimationXML.Image.TilesX).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageH", (FullImage.Height / AnimationXML.Image.TilesY).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageX", (parentX).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("imageY", (parentY).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("random", rand.Next(0, 100).ToString(CultureInfo.InvariantCulture)); sText = sText.Replace("randS", iRandomSpawn.ToString(CultureInfo.InvariantCulture)); var v = dt.Compute(sText, ""); double dv; if (double.TryParse(v.ToString(), out dv)) { iRet = (int)dv; } else { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "Unable to parse integer: " + sText); } return(iRet); }
/// <summary> /// Add a sound to the sound dictionary. Sounds are defined in the XML. /// </summary> /// <param name="ID">Animation ID.</param> /// <param name="Probability">Probability this sound will be played with the animation sequence.</param> /// <param name="Loop">How many times the sound should be looped.</param> /// <param name="Base64">Base 64 string with the encoded mp3 file.</param> /// <returns></returns> public void AddSound(int ID, int Probability, int Loop, string Base64) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "adding sound (ani." + ID.ToString() + ")"); try { if (Base64.IndexOf(";base64,") > 0) { Base64 = Base64.Substring(Base64.IndexOf(";base64,") + 8); } TSound sound = new TSound(); sound.Load(Convert.FromBase64String(Base64)); sound.AnimationID = ID; sound.Probability = Probability; sound.Loop = Loop; SheepSound.Add(ID, sound); } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "can't open sound:" + ex.Message); } }
/// <summary> /// Read images from XML file and store them in the application. /// </summary> private void readImages() { try { if (Properties.Settings.Default.Images.Length < 2) { throw new InvalidDataException(); } images.bitmapImages = new MemoryStream(Convert.FromBase64String(Properties.Settings.Default.Images)); StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "user images loaded"); } catch (Exception) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "user images not found, loading defaults"); try { Properties.Settings.Default.Images = AnimationXML.Image.Png; int mod4 = Properties.Settings.Default.Images.Length % 4; if (mod4 > 0) { Properties.Settings.Default.Images += new string('=', 4 - mod4); } Properties.Settings.Default.Save(); } catch (Exception ex) { MessageBox.Show(ex.Message); } try { images.bitmapImages = new MemoryStream(Convert.FromBase64String(Properties.Settings.Default.Images)); } catch (Exception ex) { MessageBox.Show(ex.Message); } } try { if (Properties.Settings.Default.Icon.Length < 100) { throw new InvalidDataException(); } bitmapIcon = new MemoryStream(Convert.FromBase64String(Properties.Settings.Default.Icon)); StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "user icon loaded"); } catch (Exception) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "no user icon, loading default"); try { Properties.Settings.Default.Icon = AnimationXML.Header.Icon; int mod4 = Properties.Settings.Default.Icon.Length % 4; if (mod4 > 0) { Properties.Settings.Default.Icon += new string('=', 4 - mod4); } Properties.Settings.Default.Save(); } catch (Exception ex) { MessageBox.Show(ex.Message); } try { bitmapIcon = new MemoryStream(Convert.FromBase64String(Properties.Settings.Default.Icon)); } catch (Exception ex) { MessageBox.Show(ex.Message); } } FullImage = new Bitmap(images.bitmapImages); }
/// <summary> /// Start the next animation once the gravity was detected. /// </summary> /// <param name="animationID">ID of the animation.</param> /// <param name="where">Where the pet is "walking"</param> /// <returns>ID of the next animation to play. -1 if there is no animation.</returns> public int SetNextGravityAnimation(int animationID, TNextAnimation.TOnly where) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "gravity detected"); return(SetNextGeneralAnimation(SheepAnimations[animationID].EndGravity, where)); }
/// <summary> /// Start the next animation once the sequence was over. /// </summary> /// <param name="animationID">ID of the animation.</param> /// <param name="where">Where the pet is "walking"</param> /// <returns>ID of the next animation to play. -1 if there is no animation.</returns> public int SetNextSequenceAnimation(int animationID, TNextAnimation.TOnly where) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "animation is over"); return(SetNextGeneralAnimation(SheepAnimations[animationID].EndAnimation, where)); }
/// <summary> /// The most important function. Each movement step is managed by this function:<br /> /// Will calculate how much and where a pet should be positioned in the next step.<br /> /// This function is called from <see cref="timer1_Tick(object, EventArgs)"/>. /// </summary> private void NextStep() { // If there is no repeat, we don't need to calculate the frame index. if (iAnimationStep < CurrentAnimation.Sequence.Frames.Count) { pictureBox1.Image = imageList1.Images[CurrentAnimation.Sequence.Frames[iAnimationStep]]; } else { int index = ((iAnimationStep - CurrentAnimation.Sequence.Frames.Count + CurrentAnimation.Sequence.RepeatFrom) % (CurrentAnimation.Sequence.Frames.Count - CurrentAnimation.Sequence.RepeatFrom)) + CurrentAnimation.Sequence.RepeatFrom; pictureBox1.Image = imageList1.Images[CurrentAnimation.Sequence.Frames[index]]; } // Get interval, opacity and offset interpolated from START and END values. timer1.Interval = CurrentAnimation.Start.Interval.Value + ((CurrentAnimation.End.Interval.Value - CurrentAnimation.Start.Interval.Value) * iAnimationStep / CurrentAnimation.Sequence.TotalSteps); Opacity = CurrentAnimation.Start.Opacity + (CurrentAnimation.End.Opacity - CurrentAnimation.Start.Opacity) * iAnimationStep / CurrentAnimation.Sequence.TotalSteps; dOffsetY = CurrentAnimation.Start.OffsetY + (double)(CurrentAnimation.End.OffsetY - CurrentAnimation.Start.OffsetY * iAnimationStep / CurrentAnimation.Sequence.TotalSteps); // If dragging is enabled, move the pet to the mouse position. if (bDragging) { dPosX = Left = Cursor.Position.X - Width / 2; dPosY = Top = Cursor.Position.Y - 2; return; } double x = CurrentAnimation.Start.X.Value; double y = CurrentAnimation.Start.Y.Value; // if TotalSteps is more than 1, we have to interpolate START and END values) if (CurrentAnimation.Sequence.TotalSteps > 1) { x += ((CurrentAnimation.End.X.Value - CurrentAnimation.Start.X.Value) * (double)iAnimationStep / (CurrentAnimation.Sequence.TotalSteps - 1.0)); y += ((CurrentAnimation.End.Y.Value - CurrentAnimation.Start.Y.Value) * (double)iAnimationStep / (CurrentAnimation.Sequence.TotalSteps - 1.0)); } // If a new animation need to be started bool bNewAnimation = false; // If the pet is "flipped", mirror the movement if (!bMoveLeft) { x = -x; } if (x < 0) // moving left (detect left borders) { if (hwndWindow == (IntPtr)0) { if (dPosX + x < 0) // left screen border! { int iBorderAnimation = Animations.SetNextBorderAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.VERTICAL); if (iBorderAnimation >= 0) { x = 0; SetNewAnimation(iBorderAnimation); bNewAnimation = true; } } } else { NativeMethods.RECT rct; if (NativeMethods.GetWindowRect(new HandleRef(this, hwndWindow), out rct)) { if (dPosX + x < rct.Left) // left window border! { int iBorderAnimation = Animations.SetNextBorderAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.WINDOW); if (iBorderAnimation >= 0) { x = rct.Left; SetNewAnimation(iBorderAnimation); bNewAnimation = true; } else { // not anymore on the window hwndWindow = (IntPtr)0; } } } } } else if (x > 0) // moving right (detect right borders) { if (hwndWindow == (IntPtr)0) { if (dPosX + x + Width > Screen.PrimaryScreen.WorkingArea.Width) // right screen border! { int iBorderAnimation = Animations.SetNextBorderAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.VERTICAL); if (iBorderAnimation >= 0) { x = Screen.PrimaryScreen.WorkingArea.Width - Width; SetNewAnimation(iBorderAnimation); bNewAnimation = true; } } } else { NativeMethods.RECT rct; if (NativeMethods.GetWindowRect(new HandleRef(this, hwndWindow), out rct)) { if (dPosX + x + Width > rct.Right) // right window border! { int iBorderAnimation = Animations.SetNextBorderAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.WINDOW); if (iBorderAnimation >= 0) { x = rct.Right - Width; SetNewAnimation(iBorderAnimation); bNewAnimation = true; } else { // not anymore on the window hwndWindow = (IntPtr)0; } } } } } if (y > 0) // moving down (detect taskbar and windows) { if (CurrentAnimation.EndBorder.Count > 0) { int bottomY = Screen.PrimaryScreen.WorkingArea.Height + Screen.PrimaryScreen.WorkingArea.Y; if (dPosY + y > bottomY - Height) // border detected! { y = bottomY - (int)(dPosY + Height); dOffsetY = 0; SetNewAnimation(Animations.SetNextBorderAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.TASKBAR)); bNewAnimation = true; } else { int iWindowTop = FallDetect((int)y); if (iWindowTop > 0) { y = iWindowTop - dPosY - Height; dOffsetY = 0; SetNewAnimation(Animations.SetNextBorderAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.WINDOW)); bNewAnimation = true; if (CurrentAnimation.Start.Y.Value != 0) { hwndWindow = (IntPtr)0; } } } } } else if (y < 0) // moving up, detect upper screen border { if (CurrentAnimation.EndBorder.Count > 0) { if (dPosY < Screen.PrimaryScreen.WorkingArea.Y) // border detected! { y = 0; SetNewAnimation(Animations.SetNextBorderAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.HORIZONTAL)); bNewAnimation = true; } } } if (iAnimationStep >= CurrentAnimation.Sequence.TotalSteps) // animation over { int iNextAni = -1; if (CurrentAnimation.Sequence.Action == "flip") { // flip all images bMoveLeft = !bMoveLeft; for (int i = 0; i < imageList1.Images.Count; i++) { Image im = imageList1.Images[i]; im.RotateFlip(RotateFlipType.RotateNoneFlipX); imageList1.Images[i] = im; } } if (hwndWindow != (IntPtr)0) { iNextAni = Animations.SetNextSequenceAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.WINDOW); } else { // If pet is outside the borders, spawn it again. if (Left < -Width || Left > Screen.PrimaryScreen.Bounds.Width) { iNextAni = -1; } else { iNextAni = Animations.SetNextSequenceAnimation(CurrentAnimation.ID, dPosY + Height + y >= Screen.PrimaryScreen.WorkingArea.Height - 2 ? TNextAnimation.TOnly.TASKBAR : TNextAnimation.TOnly.NONE); } } if (CurrentAnimation.ID == Animations.AnimationKill) { double op; if (timer1.Tag == null || !double.TryParse(timer1.Tag.ToString(), out op)) { timer1.Tag = 1.0; } op = double.Parse(timer1.Tag.ToString()); timer1.Tag = op - 0.1; Opacity = op; if (op <= 0.1) { Close(); } } else if (iNextAni >= 0) { SetNewAnimation(iNextAni); bNewAnimation = true; } else { // Child doesn't have a spawn, they will be closed once the animation is over. if (Name.IndexOf("child") == 0) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "removing child"); Close(); } else { Play(false); } } } // If there is a Gravity-Next animation, check if gravity is present. else if (CurrentAnimation.Gravity) { if (hwndWindow == (IntPtr)0) { if (dPosY + y < Screen.PrimaryScreen.WorkingArea.Height - Height) { if (dPosY + y + 3 >= Screen.PrimaryScreen.WorkingArea.Height - Height) // allow 3 pixels to move without fall { y = Screen.PrimaryScreen.WorkingArea.Height - (int)dPosY - Height; } else { SetNewAnimation(Animations.SetNextGravityAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.NONE)); bNewAnimation = true; } } } else { if (iAnimationStep > 0 && CheckTopWindow(true)) { hwndWindow = (IntPtr)0; SetNewAnimation(Animations.SetNextGravityAnimation(CurrentAnimation.ID, TNextAnimation.TOnly.WINDOW)); bNewAnimation = true; } } } // If a new animation was started, set the interval and the first animation frame image. if (bNewAnimation) { timer1.Interval = 1; // execute immediately the first step of the next animation. x = 0; // don't move the pet, if a new animation must be started //y = 0; // if falling, set the pet to the new position pictureBox1.Image = imageList1.Images[CurrentAnimation.Sequence.Frames[0]]; } // Set the new pet position (and offset) in the screen. dPosX += x; dPosY += y; Left = (int)dPosX; Top = (int)(dPosY + dOffsetY); }
/// <summary> /// This function will load the XML. If something can't be loaded as expected, the default XML will be loaded. /// </summary> /// <returns>true, if the XML was loaded successfully.</returns> public bool readXML() { bool bError = false; // Construct an instance of the XmlSerializer with the type // of object that is being deserialized. XmlSerializer mySerializer = new XmlSerializer(typeof(RootNode)); // To read the file, create a FileStream. MemoryStream stream = new MemoryStream(); StreamWriter writer = new StreamWriter(stream); // Try to load local XML try { if (File.Exists(Application.StartupPath + "\\installpet.xml")) { string sXML = System.Text.Encoding.Default.GetString(File.ReadAllBytes(Application.StartupPath + "\\installpet.xml")); File.Delete(Application.StartupPath + "\\installpet.xml"); writer.Write(sXML); AnimationXMLString = sXML; Properties.Settings.Default.xml = sXML; Properties.Settings.Default.Save(); } else if (Program.ArgumentLocalXML != "") { string sXML = System.Text.Encoding.Default.GetString(File.ReadAllBytes(Program.ArgumentLocalXML)); writer.Write(sXML); AnimationXMLString = sXML; } else if (Program.ArgumentWebXML != "") { System.Net.WebClient client = new System.Net.WebClient(); string sXML = client.DownloadString(Program.ArgumentWebXML); writer.Write(sXML); AnimationXMLString = sXML; } else { writer.Write(Properties.Settings.Default.xml); AnimationXMLString = Properties.Settings.Default.xml; } // Don't load personal pets anymore Program.ArgumentLocalXML = ""; Program.ArgumentWebXML = ""; //writer.Write(Properties.Resources.animations); writer.Flush(); stream.Position = 0; // Call the Deserialize method and cast to the object type. AnimationXML = (RootNode)mySerializer.Deserialize(stream); stream.Close(); Properties.Settings.Default.Images = AnimationXML.Image.Png; Properties.Settings.Default.Icon = AnimationXML.Header.Icon; } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "User XML error: " + ex.ToString()); if (Properties.Settings.Default.xml.Length > 100) { MessageBox.Show("Error parsing animation XML:" + ex.ToString(), "XML error", MessageBoxButtons.OK, MessageBoxIcon.Error); } writer.Write(Properties.Resources.animations); writer.Flush(); AnimationXMLString = Properties.Resources.animations; stream.Position = 0; // Call the Deserialize method and cast to the object type. AnimationXML = (RootNode)mySerializer.Deserialize(stream); Properties.Settings.Default.Images = AnimationXML.Image.Png; Properties.Settings.Default.Icon = AnimationXML.Header.Icon; } finally { // if the images were loaded from external make some memory available. // don't need it again as its in Properties.Settings.Default.Images AnimationXML.Image.Png = string.Empty; // don't need it again as its in Properties.Settings.Default.Icon AnimationXML.Header.Icon = string.Empty; try { readImages(); if (AnimationXML.Header.Petname.Length > 16) { AnimationXML.Header.Petname = AnimationXML.Header.Petname.Substring(0, 16); } } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "Error reading XML: " + ex.Message); bError = true; } } if (bError) { MessageBox.Show("Error, can't load animations file. The original pet will be loaded", "XML error", MessageBoxButtons.OK, MessageBoxIcon.Error); } return(!bError); }
/// <summary> /// This function will load the XML. If something can't be loaded as expected, the default XML will be loaded. /// </summary> /// <returns>true, if the XML was loaded successfully.</returns> public bool readXML() { bool bError = false; // Construct an instance of the XmlSerializer with the type // of object that is being deserialized. XmlSerializer mySerializer = new XmlSerializer(typeof(XmlData.RootNode)); // To read the file, create a FileStream. MemoryStream stream = new MemoryStream(); StreamWriter writer = new StreamWriter(stream); // Try to load local XML try { writer.Write(Program.MyData.GetXml()); AnimationXMLString = Program.MyData.GetXml(); //writer.Write(Properties.Resources.animations); writer.Flush(); stream.Position = 0; // Call the Deserialize method and cast to the object type. AnimationXML = (XmlData.RootNode)mySerializer.Deserialize(stream); stream.Close(); Program.MyData.SetImages(AnimationXML.Image.Png); Program.MyData.SetIcon(AnimationXML.Header.Icon); } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "User XML error: " + ex.ToString()); if (Program.MyData.GetXml().Length > 100) { MessageBox.Show("Error parsing animation XML:" + ex.ToString(), "XML error", MessageBoxButtons.OK, MessageBoxIcon.Error); } stream.Flush(); stream.Position = 0; writer.Write(Properties.Resources.animations); writer.Flush(); AnimationXMLString = Properties.Resources.animations; stream.Position = 0; // Call the Deserialize method and cast to the object type. AnimationXML = (XmlData.RootNode)mySerializer.Deserialize(stream); Program.MyData.SetXml(Properties.Resources.animations, "esheep64"); Program.MyData.SetImages(AnimationXML.Image.Png); Program.MyData.SetIcon(AnimationXML.Header.Icon); } finally { // if the images were loaded from external make some memory available. // don't need it again as its in Properties.Settings.Default.Images AnimationXML.Image.Png = string.Empty; // don't need it again as its in Properties.Settings.Default.Icon AnimationXML.Header.Icon = string.Empty; try { readImages(); if (AnimationXML.Header.Petname.Length > 16) { AnimationXML.Header.Petname = AnimationXML.Header.Petname.Substring(0, 16); } } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "Error reading XML: " + ex.Message); bError = true; } } if (bError) { MessageBox.Show("Error, can't load animations file. The original pet will be loaded", "XML error", MessageBoxButtons.OK, MessageBoxIcon.Error); } return(!bError); }
/// <summary> /// Add another Child to the Child dictionary. Childs are defined in the XML. /// <seealso cref="AddAnimation(int, string)"/> /// <seealso cref="AddSpawn(int, int)"/> /// </summary> /// <param name="ID">Child unique ID.</param> /// <returns></returns> public TChild AddChild(int ID) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "adding child (ani." + ID.ToString() + ")"); SheepChild.Add(ID, new TChild()); return(SheepChild[ID]); }
/// <summary> /// Load the animations (read them from XML file) /// </summary> /// <param name="animations">Animation class where the animations should be saved</param> public void LoadAnimations(Animations animations) { if (AnimationXML.Animations == null) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "No animations for this pet"); return; } // for each animation foreach (XmlData.AnimationNode node in AnimationXML.Animations.Animation) { TAnimation ani = animations.AddAnimation(node.Id, node.Id.ToString()); ani.Border = node.Border != null; ani.Gravity = node.Gravity != null; ani.Name = node.Name; switch (ani.Name) { case "fall": animations.AnimationFall = node.Id; break; case "drag": animations.AnimationDrag = node.Id; break; case "kill": animations.AnimationKill = node.Id; break; case "sync": animations.AnimationSync = node.Id; break; } ani.Start.X = GetXMLCompute(node.Start.X, "animation " + node.Id + ": node.start.X"); ani.Start.Y = GetXMLCompute(node.Start.Y, "animation " + node.Id + ": node.start.Y"); ani.Start.Interval = GetXMLCompute(node.Start.Interval, "animation " + node.Id + ": node.start.Interval"); ani.Start.OffsetY = node.Start.OffsetY; ani.Start.Opacity = node.Start.Opacity; ani.End.X = GetXMLCompute(node.End.X, "animation " + node.Id + ": node.end.X"); ani.End.Y = GetXMLCompute(node.End.Y, "animation " + node.Id + ": node.end.Y"); ani.End.Interval = GetXMLCompute(node.End.Interval, "animation " + node.Id + ": node.end.Interval"); ani.End.OffsetY = node.End.OffsetY; ani.End.Opacity = node.End.Opacity; ani.Sequence.RepeatFrom = node.Sequence.RepeatFromFrame; ani.Sequence.Action = node.Sequence.Action; ani.Sequence.Repeat = GetXMLCompute(node.Sequence.RepeatCount, "animation " + node.Id + ": node.sequence.Repeat"); ani.Sequence.Frames.AddRange(node.Sequence.Frame); if (ani.Sequence.RepeatFrom > 0) { ani.Sequence.TotalSteps = ani.Sequence.Frames.Count + (ani.Sequence.Frames.Count - ani.Sequence.RepeatFrom - 1) * ani.Sequence.Repeat.Value; } else { ani.Sequence.TotalSteps = ani.Sequence.Frames.Count + ani.Sequence.Frames.Count * ani.Sequence.Repeat.Value; } if (node.Sequence.Next != null) { foreach (XmlData.NextNode nextNode in node.Sequence.Next) { TNextAnimation.TOnly where; switch (nextNode.OnlyFlag) { case "taskbar": where = TNextAnimation.TOnly.TASKBAR; break; case "window": where = TNextAnimation.TOnly.WINDOW; break; case "horizontal": where = TNextAnimation.TOnly.HORIZONTAL; break; case "horizontal+": where = TNextAnimation.TOnly.HORIZONTAL_; break; case "vertical": where = TNextAnimation.TOnly.VERTICAL; break; default: where = TNextAnimation.TOnly.NONE; break; } ani.EndAnimation.Add( new TNextAnimation( nextNode.Value, nextNode.Probability, where ) ); } } if (ani.Border) { foreach (XmlData.NextNode nextNode in node.Border.Next) { TNextAnimation.TOnly where; switch (nextNode.OnlyFlag) { case "taskbar": where = TNextAnimation.TOnly.TASKBAR; break; case "window": where = TNextAnimation.TOnly.WINDOW; break; case "horizontal": where = TNextAnimation.TOnly.HORIZONTAL; break; case "horizontal+": where = TNextAnimation.TOnly.HORIZONTAL_; break; case "vertical": where = TNextAnimation.TOnly.VERTICAL; break; default: where = TNextAnimation.TOnly.NONE; break; } ani.Border = true; ani.EndBorder.Add( new TNextAnimation( nextNode.Value, nextNode.Probability, where ) ); } } if (ani.Gravity) { foreach (XmlData.NextNode nextNode in node.Gravity.Next) { TNextAnimation.TOnly where; switch (nextNode.OnlyFlag) { case "taskbar": where = TNextAnimation.TOnly.TASKBAR; break; case "window": where = TNextAnimation.TOnly.WINDOW; break; case "horizontal": where = TNextAnimation.TOnly.HORIZONTAL; break; case "horizontal+": where = TNextAnimation.TOnly.HORIZONTAL_; break; case "vertical": where = TNextAnimation.TOnly.VERTICAL; break; default: where = TNextAnimation.TOnly.NONE; break; } ani.Gravity = true; ani.EndGravity.Add( new TNextAnimation( nextNode.Value, nextNode.Probability, where ) ); } } animations.SaveAnimation(ani, node.Id); } // for each spawn if (AnimationXML.Spawns.Spawn != null) { foreach (XmlData.SpawnNode node in AnimationXML.Spawns.Spawn) { TSpawn ani = animations.AddSpawn( node.Id, node.Probability); ani.Start.X = GetXMLCompute(node.X, "spawn " + node.Id + ": node.X"); ani.Start.Y = GetXMLCompute(node.Y, "spawn " + node.Id + ": node.X"); ani.Next = node.Next.Value; animations.SaveSpawn(ani, node.Id); } } // for each child if (AnimationXML.Childs.Child != null) { foreach (XmlData.ChildNode node in AnimationXML.Childs.Child) { TChild aniChild = animations.AddChild(node.Id); aniChild.AnimationID = node.Id; aniChild.Position.X = GetXMLCompute(node.X, "child " + node.Id + ": node.X"); aniChild.Position.Y = GetXMLCompute(node.Y, "child " + node.Id + ": node.Y"); aniChild.Next = node.Next; animations.SaveChild(aniChild, node.Id); } } // for each sound if (AnimationXML.Sounds != null && AnimationXML.Sounds.Sound != null) { foreach (XmlData.SoundNode node in AnimationXML.Sounds.Sound) { animations.AddSound(node.Id, node.Probability, node.Loop, node.Base64); } } }
/// <summary> /// Add another spawn to the spawn dictionary. Spawns are defined in the XML. /// <seealso cref="AddAnimation(int, string)"/> /// <seealso cref="AddChild(int)"/> /// </summary> /// <param name="ID">Spawn unique ID.</param> /// <param name="probability">Probability this spawn will be taken.</param> /// <returns></returns> public TSpawn AddSpawn(int ID, int probability) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "adding spawn: " + ID.ToString()); SheepSpawn.Add(ID, new TSpawn(probability)); return(SheepSpawn[ID]); }
/// <summary> /// Read images from XML file and store them in the application. /// </summary> private void readImages() { MemoryStream imageStream = null; try { if (Program.MyData.GetImages().Length < 2) { throw new InvalidDataException(); } imageStream = new MemoryStream(Convert.FromBase64String(Program.MyData.GetImages())); // only decode once so dont need to keep the source string for image Program.MyData.SetImages(string.Empty); StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "user images loaded"); } catch (Exception) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "user images not found, loading defaults"); try { string pngStr = AnimationXML.Image.Png; int mod4 = pngStr.Length % 4; if (mod4 > 0) { pngStr += new string('=', 4 - mod4); } Program.MyData.SetImages(pngStr); } catch (Exception ex) { MessageBox.Show(ex.Message); } try { imageStream = new MemoryStream(Convert.FromBase64String(Program.MyData.GetImages())); // only decode once so dont need to keep the source string for image Program.MyData.SetImages(string.Empty); } catch (Exception ex) { MessageBox.Show(ex.Message); } } try { if (Program.MyData.GetIcon().Length < 100) { throw new InvalidDataException(); } bitmapIcon = new MemoryStream(Convert.FromBase64String(Program.MyData.GetIcon())); StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.info, "user icon loaded"); } catch (Exception) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "no user icon, loading default"); try { var strIco = AnimationXML.Header.Icon; int mod4 = strIco.Length % 4; if (mod4 > 0) { strIco += new string('=', 4 - mod4); } Program.MyData.SetIcon(strIco); } catch (Exception ex) { MessageBox.Show(ex.Message); } try { bitmapIcon = new MemoryStream(Convert.FromBase64String(Program.MyData.GetIcon())); } catch (Exception ex) { MessageBox.Show(ex.Message); } } var image = new Bitmap(imageStream); // no longer need stream imageStream.Close(); spriteWidth = image.Width / AnimationXML.Image.TilesX; spriteHeight = image.Height / AnimationXML.Image.TilesY; sprites = BuildSprites(image); // have sprites no longer need source sheet image.Dispose(); }
/// <summary> /// This function will load the XML. If something can't be loaded as expected, the default XML will be loaded. /// </summary> /// <returns>true, if the XML was loaded successfully.</returns> public bool readXML() { bool bError = false; // Construct an instance of the XmlSerializer with the type // of object that is being deserialized. XmlSerializer mySerializer = new XmlSerializer(typeof(RootNode)); // To read the file, create a FileStream. MemoryStream stream = new MemoryStream(); StreamWriter writer = new StreamWriter(stream); // Try to load local XML try { writer.Write(Properties.Settings.Default.xml); //writer.Write(Properties.Resources.animations); writer.Flush(); stream.Position = 0; // Call the Deserialize method and cast to the object type. AnimationXML = (RootNode)mySerializer.Deserialize(stream); Properties.Settings.Default.Images = AnimationXML.Image.Png; Properties.Settings.Default.Icon = AnimationXML.Header.Icon; } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.warning, "User XML error: " + ex.ToString()); if (Properties.Settings.Default.xml.Length > 100) { MessageBox.Show("Error parsing animation XML:" + ex.ToString(), "XML error", MessageBoxButtons.OK, MessageBoxIcon.Error); } writer.Write(Properties.Resources.animations); writer.Flush(); stream.Position = 0; // Call the Deserialize method and cast to the object type. AnimationXML = (RootNode)mySerializer.Deserialize(stream); Properties.Settings.Default.Images = AnimationXML.Image.Png; Properties.Settings.Default.Icon = AnimationXML.Header.Icon; } finally { try { readImages(); if (AnimationXML.Header.Petname.Length > 16) { AnimationXML.Header.Petname = AnimationXML.Header.Petname.Substring(0, 16); } } catch (Exception ex) { StartUp.AddDebugInfo(StartUp.DEBUG_TYPE.error, "Error reading XML: " + ex.Message); bError = true; } } if (bError) { MessageBox.Show("Error, can't load animations file. The original pet will be loaded", "XML error", MessageBoxButtons.OK, MessageBoxIcon.Error); } return(!bError); }