Advertisement
SuperLemrick

Swarm Finished Source Code

Mar 28th, 2015
319
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 23.24 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////
  2. // Copyright 2013, CompuScholar, Inc.
  3. //
  4. // This source code is for use by the students and teachers who
  5. // have purchased the corresponding TeenCoder or KidCoder product.
  6. // It may not be transmitted to other parties for any reason
  7. // without the written consent of CompuScholar, Inc.
  8. // This source is provided as-is for educational purposes only.
  9. // CompuScholar, Inc. makes no warranty and assumes
  10. // no liability regarding the functionality of this program.
  11. //
  12. ////////////////////////////////////////////////////////////////
  13.  
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Linq;
  17. using Microsoft.Xna.Framework;
  18. using Microsoft.Xna.Framework.Audio;
  19. using Microsoft.Xna.Framework.Content;
  20. using Microsoft.Xna.Framework.GamerServices;
  21. using Microsoft.Xna.Framework.Graphics;
  22. using Microsoft.Xna.Framework.Input;
  23. using Microsoft.Xna.Framework.Media;
  24. using Microsoft.Xna.Framework.Net;
  25. using Microsoft.Xna.Framework.Storage;
  26.  
  27. using SpriteLibrary;
  28.  
  29. namespace Swarm
  30. {
  31.     /// <summary>
  32.     /// This is the main type for your game
  33.     /// </summary>
  34.     public class Swarm : Microsoft.Xna.Framework.Game
  35.     {
  36.         GraphicsDeviceManager graphics;
  37.         SpriteBatch spriteBatch;
  38.        
  39.         // the following constants control how many of each type of sprite are possible
  40.         const int NUM_COLS = 5;
  41.         const int NUM_BEES_PER_COL = 4;
  42.         const int MAX_BEE_SHOTS = 5;
  43.         const int MAX_SMOKE_SHOTS = 2;
  44.  
  45.         const int NUM_HIVES = 3;
  46.         const int NUM_HONEYCOMBS = 20;
  47.  
  48.         // initialize a new random number generator
  49.         Random randomNumGen = new Random(DateTime.Now.Millisecond);
  50.  
  51.         // font used to display user messages
  52.         SpriteFont gameFont;
  53.  
  54.         // textures used in the game
  55.         Texture2D beeTexture;
  56.         Texture2D beeShotTexture;
  57.         Texture2D beeStripTexture;
  58.         Texture2D hive1Texture;
  59.         Texture2D hive2Texture;
  60.         Texture2D smokeTexture;
  61.         Texture2D smokeSprayerTexture;
  62.         Texture2D smokeSprayerStripTexture;
  63.         Texture2D smokeStripTexture;
  64.  
  65.  
  66.         // the following members form the Game State for this program!
  67.  
  68.         // this sprite represents the player at the bottom
  69.         Sprite smokeSprayer;
  70.        
  71.         // these sprites represent the smoke balls fired from the smoke gun
  72.         LinkedList<Sprite> smokeShots = new LinkedList<Sprite>();
  73.  
  74.         // these sprites represent the individual honeycomb sections of the hive bunkers
  75.         LinkedList<Sprite> hiveSections = new LinkedList<Sprite>();
  76.  
  77.         // these sprites represent the bees in the swarm
  78.         LinkedList<Sprite> bees = new LinkedList<Sprite>();
  79.  
  80.         // these sprites represent the stinger shots fired from the bees
  81.         LinkedList<Sprite> beeShots = new LinkedList<Sprite>();
  82.  
  83.         // the time the most recent bee shot was fired
  84.         double lastBeeShotFired = 0;
  85.  
  86.         // the current bee movement speed
  87.         float beeSpeed = 1.0f;
  88.  
  89.         // if true, the current game is over
  90.         bool gameOver = false;
  91.  
  92.         // this string contains the message that is currently displayed to the user
  93.         String displayMessage = "";
  94.  
  95.         // previous keyboard state
  96.         KeyboardState oldKeyboardState;
  97.  
  98.         //previous Xbox controller state
  99.         GamePadState oldGamePadState;
  100.  
  101.         public Swarm()
  102.         {
  103.             graphics = new GraphicsDeviceManager(this);
  104.             Content.RootDirectory = "Content";
  105.         }
  106.  
  107.         /// <summary>
  108.         /// Allows the game to perform any initialization it needs to before starting to run.
  109.         /// This is where it can query for any required services and load any non-graphic
  110.         /// related content.  Calling base.Initialize will enumerate through any components
  111.         /// and initialize them as well.
  112.         /// </summary>
  113.         // This method is provided fully complete as part of the activity starter.
  114.         protected override void Initialize()
  115.         {
  116.             // call base.Initialize() first to get LoadContent called
  117.             // (and therefore all textures initialized) prior to starting game!
  118.             base.Initialize();
  119.  
  120.             startGame();
  121.         }
  122.  
  123.         // This method is provided partially complete as part of the activity starter.
  124.         private void startGame()
  125.         {
  126.             // reset game over flag
  127.             gameOver = false;
  128.  
  129.             // create new smoke sprayer, bees, and hives
  130.             initializeSmokeSprayer();
  131.             initializeBees();
  132.             initializeHives();
  133.  
  134.             // clear all prior shots
  135.             smokeShots.Clear();
  136.             beeShots.Clear();
  137.  
  138.         }
  139.  
  140.  
  141.         // The student will complete this function as part of an activity
  142.         private void initializeSmokeSprayer()
  143.         {
  144.             smokeSprayer = new Sprite();
  145.  
  146.             smokeSprayer.SetTexture(smokeSprayerTexture);
  147.  
  148.             int startingX = GraphicsDevice.Viewport.Width / 2;
  149.             int startingY = GraphicsDevice.Viewport.Height - smokeSprayer.GetHeight() - 20;
  150.             smokeSprayer.UpperLeft = new Vector2(startingX, startingY);
  151.  
  152.             smokeSprayer.IsAlive = true;
  153.         }
  154.  
  155.         // This method is provided fully complete as part of the activity starter.
  156.         private void initializeHives()
  157.         {
  158.             // this method will initialize all of the little hive sections as
  159.             // individual sprites that can be destroyed by shots and bees
  160.             hiveSections.Clear();
  161.  
  162.             // pick starting Y location
  163.             float hiveStartingY = GraphicsDevice.Viewport.Height - 150;
  164.             if (smokeSprayer != null)
  165.                 hiveStartingY = smokeSprayer.UpperLeft.Y - 100;
  166.            
  167.             // spacing between hives
  168.             float hiveSpacing = 200;
  169.  
  170.             // for each hive
  171.             for (int i = 0; i < NUM_HIVES; i++)
  172.             {
  173.                 // for each honeycomb in the hive
  174.                 for (int j = 0; j < NUM_HONEYCOMBS; j++)
  175.                 {
  176.                     // create a new sprite
  177.                     Sprite hiveSection = new Sprite();
  178.  
  179.                     // alternate the colors on odd/even blocks
  180.                     if (j % 2 == 0)
  181.                         hiveSection.SetTexture(hive1Texture);
  182.                     else
  183.                         hiveSection.SetTexture(hive2Texture);
  184.  
  185.                     // first 8 squares go along the bottom
  186.                     if (j < 8)
  187.                     {
  188.                         hiveSection.UpperLeft.Y = hiveStartingY + 3 * hiveSection.GetHeight();
  189.                         hiveSection.UpperLeft.X = ((hiveSpacing * (i + 1)) + (j * hiveSection.GetWidth()));
  190.                     }
  191.                     // next 6 squares go along the middle
  192.                     else if (j < 14)
  193.                     {
  194.                         hiveSection.UpperLeft.Y = hiveStartingY + 2 * hiveSection.GetHeight();
  195.                         hiveSection.UpperLeft.X = ((hiveSpacing * (i + 1)) + ((j - 7) * hiveSection.GetWidth()));
  196.                     }
  197.                     // next 4 squares along the top
  198.                     else if (j < 18)
  199.                     {
  200.                         hiveSection.UpperLeft.Y = hiveStartingY + hiveSection.GetHeight();
  201.                         hiveSection.UpperLeft.X = ((hiveSpacing * (i + 1)) + ((j - 12) * hiveSection.GetWidth()));
  202.                     }
  203.                     // small group of squares at the peak
  204.                     else
  205.                     {
  206.                         hiveSection.UpperLeft.Y = hiveStartingY;
  207.                         hiveSection.UpperLeft.X = ((hiveSpacing * (i + 1)) + ((j - 15) * hiveSection.GetWidth()));
  208.                     }
  209.  
  210.                     // set hive section to alive and add to list
  211.                     hiveSection.IsAlive = true;
  212.  
  213.                     hiveSections.AddLast(hiveSection);
  214.                 }
  215.             }
  216.         }
  217.  
  218.  
  219.         // The student will complete this function as part of an activity
  220.         private void initializeBees()
  221.         {
  222.             bees.Clear();
  223.  
  224.             for (int i = 0; i < NUM_COLS; i++)
  225.             {
  226.                 for (int j = 0; j < NUM_BEES_PER_COL; j++)
  227.                 {
  228.                     Sprite bee = new Sprite();
  229.  
  230.                     bee.UpperLeft = new Vector2((i + 1) * 100.0f, j * 75.0f);
  231.  
  232.                     bee.SetTexture(beeTexture);
  233.                     bees.AddLast(bee);
  234.                     bee.SetSpeedAndDirection(beeSpeed, 0);
  235.                 }
  236.             }
  237.         }
  238.  
  239.         // The student will complete this function as part of an activity
  240.         private void stopGame(bool won, String message)
  241.         {
  242.             displayMessage = message;
  243.             gameOver = true;
  244.  
  245.             if (won)
  246.             {
  247.                 beeSpeed += 0.3f;
  248.             }
  249.             else
  250.             {
  251.                 beeSpeed -= 0.3f;
  252.                 if (beeSpeed < 0.3f)
  253.                     beeSpeed = 0.3f;
  254.             }
  255.         }
  256.  
  257.  
  258.  
  259.         /// <summary>
  260.         /// LoadContent will be called once per game and is the place to load
  261.         /// all of your content.
  262.         /// </summary>
  263.         // This method is provided partially complete as part of the activity starter.
  264.         protected override void LoadContent()
  265.         {
  266.             // Create a new SpriteBatch, which can be used to draw textures.
  267.             spriteBatch = new SpriteBatch(GraphicsDevice);
  268.  
  269.             // load all textures used in the game
  270.             beeTexture = Content.Load<Texture2D>("Images\\Bee");
  271.             beeShotTexture = Content.Load<Texture2D>("Images\\BeeShot");
  272.             beeStripTexture = Content.Load<Texture2D>("Images\\BeeStrip");
  273.             hive1Texture = Content.Load<Texture2D>("Images\\Hive1");
  274.             hive2Texture = Content.Load<Texture2D>("Images\\Hive2");
  275.             smokeTexture = Content.Load<Texture2D>("Images\\Smoke");
  276.             smokeSprayerTexture = Content.Load<Texture2D>("Images\\SmokeSprayer");
  277.             smokeSprayerStripTexture = Content.Load<Texture2D>("Images\\SmokeSprayerStrip");
  278.             smokeStripTexture = Content.Load<Texture2D>("Images\\SmokeStrip");
  279.  
  280.             // load all fonts used in the game
  281.             gameFont = Content.Load<SpriteFont>("GameFont");
  282.  
  283.            
  284.         }
  285.  
  286.         /// <summary>
  287.         /// UnloadContent will be called once per game and is the place to unload
  288.         /// all content.
  289.         /// </summary>
  290.         // This method is provided fully complete as part of the activity starter.
  291.         protected override void UnloadContent()
  292.         {
  293.             // TODO: Unload any non ContentManager content here
  294.         }
  295.  
  296.         /// <summary>
  297.         /// Allows the game to run logic such as updating the world,
  298.         /// checking for collisions, gathering input, and playing audio.
  299.         /// </summary>
  300.         /// <param name="gameTime">Provides a snapshot of timing values.</param>
  301.         // This method is provided fully complete as part of the activity starter.
  302.         protected override void Update(GameTime gameTime)
  303.         {
  304.             // Allows the game to exit
  305.             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
  306.                 this.Exit();
  307.  
  308.             // if the game is still going on
  309.             if (!gameOver)
  310.             {
  311.                 // check to see if the player has beaten all the bees
  312.                 if (bees.Count == 0)
  313.                 {
  314.                     stopGame(true,"You have defeated the swarm!");
  315.                 }
  316.                 else
  317.                 {
  318.  
  319.                     // see if any more bee stingers need to be fired
  320.                     checkBeeShots(gameTime);
  321.  
  322.                     // move the bees
  323.                     moveBees(gameTime);
  324.  
  325.                     // move any bee shots that are on the screen
  326.                     moveBeeShots();
  327.  
  328.                     // move any smoke shots that are on the screen
  329.                     moveSmokeShots(gameTime);
  330.  
  331.                     // handle all collisions
  332.                     checkCollisions();
  333.                 }
  334.             }
  335.  
  336.             // if the smoke sprayer is currently animating, advance the frame
  337.             if (smokeSprayer != null)
  338.                 if (smokeSprayer.IsAnimating())
  339.                     smokeSprayer.Animate(gameTime);
  340.  
  341.             // handle all user input
  342.             handleKeyPress();
  343.  
  344.             // Optionally handle Xbox gamepad
  345.             handleXboxGamepad();
  346.            
  347.             base.Update(gameTime);
  348.         }
  349.  
  350.         // The student will complete this function as part of an activity
  351.         private void checkBeeShots(GameTime gameTime)
  352.         {
  353.             if (gameTime.TotalGameTime.TotalMilliseconds > (lastBeeShotFired + 1000))
  354.             {
  355.                 fireBeeShot();
  356.  
  357.                 lastBeeShotFired = gameTime.TotalGameTime.TotalMilliseconds;
  358.             }
  359.         }
  360.  
  361.         // The student will complete this function as part of an activity
  362.         private void fireBeeShot()
  363.         {
  364.             if (beeShots.Count < MAX_BEE_SHOTS)
  365.             {
  366.                 int beeNumber = randomNumGen.Next(0, bees.Count);
  367.                 Sprite bee = bees.ElementAt(beeNumber);
  368.  
  369.                 Sprite newBeeShot = new Sprite();
  370.                 newBeeShot.SetTexture(beeShotTexture);
  371.  
  372.                 newBeeShot.SetVelocity(0, 2);
  373.                 newBeeShot.IsAlive = true;
  374.  
  375.                 newBeeShot.UpperLeft.X = bee.UpperLeft.X + (bee.GetCenter().X - newBeeShot.GetWidth() / 2);
  376.                 newBeeShot.UpperLeft.Y = bee.UpperLeft.Y + bee.GetHeight();
  377.  
  378.                 beeShots.AddLast(newBeeShot);
  379.             }
  380.         }
  381.  
  382.         // This method is provided fully complete as part of the activity starter.
  383.         private Sprite findEdgeBee(bool leftSide)
  384.         {
  385.             // create variable to trach the bee we think is on the edge
  386.             Sprite edgeSprite = null;
  387.  
  388.             // check all remaining bees
  389.             foreach (Sprite bee in bees)
  390.             {
  391.                 // if this is the first bee, just save it as current edge bee
  392.                 if (edgeSprite == null)
  393.                     edgeSprite = bee;
  394.                 else
  395.                 {
  396.                     // if we are looking for the leftmost bee
  397.                     if (leftSide)
  398.                     {
  399.                         // if this bee is to left of current edge bee
  400.                         if (bee.UpperLeft.X < edgeSprite.UpperLeft.X)
  401.                             edgeSprite = bee;   // we have a new edge bee
  402.                     }
  403.                     else // we are looking for the rightmost bee
  404.                     {
  405.                         // if this bee is to right of current edge bee
  406.                         if (bee.UpperLeft.X > edgeSprite.UpperLeft.X)
  407.                             edgeSprite = bee;   // we have a new edge bee
  408.                     }
  409.                 }
  410.             }
  411.            
  412.             // return the edge bee we found
  413.             return edgeSprite;
  414.         }
  415.  
  416.         // The student will complete this function as part of an activity
  417.         private void moveSmokeShots(GameTime gameTime)
  418.         {
  419.             foreach (Sprite smokeShot in smokeShots)
  420.             {
  421.                 smokeShot.MoveAndVanish(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
  422.             }
  423.         }
  424.  
  425.         // The student will complete this function as part of an activity
  426.         private void moveBeeShots()
  427.         {
  428.             foreach (Sprite beeShot in beeShots)
  429.             {
  430.                 beeShot.MoveAndVanish(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
  431.             }
  432.         }
  433.  
  434.         // The student will complete this function as part of an activity
  435.         private void moveBees(GameTime gameTime)
  436.         {
  437.             Sprite leftmostBee = findEdgeBee(true);
  438.             Sprite rightmostBee = findEdgeBee(false);
  439.             if ((leftmostBee == null) || (rightmostBee == null))
  440.             {
  441.                 return;
  442.             }
  443.  
  444.             if (((leftmostBee.UpperLeft.X) < 0) ||
  445.                  ((rightmostBee.UpperLeft.X + rightmostBee.GetWidth()) > GraphicsDevice.Viewport.Width))
  446.             {
  447.                 foreach (Sprite bee in bees)
  448.                 {
  449.                     Vector2 velocity = bee.GetVelocity();
  450.                     velocity.X *= -1;
  451.                     bee.SetVelocity(velocity.X,velocity.Y);
  452.  
  453.                     bee.UpperLeft.Y += 25;
  454.                 }
  455.             }
  456.             foreach (Sprite bee in bees)
  457.             {
  458.                 bee.Move();
  459.  
  460.                 if (bee.UpperLeft.Y >= smokeSprayer.UpperLeft.Y)
  461.                 {
  462.                     stopGame(false, "The bees have reached you!");
  463.                 }
  464.             }
  465.         }
  466.  
  467.         // The student will complete this function as part of an activity
  468.         private void checkCollisions()
  469.         {
  470.             foreach (Sprite bee in bees)
  471.             {
  472.                 foreach (Sprite smokeShot in smokeShots)
  473.                 {
  474.                     if (smokeShot.IsCollided(bee))
  475.                     {
  476.                         bee.IsAlive = false;
  477.                         smokeShot.IsAlive = false;
  478.                     }
  479.                 }
  480.             }
  481.             foreach (Sprite hiveSection in hiveSections)
  482.             {
  483.                 foreach (Sprite beeShot in beeShots)
  484.                 {
  485.                     if (beeShot.IsCollided(hiveSection))
  486.                     {
  487.                         hiveSection.IsAlive = false;
  488.                         beeShot.IsAlive = false;
  489.                     }
  490.                 }
  491.                 foreach (Sprite smokeShot in smokeShots)
  492.                 {
  493.                     if (smokeShot.IsCollided(hiveSection))
  494.                     {
  495.                         hiveSection.IsAlive = false;
  496.                         smokeShot.IsAlive = false;
  497.                     }
  498.                 }
  499.                 foreach (Sprite bee in bees)
  500.                 {
  501.                     if (bee.IsCollided(hiveSection))
  502.                     {
  503.                         hiveSection.IsAlive = false;
  504.                     }
  505.                 }
  506.             }
  507.             foreach (Sprite beeShot in beeShots)
  508.             {
  509.                 if (beeShot.IsCollided(smokeSprayer))
  510.                 {
  511.                     stopGame(false, "You have been stung!");
  512.                 }
  513.             }
  514.             // remove all dead sprites from their lists
  515.             pruneList(beeShots);
  516.             pruneList(smokeShots);
  517.             pruneList(bees);
  518.             pruneList(hiveSections);
  519.         }
  520.  
  521.         // The student will complete this function as part of an activity
  522.         private void handleKeyPress()
  523.         {
  524.             KeyboardState currentKeyboard = Keyboard.GetState();
  525.             if (oldKeyboardState == null)
  526.                 oldKeyboardState = currentKeyboard;
  527.  
  528.             if (!oldKeyboardState.IsKeyDown(Keys.Space) &&
  529.                 (currentKeyboard.IsKeyDown(Keys.Space)))
  530.             {
  531.                 if (gameOver)
  532.                 {
  533.                     startGame();
  534.                 }
  535.                 else
  536.                 {
  537.                     shootSmokeSprayer();
  538.                 }
  539.             }
  540.  
  541.             if (!gameOver)
  542.             {
  543.                 if (currentKeyboard.IsKeyDown(Keys.Right))
  544.                 {
  545.                     if (smokeSprayer.UpperLeft.X <
  546.                         GraphicsDevice.Viewport.Width - smokeSprayer.GetWidth())
  547.                         smokeSprayer.UpperLeft.X += 2;
  548.                 }
  549.  
  550.                 if (currentKeyboard.IsKeyDown(Keys.Left))
  551.                 {
  552.                     if (smokeSprayer.UpperLeft.X > smokeSprayer.GetWidth())
  553.                         smokeSprayer.UpperLeft.X -= 2;
  554.                 }
  555.             }
  556.  
  557.             oldKeyboardState = currentKeyboard;
  558.         }
  559.  
  560.         //*************************************************************************************************************
  561.         // OPTIONAL: If the student is using Xbox gamepads, they can optionally complete this method
  562.         // If not, they should complete the handleKeyPress() method mentioned above.
  563.  
  564.         private void handleXboxGamepad()
  565.         {
  566.            
  567.         }
  568.         //*****************************************************************************************************************
  569.  
  570.  
  571.  
  572.         // The student will complete this function as part of an activity
  573.         private void shootSmokeSprayer()
  574.         {
  575.             if (smokeShots.Count < MAX_SMOKE_SHOTS)
  576.             {
  577.                 Sprite newSmokeShot = new Sprite();
  578.  
  579.                 newSmokeShot.SetTexture(smokeTexture);
  580.  
  581.                 newSmokeShot.SetVelocity(0, -4);
  582.                 newSmokeShot.IsAlive = true;
  583.  
  584.                 newSmokeShot.UpperLeft.X = smokeSprayer.UpperLeft.X + (smokeSprayer.GetCenter().X - newSmokeShot.GetWidth() / 2);
  585.                 newSmokeShot.UpperLeft.Y = smokeSprayer.UpperLeft.Y;
  586.  
  587.                 smokeShots.AddLast(newSmokeShot);
  588.             }
  589.         }
  590.  
  591.         /// <summary>
  592.         /// This is called when the game should draw itself.
  593.         /// </summary>
  594.         /// <param name="gameTime">Provides a snapshot of timing values.</param>
  595.         // The student will complete this function as part of an activity
  596.         protected override void Draw(GameTime gameTime)
  597.         {
  598.             GraphicsDevice.Clear(Color.SkyBlue);
  599.  
  600.             spriteBatch.Begin();
  601.  
  602.             // draw the smoke sprayer
  603.             if (smokeSprayer != null)
  604.                 smokeSprayer.Draw(spriteBatch);
  605.  
  606.             // draw all active smoke shots
  607.             foreach (Sprite smokeShot in smokeShots)
  608.             {
  609.                 smokeShot.Draw(spriteBatch);
  610.             }
  611.  
  612.             // draw all active bee shots
  613.             foreach (Sprite beeShot in beeShots)
  614.             {
  615.                 beeShot.Draw(spriteBatch);
  616.             }
  617.  
  618.             // draw all active bees
  619.             foreach (Sprite bee in bees)
  620.             {
  621.                 bee.Draw(spriteBatch);
  622.             }
  623.  
  624.             // draw all remaining hive sections
  625.             foreach (Sprite hiveSection in hiveSections)
  626.             {
  627.                 hiveSection.Draw(spriteBatch);
  628.             }
  629.  
  630.             //*****************************************************************
  631.             // Student will add some "game over" logic here in an activity
  632.             if (gameOver)
  633.             {
  634.                 spriteBatch.DrawString(gameFont, displayMessage, new Vector2(200, 20), Color.Blue);
  635.             }
  636.             //*****************************************************************
  637.  
  638.             spriteBatch.End();
  639.  
  640.             base.Draw(gameTime);
  641.         }
  642.  
  643.  
  644.         // This method is provided fully complete as part of the activity starter.
  645.         private void pruneList(LinkedList<Sprite> spriteList)
  646.         {
  647.             // clip out any sprites from the list where IsAlive = false
  648.             for (int i = spriteList.Count - 1; i >= 0; i--)
  649.             {
  650.                 Sprite s = spriteList.ElementAt(i);
  651.                 if (!s.IsAlive)
  652.                 {
  653.                     spriteList.Remove(s);
  654.                 }
  655.             }
  656.         }
  657.     }
  658. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement