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

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

Poing versiohallintaan.

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