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

Revision 6479, 37.8 KB checked in by empaheik, 4 years ago (diff)

Kultuuria voi kerätä loputtomasti, superbarbaarien todennäköisyys skaalautuu vähän mielekkäämmin. Haaveilen vieläkin, että tekisin tähän toisen kentän joksus, kun on aikaa.

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