source: 2012/kerho/vivevinu/trunk/Poing/Poing/Poing.cs @ 3907

Revision 3907, 68.9 KB checked in by anlakane, 10 years ago (diff)

Paivitettiin Poing

Line 
1using System;
2using System.Collections.Generic;
3using Jypeli;
4using Jypeli.Assets;
5using Jypeli.Controls;
6using Jypeli.Effects;
7using Jypeli.Widgets;
8using System.IO;
9
10public class Poing : PhysicsGame
11{
12    private const int HORIZONTAL_RADIUS = 900;
13    private const int VERTICAL_RADIUS = 600;
14
15    private static Image seitti = LoadImage("seitti");
16    private static Image sydan = LoadImage("sydan");
17    private static Image rajahdys = LoadImage("rajahdys");
18    private static Image pilvi = LoadImage("pilvi");
19    private static Image jaaPuikko = LoadImage("jaapuikko");
20    private static Image[] aarreJaLahde = LoadImages("aarrearkku", "lahde");
21    private static Image[] kolikkoKuvat = LoadImages("coinFront", "coinTurning1", "coinTurning2", "coinTurning3");
22    private static Animation pyorivaKolikko;
23    private static Image boost = LoadImage("boost");
24    private static Image raketti = LoadImage("ohjus");
25    private static Image kilpi = LoadImage("mystic");
26    private static Image pelaajanKuva = LoadImage("tuliolio");
27    private static Image tulipallo = LoadImage("tulipallo2");
28    private static Image jaapallo = LoadImage("icebolt");
29    private static Image tulipallo2 = LoadImage("firebolt");
30    private static Image tulipallo3 = LoadImage("firebolt2");
31
32    private Jumper pelaaja;
33    private DoubleMeter omaHP;
34    private double speed;
35    private double jumpPower;
36    private double maximumJumpPower = 3000;
37    private List<Label> inventory = new List<Label>();
38
39    private Shape icicleShape;
40    private Timer apuAjastin;
41    private int tasks;
42    private const String TIEDOSTO = "Data.txt";
43
44    private String tunnusGlob = "";
45    private int profiili = -1;
46    private bool lock2 = true;
47    private bool lock3 = true;
48
49
50    /// <summary>
51    /// tehdaan lyhyet alkuvalmistelut (hiiri nakyville, muoto talteen ja oikea zoomi) ja siirrytaan aloitusvalikkoon
52    /// </summary>
53    public override void Begin()
54    {
55        Camera.ZoomFactor = Math.Min(386 / Screen.Top, 483 / Screen.Right);
56        IsMouseVisible = true;
57        icicleShape = Shape.FromImage(jaaPuikko);
58        Valikko();
59    }
60
61
62    /// <summary>
63    /// luodaan aloitusvalikko, josta siirrytaan kenttiin, hallitaan profiileja ja katsotaan ohjeet
64    /// </summary>
65    public void Valikko()
66    {
67        pyorivaKolikko = new Animation(kolikkoKuvat[0], kolikkoKuvat[1], kolikkoKuvat[2], kolikkoKuvat[3], Image.Mirror(kolikkoKuvat[3]), Image.Mirror(kolikkoKuvat[2]), Image.Mirror(kolikkoKuvat[1]));
68        Level.Background.CreateGradient(Color.Crimson, Color.DarkAzure);
69        Label[] otsikko = LuoOtsikko();
70        Label naytto = NaytaKirjautunut();
71
72        String teksti2 = lock2 ? "2. kentta (locked)" : "2. kentta";
73        String teksti3 = lock3 ? "3. kentta (locked)" : "3. kentta";
74        MultiSelectWindow msw = new MultiSelectWindow("", "1. kentta", teksti2, teksti3, "kirjaudu sisaan", "luo tunnus", "ohjeet", "Poistu");
75        msw.ItemSelected += delegate(int valittu)
76        {
77            apuAjastin = null;
78            naytto.Destroy();
79            foreach (Label kirjain in otsikko) kirjain.Destroy();
80            switch (valittu)
81            {
82                case 0:
83                    AloitaKentta1();
84                    break;
85                case 1:
86                    if (lock2) Valikko();
87                    else AloitaKentta2();
88                    break;
89                case 2:
90                    if (lock3) Valikko();
91                    else AloitaKentta3();
92                    break;
93                case 3:
94                    KasitteleKirjautuminen();
95                    break;
96                case 4:
97                    LuoTunnus();
98                    break;
99                case 5:
100                    NaytaOhjeet();
101                    break;
102                default:
103                    Exit();
104                    break;
105            }
106        };
107        msw.Y = -100;
108        Add(msw);
109    }
110
111
112    /// <summary>
113    /// kysytaan kayttajatunnus ja salasana, ja jos annetut sopivat yhteen niin siirrytaan ko. profiilille
114    /// </summary>
115    private void KasitteleKirjautuminen()
116    {
117        if (!File.Exists(TIEDOSTO))
118        {
119            MessageDisplay.Add("Profiileja ei ole luotu");
120            Valikko();
121            return;
122        }
123        FileStream tiedostovirta = new FileStream(TIEDOSTO, FileMode.Open);
124        StreamReader virtaLukija = new StreamReader(tiedostovirta);
125
126        List<String> tunnukset = new List<String>();
127        List<String> salasanat = new List<String>();
128        List<bool> locks2 = new List<bool>();
129        List<bool> locks3 = new List<bool>();
130
131        String rivi;
132        while ((rivi = virtaLukija.ReadLine()) != null && rivi != "")
133        {
134            String[] data = rivi.Split(' ');
135            tunnukset.Add(data[0]);
136            salasanat.Add(data[1]);
137            locks2.Add(bool.Parse(data[2]));
138            locks3.Add(bool.Parse(data[3]));
139        }
140        virtaLukija.Close();
141
142        InputWindow iw = new InputWindow("Syota kayttajatunnuksesi");
143        iw.TextEntered += delegate
144        {
145            String tunnus = Encode(iw.InputBox.Text);
146            if (tunnukset.Contains(tunnus))
147            {
148                int index = tunnukset.IndexOf(tunnus);
149                String salasana = "";
150                InputWindow iw2 = new InputWindow("Syota salasanasi");
151                iw2.InputBox.TextChanged += delegate
152                {
153                    try
154                    {
155                        int lastIndex = iw2.InputBox.Text.Length - 1;
156                        salasana += iw2.InputBox.Text[lastIndex];
157                        iw2.InputBox.Text = iw2.InputBox.Text.Substring(0, lastIndex) + "*";
158                    }
159                    catch (IndexOutOfRangeException iore)
160                    {
161                        MessageDisplay.Add("Lue ohjeet");
162                        iw2.Destroy();
163                    }
164                };
165                iw2.TextEntered += delegate
166                {
167                    if (salasanat[index] == Encode(salasana))
168                    {
169                        lock2 = locks2[index];
170                        lock3 = locks3[index];
171                        profiili = index;
172                        tunnusGlob = iw.InputBox.Text;
173                    }
174                    else MessageDisplay.Add("Salasana-tunnus-pari on kelvoton");
175                    Valikko();
176                };
177                Add(iw2);
178            }
179            else
180            {
181                MessageDisplay.Add("Pyydetty tunnus ei ole olemassa");
182                Valikko();
183            }
184        };
185        Add(iw);
186    }
187
188
189    /// <summary>
190    /// luodaan uusi kayttajatunnus
191    /// </summary>
192    private void LuoTunnus()
193    {
194        InputWindow iw = new InputWindow("Syota uusi kayttajatunnuksesi");
195        iw.TextEntered += delegate
196        {
197            String tunnus = Encode(iw.InputBox.Text);
198            if (tunnus.Length < 1)
199            {
200                iw.Destroy();
201                Valikko();
202                return;
203            }
204            int pituus = 0;
205            if (File.Exists(TIEDOSTO))
206            {
207                FileStream tiedostovirta = new FileStream(TIEDOSTO, FileMode.Open);
208                StreamReader virtaLukija = new StreamReader(tiedostovirta);
209
210                List<String> tunnukset = new List<String>();
211                List<String> salasanat = new List<String>();
212
213                String rivi;
214                while ((rivi = virtaLukija.ReadLine()) != null && rivi != "")
215                {
216                    String[] data = rivi.Split(' ');
217                    tunnukset.Add(data[0]);
218                    salasanat.Add(data[1]);
219                    pituus++;
220                }
221                virtaLukija.Close();
222                if (tunnukset.Contains(tunnus))
223                {
224                    MessageDisplay.Add("Tunnus on jo olemassa");
225                    LuoTunnus();
226                    return;
227                }
228            }
229
230            String salasana = "";
231            InputWindow iw2 = new InputWindow("Syota salasana");
232            iw2.InputBox.TextChanged += delegate
233            {
234                try
235                {
236                    int lastIndex = iw2.InputBox.Text.Length - 1;
237                    salasana += iw2.InputBox.Text[lastIndex];
238                    iw2.InputBox.Text = iw2.InputBox.Text.Substring(0, lastIndex) + "*";
239                }
240                catch (IndexOutOfRangeException iore)
241                {
242                    MessageDisplay.Add("Lue ohjeet");
243                    iw2.Destroy();
244                }
245            };
246            iw2.TextEntered += delegate
247            {
248                if (salasana.Length < 4)
249                {
250                    MessageDisplay.Add("Vaaditaan pidempi salasana");
251                    Valikko();
252                    return;
253                }
254                FileStream tiedostovirta2;
255                if (!File.Exists(TIEDOSTO))
256                {
257                    tiedostovirta2 = new FileStream(TIEDOSTO, FileMode.Create);
258                    tiedostovirta2.Close();
259                }
260                FileStream tiedostovirta3 = new FileStream(TIEDOSTO, FileMode.Append);
261                StreamWriter virtakirjoittaja = new StreamWriter(tiedostovirta3);
262                virtakirjoittaja.WriteLine(tunnus + " " + Encode(salasana) + " true true");
263                virtakirjoittaja.Close();
264
265                tunnusGlob = iw.InputBox.Text;
266                profiili = pituus;
267                lock2 = true;
268                lock3 = true;
269                Valikko();
270            };
271            Add(iw2);
272        };
273        Add(iw);
274    }
275
276
277    /// <summary>
278    /// luodaan naytto kuvaruudun vasempaan ylakulmaan, jossa on muuttujan tunnusGlob arvo.
279    /// Paitsi jos tunnusBlob == "", jolloin nayton teksti on "Ei kirjauduttu"
280    /// </summary>
281    /// <returns>luotu naytto</returns>
282    private Label NaytaKirjautunut()
283    {
284        Label naytto = new Label("Kirjautuneena: " + tunnusGlob);
285        if (tunnusGlob == "") naytto.Text = "Ei kirjauduttu";
286        naytto.TextScale = new Vector(1.5, 1.5);
287        naytto.TextColor = Color.LightCyan;
288        naytto.X = -500;
289        naytto.Y = 350;
290        Add(naytto);
291        return naytto;
292    }
293
294
295    /// <summary>
296    /// tuo nakyville lyhyet ohjeet pelia varten
297    /// </summary>
298    private void NaytaOhjeet()
299    {
300        MessageWindow mw = new MessageWindow("Ohjeita pelaamiseen:\nVoit liikkua ja hypata ollessasi tasolla sopivassa kulmassa nuolinappaimilla;\nVoit kaantya nappaimilla 1 ja 2;\nVoit ampua kirjoittamalla 'fire';\nKeratessasi tavaran ruudun vasempaan laitaan tulee teksti, jonka kirjoittamalla voit kayttaa tavaran\n\nOhjeita kayttajatunnuksiin:\nKun lapaiset kentan, seuraava aukeaa nykyiselle kayttajatunnukselle;\nKayttajatunnus ei saa olla tyhja,\nsalasanan on oltava vahintaan nelja (4) merkkia pitka;\nAla kayta erikoismerkkeja, salasanaa kirjoitettaessa merkkeja ei voi kumittaa (vaikka silta nayttaakin)");
301        mw.Closed += delegate { Valikko(); };
302        Add(mw);
303    }
304
305
306    /// <summary>
307    /// muuttaa tekstijonoa
308    /// </summary>
309    /// <param name="koodattava">muutettava tekstijono</param>
310    /// <returns>uusi tekstijono (koostuu numeroista)</returns>
311    private String Encode(String koodattava)
312    {
313        String koodattu = "";
314        for (int i = 0; i < koodattava.Length / 2; i++)
315        {
316            int kanta = koodattava[2 * i];
317            for (int j = 0; j < 16; j++) kanta *= 2;
318            kanta += koodattava[2 * i + 1];
319            int seed = 1;
320            for (int j = 0; j < koodattava[2 * i]; j++) seed = (3 * seed) % kanta;
321            koodattu += seed.ToString();
322            for (int j = 0; j < koodattava[2 * i + 1]; j++) seed = (3 * seed) % kanta;
323            koodattu += seed.ToString();
324        }
325        if (koodattava.Length % 2 == 1) koodattu += ((int)koodattava[koodattava.Length - 1]).ToString();
326        return koodattu;
327    }
328
329
330    /// <summary>
331    /// luodaan kuvaruudun ylalaitaan otsikko "Poing", jossa kirjaimet hyppivat jaksollisesti.
332    /// palautetaan otsikon kirjaimet taulukossa
333    /// </summary>
334    private Label[] LuoOtsikko()
335    {
336        Label[] otsikko = new Label[5];
337        double size = 100;
338        double korkeus = 300;
339
340        otsikko[0] = LuoTeksti("P", new Vector(-2 * size, korkeus), size);
341        otsikko[1] = LuoTeksti("o", new Vector(-size, korkeus), size);
342        otsikko[2] = LuoTeksti("i", new Vector(0, korkeus), size);
343        otsikko[3] = LuoTeksti("n", new Vector(size, korkeus), size);
344        otsikko[4] = LuoTeksti("g", new Vector(2 * size, korkeus), size);
345
346        int kirjainNro = 0;
347        apuAjastin = new Timer();
348        apuAjastin.Interval = 0.4;
349        apuAjastin.Timeout += delegate
350        {
351            int kirjainNroNyt = kirjainNro;
352            otsikko[kirjainNro].MoveTo(new Vector((kirjainNro - 2) * size, korkeus + size), 500, delegate
353            {
354                otsikko[kirjainNroNyt].MoveTo(new Vector((kirjainNroNyt - 2) * size, korkeus), 500);
355            });
356            kirjainNro = (kirjainNro + 1) % 5;
357        };
358        apuAjastin.Start();
359        return otsikko;
360    }
361
362    /// <summary>
363    /// luodaan Label, jossa annettu teksti ja palautetaan se
364    /// </summary>
365    /// <param name="sana">teksti</param>
366    /// <param name="paikka">tekstin paikka kuvaruudulla</param>
367    /// <param name="koko">Labelin koko, johon teksti asetetaan</param>
368    /// <returns>luotu Label, jossa teksti</returns>
369    private Label LuoTeksti(String sana, Vector paikka, double koko)
370    {
371        Label word = new Label(koko, koko, sana);
372        word.Position = paikka;
373        //word.Font = Font.DefaultLarge;
374        //word.SizeMode = TextSizeMode.StretchText;
375        word.TextScale = new Vector(7, 7);
376        word.TextColor = Color.OrangeRed;
377        Add(word);
378        return word;
379    }
380
381
382    /// <summary>
383    /// piirretaan kutistuvat merkit 3, 2, 1, GO! ;
384    /// aikaa prosessiin kuluu 20 sekuntia
385    /// </summary>
386    private void Lahtolaskenta()
387    {
388        LahtolaskentaYksiKutistus("3", -300, 600);
389        Timer.SingleShot(5, delegate { LahtolaskentaYksiKutistus("2", -300, 600); });
390        Timer.SingleShot(10, delegate { LahtolaskentaYksiKutistus("1", -300, 600); });
391        Timer.SingleShot(15, delegate { LahtolaskentaYksiKutistus("GO!", -900, 600); });
392    }
393
394    /// <summary>
395    /// luodaan teksti joka kutistuu kuvaruudun kokoisesta pieneksi viiden (5) sekunnin kuluessa
396    /// </summary>
397    /// <param name="teksti">kutistettava teksti</param>
398    /// <param name="x">tekstin x-koordinaatti (huom. ei toimi "tavallisesti")</param>
399    /// <param name="y">teksitn y-koordinaatti (huom. ei toimi "tavallisesti")</param>
400    private void LahtolaskentaYksiKutistus(String teksti, double x, double y)
401    {
402        Label _321GO = new Label(300, 300, teksti);
403        _321GO.X = x;
404        _321GO.Y = y;
405        _321GO.TextColor = Color.Red;
406        _321GO.TextScale = new Vector(50, 50);
407        Add(_321GO);
408        _321GO.MaximumLifetime = TimeSpan.FromSeconds(5);
409
410        apuAjastin = new Timer();
411        apuAjastin.Interval = 0.1;
412        apuAjastin.Timeout += delegate
413        {
414            _321GO.TextScale *= 0.95;
415            _321GO.Position *= 0.95;
416        };
417        apuAjastin.Start(50);
418    }
419
420
421    /// <summary>
422    /// luodaan kenttapohja, pelaaja, viholiset, kerattavat esineet, ja asetataan kontrollit
423    /// </summary>
424    private void AloitaKentta1()
425    {
426        Camera.ZoomToLevel();
427        LuoKentta1();
428        Lahtolaskenta();
429        tasks = 3;
430        Timer.SingleShot(20, delegate
431        {
432            LuoPelaaja(100, 60, 1000, 1);
433            LuoVihut1();
434            AsetaKontrollit();
435
436            LueSanat(new String[] { "fire", "burst", "heal" },
437                new Action[] {
438                new Action(delegate
439                {
440                    Vector voima = Vector.FromLengthAndAngle(500, pelaaja.Angle + Angle.RightAngle);
441                    Ammu(pelaaja.Position + pelaaja.Height * voima.Normalize() / 2, voima); 
442                }),
443                new Action(delegate
444                {
445                    if (InventoryContains("burst"))
446                    {
447                        PaivitaVarastoa("burst", false);
448                        Burst(9);
449                        Timer.SingleShot(1.5, delegate { Burst(9); });
450                    }
451                    else MessageDisplay.Add("No bursts left");
452                }),
453                new Action(delegate
454               
455                {
456                    if (InventoryContains("heal"))
457                    {
458                        PaivitaVarastoa("heal", false);
459                        omaHP.Value = omaHP.MaxValue;
460                    }
461                    else MessageDisplay.Add("No heals left");
462                })});
463
464            apuAjastin = new Timer();
465            apuAjastin.Interval = 7;
466            apuAjastin.Timeout += delegate
467            {
468                if (RandomGen.NextInt(4) == 0) LuoKerattava("heal", sydan, Level.Bottom, Level.Top, Level.Left, Level.Right);
469                if (RandomGen.NextInt(4) == 0) LuoKerattava("burst", rajahdys, Level.Bottom, Level.Top, Level.Left, Level.Right);
470            };
471            apuAjastin.Start();
472        });
473    }
474
475
476    /// <summary>
477    /// laittaa pelaajan ampumaan monta panosta kerrallaan (kerran)
478    /// </summary>
479    /// <param name="panoksia">kuinka monta panosta ammutaan</param>
480    private void Burst(int panoksia)
481    {
482        Random rand = new Random();
483        for (int i = 0; i < panoksia; i++)
484        {
485            Vector voima = Vector.FromLengthAndAngle(500, pelaaja.Angle + Angle.FromDegrees(rand.Next(160)));
486            Ammu(pelaaja.Position + pelaaja.Height * voima.Normalize() / 2, voima);
487        }
488    }
489
490
491    /// <summary>
492    /// Luodaan kentta, joka sisaltaa:
493    /// ellipsimuodostelmassa liikkuvat laatat;
494    /// reunat, jotka tekevat kentasta topologisesti toroidin
495    /// ts. siirtavat tormaajan toiselle puolelle kenttaa;
496    /// painovoiman ja taustavarin
497    /// </summary>
498    private void LuoKentta1()
499    {
500        MovingLevel[] laatat = new MovingLevel[9];
501        int l = laatat.Length;
502        for (int i = 0; i < l; i++)
503        {
504            MovingLevel laatta = new MovingLevel(100, 20, 25);
505            laatta.X = HORIZONTAL_RADIUS * Math.Cos(2 * Math.PI * i / l) / 2;
506            laatta.Y = VERTICAL_RADIUS * Math.Sin(2 * Math.PI * i / l) / 2;
507            laatta.Color = Color.Brown;
508            Add(laatta);
509            laatta.Angle = Angle.FromRadians(2 * Math.PI * (i - 1) / l + Math.PI / 6);
510            laatta.Move(i, l, HORIZONTAL_RADIUS, VERTICAL_RADIUS);
511            laatat[i] = laatta;
512        }
513
514        Gravity = new Vector(0, -300);
515        Level.Background.CreateGradient(Color.White, Color.SkyBlue);
516
517        #region reunat
518        PhysicsObject ylareuna = PhysicsObject.CreateStaticObject(Screen.Width, 10);
519        ylareuna.Color = new Color(0, 0, 0, 0);
520        ylareuna.Y = Screen.Top + 30;
521        ylareuna.IgnoresCollisionResponse = true;
522        AddCollisionHandler(ylareuna, delegate(IPhysicsObject reuna, IPhysicsObject tormaaja)
523        {
524            tormaaja.Y = Screen.Bottom - 20 + Math.Max(tormaaja.Width, tormaaja.Height) / 2;
525        });
526        Add(ylareuna);
527
528        PhysicsObject alareuna = PhysicsObject.CreateStaticObject(Screen.Width, 10);
529        alareuna.Color = new Color(0, 0, 0, 0);
530        alareuna.Y = Screen.Bottom - 30;
531        alareuna.IgnoresCollisionResponse = true;
532        AddCollisionHandler(alareuna, delegate(IPhysicsObject reuna, IPhysicsObject tormaaja)
533        {
534            tormaaja.Y = Screen.Top + 20 - Math.Max(tormaaja.Width, tormaaja.Height) / 2;
535        });
536        Add(alareuna);
537
538        PhysicsObject oikeareuna = PhysicsObject.CreateStaticObject(10, Screen.Height);
539        oikeareuna.Color = new Color(0, 0, 0, 0);
540        oikeareuna.X = Screen.Right + 30;
541        oikeareuna.IgnoresCollisionResponse = true;
542        AddCollisionHandler(oikeareuna, delegate(IPhysicsObject reuna, IPhysicsObject tormaaja)
543        {
544            tormaaja.X = Screen.Left - 20 + Math.Max(tormaaja.Width, tormaaja.Height) / 2;
545        });
546        Add(oikeareuna);
547
548        PhysicsObject vasenreuna = PhysicsObject.CreateStaticObject(10, Screen.Height);
549        vasenreuna.Color = new Color(0, 0, 0, 0);
550        vasenreuna.X = Screen.Left - 30;
551        vasenreuna.IgnoresCollisionResponse = true;
552        AddCollisionHandler(vasenreuna, delegate(IPhysicsObject reuna, IPhysicsObject tormaaja)
553        {
554            tormaaja.X = Screen.Right + 20 - Math.Max(tormaaja.Width, tormaaja.Height) / 2;
555        });
556        Add(vasenreuna);
557        #endregion
558    }
559
560
561    /// <summary>
562    /// luodaan pelaaja
563    /// </summary>
564    /// <param name="hp">pelaajalle annettavat elamapisteet</param>
565    /// <param name="vauhti">liikkumisnopeus</param>
566    private void LuoPelaaja(double hp, double vauhti, double hyppyvoima, int kentta)
567    {
568        pelaaja = new Jumper(30, 30, 1);
569        pelaaja.Image = pelaajanKuva;
570        Add(pelaaja);
571        speed = vauhti;
572        jumpPower = hyppyvoima;
573
574        omaHP = new DoubleMeter(hp, 0, hp);
575        omaHP.LowerLimit += delegate { Tappio(kentta); };
576        Timer healer = new Timer();
577        healer.Interval = 5;
578        healer.Timeout += delegate { omaHP.AddValue(2); };
579        healer.Start();
580
581        LuoPalkkiNaytto(omaHP, "your health", new Vector(600, 250));
582    }
583
584
585    /// <summary>
586    /// luodaan annettua mittaria nayttava palkki otsikolla
587    /// </summary>
588    /// <param name="mittari">mittari, joka esitetaan graafisesti palkilla</param>
589    /// <param name="otsikko">palkin otsikko</param>
590    /// <param name="paikka">paikka, johon palkki luodaan</param>
591    /// <returns>palkki, johon mittari on sidottu</returns>
592    private ProgressBar LuoPalkkiNaytto(DoubleMeter mittari, String otsikko, Vector paikka)
593    {
594        Label title = new Label(otsikko);
595        title.TextColor = Color.DarkGreen;
596        title.X = paikka.X;
597        title.Y = paikka.Y + title.Height / 2;
598        Add(title);
599
600        ProgressBar palkki = new ProgressBar(60, 10);
601        palkki.BindTo(mittari);
602        palkki.X = paikka.X;
603        palkki.Y = paikka.Y - palkki.Height / 2;
604        palkki.Color = Color.White;
605        palkki.BorderColor = Color.Black;
606        palkki.BarColor = new Color((int)Math.Round(255 * (1 - mittari.Value / mittari.MaxValue)), (int)Math.Round(255 * mittari.Value / mittari.MaxValue), 0);
607        mittari.Changed += delegate
608        {
609            palkki.BarColor = new Color((int)Math.Round(255 * (1 - mittari.Value / mittari.MaxValue)), (int)Math.Round(255 * mittari.Value / mittari.MaxValue), 0);
610        };
611        Add(palkki);
612
613        Timer seuraa = new Timer();
614        seuraa.Interval = 0.05;
615        seuraa.Timeout += delegate { title.X = palkki.X; title.Y = palkki.Y + title.Height; };
616        seuraa.Start();
617
618        return palkki;
619    }
620
621
622    /// <summary>
623    /// lopettaa kentan ja tuo esille valikon, josta voi siirtya eteenpain
624    /// </summary>
625    private void Tappio(int kentta)
626    {
627        ClearAll();
628        Timer.SingleShot(0.1, delegate
629        {
630            ClearAll();
631            MultiSelectWindow msw = new MultiSelectWindow("Havisit pelin :(", "yrita uudestaan", "palaa aloitusvalikkoon");
632            msw.ItemSelected += delegate(int item)
633            {
634                if (item == 0)
635                {
636                    if (kentta == 1) AloitaKentta1();
637                    if (kentta == 2) AloitaKentta2();
638                    if (kentta == 3) AloitaKentta3();
639                }
640                if (item == 1) Valikko();
641            };
642            Add(msw);
643        });
644    }
645
646
647    /// <summary>
648    /// asetetaan "peruskontrollit" eli liikkuminen pelaajalle ja pelista poistuminen
649    /// </summary>
650    private void AsetaKontrollit()
651    {
652        Keyboard.Listen(Key.Left, ButtonState.Pressed, delegate { pelaaja.MoveOnLevel(speed); }, "kierra tasoa vastapaivaan");
653        Keyboard.Listen(Key.Left, ButtonState.Released, pelaaja.MoveOnLevel, null, 0.0);
654        Keyboard.Listen(Key.Right, ButtonState.Pressed, delegate { pelaaja.MoveOnLevel(-speed); }, "kierra tasoa myotapaivaan");
655        Keyboard.Listen(Key.Right, ButtonState.Released, pelaaja.MoveOnLevel, null, 0.0);
656
657        Keyboard.Listen(Key.Up, ButtonState.Pressed, delegate { pelaaja.Jump(Math.Min(jumpPower, maximumJumpPower)); }, "hyppaa");
658
659        Keyboard.Listen(Key.D1, ButtonState.Down, pelaaja.Turn, "kaanny vastapaivaan", 1.0);
660        Keyboard.Listen(Key.D1, ButtonState.Released, pelaaja.Turn, null, 0.0);
661        Keyboard.Listen(Key.D2, ButtonState.Down, pelaaja.Turn, "kaanny myotapaivaan", -1.0);
662        Keyboard.Listen(Key.D2, ButtonState.Released, pelaaja.Turn, null, 0.0);
663
664        Keyboard.Listen(Key.Escape, ButtonState.Pressed, delegate
665        {
666            MultiSelectWindow valikko = new MultiSelectWindow("Peli jatkuu, valitse nopeasti :)", "jatka pelaamista", "palaa aloitusvalikkoon");
667            valikko.ItemSelected += delegate(int item)
668            {
669                switch (item)
670                {
671                    case 0:
672                        break;
673                    case 1:
674                        ClearAll();
675                        Valikko();
676                        break;
677                }
678            };
679            Add(valikko);
680        }, "palaa aloitusvalikkoon");
681    }
682
683
684    /// <summary>
685    /// kirjoitettaessa tietty sana (vain kirjaimilla), niin tapahtuu
686    /// tietty tapahtuma. sanaa kirjoitettaessa tulostetaan kirjaimet nakyville
687    /// </summary>
688    /// <param name="sanat">sanat, joihin liittyy tapahtuma (annettava yhta paljon kuin tapahtumia)</param>
689    /// <param name="tapahtumat">tapahtumat, jotka on sidottu sanoihin (annettava yhta paljon kuin sanoja)</param>
690    private void LueSanat(String[] sanat, Action[] tapahtumat)
691    {
692        int paikka = 0;
693        List<String> mahdollisetSanat = new List<String>();
694        foreach (String sana in sanat) mahdollisetSanat.Add(sana);
695
696        Label naytto = new Label();
697        naytto.Y = 350;
698        naytto.TextColor = new Color(0, 0, 0, 100);
699        Add(naytto);
700
701        Keyboard.ListenAll(ButtonState.Pressed, delegate(Key painettu)
702        {
703            if (!Keyboard.IsChar(painettu) || Char.IsDigit(Keyboard.ToChar(painettu))) return;
704            char merkki = Keyboard.ToChar(painettu);
705            naytto.Text += merkki;
706            for (int i = 0; i < mahdollisetSanat.Count; i++)
707            {
708                if (mahdollisetSanat[i][paikka] != merkki) mahdollisetSanat.RemoveAt(i--);
709            }
710
711            if (mahdollisetSanat.Count == 0)
712            {
713                mahdollisetSanat.Clear();
714                foreach (String sana in sanat) mahdollisetSanat.Add(sana);
715                naytto.Text = "";
716                paikka = 0;
717                return;
718            }
719            paikka++;
720            for (int i = 0; i < mahdollisetSanat.Count; i++)
721            {
722                if (mahdollisetSanat[i].Length == paikka)
723                {
724                    tapahtumat[Array.IndexOf(sanat, mahdollisetSanat[i])]();
725
726                    mahdollisetSanat.Clear();
727                    foreach (String sana in sanat) mahdollisetSanat.Add(sana);
728                    paikka = 0;
729                    naytto.Text = "";
730                    return;
731                }
732            }
733        });
734    }
735
736
737    /// <summary>
738    /// luodaan kentan 1 viholliset:
739    /// 1) "perus" kohti tuleva ja hyokkaava vihu, jonka panoksista lisaksi jaa esteita
740    /// 2) tasoilla liikkuva vihu, joka hyokkaa seka kaukaa, etta lahelta
741    /// 3) melkolailla paikallaan pysyva vihu, joka voi vahingoittaa myos muita vihuja
742    /// </summary>
743    private void LuoVihut1()
744    {
745        Freezer kylmaVihu = LuoJaadyttaja(new Vector(600, -300), 65, 65, 13, "Freezer's health", 12, 600, 150);
746        kylmaVihu.HP.LowerLimit += delegate { tasks--; if (tasks == 0) Voitto(1); };
747        Add(kylmaVihu);
748        Spider hamahakki = LuoHamahakki(2, new Vector(-180, 400), 50, 40, 10, "Spider's health", 24, 6, 600, 10);
749        hamahakki.HP.LowerLimit += delegate { tasks--; if (tasks == 0) Voitto(1); };
750        Add(hamahakki);
751        LightningCaster ukkonen = LuoMyrskypilvi(new Vector(550, 300), 150, 80, 22, "Cloud's health", 20, 3, 600, 80);
752        ukkonen.HP.LowerLimit += delegate { tasks--; if (tasks == 0) Voitto(1); };
753        ukkonen.AddVulnerable(kylmaVihu);
754        ukkonen.AddVulnerable(hamahakki);
755        Add(ukkonen);
756    }
757
758
759    /// <summary>
760    /// palauttaa (ei lisaa peliin) ilmassa liikkuvan vihollisen, joka hyokkaa kaukaa pelaajaan
761    /// luoden samalla (liikkuvia) esteita
762    /// </summary>
763    /// <param name="paikka">mika annetaan paikaksi</param>
764    /// <param name="leveys">leveys</param>
765    /// <param name="korkeus">korkeus</param>
766    /// <param name="hp">elamapisteet</param>
767    /// <param name="hpPalkkiOtsikko">hp palkin otsikko</param>
768    /// <param name="vahinko">vahinko osuessa pelaajaan</param>
769    /// <param name="hpPalkkiX">hp palkin x-koordinaatti, jos NaN, niin seuraa vihollista</param>
770    /// <param name="hpPalkkiY">hp palkin y-koordinaatti, jos NaN, niin seuraa vihollista</param>
771    /// <param name="vauhti">nopeus, jolla vihollinen liikkuu</param>
772    /// <returns>alustettu vihollinen</returns>
773    private Freezer LuoJaadyttaja(Vector paikka, double leveys, double korkeus, double hp, String hpPalkkiOtsikko = "", double vahinko = 12, double hpPalkkiX = double.NaN, double hpPalkkiY = double.NaN, double vauhti = 50)
774    {
775        Freezer kylmaVihu = new Freezer(leveys, korkeus, hp, vauhti);
776        kylmaVihu.Shape = Shape.Ellipse;
777        kylmaVihu.Target = pelaaja;
778        kylmaVihu.HitAction = delegate
779        {
780            omaHP.Value -= vahinko;
781            speed /= 2;
782            Timer.SingleShot(7, delegate { speed *= 2; });
783        };
784        kylmaVihu.IgnoresGravity = true;
785        kylmaVihu.Position = paikka;
786        kylmaVihu.Tag = "vihu";
787
788        ProgressBar naytto = LuoPalkkiNaytto(kylmaVihu.HP, hpPalkkiOtsikko, Vector.Zero);
789        if (double.IsNaN(hpPalkkiX) || double.IsNaN(hpPalkkiY))
790        {
791            naytto.Position = kylmaVihu.Position + new Vector(0, kylmaVihu.Height) - Camera.Position;
792            Timer seuraa = new Timer();
793            seuraa.Interval = 0.05;
794            seuraa.Timeout += delegate { naytto.Position = kylmaVihu.Position + new Vector(0, kylmaVihu.Height) - Camera.Position; };
795            seuraa.Start();
796            kylmaVihu.HP.LowerLimit += delegate { seuraa.Stop(); };
797        }
798        else naytto.Position = new Vector(hpPalkkiX, hpPalkkiY);
799        kylmaVihu.HP.LowerLimit += delegate { kylmaVihu.Destroy(); naytto.Destroy(); };
800        return kylmaVihu;
801    }
802
803    /// <summary>
804    /// palautetaan tasoilla liikkuva vihollinen, joka hyokkaa kaukaa ja lahelta pelaajaan
805    /// </summary>
806    /// <param name="id">CollisionIgnoreGroup, johon vihollinen ja taso, jolla ollaan siirtyvat</param>
807    /// <param name="paikka">vihollisen paikka</param>
808    /// <param name="leveys">leveys</param>
809    /// <param name="korkeus">korkeus</param>
810    /// <param name="hp">elemapisteet</param>
811    /// <param name="hpPalkkiOtsikko">otsikko hpPalkille</param>
812    /// <param name="lahiVahinko">lahelta tehtavassa iskussa tuotettava vahinko</param>
813    /// <param name="kaukoVahinko">kaukaa tehtavassa iskussa tuotettava vahinko</param>
814    /// <param name="hpPalkkiX">hp palkin x-koordinaatti, jos NaN, niin seuraa vihollista</param>
815    /// <param name="hpPalkkiY">hp palkin y-koordinaatti, jos NaN, niin seuraa vihollista</param>
816    /// <param name="vauhti">vauhti, jolla vihollinen liikkuu tasolla</param>
817    /// <param name="regeneration">20 sekuntin valein lisattava hp maara</param>
818    /// <returns>alustettu vihollinen</returns>
819    private Spider LuoHamahakki(int id, Vector paikka, double leveys, double korkeus, double hp, String hpPalkkiOtsikko = "", double lahiVahinko = 24, double kaukoVahinko = 6, double hpPalkkiX = double.NaN, double hpPalkkiY = double.NaN, double vauhti = 80, double regeneration = 1)
820    {
821        Spider hamahakki = new Spider(leveys, korkeus, hp, id);
822        hamahakki.Position = paikka;
823        hamahakki.Target = pelaaja;
824        hamahakki.Speed = vauhti;
825        hamahakki.Mass = 100;
826        hamahakki.Tag = "vihu";
827        hamahakki.RangeHitAction = delegate
828        {
829            omaHP.Value -= kaukoVahinko;
830            if (omaHP.Value > 0)
831            {
832                PhysicsObject net = new PhysicsObject(40, 40, Shape.Ellipse);
833                net.Position = pelaaja.Position;
834                net.Image = seitti;
835                net.LinearDamping = 0.95;
836                net.MaximumLifetime = TimeSpan.FromSeconds(8);
837                Add(net);
838                AxleJoint liitos = new AxleJoint(net, pelaaja);
839                liitos.Softness = 10;
840                Add(liitos);
841                Timer.SingleShot(9, delegate { liitos.Destroy(); });
842            }
843        };
844        hamahakki.MeleeHitAction = delegate
845        {
846            omaHP.Value -= lahiVahinko;
847        };
848
849        Timer healer = new Timer();
850        healer.Interval = 20;
851        healer.Timeout += delegate { hamahakki.HP.AddValue(regeneration); };
852        healer.Start();
853        ProgressBar naytto = LuoPalkkiNaytto(hamahakki.HP, hpPalkkiOtsikko, Vector.Zero);
854        if (double.IsNaN(hpPalkkiX) || double.IsNaN(hpPalkkiY))
855        {
856            naytto.Position = hamahakki.Position + new Vector(0, hamahakki.Height) - Camera.Position;
857            Timer seuraa = new Timer();
858            seuraa.Interval = 0.05;
859            seuraa.Timeout += delegate { naytto.Position = hamahakki.Position + new Vector(0, hamahakki.Height) - Camera.Position; };
860            seuraa.Start();
861            hamahakki.HP.LowerLimit += delegate { seuraa.Stop(); };
862        }
863        else naytto.Position = new Vector(hpPalkkiX, hpPalkkiY);
864        hamahakki.HP.LowerLimit += delegate { hamahakki.Destroy(); healer.Stop(); naytto.Destroy(); };
865        return hamahakki;
866    }
867
868    /// <summary>
869    /// palauttaa melko paikallaan pysyvan vihollisen, joka hyokkaa kaukaa haarautvilla iskuilla kohti pelaajaa
870    /// </summary>
871    /// <param name="paikka">vihollisen paikka</param>
872    /// <param name="leveys">leveys</param>
873    /// <param name="korkeus">korkeus</param>
874    /// <param name="hp">elamapisteet</param>
875    /// <param name="hpPalkkiOtsikko">hp palkin otsikko</param>
876    /// <param name="vahinko">vahinko pelaajaan</param>
877    /// <param name="vihuVahinko">vahinko, jonka "vihu" tagilla varustetut vahingoittuvat kohteet karsivat</param>
878    /// <param name="hpPalkkiX">hp palkin x-koordinaatti, jos NaN, niin seuraa vihollista</param>
879    /// <param name="hpPalkkiY">hp palkin y-koordinaatti, jos NaN, niin seuraa vihollista</param>
880    /// <param name="vauhti">nopeus, jolla vihollinen liikkuu</param>
881    /// <returns>alustettu vihollinen</returns>
882    private LightningCaster LuoMyrskypilvi(Vector paikka, double leveys, double korkeus, double hp, String hpPalkkiOtsikko = "", double vahinko = 20, double vihuVahinko = 3, double hpPalkkiX = double.NaN, double hpPalkkiY = double.NaN, double vauhti = 20)
883    {
884        LightningCaster ukkonen = new LightningCaster(leveys, korkeus, Shape.Ellipse, hp);
885        ukkonen.Position = paikka;
886        ukkonen.WantedPosition = paikka;
887        ukkonen.IgnoresGravity = true;
888        ukkonen.Tag = "vihu";
889        ukkonen.Mass = 100;
890        ukkonen.CanRotate = false;
891        ukkonen.HitAction = delegate(IPhysicsObject kohde)
892        {
893            if (kohde == pelaaja) omaHP.Value -= vahinko;
894            if (kohde.Tag == "vihu") Vahingoita(kohde, vihuVahinko);
895        };
896
897        ukkonen.Target = pelaaja;
898        ukkonen.AddVulnerable(pelaaja);
899
900        ProgressBar naytto = LuoPalkkiNaytto(ukkonen.HP, hpPalkkiOtsikko, Vector.Zero);
901        if (double.IsNaN(hpPalkkiX) || double.IsNaN(hpPalkkiY))
902        {
903            naytto.Position = ukkonen.Position + new Vector(0, ukkonen.Height) - Camera.Position;
904            Timer seuraa = new Timer();
905            seuraa.Interval = 0.05;
906            seuraa.Timeout += delegate { naytto.Position = ukkonen.Position + new Vector(0, ukkonen.Height) - Camera.Position; };
907            seuraa.Start();
908            ukkonen.HP.LowerLimit += delegate { seuraa.Stop(); };
909        }
910        else naytto.Position = new Vector(hpPalkkiX, hpPalkkiY);
911        ukkonen.HP.LowerLimit += delegate { ukkonen.Destroy(); naytto.Destroy(); };
912        return ukkonen;
913    }
914
915
916    /// <summary>
917    /// vahingoittaa annettua objektia. tata voi kayttaa myos Spidereihin
918    /// </summary>
919    /// <param name="kohde">objekti, jota vahingoitetaan</param>
920    /// <param name="vahinko">arvo, joka verran kohteen elamapisteita pienennetaan</param>
921    private void Vahingoita(IPhysicsObject kohde, double vahinko)
922    {
923        HealthObject tmp1 = kohde as HealthObject;
924        if (tmp1 != null) tmp1.HP.Value -= vahinko;
925        Spider tmp2 = kohde as Spider;
926        if (tmp2 != null) tmp2.HP.Value -= vahinko;
927    }
928
929
930    /// <summary>
931    /// lopetetaan kentta ja luodaan valikko, josta voi jatkaa eteenpain
932    /// </summary>
933    private void Voitto(int kentta)
934    {
935        ClearAll();
936
937        if (0 <= profiili && File.Exists(TIEDOSTO) && kentta < 3)
938        {
939            FileStream tiedostovirta = new FileStream(TIEDOSTO, FileMode.Open, FileAccess.ReadWrite);
940            StreamReader virtalukija = new StreamReader(tiedostovirta);
941
942            String sisalto = virtalukija.ReadToEnd();
943            String[] rivit = sisalto.Split(new String[] { "\r\n" }, StringSplitOptions.None);
944            String[] palat = rivit[profiili].Split(' ');
945            if (kentta == 1)
946            {
947                rivit[profiili] = palat[0] + " " + palat[1] + " false " + palat[3];
948                lock2 = false;
949            }
950            else
951            {
952                rivit[profiili] = palat[0] + " " + palat[1] + " " + palat[2] + " false";
953                lock3 = false;
954            }
955            virtalukija.Close();
956
957            tiedostovirta = new FileStream(TIEDOSTO, FileMode.Truncate);
958            tiedostovirta.Close();
959            tiedostovirta = new FileStream(TIEDOSTO, FileMode.Append);
960            StreamWriter virtakirjoittaja = new StreamWriter(tiedostovirta);
961            for (int i = 0; i < rivit.Length; i++) virtakirjoittaja.WriteLine(rivit[i]);
962            virtakirjoittaja.Close();
963        }
964
965        Timer.SingleShot(0.1, delegate
966        {
967            ClearAll();
968            MultiSelectWindow msw = new MultiSelectWindow("Lapaisit kentan :)", "jatka eteenpain", "aloita alusta", "palaa aloitusvalikkoon");
969            msw.ItemSelected += delegate(int item)
970            {
971                if (item == 0)
972                {
973                    if (kentta == 1) AloitaKentta2();
974                    if (kentta == 2) AloitaKentta3();
975                    if (kentta == 3) ;
976                }
977                if (item == 1)
978                {
979                    if (kentta == 1) AloitaKentta1();
980                    if (kentta == 2) AloitaKentta2();
981                    if (kentta == 3) AloitaKentta3();
982                }
983                if (item == 2) Valikko();
984            };
985            Add(msw);
986        });
987    }
988
989
990    /// <summary>
991    /// luodaan kerattava esine satunnaisesti annetulle alueelle. kerattaessa esineen
992    /// teksti lisataan pelaajan tavaroihin (inventory)
993    /// </summary>
994    /// <param name="name">tavaran teksti (jonka perusteella maaraytyy mitä tavaralla voi tehda)</param>
995    /// <param name="kuva">kuva, joka annetaan kerattavalle tavaralle</param>
996    /// <param name="bottom">luontialueen alaraja</param>
997    /// <param name="top">luontialueen ylaraja</param>
998    /// <param name="left">luontialueen vasen raja</param>
999    /// <param name="right">luontialueen oikea raja</param>
1000    /// <param name="animaatio">tavaralle annettava animaatio</param>
1001    /// <param name="lifeTime">kuinka monen sekuntin kuluttu luonnista tavara viimeistaan tuhotaan</param>
1002    /// <param name="ig">jos true, niin tavaroihin ei vaikuta painovoima</param>
1003    private void LuoKerattava(String name, Image kuva, double bottom, double top, double left, double right, Animation animaatio = null, double lifeTime = 10, bool ig = true)
1004    {
1005        PhysicsObject item = new PhysicsObject(20, 20);
1006        item.Position = RandomGen.NextVector(left, bottom, right, top);
1007        item.IgnoresCollisionResponse = true;
1008        item.MaximumLifetime = TimeSpan.FromSeconds(lifeTime);
1009        item.IgnoresGravity = ig;
1010        if (animaatio == null) item.Image = kuva;
1011        else
1012        {
1013            item.Animation = animaatio;
1014            item.Animation.Start();
1015        }
1016        item.Oscillate(Vector.UnitX, 8, 1);
1017        UnlimitedAngle tmp = new UnlimitedAngle();
1018        tmp.Radians = Math.PI / 6;
1019        item.OscillateAngle(1, tmp, 1.4);
1020        Add(item);
1021        AddCollisionHandler(item, pelaaja, delegate
1022        {
1023            item.Destroy();
1024            PaivitaVarastoa(name, true);
1025        });
1026    }
1027
1028
1029    /// <summary>
1030    /// tonaistaan annettua oliota annetulla voimalla
1031    /// </summary>
1032    /// <param name="voima">voima (suuruus ja suunta), jolla oliota tonaistaan</param>
1033    /// <param name="liikkuja">olio, jota tonaistaan</param>
1034    private void Tonaise(Vector voima, PhysicsObject liikkuja)
1035    {
1036        liikkuja.Hit(voima);
1037    }
1038
1039
1040    /// <summary>
1041    /// luo panoksen, joka tormatessaan vahingoittaa objekteja, joilla on maaratty tagi
1042    /// </summary>
1043    /// <param name="paikka">paikka, josta ammus lahtee</param>
1044    /// <param name="voima">voima (suunta ja suuruus), jolla ammus ammutaan</param>
1045    /// <param name="noCollisionResponse">jos true, niin ammus voi kulkea esteiden lapi</param>
1046    /// <param name="tag">ammuksen mahdollisten kohteiden tagi</param>
1047    private void Ammu(Vector paikka, Vector voima, bool noCollisionResponse = false, String tag = "vihu")
1048    {
1049        PhysicsObject ammus = new PhysicsObject(15, 15);
1050        ammus.Position = paikka;
1051        ammus.MaximumLifetime = TimeSpan.FromSeconds(4);
1052        ammus.Image = tulipallo;
1053        Add(ammus);
1054        ammus.Hit(voima);
1055        AddCollisionHandler<PhysicsObject, HealthObject>(ammus, "vihu", delegate(PhysicsObject tama, HealthObject vihu) { vihu.HP.Value--; ammus.Destroy(); });
1056        AddCollisionHandler<PhysicsObject, Spider>(ammus, "vihu", delegate(PhysicsObject tama, Spider vihu) { vihu.HP.Value--; ammus.Destroy(); });
1057        AddCollisionHandler<PhysicsObject, Wizard>(ammus, "vihu", delegate(PhysicsObject tama, Wizard vihu) { ((HealthObject)vihu).HP.Value--; ammus.Destroy(); });
1058    }
1059
1060
1061    /// <summary>
1062    /// luo panoksen, joka tormatessaan vahingoittaa objekteja, joilla on maaratty tagi
1063    /// </summary>
1064    /// <param name="paikka">paikka, josta ammus lahtee</param>
1065    /// <param name="voima">voima (suunta ja suuruus), jolla ammus ammutaan</param>
1066    /// <param name="lifeTime">ammuksen elinaika</param>
1067    /// <param name="ammuksenKuva">ammuksen kuva</param>
1068    /// <param name="noCollisionResponse">jos true, niin ammus voi kulkea esteiden lapi</param>
1069    /// <param name="tag">ammuksen mahdollisten kohteiden tagi</param>
1070    private void Ammu(Vector paikka, Vector voima, Image ammuksenKuva, double lifeTime = 4, bool noCollisionResponse = false, String tag = "vihu")
1071    {
1072        PhysicsObject ammus = new PhysicsObject(15, 15);
1073        ammus.Position = paikka;
1074        ammus.MaximumLifetime = TimeSpan.FromSeconds(lifeTime);
1075        ammus.Image = ammuksenKuva;
1076        Add(ammus);
1077        ammus.Hit(voima);
1078        AddCollisionHandler<PhysicsObject, HealthObject>(ammus, "vihu", delegate(PhysicsObject tama, HealthObject vihu) { vihu.HP.Value--; ammus.Destroy(); });
1079        AddCollisionHandler<PhysicsObject, Spider>(ammus, "vihu", delegate(PhysicsObject tama, Spider vihu) { vihu.HP.Value--; ammus.Destroy(); });
1080        AddCollisionHandler<PhysicsObject, Wizard>(ammus, "vihu", delegate(PhysicsObject tama, Wizard vihu) { ((HealthObject)vihu).HP.Value--; ammus.Destroy(); });
1081    }
1082
1083
1084    /// <summary>
1085    /// kaantaa olion kulmaan siten, etta alapuoli osoittaa kulkusuuntaan
1086    /// </summary>
1087    /// <param name="olio">kaannettava objekti</param>
1088    public static void AsetaKulma(GameObject olio)
1089    {
1090        olio.Angle = Angle.FromRadians(olio.Position.Angle.Radians - Math.PI / 2);
1091    }
1092
1093
1094    /// <summary>
1095    /// palauttaa tiedon sisaltaako inventory ko. tekstin omaavan alkion
1096    /// </summary>
1097    /// <param name="name">teksti, jota etsitaan inventoryn alkioilta</param>
1098    /// <returns>onko inventoryssa alkio, jolla on etsitty teksti</returns>
1099    private bool InventoryContains(String name)
1100    {
1101        bool contains = false;
1102        foreach (Label item in inventory) contains |= item.Text == name;
1103        return contains;
1104    }
1105
1106
1107    /// <summary>
1108    /// lisataan tai poistetaan varastosta annetun niminen tavara
1109    /// </summary>
1110    /// <param name="name">lisattavan tai poistettavan tavaran nimi</param>
1111    /// <param name="lisaa">true = lisaa; false = poista</param>
1112    private void PaivitaVarastoa(String name, bool lisaa)
1113    {
1114        if (lisaa)
1115        {
1116            Label naytto = new Label(name);
1117            naytto.TextScale = 1.5 * Vector.Diagonal;
1118            naytto.TextColor = new Color(0, 0, 0, 150);
1119            naytto.X = -600;
1120            Add(naytto);
1121            inventory.Add(naytto);
1122        }
1123        else
1124        {
1125            for (int i = 0; i < inventory.Count; i++)
1126            {
1127                if (inventory[i].Text == name)
1128                {
1129                    inventory[i].Destroy();
1130                    inventory.RemoveAt(i);
1131                    break;
1132                }
1133            }
1134        }
1135        for (int i = 0; i < inventory.Count; i++)
1136        {
1137            inventory[i].Y = 100 * (3 - i);
1138        }
1139    }
1140
1141
1142    /// <summary>
1143    /// aloitetaan 2. kentta
1144    /// </summary>
1145    private void AloitaKentta2()
1146    {
1147        LuoPelaaja(100, 90, 800, 2);
1148        List<PhysicsObject> pilvet = LuoKentta2();
1149        AsetaKontrollit();
1150        LuoVihut2();
1151        tasks = 4;
1152
1153        // kolikon tiputuspaikat
1154        Vector[] loppuPaikka = new Vector[] { new Vector(-1200, 460), new Vector(1200, 460) };
1155        String[] loppuPaikkaNimi = new String[] { "chest", "fountain" };
1156        int kumpi = RandomGen.NextInt(2);
1157        MessageDisplay.Clear();
1158        MessageDisplay.Add("Get a coin from the top level and drop it to the " + loppuPaikkaNimi[kumpi] + ". You'll need to do that four times so hurry up!");
1159        for (int i = 0; i < 2; i++)
1160        {
1161            PhysicsObject place = PhysicsObject.CreateStaticObject(80, 50);
1162            place.Position = loppuPaikka[i];
1163            place.Image = aarreJaLahde[i];
1164            place.Oscillate(Vector.UnitX, 10, 1);
1165            Add(place);
1166        }
1167
1168        // aika, jossa suoritettava tehtavat
1169        double aika = 1000;
1170        Label naytto = new Label();
1171        DoubleMeter kello = new DoubleMeter(aika);
1172        naytto.BindTo(kello);
1173        kello.AddOverTime(-aika, aika, delegate { Tappio(2); });
1174        naytto.Position = new Vector(600, 350);
1175        Add(naytto);
1176
1177        LueSanat(new String[] 
1178        {
1179            "fire", "dropcoin", "heal", "boost", "shield", "missile"
1180        }, new Action[]
1181        { 
1182            new Action(delegate
1183                {
1184                    Vector voima = Vector.FromLengthAndAngle(1000, pelaaja.Angle + Angle.RightAngle);
1185                    Ammu(pelaaja.Position + pelaaja.Height * voima.Normalize() / 2, voima); 
1186                }),
1187            new Action(delegate
1188                {
1189                    if (InventoryContains("dropcoin"))
1190                    {
1191                        if (Vector.Distance(pelaaja.Position, loppuPaikka[kumpi]) < 100)
1192                        {
1193                            PaivitaVarastoa("dropcoin", false);
1194                            tasks--;
1195                            if (tasks == 0) 
1196                            {
1197                                tasks = pilvet.Count;
1198                                kello.Stop();
1199                                MessageDisplay.Add("Well done! You shall be revarded at the top level - if you get there...");
1200                                VaihdaPilvet(pilvet.ToArray(), 0);
1201                                LuoFinaaliTavarat();
1202                                return;
1203                            }
1204                            LuoKerattava("dropcoin", null, 1600, 1610, -10, 10, pyorivaKolikko, 1000000000);
1205                            kumpi = RandomGen.NextInt(2);
1206                            MessageDisplay.Add("Get a coin from the top level and drop it to the " + loppuPaikkaNimi[kumpi]);
1207                        }
1208                        else MessageDisplay.Add("Drop your coin to the " + loppuPaikkaNimi[kumpi]);
1209                    }
1210                    else MessageDisplay.Add("You don't have a coin to drop");
1211                }),
1212            new Action(delegate
1213                {
1214                    if (InventoryContains("heal"))
1215                    {
1216                        PaivitaVarastoa("heal", false);
1217                        omaHP.Value = omaHP.MaxValue;
1218                    }
1219                    else MessageDisplay.Add("No heals left");
1220                }),
1221            new Action(delegate
1222                {
1223                    if (InventoryContains("boost"))
1224                    {
1225                        PaivitaVarastoa("boost", false);
1226                        speed *= 2;
1227                        jumpPower *= 3;
1228                        omaHP.AddOverTime(60, 30);
1229                        Timer.SingleShot(30, delegate { speed /= 2; jumpPower /= 3; });
1230                    }
1231                    else MessageDisplay.Add("No boosts left");
1232                }),
1233            new Action(delegate
1234                {
1235                    if (InventoryContains("shield"))
1236                    {
1237                        PaivitaVarastoa("shield", false);
1238                        PhysicsObject shield = new PhysicsObject(100, 100, Shape.Ellipse);
1239                        shield.Position = pelaaja.Position;
1240                        shield.IgnoresCollisionResponse = true;
1241                        shield.IgnoresGravity = true;
1242                        shield.Color = new Color(255, 0, 100, 150);
1243                        shield.Mass = 0.1;
1244                        shield.Tag = "shield";
1245                        Add(shield);
1246                        AxleJoint joint = new AxleJoint(shield, pelaaja);
1247                        Add(joint);
1248                        AddCollisionHandler<PhysicsObject, HealthObject>(shield, "vihu", delegate(PhysicsObject tama, HealthObject vihu){vihu.HP.Value = 0;});
1249                        AddCollisionHandler<PhysicsObject, Spider>(shield, "vihu", delegate(PhysicsObject tama, Spider vihu) { vihu.HP.Value = 0; });
1250                        AddCollisionHandler<PhysicsObject, PhysicsObject>(shield, "icicle", delegate(PhysicsObject tama, PhysicsObject jaa) { jaa.Destroy(); });
1251                        shield.MaximumLifetime = TimeSpan.FromSeconds(150);
1252                        double factor = 1000000;
1253                        omaHP.MaxValue *= factor;
1254                        omaHP.Value *= factor;
1255                        Timer.SingleShot(150, delegate
1256                        {
1257                            omaHP.Value /= factor;
1258                            omaHP.MaxValue /= factor;
1259                        });
1260                    }
1261                    else MessageDisplay.Add("No shields left");
1262                }),
1263            new Action(delegate
1264                {
1265                    if (InventoryContains("missile"))
1266                    {
1267                        PaivitaVarastoa("missile", false);
1268                        PhysicsObject ohjus = new PhysicsObject(50, 10);
1269                        ohjus.Image = raketti;
1270                        ohjus.IgnoresGravity = true;
1271                        ohjus.Position = pelaaja.Position + new Vector(0, 30);
1272                        Add(ohjus);
1273                        ohjus.Collided += delegate(IPhysicsObject tama, IPhysicsObject kohde)
1274                        {
1275                            if (kohde == pelaaja || kohde.Tag == "shield") return;
1276                            Explosion paineaalto = new Explosion(200);
1277                            paineaalto.Position = ohjus.Position;
1278                            ohjus.Destroy();
1279                            if (kohde.Tag == "vihu")
1280                            {
1281                                HealthObject tyypitetty = kohde as HealthObject;
1282                                if (tyypitetty != null) tyypitetty.HP.Value = 0;
1283                                else ((Spider)kohde).HP.Value = 0;
1284                            }
1285                            else if (kohde.Tag == "icicle") kohde.Destroy();
1286                            paineaalto.ShockwaveReachesObject += delegate(IPhysicsObject kohde2, Vector vektori)
1287                            {
1288                                if (kohde2.Tag == "vihu")
1289                                {
1290                                    HealthObject kohdeTyypitetty = kohde2 as HealthObject;
1291                                    if (kohdeTyypitetty != null) kohdeTyypitetty.HP.Value = 0;
1292                                    else ((Spider)kohde2).HP.Value = 0;
1293                                }
1294                                else if (kohde2.Tag == "icicle") kohde.Destroy();
1295                            };
1296                            Add(paineaalto);
1297                        };
1298                        Timer liiku = new Timer();
1299                        liiku.Interval = 0.5;
1300                        liiku.Timeout += delegate
1301                        {
1302                            Vector suunta = (Mouse.PositionOnWorld - ohjus.Position).Normalize(); 
1303                            ohjus.Velocity = 500 * (Mouse.PositionOnWorld - ohjus.Position).Normalize();
1304                            ohjus.Angle = suunta.Angle + Angle.StraightAngle;
1305                        };
1306                        liiku.Start();
1307                    }
1308                    else MessageDisplay.Add("No missiles left");
1309                })
1310        });
1311
1312        // kerattavia esineita
1313        apuAjastin = new Timer();
1314        apuAjastin.Interval = 6;
1315        apuAjastin.Timeout += delegate
1316        {
1317            LuoKerattava("heal", sydan, -350, 1600, -1000, 1000);
1318            LuoKerattava("boost", boost, -350, 1600, -1000, 1000);
1319            if (RandomGen.NextInt(4) == 0) LuoKerattava("shield", kilpi, -350, 1600, -1000, 1000);
1320            if (RandomGen.NextInt(4) == 0) LuoKerattava("missile", raketti, 1000, 1600, -1000, 1000);
1321        };
1322        apuAjastin.Start();
1323    }
1324
1325
1326    /// <summary>
1327    /// luo kenttapohjan, jossa on erilaisia melko stationaarisia tasoja, joilla voi hyppia, ja
1328    /// laitetaan kamera seuraamaan pelaajaa
1329    /// </summary>
1330    private List<PhysicsObject> LuoKentta2()
1331    {
1332        Camera.Follow(pelaaja);
1333        Gravity = new Vector(0, -500);
1334        Level.Background.CreateGradient(Color.White, Color.SkyBlue);
1335
1336        JumpingLevel pohja = new JumpingLevel(2000, 100);
1337        pohja.MakeStatic();
1338        pohja.Y = Level.Bottom;
1339        pohja.Color = Color.Brown;
1340        Add(pohja);
1341        PhysicsObject seina1 = PhysicsObject.CreateStaticObject(2000, 50);
1342        seina1.X = 1500;
1343        seina1.Y = 500 * Math.Sqrt(3) + Level.Bottom;
1344        seina1.Angle = Angle.FromRadians(Math.PI / 3);
1345        seina1.Color = Color.Brown;
1346        Add(seina1);
1347        PhysicsObject seina2 = PhysicsObject.CreateStaticObject(2000, 50);
1348        seina2.X = -1500;
1349        seina2.Y = 500 * Math.Sqrt(3) + Level.Bottom;
1350        seina2.Angle = Angle.FromRadians(2 * Math.PI / 3);
1351        seina2.Color = Color.Brown;
1352        Add(seina2);
1353
1354        List<PhysicsObject> pilviLaatat = new List<PhysicsObject>();
1355        for (int i = -9; i < 10; i++)
1356        {
1357            if (i == 0) continue;
1358            JumpingLevel laatta = new JumpingLevel(150, 30);
1359            Vector paikka = new Vector(130 * i, -350 + 80 * Math.Abs(i));
1360            laatta.Position = paikka;
1361            laatta.IgnoresGravity = true;
1362            laatta.Image = pilvi;
1363            AxleJoint joint = new AxleJoint(laatta, paikka);
1364            joint.Softness = 4;
1365            Add(joint);
1366            laatta.Mass = 80;
1367            Add(laatta);
1368            pilviLaatat.Add(laatta);
1369        }
1370        MessageDisplay.Add(pelaaja.Mass.ToString());
1371
1372        for (int i = 0; i < 10; i++)
1373        {
1374            JumpingLevel laatta = new JumpingLevel(70, 35 * Math.Sqrt(3), Shape.Triangle);
1375            if (i % 2 == 0) laatta.X = 200;
1376            else laatta.X = -200;
1377            laatta.Y = 120 * (i + 1);
1378            laatta.MakeStatic();
1379            laatta.AngularVelocity = 0.5;
1380            laatta.Color = RandomGen.NextColor();
1381            Add(laatta);
1382        }
1383
1384        JumpingLevel katto = new JumpingLevel(500, 70);
1385        katto.Y = 1500;
1386        katto.MakeStatic();
1387        katto.Color = Color.Silver;
1388        Add(katto);
1389        bool exists = false;
1390        AddCollisionHandler(katto, pelaaja, delegate
1391        {
1392            if (!exists)
1393            {
1394                Spider hamahakki = LuoHamahakki(1, RandomGen.NextVector(-200, 1580, 200, 1600), 50, 40, 10);
1395                hamahakki.HP.LowerLimit += delegate { exists = false; };
1396                Add(hamahakki);
1397                exists = true;
1398            }
1399        });
1400
1401        LuoKerattava("dropcoin", null, 1600, 1610, -10, 10, pyorivaKolikko, 1000000000);
1402        return pilviLaatat;
1403    }
1404
1405
1406    /// <summary>
1407    /// luodaan osa 2. kentan vihollisista siis jaadyttajia pienin aikavalein
1408    /// </summary>
1409    private void LuoVihut2()
1410    {
1411        Timer lisaaVihuja = new Timer();
1412        lisaaVihuja.Interval = 120;
1413        lisaaVihuja.Timeout += delegate { Add(LuoJaadyttaja(RandomGen.NextVector(-1000, 800, 1000, 2000), 60, 60, 3, "", 7)); };
1414        lisaaVihuja.Start();
1415    }
1416
1417
1418    /// <summary>
1419    /// Vaihdetaan hitaasti kaikki pilvet taulukon alkiot vihollisiksi. Naiden tappamisesta tehtavat vahenevat (siis tasks--).
1420    /// </summary>
1421    /// <param name="pilvet">fysiikkaoliot, jotka muutetaan vihollisiki</param>
1422    /// <param name="index">aloitusindeksi, aloitetaan seka alusta etta lopusta</param>
1423    private void VaihdaPilvet(PhysicsObject[] pilvet, int index)
1424    {
1425        if (pilvet.Length <= 2 * index) return;
1426        VaihdaPilvetApu(pilvet[index]);
1427        VaihdaPilvetApu(pilvet[pilvet.Length - index - 1]);
1428        Timer.SingleShot(15, delegate { VaihdaPilvet(pilvet, index + 1); });
1429    }
1430
1431    /// <summary>
1432    /// vaihdetaan annettu fysiikkaolio vihollisolioksi (siis tuhotaan annettu olio ja luodaan uusi)
1433    /// </summary>
1434    /// <param name="pilvi">vahdettava (tuhottava) olio</param>
1435    private void VaihdaPilvetApu(PhysicsObject pilvi)
1436    {
1437        LightningCaster ukkospilvi = LuoMyrskypilvi(pilvi.Position, pilvi.Width, pilvi.Height, 11);
1438        ukkospilvi.WantedPosition = new Vector(0, 1700);
1439        ukkospilvi.Speed = 5;
1440        ukkospilvi.Angle = pilvi.Angle;
1441        ukkospilvi.HP.LowerLimit += delegate { tasks--; if (tasks == 0) Voitto(2); };
1442        Add(ukkospilvi);
1443        pilvi.Destroy();
1444    }
1445
1446
1447    /// <summary>
1448    /// luodaan 2. kentassa tavaroita ylatasolle
1449    /// </summary>
1450    private void LuoFinaaliTavarat()
1451    {
1452        for (int i = 0; i < 5; i++) LuoKerattava("missile", raketti, 1580, 1590, -200, 200, null, 1000000);
1453        for (int i = 0; i < 3; i++) LuoKerattava("heal", sydan, 1580, 1590, -200, 200, null, 1000000);
1454        LuoKerattava("shield", kilpi, 1580, 1590, -200, 200, null, 1000000);
1455    }
1456
1457
1458    /// <summary>
1459    /// aloitetaan 3. kentta
1460    /// </summary>
1461    private void AloitaKentta3()
1462    {
1463        LuoPelaaja(100, 90, 800, 3);
1464        LuoKentta3();
1465        AsetaKontrollit();
1466        LuoVihut3();
1467
1468        LueSanat(new String[] { "fire", "heal", "boost", "autofire", "flamebolt" }, new Action[] 
1469        {
1470            new Action(delegate
1471                {
1472                    Vector voima = Vector.FromLengthAndAngle(1000, pelaaja.Angle + Angle.RightAngle);
1473                    Ammu(pelaaja.Position + pelaaja.Height * voima.Normalize() / 2, voima); 
1474                }),
1475            new Action(delegate
1476                {
1477                    if (InventoryContains("heal"))
1478                    {
1479                        PaivitaVarastoa("heal", false);
1480                        omaHP.Value = omaHP.MaxValue;
1481                    }
1482                    else MessageDisplay.Add("No heals left");
1483                }),
1484            new Action(delegate
1485                {
1486                    if (InventoryContains("boost"))
1487                    {
1488                        PaivitaVarastoa("boost", false);
1489                        speed *= 2;
1490                        jumpPower *= 3;
1491                        omaHP.AddOverTime(60, 30);
1492                        Timer.SingleShot(30, delegate { speed /= 2; jumpPower /= 3; });
1493                    }
1494                    else MessageDisplay.Add("No boosts left");
1495                }),
1496            new Action(delegate
1497                {
1498                    if (InventoryContains("autofire"))
1499                    {
1500                        PaivitaVarastoa("autofire", false);
1501                        Timer fire = new Timer();
1502                        fire.Interval = 2;
1503                        fire.Timeout += delegate { Ammu(pelaaja.Position, 800 * (Mouse.PositionOnWorld - pelaaja.Position).Normalize(), tulipallo2, 2, true); };
1504                        fire.Start(30);
1505                    }
1506                    else MessageDisplay.Add("No autofires left");
1507                }), 
1508            new Action(delegate
1509                {
1510                    if (InventoryContains("flamebolt"))
1511                    {
1512                        PaivitaVarastoa("flamebolt", false);
1513                        PhysicsObject flamebolt = new PhysicsObject(200, 150);
1514                        flamebolt.Position = pelaaja.Position;
1515                        flamebolt.Image = tulipallo3;
1516                        flamebolt.IgnoresGravity = true;
1517                        flamebolt.IgnoresCollisionResponse = true;
1518                        flamebolt.MaximumLifetime = TimeSpan.FromSeconds(10);
1519                        Add(flamebolt);
1520                        AddCollisionHandler(flamebolt, "vihu", delegate(IPhysicsObject bolt, HealthObject vihu) { vihu.HP.Value -= 10; });
1521                        AddCollisionHandler(flamebolt, "vihu", delegate(IPhysicsObject bolt, Wizard vihu) { ((HealthObject)vihu).HP.Value -= 10; });
1522                        AddCollisionHandler(flamebolt, "icicle", delegate(IPhysicsObject bolt, IPhysicsObject jaapuikko) { jaapuikko.Destroy(); });
1523                        AddCollisionHandler(flamebolt, "icelevel", delegate(IPhysicsObject bolt, IPhysicsObject jaataso) { jaataso.Destroy(); });
1524                        AddCollisionHandler(flamebolt, "teleport", delegate(IPhysicsObject bolt, IPhysicsObject teleportti) { teleportti.Destroy(); });
1525                        flamebolt.Angle = pelaaja.Angle + Angle.RightAngle;
1526                        flamebolt.Hit(Vector.FromLengthAndAngle(500, pelaaja.Angle + Angle.RightAngle));
1527                    }
1528                    else MessageDisplay.Add("No flamebolts left");
1529                })
1530        });
1531
1532        apuAjastin = new Timer();
1533        apuAjastin.Interval = 5;
1534        apuAjastin.Timeout += delegate
1535        {
1536            LuoKerattava("heal", sydan, Level.Bottom + 50, 1500, -1000, 1000);
1537            if (RandomGen.NextInt(2) == 0) LuoKerattava("boost", boost, Level.Bottom + 50, 900, -1000, 1000);
1538            if (RandomGen.NextInt(5) == 0) LuoKerattava("autofire", tulipallo2, 1000, 2000, -1500, 1500);
1539            if (RandomGen.NextInt(6) == 0) LuoKerattava("flamebolt", tulipallo, 1000, 2000, -1500, 1500);
1540        };
1541        apuAjastin.Start();
1542    }
1543
1544
1545    /// <summary>
1546    /// luodaan 3. kentan pohja eli pohjataso (jolla voi liikkua) ja pitkat ulospain vinot reunat (joilla ei voi liikkua)
1547    /// </summary>
1548    private void LuoKentta3()
1549    {
1550        Camera.Follow(pelaaja);
1551        Gravity = new Vector(0, -500);
1552        Level.Background.CreateGradient(Color.White, Color.SkyBlue);
1553
1554        JumpingLevel pohja = new JumpingLevel(2000, 100);
1555        pohja.Y = Level.Bottom;
1556        pohja.Color = Color.Brown;
1557        pohja.MakeStatic();
1558        Add(pohja);
1559
1560        PhysicsObject reuna = PhysicsObject.CreateStaticObject(2000, 50);
1561        reuna.X = -1500;
1562        reuna.Y = Level.Bottom + 500 * Math.Sqrt(3);
1563        reuna.Angle = Angle.FromRadians(2 * Math.PI / 3);
1564        reuna.Color = Color.Brown;
1565        Add(reuna);
1566
1567        reuna = PhysicsObject.CreateStaticObject(2000, 50);
1568        reuna.X = 1500;
1569        reuna.Y = Level.Bottom + 500 * Math.Sqrt(3);
1570        reuna.Angle = Angle.FromRadians(Math.PI / 3);
1571        reuna.Color = Color.Brown;
1572        Add(reuna);
1573
1574        reuna = PhysicsObject.CreateStaticObject(2000, 50);
1575        reuna.X = -2500;
1576        reuna.Y = Level.Bottom + 1500 * Math.Sqrt(3);
1577        reuna.Angle = Angle.FromRadians(2 * Math.PI / 3);
1578        reuna.Color = Color.Brown;
1579        Add(reuna);
1580
1581        reuna = PhysicsObject.CreateStaticObject(2000, 50);
1582        reuna.X = 2500;
1583        reuna.Y = Level.Bottom + 1500 * Math.Sqrt(3);
1584        reuna.Angle = Angle.FromRadians(Math.PI / 3);
1585        reuna.Color = Color.Brown;
1586        Add(reuna);
1587
1588        reuna = PhysicsObject.CreateStaticObject(2000, 50);
1589        reuna.X = -3500;
1590        reuna.Y = Level.Bottom + 2500 * Math.Sqrt(3);
1591        reuna.Angle = Angle.FromRadians(2 * Math.PI / 3);
1592        reuna.Color = Color.Brown;
1593        Add(reuna);
1594
1595        reuna = PhysicsObject.CreateStaticObject(2000, 50);
1596        reuna.X = 3500;
1597        reuna.Y = Level.Bottom + 2500 * Math.Sqrt(3);
1598        reuna.Angle = Angle.FromRadians(Math.PI / 3);
1599        reuna.Color = Color.Brown;
1600        Add(reuna);
1601    }
1602
1603
1604    /// <summary>
1605    /// luodaan 3. kentan vihollisia siis yksi velho paavastukseksi ja sen loitsuista lisaa voihollisia
1606    /// </summary>
1607    private void LuoVihut3()
1608    {
1609        Wizard boss = new Wizard(40, 60, 50);
1610        boss.X = -100;
1611        boss.Y = Level.Bottom + 80;
1612        boss.Tag = "vihu";
1613        boss.Target = pelaaja;
1614        LuoPalkkiNaytto(((HealthObject)boss).HP, "Wizard's health", new Vector(600, 150));
1615        ((HealthObject)boss).HP.LowerLimit += delegate { Voitto(3); };
1616        boss.AddSpell(delegate
1617        {
1618            LightningCaster ukkonen = LuoMyrskypilvi(boss.Position + new Vector(0, 80), 100, 60, 9, "", 14);
1619            ukkonen.Wanders = true;
1620            Add(ukkonen);
1621            Timer sade = new Timer();
1622            sade.Interval = 20;
1623            sade.Timeout += delegate { Add(LuoJaadyttaja(ukkonen.Position + new Vector(0, -45), 30, 30, 3, "", 7)); };
1624            sade.Start();
1625            ukkonen.HP.LowerLimit += delegate { sade.Stop(); };
1626        }, 15, 500);
1627        boss.AddSpell(delegate
1628        {
1629            GameObject[] icebolts = new GameObject[4];
1630            for (int i = 0; i < 4; i++)
1631            {
1632                icebolts[i] = new GameObject(400, 100);
1633                icebolts[i].Image = jaapallo;
1634                icebolts[i].Position = Vector.FromLengthAndAngle(500, Angle.FromRadians(Math.PI * (1 + 2 * i) / 4));
1635                icebolts[i].Angle = Angle.FromRadians(Math.PI * (5 + 2 * i) / 4);
1636                pelaaja.Add(icebolts[i]);
1637            }
1638            Timer liike = new Timer();
1639            liike.Interval = 0.1;
1640            liike.Timeout += delegate
1641            {
1642                for (int i = 0; i < 4; i++)
1643                {
1644                    icebolts[i].Size *= 0.92;
1645                    icebolts[i].Position *= 0.9;
1646                }
1647            };
1648            liike.Start(20);
1649            Timer.SingleShot(2, delegate
1650            {
1651                for (int i = 0; i < 4; i++) icebolts[i].Destroy();
1652                omaHP.Value -= 20;
1653                PhysicsObject icicle = new PhysicsObject(jaaPuikko);
1654                icicle.Shape = icicleShape;
1655                icicle.Position = pelaaja.Position + new Vector(0, -200);
1656                icicle.MaximumLifetime = TimeSpan.FromSeconds(40);
1657                icicle.Tag = "icicle";
1658                Add(icicle, -1);
1659                Timer.SingleShot(20, delegate
1660                {
1661                    Timer sula = new Timer();
1662                    sula.Interval = 0.1;
1663                    sula.Timeout += delegate { icicle.Size *= 0.982; };
1664                    sula.Start(200);
1665                });
1666            });
1667        }, 15);
1668        Add(boss);
1669    }
1670}
Note: See TracBrowser for help on using the repository browser.