source: 2015/24/ohjaajat/Dungeon/Dungeon/Dungeon/Dungeon.cs @ 6110

Revision 6110, 36.4 KB checked in by sieerinn, 7 years ago (diff)

Luola räjähtää.

Line 
1using System;
2using System.CodeDom;
3using System.Linq;
4using System.Collections.Generic;
5using System.Globalization;
6using System.Runtime.InteropServices;
7using System.Security.Cryptography;
8using Jypeli;
9using Jypeli.Assets;
10using Jypeli.Controls;
11using Jypeli.Effects;
12using Jypeli.Widgets;
13using Point = Microsoft.Xna.Framework.Point;
14
15/* Tässä on jotain dokumentaation tapaista:
16 *
17 * Layerit
18 *   3 - Kaivuunuoli ja partikkeliefektit
19 *   2 - Partikkelien varjot
20 *   1 - Huoneiden katto
21 *   0 - Huoneiden seinät ja barbaarit
22 *  -1 - Päivitykset
23 *  -2 - Huone (eli lattiat siis)
24 * 
25 * Ideoita:
26 *  - Pahempia vihollisia, joihin ei tehoa piikkiansat
27 *    vaan pitää ostaa kalliimpia ansoja niitä varten.
28 *  - Kultuurihuoneita, jotka tuottavat eriäviä määriä
29 *    kultuuria tai kestävät yhden barbaarin iskun.
30*/
31
32/// <summary>
33/// Päivitys joka voi olla huoneessa.
34/// </summary>
35public abstract class Upgrade : GameObject
36{
37    public int Price { get; set; }
38
39    public SoundEffect HajotusAani { get; set; }
40
41    protected Upgrade()
42        : base(Dungeon.RUUDUN_KOKO, Dungeon.RUUDUN_KOKO)
43    {
44    }
45
46    /// <summary>
47    /// Tätä kutsutaan kun päivitys on rakennettu huoneeseen.
48    /// </summary>
49    public virtual void Built(Dungeon peli) { }
50
51    /// <summary>
52    /// Tätä kutsutaan kun barbaari tulee kylään.
53    /// </summary>
54    public virtual void Invasion(Dungeon peli, Barbaari barbaari, Room huone) { }
55
56    /// <summary>
57    /// Kutsutaan joka syklin alussa.
58    /// </summary>
59    public virtual void SykliPaivitys() { }
60}
61
62class TrapUpgrade : Upgrade
63{
64    public int Damage { get; set; }
65
66    public bool Active
67    {
68        get { return LatausMittari.Value == LatausMittari.MaxValue; }
69    }
70
71    // Jos täynnä, niin ansa on aktiivinen.
72    public IntMeter LatausMittari { get; set; }
73
74    public TrapUpgrade()
75    {
76        LatausMittari = new IntMeter(4, 0, 4);
77        LatausMittari.UpperLimit += delegate
78        {
79            // Askelletaan vikasta framesta ekaan.
80            Animation.Step();
81        };
82    }
83
84    public override void Invasion(Dungeon peli, Barbaari barbaari, Room huone)
85    {
86        if (!Active) return;
87
88        barbaari.Tenacity.Value -= ((TrapUpgrade)(huone.Upgrade)).Damage;
89
90        peli.Splatter(huone.Position);
91
92        // Barbaarin tappo pudottaa latausmittarin nollaan.
93        LatausMittari.Value = LatausMittari.MinValue;
94
95        Animation.StopOnLastFrame = true;
96        Animation.Start(1);
97    }
98
99    public override void SykliPaivitys()
100    {
101        base.SykliPaivitys();
102        if (LatausMittari.Value < LatausMittari.MaxValue)
103        {
104            LatausMittari.Value++;
105        }
106    }
107}
108
109class CultureUpgrade : Upgrade
110{
111    // Tämän päivityksen antama kultuurin määrä.
112    public IntMeter Culture { get; set; }
113    public int Max { get; set; } //Kultuurimittarin maksimiarvo
114
115    // Label joka näyttää päivityksen antaman kultuurin määrän.
116    public Label KultuuriNaytto { get; set; }
117
118    public override void Built(Dungeon peli)
119    {
120        base.Built(peli);
121
122        Culture = new IntMeter(0, 0, Max);
123
124        // Luodaan kultuurin ilmaisin.
125        KultuuriNaytto = new Label("asd");
126        KultuuriNaytto.TextColor = Color.HotPink;
127        KultuuriNaytto.Color = Color.Black;
128        KultuuriNaytto.Position = peli.Camera.WorldToScreen(this.Position + new Vector(0, Dungeon.RUUDUN_KOKO * 0.5));
129        KultuuriNaytto.BindTo(Culture);
130        peli.Add(KultuuriNaytto);
131
132        // Näytetään kultuurin määrä kun hiiri on päivityksen päällä.
133        var kuuntelija = peli.Mouse.ListenMovement(0.1, _ => KultuuriNaytto.IsVisible = peli.Mouse.IsCursorOn(this), null);
134
135        this.Destroyed += delegate
136        {
137            KultuuriNaytto.Destroy();
138            kuuntelija.Destroy();
139        };
140    }
141
142    public override void Invasion(Dungeon peli, Barbaari barbaari, Room huone)
143    {
144        this.Destroy();
145        huone.Upgrade = null;
146        if (HajotusAani != null)
147        {
148            HajotusAani.Play();
149        }
150        if (peli.KultuuriHuoneidenPaikat().Count < 1)
151        {
152            peli.LopetaPeli();
153        }
154    }
155}
156
157public class Room : GameObject
158{
159    // Sijainti pelin ruudukossa.
160    public Point Location { get; set; }
161
162    // Päällä näkyvä "katto" kun huone ei ole vielä kaivettu.
163    public GameObject Roof { get; set; }
164
165    // Neljä seinää, jotka on GameObjekteja.
166    public Dictionary<Direction, GameObject> Walls { get; set; }
167
168    // Huoneen sisältämä päivitys.
169    public Upgrade Upgrade { get; set; }
170
171    private bool dug; // Onko huone kaivettu?
172    public bool Dug
173    {
174        get { return dug; }
175        set
176        {
177            dug = value;
178            Roof.IsVisible = !Dug;
179        }
180    }
181
182    public Room(Point paikka)
183        : base(Dungeon.RUUDUN_KOKO, Dungeon.RUUDUN_KOKO)
184    {
185        Walls = new Dictionary<Direction, GameObject>();
186        Location = paikka;
187    }
188}
189
190public class Barbaari : GameObject
191{
192    public List<Point> Reitti { get; set; }
193
194    public Point Kohde { get; set; }
195
196    public Point Location { get; set; }
197
198    public IntMeter Tenacity { get; set; }
199
200    public Barbaari(double width, double height)
201        : this(width, height, 0, new Image[1])
202    {
203        Reitti = new List<Point>();
204    }
205
206    public Barbaari(double width, double height, int tenacity, Image[] animaatio)
207        : base(width, height)
208    {
209        this.Animation = new Animation(animaatio) { FPS = 8 };
210        this.Tenacity = new IntMeter(tenacity, 0, 2);
211
212    }
213}
214
215public class Dungeon : PhysicsGame
216{
217    public const int RUUDUN_KOKO = 64;
218
219    public static Func<int, int, string, Image[]> LoadImages2 = (a, b, fmt) =>
220        LoadImages((from i in Enumerable.Range(a, b) select string.Format(fmt, i)).ToArray());
221
222    #region Kuvat
223    Image lattiaKuva = LoadImage("floor");
224    Image seinaKuva = LoadImage("wall");
225    Image reikaSeinaKuva = LoadImage("wallhole");
226    Image kiviKuva = LoadImage("rock");
227    private Image[][] kultuuriKuvat = {LoadImages2(1, 6, "fountain/f{0:0000}"), LoadImages("patsas"), LoadImages("piano")};
228    private Image[] piikkiAnsaKuvat = LoadImages2(1, 7, "piikit/piikit{0:0000}");
229    private Image[] murskausAnsaKuvat = LoadImages2(1, 9, "smash/smash{0:0000}");
230    public Image[] vihuKuvat = LoadImages2(1, 10, "vihu/v{0:0000}");
231    public Image[] kirvesVihuKuvat = LoadImages2(1, 10, "kirvesvihu/kv{0:0000}");
232    Image[] ansaKuvat;
233    List<Animation> ansaAnimaatiot = new List<Animation>();
234    Image partikkeliKuva = LoadImage("partikkeli");
235    Image taideVeri = LoadImage("taideveri");
236    private Image[] loppuKuvat = LoadImages2(1, 35, "break/b{0:0000}");
237    #endregion
238
239    private SoundEffect[] hajotusAanet = { LoadSoundEffect("fountainbreak"), LoadSoundEffect("boom"), LoadSoundEffect("piano2") };
240
241    int[] hinnat = { 75, 200, 300, 100 };
242    int[] vahingot = { 1, 2 };
243    int[] ansaHinnat = { 300, 600 };
244    int[] kultuuriTuotot = { 100, 200, 400 };
245    private int barbaariMaara = 2;
246
247    private Label kaivuuHintaLabel;
248    private Label kierrosIlmaisin;
249    //private bool kierrosKaynnissa;
250    private int kierros;
251
252    public int KierrosKaynnissa
253    {
254        get
255        {
256            return kierros;
257        }
258        set
259        {
260            kierros = value;
261            kierrosIlmaisin.Text = "Vaihe: " + (kierros % 2 == 0 ? "Barbaari-invaasio" : "Rakennusvaihe");
262        }
263    }
264
265    Room[,] huoneet;
266    //public List<Room> kohteet = new List<Room>();
267    public List<Barbaari> barbaarit;
268    Room spawn;
269    Timer barbaariAjastin;
270    Timer sykliAjastin;
271    Upgrade ostamassa;
272    Point digStart; // Huoneen sijainti, josta kaivuu aloitetaan.
273
274    private bool digging = false;
275
276    public bool Digging
277    {
278        get
279        {
280            return digging;
281        }
282        set
283        {
284            digging = value;
285            kaivuuHintaLabel.IsVisible = Digging;
286        }
287    }
288
289    GameObject digArrow;
290    GameObject digArrowHead;
291
292    IntMeter kultuuri = new IntMeter(0, 0, 2000);
293
294    const int MASSI = 2000;
295    const int VAAKA_HUONEET = 12;
296    const int PYSTY_HUONEET = 8;
297    const int HUONE_KAIVUU_HINTA = 50;
298
299    // Paljonko peliruudukko on siirtynyt origosta.
300    Vector huoneSiirtyma = new Vector(-200, 0);
301
302    private MainMenu menu;
303
304    public override void Begin()
305    {
306        ClearAll();
307
308        kultuuri.Value = MASSI;
309        kierros = 0;
310        barbaariAjastin = new Timer();
311        barbaarit = new List<Barbaari>();
312
313        SmoothTextures = false;
314        IsMouseVisible = true;
315
316        //SetWindowSize(1024, 768); // Riippuu Jypelin versiosta.
317        Window.Width = 1024;
318        Window.Height = 768;
319
320        ansaKuvat = new Image[] { piikkiAnsaKuvat[0], murskausAnsaKuvat[0] };
321        ansaAnimaatiot.Add(new Animation(piikkiAnsaKuvat));
322        ansaAnimaatiot.Add(new Animation(murskausAnsaKuvat));
323        menu = new MainMenu(this, "New game", "Highscores", "Help", "Quit");
324        menu.Painikkeet[0].Clicked += delegate
325        {
326            AloitaPeli();
327            menu = null;
328        };
329        menu.Painikkeet[3].Clicked += Exit;
330    }
331
332    void AloitaPeli()
333    {
334        ClearAll();
335        MediaPlayer.Play("In_The_Dark_Flashes");
336        Kontrollit();
337        UlkoAsuRoskaa();
338        Kauppa();
339        Nuoli();
340
341        // Luodaan huoneet ruutuihin.
342        huoneet = new Room[VAAKA_HUONEET, PYSTY_HUONEET];
343        foreach (var paikka in RuutujenPaikat())
344        {
345            var huone = CreateRoom(paikka);
346            Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Pressed, () => RoomPressed(huone), null);
347            Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Released, () => RoomReleased(huone), null);
348            Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Pressed, AsetaPaivitys, "Asetetaan ostettu päivitys paikoilleen", huone);
349            Mouse.Listen(MouseButton.Right, ButtonState.Pressed, delegate { ostamassa = null; }, "Perutaan ostos");
350            Mouse.ListenOn(huone, MouseButton.Right, ButtonState.Pressed, PoistaPaivitys, "Poistetaan asetettu päivitys", huone);
351            huoneet[paikka.X, paikka.Y] = huone;
352        }
353
354        LuoSpawn();
355
356        sykliAjastin = new Timer { Interval = 1.0 };
357        sykliAjastin.Timeout += Sykli;
358        sykliAjastin.Start();
359
360        barbaariAjastin.Timeout += LuoBarbaareja;
361        barbaariAjastin.Interval = sykliAjastin.Interval;   //TODO: säätöjä tähän, barbaarien määrään ja superbarbaarien todennäköisyyteen, kunnes peli tuntuu mielekkäältä
362
363        Level.Width = 1300;
364        Camera.ZoomToLevel();
365    }
366
367    void Nuoli()
368    {
369        digArrow = new GameObject(5, 5);
370        digArrowHead = new GameObject(15, 15);
371        digArrowHead.Shape = Shape.Triangle;
372        digArrowHead.IsVisible = digArrow.IsVisible = false;
373        Add(digArrow, 3);
374        Add(digArrowHead, 3);
375    }
376
377    void UlkoAsuRoskaa()
378    {
379        Level.Background.Color = Color.Black;
380
381        kierrosIlmaisin = new Label("asd");
382        kierrosIlmaisin.TextColor = Color.White;
383        kierrosIlmaisin.Y = Screen.Top - 150;
384        Add(kierrosIlmaisin);
385        KierrosKaynnissa = KierrosKaynnissa; // Aiheuttaa labelin päivittymisen.
386
387        kaivuuHintaLabel = new Label("0");
388        kaivuuHintaLabel.IsVisible = false;
389        kaivuuHintaLabel.TextColor = Color.HotPink;
390        kaivuuHintaLabel.Color = Color.Black;
391        Add(kaivuuHintaLabel);
392
393        Label rahat = new Label();
394        rahat.BindTo(kultuuri);
395        rahat.Position = new Vector(Screen.Right - 200, Screen.Bottom + 50);
396        //rahat.Position = new Vector(Level.Right + Level.Width * 0.2, Level.Bottom + Level.Height * 0.1);
397        rahat.TextColor = Color.White;
398        rahat.IntFormatString = "Käytettävää kulttuuria: {0:D3}";
399        Add(rahat);
400    }
401
402    public void LopetaPeli()
403    {
404        // Tuhotaan melkein kaikki.
405        ClearControls();
406        ClearLights();
407        ClearTimers();
408        GetObjects(o => o is Widget || o is Barbaari).ForEach(o => o.Destroy());
409
410        // Haetaan jäljellä olevat objektit.
411        var objs = GetObjects(o => !o.IsDestroyed);
412        // Piilotetaan ovelasti lisätietoa tagiin.
413        //                                                          kulmanopeus                  nopeus                      kasvu
414        objs.ForEach(o => o.Tag = new Tuple<double, double, double>(RandomGen.NextDouble(5, 60), RandomGen.NextDouble(1, 5), RandomGen.NextDouble(0.05, 0.1)));
415
416        const double dt = 0.02;
417        var ajastin = new Timer();
418        ajastin.Interval = dt;
419        ajastin.Timeout += delegate
420        {
421            foreach (var obj in objs)
422            {
423                var info = (Tuple<double, double, double>)obj.Tag;
424                obj.Angle += Angle.FromDegrees(info.Item1 * dt);
425                obj.Position += obj.Angle.GetVector() * info.Item2 * dt;
426                obj.Size += new Vector(1, 1) * info.Item3;
427
428                obj.Tag = new Tuple<double, double, double>(info.Item1 * 1.01, info.Item2 * 1.1, info.Item3);
429            }
430        };
431        ajastin.Start();
432
433        Timer.SingleShot(3.5, HavioViesti);
434    }
435
436    public void HavioViesti()
437    {
438        ClearAll();
439        Level.Background.Color = Color.Black;
440        var patsas = new GameObject(400, 300);
441        patsas.Image = loppuKuvat[0];
442        patsas.Animation = new Animation(loppuKuvat) { FPS = 20, StopOnLastFrame = true };
443        Add(patsas);
444
445        Timer.SingleShot(3.0, delegate
446        {
447            patsas.Animation.Start(1);
448            hajotusAanet[1].Play();
449        });
450
451        Label havisit = new Label("Hävisit muuten belin");
452        havisit.TextColor = Color.Black;
453        havisit.TextScale *= 3;
454        havisit.Top = Screen.Top - 30.0;
455        Add(havisit, 2);
456
457        const double fadeAika = 5.0;
458        var fadeAjastin = new Timer();
459        fadeAjastin.Interval = 0.02;
460        fadeAjastin.Timeout += delegate
461        {
462            havisit.TextColor = Color.Lerp(Color.Black, Color.White, fadeAjastin.SecondCounter.Value / fadeAika);
463            if (fadeAjastin.SecondCounter.Value > fadeAika)
464            {
465                fadeAjastin.Stop();
466            }
467        };
468        fadeAjastin.Start();
469
470        Keyboard.Listen(Key.Escape, ButtonState.Pressed, delegate { ClearAll(); Begin(); }, null);
471    }
472
473    void Kauppa()
474    {
475        for (int i = 0; i < kultuuriKuvat.Length; i++)
476        {
477            PushButton kuva = new PushButton(kultuuriKuvat[i][0]);
478            kuva.Size = new Vector(1, 1) * RUUDUN_KOKO;
479            kuva.X = Window.ClientBounds.Width / 2 - 200;
480            kuva.Y = Window.ClientBounds.Height / 2 - (100 + RUUDUN_KOKO * i);
481            //kuva.Position = new Vector((Level.Right + Level.Width * 0.05), (Level.Top - Level.Height * 0.25 - (i * RUUDUN_KOKO)));
482            //kuva.Position = new Vector(Window.ClientBounds.Right, 0);
483            Add(kuva);
484
485            int indeksi = i; // Alla oleva delegaatti vaatii uuden indeksi muuttujan toimiakseen.
486            kuva.Clicked += delegate
487            {
488                ostamassa = LuoKultuuriPaivitys(kultuuriKuvat[indeksi], hinnat[indeksi], kultuuriTuotot[indeksi], hajotusAanet[indeksi]);   // TODO: tuotto[indeksi]
489            };
490
491            Add(new Label
492            {
493                Position = kuva.Position + new Vector((RUUDUN_KOKO * 1.2), 0),
494                TextColor = Color.White,
495                Text = hinnat[i].ToString()
496            });
497        }
498
499        for (int i = 0; i < ansaKuvat.Length; i++)
500        {
501            PushButton kuva = new PushButton(ansaKuvat[i]);
502            kuva.Size = new Vector(1, 1) * RUUDUN_KOKO;
503            kuva.Color = Color.Gray;
504            kuva.X = Window.ClientBounds.Width / 2 - 200;
505            kuva.Y = Window.ClientBounds.Height / 2 - (100 + RUUDUN_KOKO * (kultuuriKuvat.Count() + i));
506            //kuva.Position = new Vector((Level.Right + Level.Width * 0.05), (Level.Top - Level.Height * 0.25 - ((kultuuriKuvat.Count() + i) * RUUDUN_KOKO)));
507            Add(kuva);
508
509            int indeksi = i;
510            kuva.Clicked += delegate
511            {
512                ostamassa = LuoAnsaPaivitys(ansaKuvat[indeksi], ansaHinnat[indeksi], ansaAnimaatiot[indeksi], vahingot[indeksi]);
513            };
514
515            Add(new Label
516            {
517                Position = kuva.Position + new Vector((RUUDUN_KOKO * 1.2), 0),
518                TextColor = Color.White,
519                Text = ansaHinnat[i].ToString()
520            });
521        }
522    }
523
524    private void LuoAnsaHuoneenPainike(Image image, int hinta, Animation animation, int paikka, int vahinko)
525    {
526        PushButton kuva = new PushButton(image);
527        kuva.Size = new Vector(1, 1) * RUUDUN_KOKO;
528        kuva.Color = Color.Gray;
529        kuva.X = Window.ClientBounds.Width / 2 - 200;
530        kuva.Y = Window.ClientBounds.Height / 2 - (100 + RUUDUN_KOKO * (kultuuriKuvat.Count() + paikka));
531        //kuva.Position = new Vector((Level.Right + Level.Width * 0.05), (Level.Top - Level.Height * 0.25 - ((kultuuriKuvat.Count() + i) * RUUDUN_KOKO)));
532        Add(kuva);
533
534        kuva.Clicked += delegate
535        {
536            ostamassa = LuoAnsaPaivitys(image, hinta, animation, vahinko);
537        };
538
539        Add(new Label
540        {
541            Position = kuva.Position + new Vector((RUUDUN_KOKO * 1.2), 0),
542            TextColor = Color.White,
543            Text = hinta.ToString()
544        });
545    }
546
547
548
549    Upgrade LuoAnsaPaivitys(Image kuva, int hinta, Animation animaatio, int vahinko)
550    {
551        return new TrapUpgrade
552        {
553            Image = kuva,
554            Size = new Vector(0.5, 0.5) * RUUDUN_KOKO,
555            Price = hinta,
556            Damage = vahinko,
557            Animation = new Animation(animaatio)
558        };
559    }
560
561    Upgrade LuoKultuuriPaivitys(Image[] kuvat, int hinta, int kultuuriMaara, SoundEffect hajotusAani)
562    {
563        var upg = new CultureUpgrade();
564        upg.HajotusAani = hajotusAani;
565        upg.Image = kuvat[0];
566        upg.Size = new Vector(0.7, 0.7)*RUUDUN_KOKO;
567        upg.Price = hinta;
568        upg.Max = kultuuriMaara;
569        upg.Animation = new Animation(kuvat) { FPS = 10 };
570        upg.Animation.Start();
571        return upg;
572    }
573
574    void LuoBarbaareja()
575    {
576        Barbaari barbaari = ((RandomGen.NextInt((int)(kierros * 0.90)) + 3 > kierros) ? new Barbaari(RUUDUN_KOKO * 0.4, RUUDUN_KOKO * 0.4, 1, vihuKuvat) : new Barbaari(RUUDUN_KOKO * 0.4, RUUDUN_KOKO * 0.4, 2, kirvesVihuKuvat));
577        barbaari.Tenacity.LowerLimit += delegate
578        {
579            barbaarit.Remove(barbaari);
580            barbaari.Destroy();
581        };
582        //Barbaari barbaari = new Barbaari(RUUDUN_KOKO * 0.4, RUUDUN_KOKO * 0.4, 0);
583        barbaari.Color = Color.Red;
584        barbaari.Position = spawn.Position;
585        barbaari.Location = spawn.Location;
586        //barbaari.Animation = new Animation(vihuKuvat) { FPS = 10 };
587        barbaari.Animation.Start();
588        Add(barbaari);
589        barbaarit.Add(barbaari);
590
591        EtsiBarbaarinReitti(barbaari);
592    }
593
594    void EtsiBarbaarinReitti(Barbaari barbaari)
595    {
596        var kohteet = KultuuriHuoneidenPaikat();
597        barbaari.Kohde = kohteet[RandomGen.NextInt(kohteet.Count)];
598        barbaari.Reitti = FindPath(barbaari.Kohde, (barbaari.Location.Equals(spawn.Location)) ? spawn.Location : barbaari.Location);
599    }
600
601    public List<Point> KultuuriHuoneidenPaikat()
602    {
603        return RuutujenPaikat().Select(GetRoom).Where(r => r.Upgrade != null && r.Upgrade is CultureUpgrade).Select(r => r.Location).ToList();
604    }
605
606    void Sykli()
607    {
608        // Päivitetään huoneiden päivityksiä.
609        RuutujenPaikat().Select(GetRoom).Where(r => r.Upgrade != null).ToList().ForEach(r => r.Upgrade.SykliPaivitys());
610
611        // Päivitetään barbaareja.
612        foreach (var barbaari in barbaarit)
613        {
614            if (barbaari.Reitti.Count == 0)
615            {
616                EtsiBarbaarinReitti(barbaari);  //Etsitään uusi reitti poiston sijaan.
617                continue;
618            }
619
620            Point seuraavaPaikka = barbaari.Reitti[0];
621            barbaari.Reitti.RemoveAt(0);
622            Barbaari b = barbaari;
623            barbaari.MoveTo(huoneet[seuraavaPaikka.X, seuraavaPaikka.Y].Position, 100, () => SyklinPaatteeksi(b, seuraavaPaikka));
624        }
625
626        // Tarkistetaan onko barbaariaalto jo ohi.
627        if (KierrosKaynnissa % 2 == 0 && barbaarit.Count == 0 && barbaariAjastin.Times == barbaariAjastin.Times.MinValue)
628        {
629            KierrosKaynnissa++;
630
631            // Annetaan pelaajalle kultuuripisteet.
632            foreach (var huone in KultuuriHuoneidenPaikat().Select(GetRoom))
633            {
634                CultureUpgrade upg = huone.Upgrade as CultureUpgrade;
635                if (upg == null)
636                    continue;
637
638                kultuuri.Value += upg.Culture;
639                Label ilmoitus = new Label("+" + upg.Culture);
640                ilmoitus.TextColor = Color.HotPink;
641                ilmoitus.Color = Color.Black;
642                ilmoitus.Position = Camera.WorldToScreen(huone.Position);
643                Add(ilmoitus);
644
645                double kohdeY = ilmoitus.Y + 50;
646                var liikutusAjastin = new Timer();
647                liikutusAjastin.Interval = 0.02;
648                liikutusAjastin.Timeout += delegate
649                {
650                    ilmoitus.Y += (kohdeY - ilmoitus.Y) * 0.05;
651                };
652                liikutusAjastin.Start();
653
654                ilmoitus.LifetimeLeft = TimeSpan.FromSeconds(2.0);
655                ilmoitus.Destroyed += liikutusAjastin.Stop;
656            }
657        }
658    }
659
660    void SyklinPaatteeksi(Barbaari barbaari, Point uusiPaikka)
661    {
662        // Barbaari saapui juuri uusiPaikka kohdassa olevaan huoneeseen.
663        // Tässä pitäisi katsoa mitä huoneessa tapahtuu.
664        barbaari.Location = uusiPaikka;
665
666        Room huone = huoneet[uusiPaikka.X, uusiPaikka.Y];
667
668        if (huone.Upgrade != null)
669        {
670            huone.Upgrade.Invasion(this, barbaari, huone);
671        }
672    }
673
674    void Kontrollit()
675    {
676        IsMouseVisible = true;
677        //Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Näytä valikko");
678        //Keyboard.Listen(Key.F1, ButtonState.Pressed, Begin, null);
679        Keyboard.Listen(Key.Escape, ButtonState.Pressed, delegate { ClearAll(); Begin(); }, "Aloita uudestaan");    //Ei toimi vielä
680
681        Keyboard.Listen(Key.Space, ButtonState.Pressed, SeuraavaAalto, "Anna kivan barbaariaallon tulla");
682    }
683
684    void SeuraavaAalto()
685    {
686        if (KultuuriHuoneidenPaikat().Count == 0 || KierrosKaynnissa % 2 == 0) return;
687
688        barbaariAjastin.Interval = RandomGen.NextInt((int)sykliAjastin.Interval, 3);
689        barbaariAjastin.Start(barbaariMaara);
690        barbaariMaara = RandomGen.NextInt((int)(1 + kierros * 0.20), kierros);
691        KierrosKaynnissa++;
692    }
693
694    void LuoSpawn()
695    {
696        spawn = huoneet[(int)(huoneet.GetLength(0) * 0.5), 0];
697        spawn.Dug = true;
698
699        Direction oviSuunta = Direction.Down;
700        spawn.Walls[oviSuunta].Image = reikaSeinaKuva;
701
702        Light valo = new Light();
703        valo.Position = spawn.Position;
704        valo.Intensity = 1;
705        valo.Distance = 40;
706        Add(valo);
707    }
708
709    void RoomPressed(Room huone)
710    {
711        digStart = huone.Location;
712        Digging = true;
713        digArrowHead.IsVisible = digArrow.IsVisible = true;
714    }
715
716    void RoomReleased(Room kohdeHuone)
717    {
718        Digging = false;
719        digArrowHead.IsVisible = digArrow.IsVisible = false;
720        if (!CanDig()) return;
721
722        int dx = kohdeHuone.Location.X - digStart.X;
723        int dy = kohdeHuone.Location.Y - digStart.Y;
724        Point[] kaivettavatPaikat = RuudutSuoralta(digStart, dx, dy).ToArray();
725        for (int i = 0; i < kaivettavatPaikat.Length - 1; i++)
726        {
727            Dig(GetRoom(kaivettavatPaikat[i]), GetRoom(kaivettavatPaikat[i + 1]));
728        }
729
730        // Päivitetään huoneiden kultuuri-infot.
731        PaivitaHuoneidenKultuurit();
732    }
733
734    void Dig(Room alku, Room kohde)
735    {
736        // Hienot partikkeliefektit.
737        if (!alku.Dug)
738            LuoKiviPartikkelit(alku.Position);
739        if (!kohde.Dug)
740            LuoKiviPartikkelit(kohde.Position);
741
742        // Merkataan huoneet kaivetuksi ja maksetaan siitä kivasti.
743        alku.Dug = kohde.Dug = true;
744        kultuuri.Value -= HUONE_KAIVUU_HINTA;
745
746        // Reiät seinään.
747        Direction oviSuunta = (kohde.Position - alku.Position).Angle.MainDirection;
748        Direction toinenOviSuunta = Direction.Inverse(oviSuunta);
749        alku.Walls[oviSuunta].Image = reikaSeinaKuva;
750        kohde.Walls[toinenOviSuunta].Image = reikaSeinaKuva;
751    }
752
753    Room CreateRoom(Point paikka)
754    {
755        Room huone = new Room(paikka);
756        huone.Image = lattiaKuva;
757        huone.Position = new Vector(paikka.X - huoneet.GetLength(0) / 2, paikka.Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
758        huone.Position += huoneSiirtyma;
759        foreach (var suunta in Suunnat())
760            huone.Walls[suunta] = CreateWall(huone.Position, suunta);
761        Add(huone, -2);
762        huone.Roof = new GameObject(RUUDUN_KOKO, RUUDUN_KOKO);
763        huone.Roof.Image = kiviKuva;
764        huone.Roof.Position = huone.Position;
765        Add(huone.Roof, 1);
766
767        //Mouse.ListenOn(huone, MouseButton.Left, ButtonState.Pressed, AsetaPaivitys, "Asetetaan ostettu päivitys paikoilleen", huone);
768        //Mouse.Listen(MouseButton.Right, ButtonState.Pressed, delegate { ostamassa = null; }, "Perutaan ostos");
769        //Mouse.ListenOn(huone, MouseButton.Right, ButtonState.Pressed, PoistaPaivitys, "Poistetaan asetettu päivitys", huone);
770
771        return huone;
772    }
773
774    private void PoistaPaivitys(Room huone)
775    {
776        if (huone.Upgrade != null)
777        {
778            kultuuri.Value += (int)(huone.Upgrade.Price * 0.5);
779            huone.Upgrade.Destroy();
780            huone.Upgrade = null;
781        }
782    }
783
784    void AsetaPaivitys(Room huone)
785    {
786        if (ostamassa != null && huone.Dug && kultuuri.Value >= ostamassa.Price && huone.Upgrade == null && huone != spawn)
787        {
788            // Kultuuripäivityksistä pitää olla reitti spawniin.
789            if (ostamassa is CultureUpgrade && FindPath(huone.Location, spawn.Location).Count == 0)
790                return;
791
792            kultuuri.Value -= ostamassa.Price;
793
794            // Lisätään päivitys huoneeseen.
795            huone.Upgrade = ostamassa;
796            Add(huone.Upgrade, -1);
797            huone.Upgrade.Position = huone.Position;
798            huone.Upgrade.Built(this);
799
800            ostamassa = null;
801            PaivitaHuoneenKultuuri(huone);
802        }
803    }
804
805    void PaivitaHuoneidenKultuurit()
806    {
807        RuutujenPaikat().Select(GetRoom).ToList().ForEach(PaivitaHuoneenKultuuri); // :D ;___;; MIKSI <- koska pystyn
808    }
809
810    void PaivitaHuoneenKultuuri(Room room)  //TODO: muokkauksia tuohon kultuurinarvonvaihtoon polun pituuden perusteella kunnes peli tuntuu oikeasti miellyttäviltä.
811    {
812        if (room != null && room.Upgrade != null && room.Upgrade is CultureUpgrade)
813        {
814            var upg = room.Upgrade as CultureUpgrade;
815
816            List<Point> polku = FindPath(room.Location, spawn.Location);
817            upg.Culture.Value = Math.Max(0, upg.Culture.MaxValue - (int)(upg.Culture.MaxValue * 0.10 * polku.Count));
818        }
819    }
820
821    GameObject CreateWall(Vector paikka, Direction suunta)
822    {
823        GameObject wall = new GameObject(RUUDUN_KOKO + 2, RUUDUN_KOKO + 2);
824        wall.Position = paikka;
825        wall.Image = seinaKuva;
826        wall.Angle = suunta.Angle;
827        Add(wall, 0);
828        return wall;
829    }
830
831    bool CanDig()
832    {
833        Room kohdeHuone = GetRoom(MuunnaJypelista(Mouse.PositionOnWorld));
834        if (kohdeHuone == null || KierrosKaynnissa % 2 == 0)
835        {
836            return false;
837        }
838
839        int dx = Math.Abs(kohdeHuone.Location.X - digStart.X);
840        int dy = Math.Abs(kohdeHuone.Location.Y - digStart.Y);
841        int hinta = (dx + dy) * HUONE_KAIVUU_HINTA;
842        kaivuuHintaLabel.Text = "" + hinta;
843        return ((dx > 0 && dy == 0) || (dy > 0 && dx == 0)) && kultuuri.Value >= hinta;
844    }
845
846    #region Reitinlöytö
847
848    List<Point> FindPath(Point alku, Point loppu)
849    {
850        if (GetRoom(alku) == null || GetRoom(loppu) == null)
851            return new List<Point>();
852
853        bool[,] walkable = new bool[huoneet.GetLength(0), huoneet.GetLength(1)];
854        foreach (var paikka in RuutujenPaikat())
855        {
856            walkable[paikka.X, paikka.Y] = huoneet[paikka.X, paikka.Y].Dug;
857        }
858        var finder = new AStar.PathFinder(new AStar.SearchParameters(loppu, alku, walkable), OviTarkistus);
859        return finder.FindPath();
860    }
861
862    bool OviTarkistus(Point a, Point b)
863    {
864        Room ra = GetRoom(a);
865        Room rb = GetRoom(b);
866        Direction suunta = (new Vector(b.X, b.Y) - new Vector(a.X, a.Y)).Angle.MainDirection;
867        if (ra != null && rb != null)
868        {
869            return ra.Walls[suunta].Image == reikaSeinaKuva && rb.Walls[Direction.Inverse(suunta)].Image == reikaSeinaKuva;
870        }
871        return false;
872    }
873
874    #endregion
875
876    #region Extra Juttuja
877
878    IEnumerable<Direction> Suunnat()
879    {
880        yield return Direction.Left;
881        yield return Direction.Right;
882        yield return Direction.Up;
883        yield return Direction.Down;
884    }
885
886    IEnumerable<Point> RuutujenPaikat()
887    {
888        return from y in Enumerable.Range(0, huoneet.GetLength(1))
889               from x in Enumerable.Range(0, huoneet.GetLength(0))
890               select new Point(x, y);
891    }
892
893    /// <summary>
894    /// Palauttaa ruutuja suoralta pätkältä dx ja dy verran alkaen pisteestä "alku".
895    /// dx tai dy pitää olla nolla.
896    /// </summary>
897    IEnumerable<Point> RuudutSuoralta(Point alku, int dx, int dy)
898    {
899        if (dx != 0)
900        {
901            for (int i = 0; i < Math.Abs(dx) + 1; i++)
902            {
903                yield return new Point(alku.X + i * Math.Sign(dx), alku.Y);
904            }
905            yield break;
906        }
907        if (dy != 0)
908        {
909            for (int i = 0; i < Math.Abs(dy) + 1; i++)
910            {
911                yield return new Point(alku.X, alku.Y + i * Math.Sign(dy));
912            }
913        }
914    }
915
916    Room GetRoom(Point paikka)
917    {
918        if (paikka.X >= 0 && paikka.X < huoneet.GetLength(0) && paikka.Y >= 0 && paikka.Y < huoneet.GetLength(1))
919        {
920            return huoneet[paikka.X, paikka.Y];
921        }
922        return null;
923    }
924
925    /// <summary>
926    /// Muuntaa Jypeli-koordinaatin peliruudukon koordinaatiksi.
927    /// </summary>
928    Point MuunnaJypelista(Vector paikka)
929    {
930        Vector siirrettyOrigo = (paikka - huoneSiirtyma) + RUUDUN_KOKO * (0.5 * new Vector(huoneet.GetLength(0), huoneet.GetLength(1)) + new Vector(0.5, 0.5));
931        Vector wtf = new Vector(siirrettyOrigo.X < 0 ? -1 : 0, siirrettyOrigo.Y < 0 ? -1 : 0);
932        Vector valmis = wtf + siirrettyOrigo / RUUDUN_KOKO;
933        return new Point((int)valmis.X, (int)valmis.Y);
934    }
935
936    public void LuoLentavaPartikkeli(Vector alkupaikka, Image kuva, double koko, int maara, bool veri = false)
937    {
938        // Feikki 3D partikkeli juttu.
939        // Heittää ilmaan GameObjekteja joiden alla on varjo.
940
941        // VAROITUS: SISÄLTÄÄ JÄRKYTTÄVÄÄ KOODIA
942
943        for (int i = 0; i < maara; i++)
944        {
945            GameObject partikkeli = new GameObject(koko, koko);
946            partikkeli.Image = kuva;
947            partikkeli.Position = alkupaikka + RandomGen.NextVector(0.0, RUUDUN_KOKO * 0.4);
948            Add(partikkeli, 3);
949
950            GameObject varjo = new GameObject(koko, koko / 2.0);
951            varjo.Position = partikkeli.Position;
952            varjo.Shape = Shape.Circle;
953            varjo.Color = Color.Lerp(Color.Black, Color.Transparent, 0.5);
954            Add(varjo, 2);
955
956            Vector paikka = partikkeli.Position;
957            Vector nopeus = RandomGen.NextVector(0.2, 3.0);
958            nopeus.Y *= 0.3;
959            double g = -0.2; // painovoima
960            double z = 0.0; // sijainti z-akselilla
961            double vz = RandomGen.NextDouble(3.5, 4.5); // nopeus z-akselilla
962            double angularVelocity = RandomGen.NextDouble(-1.0, 1.0) * 8;
963
964            var verenLuontiAjastin = veri ? new Timer() : null;
965
966            var ajastin = new Timer();
967            ajastin.Interval = 0.02;
968            ajastin.Timeout += delegate
969            {
970                vz += g;
971                z += vz;
972                paikka += nopeus;
973                partikkeli.Position = paikka + new Vector(0.0, 1.0) * z;
974                partikkeli.Angle += Angle.FromDegrees(angularVelocity);
975                varjo.Position = paikka;
976
977                if (z < 0.0)
978                {
979                    ajastin.Stop();
980                    partikkeli.Destroy();
981                    varjo.Destroy();
982                    if (verenLuontiAjastin != null)
983                        verenLuontiAjastin.Stop();
984                }
985            };
986            ajastin.Start();
987
988            if (verenLuontiAjastin != null)
989            {
990                verenLuontiAjastin.Interval = 0.1;
991                verenLuontiAjastin.Timeout += delegate
992                {
993                    GameObject veriPartikkeli = new GameObject(3, 3);
994                    veriPartikkeli.Color = Color.DarkRed;
995                    Add(veriPartikkeli, 2);
996
997                    Vector veriPaikka = paikka;
998                    double veriZ = z;
999                    double veriVz = 0.0;
1000
1001                    var veriPaivitysAjastin = new Timer();
1002                    veriPaivitysAjastin.Interval = 0.02;
1003                    veriPaivitysAjastin.Timeout += delegate
1004                    {
1005                        veriVz += g;
1006                        veriZ += veriVz;
1007                        veriPartikkeli.Position = veriPaikka + new Vector(0.0, 1.0) * veriZ;
1008
1009                        if (veriZ < 0.0)
1010                        {
1011                            veriPaivitysAjastin.Stop();
1012                            veriPartikkeli.Destroy();
1013                        }
1014                    };
1015                    veriPaivitysAjastin.Start();
1016                };
1017                verenLuontiAjastin.Start();
1018            }
1019        }
1020    }
1021
1022    void LuoKiviPartikkelit(Vector alkupaikka)
1023    {
1024        LuoLentavaPartikkeli(alkupaikka, partikkeliKuva, 25, 6);
1025    }
1026
1027    public void Splatter(Vector alkupaikka)
1028    {
1029        LuoLentavaPartikkeli(alkupaikka, taideVeri, 8, 10, true);
1030    }
1031
1032    protected override void Update(Time time)
1033    {
1034        if (Digging)
1035        {
1036            Color vari = CanDig() ? Color.White : Color.Red;
1037            Vector alku = huoneet[digStart.X, digStart.Y].Position;
1038            Vector loppu = Mouse.PositionOnWorld;
1039            Vector suunta = loppu - alku;
1040            double pituus = suunta.Magnitude;
1041            if (pituus <= 2) pituus = 2;
1042
1043            digArrow.Color = vari;
1044            digArrow.Position = alku + suunta * 0.5;
1045            digArrow.Angle = suunta.Angle;
1046            digArrow.Width = pituus;
1047           
1048            digArrowHead.Color = vari;
1049            digArrowHead.Position = alku + suunta;
1050            digArrowHead.Angle = suunta.Angle - Angle.FromDegrees(90);
1051
1052            kaivuuHintaLabel.Position = Camera.WorldToScreen(alku + suunta * 0.5 + new Vector(0, 30));
1053        }
1054
1055        if (menu != null)
1056            menu.Update(time);
1057        base.Update(time);
1058    }
1059
1060    /*
1061    protected override void Paint(Canvas canvas)
1062    {
1063        canvas.BrushColor = Color.Purple;
1064
1065        var points = FindPath(new Point(6, 0), MuunnaJypelista(Mouse.PositionOnWorld));
1066        for (int i = 0; i < points.Count - 1; i++)
1067        {
1068            Vector v = huoneSiirtyma + new Vector(points[i].X - huoneet.GetLength(0) / 2, points[i].Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
1069            Vector v2 = huoneSiirtyma + new Vector(points[i + 1].X - huoneet.GetLength(0) / 2, points[i + 1].Y - huoneet.GetLength(1) / 2) * RUUDUN_KOKO;
1070            canvas.DrawLine(v, v2);
1071        }
1072
1073        base.Paint(canvas);
1074    }
1075    */
1076
1077    #endregion
1078}
Note: See TracBrowser for help on using the repository browser.