source: 2015/26/ohjaajat/HillbillyRun/HillbillyRun/HillbillyRun/HillbillyRun/HillbillyRun.cs @ 6403

Revision 6403, 49.8 KB checked in by sieerinn, 4 years ago (diff)

Loppuvastus on pelattavassa kunnossa nyt.

Line 
1using System;
2using System.Collections.Generic;
3using System.Diagnostics.CodeAnalysis;
4using System.Linq;
5using Jypeli;
6using Jypeli.Assets;
7using Jypeli.Controls;
8using Jypeli.Effects;
9using Jypeli.Widgets;
10
11/* Muistutuksia.
12 *
13 * Layerit
14 *   3 -
15 *   2 -
16 *   1 -
17 *   0 -
18 *  -1 - Näkyvä maanpinta.
19 *  -2 - Talot taustalla.
20 * 
21 * CollisionIgnoreGroupit
22 *  3 - Ryömivät ja liekit. //TODO: lisätä noidatkin tänne
23 *  2 - Kärry.
24 *
25*/
26
27#region Improvement
28public abstract class Improvement : PlatformCharacter
29{
30    public List<Animation> Animations { get; set; }
31
32    protected Improvement(double width, double height)
33        : base(width, height)
34    {
35
36    }
37
38    public HillBilly Owner
39    {
40        get { return owner; }
41        set { owner = value; }
42    }
43    private HillBilly owner;
44
45    public virtual void DoTheThing(HillbillyRun game) { }
46
47    public SoundEffect sound;
48
49    public void Rid()
50    {
51        Owner.AnimWalk = Owner.Animations[0];
52        Owner.AnimIdle = Owner.Animations[1];
53        Owner.Improvement = null;
54        Owner = null;
55    }
56}
57
58public class MilkImprovement : Improvement
59{
60    public override void DoTheThing(HillbillyRun game)
61    {
62        //HillbillyRun game = this.Game as HillbillyRun;
63        Owner.PlayAnimation(Animations[1]);
64        game.CreateMilkParticles(this.Owner, 10, 200, 300, new Vector(0, -30), "milkparticle");
65        this.sound.Play();
66    }
67
68    public MilkImprovement(double width, double height)
69        : base(width, height)
70    {
71
72    }
73}
74
75
76public class PitchForkImprovement : Improvement
77{
78    public override void DoTheThing(HillbillyRun game)
79    {
80        //HillbillyRun game = this.Game as HillbillyRun;
81        //game.CreateMilkParticles(this.Owner, 10, 200, 300, new Vector(0, -30), "milkparticle");
82        //TODO: hitting things w/ pitchfork
83        game.ForkThings(Owner);
84    }
85
86    public PitchForkImprovement(double width, double height)
87        : base(width, height)
88    {
89
90    }
91}
92#endregion
93
94public class HillBilly : PlatformCharacter
95{
96    public List<Animation> Animations { get; set; }
97
98    private IntMeter lifeCounter = new IntMeter(4, 0, 4);
99    public IntMeter Life
100    {
101        set { lifeCounter = value; }
102        get { return lifeCounter; }
103    }
104
105    public Improvement Improvement { get; set; }
106
107    public Label Name { get; set; }
108
109    private ProgressBar visibleLife;
110    public ProgressBar VisibleLife
111    {
112        get { return visibleLife; }
113        set { visibleLife = value; }
114    }
115
116    public void GainImprovement(Improvement improvement)
117    {
118
119        this.AnimWalk = improvement.Animations[0];
120        this.AnimIdle = new Animation(improvement.Animations[0].CurrentFrame);
121        this.Improvement = improvement;
122        improvement.Owner = this;
123
124        //improvement.Destroy();
125    }
126
127    public void UseImprovement()
128    {
129        HillbillyRun game = this.Game as HillbillyRun;
130        if (this.Improvement == null)
131        {
132            game.CreateMilkParticles(this, 5, 100, 100, new Vector(0, Height / 3), "tears");
133        }
134        else if (Animation != this.Improvement.Animations[1])
135        {
136            this.Improvement.DoTheThing(game);
137        }
138    }
139
140    public HillBilly(double leveys, double korkeus, String name)
141        : base(leveys, korkeus)
142    {
143
144        this.visibleLife = new ProgressBar(50, 15); //(this.Width, this.Height/8);
145        this.Add(visibleLife);
146        this.visibleLife.Position += new Vector(0, this.Height / 2 + this.Height / 5);
147        this.visibleLife.BindTo(this.lifeCounter);
148        this.visibleLife.Color = Color.Black;
149
150        this.Name = new Label(name);
151        this.Add(Name);
152        this.Name.Position += new Vector(0, this.Height / 2 + this.Height / 3);
153    }
154}
155
156/// <summary>
157/// An MMO where you go to war with mages in the lava kingdom.
158/// </summary>
159public class HillbillyRun : PhysicsGame
160{
161    private List<HillBilly> players = new List<HillBilly>();
162    private List<HillBilly> startingPlayers = new List<HillBilly>();
163
164    //private List<double> playerPositionsX = new List<double>();
165    //private List<double> playerPositionsY = new List<double>();
166
167    private const double PLAYER_SPEED = 180;
168    public const double TILE_SIZE = 70;
169
170    public String[] names = new String[] { "Adolfiina", "Rasputiina", "Hermanniina", "Joosefiina" };
171
172    private double cameraTargetX; // Sijainti jossa kameran pitäisi olla.
173    private Vector cameraTarget;
174
175    private double cameraOffset; //= 400; // TODO: Tämän voisi ehkä laskea jostain (esim. ikkunan leveydestä kolmasosa tai jotain).
176    private double cameraSpeed = 2.0; // Kameran liikkumisnopeus.
177
178    # region Images
179    private Image[] groundImages = LoadImages("ground", "ground_forest", "ground_volcano");
180    private Image[] groundTopImages = LoadImages("ground_top", "ground_top_forest", "ground_top_volcano");
181    private Image[] foregroundDecorations = LoadImages("viljaa", "grass", "grass");
182    private Image[] blockImages = LoadImages("box2", "rock");
183
184    private Image[] houseImages = LoadImages("house", "houseburned");
185
186    private Image cartImage = LoadImage("cart");
187    private Image milkImage = LoadImage("tonkkaitem");
188    private Image pitchforkImage = LoadImage("fork");
189
190    private Image cartWheelImage = LoadImage("cartwheel");
191
192    private Image smokeImage1 = LoadImage("smoke1");
193    private Image smokeImage2 = LoadImage("smoke2");
194
195    private Image treeTrunkImage = LoadImage("bigtree");
196    private Image treeBottomImage = LoadImage("bigtree3x2");
197    private Image treeBranchImage = LoadImage("bigtreebranch");
198    private Image forestBackgroundImage = LoadImage("forestbackground");
199    private Image volcanoBackgroundImage = LoadImage("volcanobackground");
200    private Image swingTrapImage = LoadImage("tukki");
201
202    private Image gateImage = LoadImage("gate");
203    private Image leverLeftImage = LoadImage("lever_left");
204    private Image leverRightImage = LoadImage("lever_right");
205
206    private Image lavaWallImage = LoadImage("lavawall");
207    private Image spikeImage = LoadImage("spikes");
208    private Image spikeLeftImage = LoadImage("spikeleft");
209
210    private Image prisonerImage = LoadImage("prisoner");
211
212    private Animation crawl;
213    private Animation blaze;
214
215    private Animation pitchforkAttack;
216    private Animation pitchforkWalk;
217    private Animation milkThrow;
218    private Animation milkWalk;
219    private Animation normalWalk;
220    private Animation playerIdle;
221    private Animation playerJump;
222    private Animation playerFall;
223    private Animation firemageAnimation;
224    private Animation firemageCastAnimation;
225    private Animation wormAnimation;
226    private Animation tattiMageAnimation;
227    private Animation tattiMageCastAnimation;
228
229    private Animation bossRiseAnimation;
230    private Animation bossFallAnimation;
231    private Animation bossHitAnimation;
232    #endregion
233
234    #region Sounds
235    private SoundEffect splash = LoadSoundEffect("splash");
236    #endregion
237
238    private double leftCamLimit;
239    private double rightCamLimit;
240    private double bottomCamLimit;
241
242    private int levelNumber = 2;
243
244    private Action activateBoss;
245
246    public override void Begin()
247    {
248        Initializing();
249        IntroSequence();
250        //MainMenu();
251        //StartGame();
252    }
253
254    #region Intro
255    void IntroSequence()
256    {
257        Level.Background.Color = Color.Black;
258
259        Keyboard.Listen(Key.Escape, ButtonState.Pressed, SkipIntro, "Skip");
260
261        ShowMadeWithJypeli();
262
263        Timer.SingleShot(4.0, delegate // TODO get rid of fixed amount of seconds
264        {
265            ShowBackgroundStory();
266        });
267
268
269
270    }
271
272    void ShowMadeWithJypeli()
273    {
274        Image madewithImage = LoadImage("madewithjypeli");
275
276        double w = Window.Width / 4;
277        double h = w * (madewithImage.Height / (double)madewithImage.Width); // take aspect ratio from the picture
278
279        GameObject madewithjypeliObject = new GameObject(w, h);
280        madewithjypeliObject.Image = madewithImage;
281        Add(madewithjypeliObject);
282
283        // Tässä oli jotain epätehokasta feidailua tuolle Made with Jypeli -kuvalle. Ei tunnu päivittyvän joka framella tai on muuten vain tosi raskas...
284
285        //fadeTimer = new Timer();
286        //fadeTimer.Interval = 0.5;
287        //fadeTimer.Timeout += delegate
288        //{
289        //    madewithjypeliObject.Image = LerpImage(madewithjypeliObject.Image, Color.Black, 0.6);
290        //};
291        //fadeTimer.Start(5);
292
293        Timer.SingleShot(1.2, delegate
294        {
295            madewithjypeliObject.Destroy();
296        });
297
298    }
299
300    Image LerpImage(Image original, Color targetColor, double ratio)
301    {
302        Image newImage = new Image(original.Width, original.Height, Color.Transparent);
303        for (int y = 0; y < original.Height; y++)
304        {
305            for (int x = 0; x < original.Width; x++)
306            {
307                newImage[y, x] = Color.Lerp(original[y, x], targetColor, ratio);
308            }
309        }
310        return newImage;
311    }
312
313    void ShowBackgroundStory()
314    {
315        ShowStoryText(new Queue<string>(new[] { "Innit just da warmest here, sis?", "Seems to me our establishment's a-burnin'.", "...Must've been 'em nasty witches." }));
316    }
317
318    void ShowStoryText(Queue<string> messages)
319    {
320        // Mennään alkuvalikkoon jos ei ole enää viestejä.
321        if (messages.Count == 0)
322        {
323            MainMenu();
324            return;
325        }
326
327        // Näytetään nykyinen viesti.
328        var storyLabel = new Label(messages.Dequeue()) { TextColor = Color.Black, TextScale = new Vector(3, 3) };
329        Add(storyLabel);
330
331        var textTimer = new Timer { Interval = 0.05 };
332        textTimer.Timeout += () => storyLabel.TextColor = Color.Lerp(storyLabel.TextColor, Color.White, 0.05);
333        textTimer.Start();
334
335        // Näytetään seuraava viesti muutaman sekunnin päästä.
336        Timer.SingleShot(4, delegate { storyLabel.Destroy(); ShowStoryText(messages); });
337    }
338
339    void SkipIntro()
340    {
341        ClearTimers();
342        ClearAll();
343        Keyboard.Clear();
344        MainMenu();
345    }
346
347    void MainMenu()
348    {
349        Level.Background.Color = Color.DarkBlue;
350
351        MultiSelectWindow mainmenu = new MultiSelectWindow("Main menu",
352"Start game", "Credits", "Exit");
353        mainmenu.AddItemHandler(0, StartGame);
354        mainmenu.AddItemHandler(1, ShowCredits);
355        mainmenu.AddItemHandler(2, Exit);
356        mainmenu.DefaultCancel = 2;
357        Add(mainmenu);
358    }
359
360    void ShowCredits()
361    {
362        MessageWindow win = new MessageWindow("This game was made in one week by\nSimo Rinne,\nEmma Heikura,\n and Jouni Potila\n using University of Jyväskylä's\n game programming library Jypeli");
363        win.Closed += delegate
364        {
365            ClearAll();
366            MainMenu();
367        };
368        Add(win);
369    }
370    #endregion
371
372    void StartGame()
373    {
374        ClearAll();
375        CreateLevel();
376        ScreenSettings();
377        SetControls();
378    }
379
380    public void NextLevel()
381    {
382        levelNumber++;
383        StartGame();
384    }
385
386    void Initializing()
387    {
388        crawl = LoadAnimation("crawl");
389        blaze = LoadAnimation("flame");
390        pitchforkAttack = LoadAnimation("attack");
391        pitchforkWalk = LoadAnimation("hanko");
392        milkThrow = LoadAnimation("heitto");
393        milkWalk = LoadAnimation("tonkka");
394        normalWalk = LoadAnimation("pwalk");
395        playerIdle = LoadAnimation("idle");
396        playerJump = LoadAnimation("jump");
397        playerFall = LoadAnimation("fall");
398        firemageAnimation = LoadAnimation("firemage");
399        firemageCastAnimation = LoadAnimation("firemagecast");
400        wormAnimation = LoadAnimation("worm");
401        tattiMageAnimation = LoadAnimation("tattimage");
402        tattiMageCastAnimation = LoadAnimation("tattimagecast");
403        bossRiseAnimation = LoadAnimation("bossrise");
404        bossFallAnimation = LoadAnimation("bossfall");
405        bossHitAnimation = LoadAnimation("bosshit");
406
407        cameraOffset = Window.Width / 4;
408    }
409
410    void ScreenSettings()
411    {
412        Window.Width = 1800;
413        Window.Height = 900;
414
415        leftCamLimit = Level.Left + Window.Width / 2.0;
416        rightCamLimit = Level.Right - Window.Width / 2.0;
417        bottomCamLimit = Level.Bottom + Window.Height / 2.0;
418
419        Camera.X = cameraTargetX = leftCamLimit;
420
421        Timer cameraTimer = new Timer();
422        cameraTimer.Interval = 1 / 30.0;
423        cameraTimer.Timeout += UpdateCamera;
424        cameraTimer.Start();
425
426        // Background trees.
427        if (levelNumber < 2)
428        {
429            GameObject forestBackground = new GameObject(Level.Width, Level.Height);
430            forestBackground.Image = forestBackgroundImage;
431            forestBackground.TextureWrapSize = new Vector(5, 1);
432            Add(forestBackground, -3);
433            Layers[-3].RelativeTransition = new Vector(0.5, 1.0);
434        }
435
436        // Background color.
437        if (levelNumber == 0)
438        {
439            Level.Background.CreateGradient(Color.Black, Color.SkyBlue);
440        }
441        else if (levelNumber == 1)
442        {
443            Level.Background.CreateGradient(Color.Black, Color.FromHexCode("495147"));
444        }
445        else if (levelNumber == 2)
446        {
447            Level.Background.Image = volcanoBackgroundImage;
448            Level.Background.FitToLevel();
449        }
450    }
451
452    #region LevelCreation
453    void CreateLevel()
454    {
455        startingPlayers.Clear();
456        players.Clear();
457        Gravity = new Vector(0, -1000);
458
459        //Tilemap
460        //ColorTileMap level = ColorTileMap.FromLevelAsset("level" + levelNumber);
461        ColorTileMap level = ColorTileMap.FromLevelAsset("bosstest");
462        level.SetTileMethod(Color.Black, CreateGroundTop);
463        level.SetTileMethod(Color.Brown, CreateGround);
464
465        level.SetTileMethod(Color.Cyan, CreateHouse);
466        level.SetTileMethod(Color.PaintDotNetBlue, CreateBurnedHouse);
467
468        level.SetTileMethod(Color.Gold, CreatePlayer);
469        level.SetTileMethod(Color.Harlequin, CreateCart);
470        level.SetTileMethod(Color.FromHexCode("A17FFF"), CreatePitchfork);
471
472        level.SetTileMethod(Color.Gray, (new AbstractTileMap<Color>.TileMethod[] { CreateCrawly, CreateWorm, null })[levelNumber]); // ಠ_ಠ
473        level.SetTileMethod(Color.Red, (new AbstractTileMap<Color>.TileMethod[] { CreateFireMage, CreateShroom, CreateBoss })[levelNumber]);
474        level.SetTileMethod(Color.White, CreateBlockObject);
475        level.SetTileMethod(Color.DarkGray, CreateMilk);
476        level.SetTileMethod(Color.Rose, CreateFlame, true);
477        //level.SetTileMethod(Color.Azure, CreateDummy, Color.Azure);   //TODO: CreateSmoke
478        //level.SetTileMethod(Color.Orange, CreateDummy, Color.Orange); //TODO: CreateTombstone
479
480        level.SetTileMethod(Color.FromHexCode("FF6A00"), CreateTreeTrunk);  //Pihhh jostain heksoista. Ikävästi haisee luovuttamiselta! :----D
481        level.SetTileMethod(Color.FromHexCode("57007F"), CreateTreeRoot);   // Heksojen käytössä ei ole mitään hävettävää :P
482        level.SetTileMethod(Color.FromHexCode("00FF21"), CreateTreeBranch);
483        level.SetTileMethod(Color.FromHexCode("5B7F00"), CreateSwingTrap);
484
485        level.SetTileMethod(Color.FromHexCode("7FBA00"), CreateGate);
486        level.SetTileMethod(Color.FromHexCode("4C7F00"), CreateLevel);
487
488        level.SetTileMethod(Color.FromHexCode("FF00DC"), CreateSpike, spikeImage);
489        level.SetTileMethod(Color.FromHexCode("C600AC"), CreateSpike, spikeLeftImage);
490
491        level.SetTileMethod(Color.FromHexCode("BADA55"), CreatePrisoner); // Lempivärini.
492
493        level.Optimize(Color.Brown);    //Color.Black   //Tekee jännittäviä asioita wheatille, jos optimoidaan (tietysti). Jotenn.
494        level.Execute(TILE_SIZE, TILE_SIZE);
495
496        // Kolmanteen kenttään laavaseinä.
497        if (levelNumber == 2)
498        {
499            GameObject lava = new GameObject(300, Level.Height);
500            lava.Image = lavaWallImage;
501            lava.X = Camera.ScreenToWorld(new Vector(-Window.Width / 2.0, 0)).X;
502            Add(lava, 3);
503
504            PhysicsObject lavaCollision = PhysicsObject.CreateStaticObject(50, Level.Height);
505            lavaCollision.IsVisible = false;
506            lavaCollision.Left = lava.Left;
507            lavaCollision.Tag = "lava";
508            Add(lavaCollision);
509
510            var updateTimer = new Timer { Interval = 0.01 };
511            updateTimer.Timeout += delegate
512            {
513                lava.Left = Camera.X - Window.Width / 2.0;
514                lavaCollision.Left = lava.Left;
515            };
516            updateTimer.Start();
517        }
518    }
519
520    void CreateBoss(Vector position, double width, double height)
521    {
522        GameObject boss = new GameObject(700, 522);
523        boss.Position = position;
524        boss.Top = position.Y - height * 0.5;
525        boss.Animation = bossRiseAnimation;
526        Add(boss, -3);
527
528        List<PhysicsObject> eyes = null; // Lista jotta voi käyttää kätevästi ForEach:ia.
529        var health = new IntMeter(6, 0, 6); // Vähenee vain heinähangolla.
530        var eyeHealth = new IntMeter(30, 0, 30); // Vähenee maidon loiskutuksella.
531
532        eyeHealth.LowerLimit += delegate
533        {
534            // Bossi kaatuaa maahan.
535            eyes.ForEach(e => e.IsVisible = false);
536            boss.Animation = bossFallAnimation;
537            boss.Animation.StopOnLastFrame = true;
538            boss.Animation.Start(1);
539
540            // Bossi palautuu takaisin lyöntianimaatioonsa hetken päästä.
541            Timer.SingleShot(5.0, delegate
542            {
543                boss.Animation = bossHitAnimation;
544                eyeHealth.Value = eyeHealth.MaxValue;
545                eyes.ForEach(e => e.IsVisible = true);
546            });
547        };
548
549        // Alue johon pitää lyödä heinähangolla.
550        var headCollision = PhysicsObject.CreateStaticObject(50, 50);
551        headCollision.IsVisible = false;
552        headCollision.IgnoresCollisionResponse = true;
553        Add(headCollision);
554        AddCollisionHandler(headCollision, "pitchfork", delegate(PhysicsObject h, PhysicsObject fork)
555        {
556            if (boss.Animation == bossFallAnimation)
557            {
558                health.Value--;
559            }
560        });
561        var headMoveTimer = new Timer { Interval = 0.01 };
562        headMoveTimer.Timeout += delegate
563        {
564            headCollision.Position = boss.Position + new Vector(-10, 0);
565        };
566        headMoveTimer.Start();
567        headCollision.Destroyed += headMoveTimer.Stop;
568
569        // Lyöntianimaation päätteeksi lisätään kiviä.
570        bossHitAnimation.Played += delegate
571        {
572            var rock = new PhysicsObject(30, 30);
573            rock.Position = boss.Position + new Vector(RandomGen.NextDouble(-300, 100), 300);
574            rock.LifetimeLeft = TimeSpan.FromSeconds(2.0);
575            Add(rock);
576        };
577
578        // Silmien luonti funktio.
579        Func<int, int, PhysicsObject> eyeFlame = (x, y) =>
580        {
581            var flame = PhysicsObject.CreateStaticObject(width * 0.3, height * 0.6);
582            flame.Animation = new Animation(blaze);
583            flame.IgnoresCollisionResponse = true;
584            flame.IsVisible = false;
585            flame.Animation.Start();
586            Add(flame);
587            AddCollisionHandler(flame, "milkparticle", delegate(PhysicsObject f, PhysicsObject particle)
588            {
589                // Otetaan vahinkoa vain kun ollaan näkyvillä.
590                if (flame.IsVisible)
591                {
592                    particle.Destroy();
593                    eyeHealth.Value--;
594                }
595            });
596            var moveTimer = new Timer { Interval = 0.01 };
597            moveTimer.Timeout += delegate
598            {
599                flame.Position = boss.Position + new Vector(x, y);
600            };
601            moveTimer.Start();
602            flame.Destroyed += moveTimer.Stop;
603            return flame;
604        };
605
606        eyes = new List<PhysicsObject>(new[] { eyeFlame(0, 150), eyeFlame(40, 145) });
607
608        // Tuhotaan bossi kun se kuolee.
609        health.LowerLimit += delegate
610        {
611            eyes.ForEach(e => e.Destroy());
612            boss.Destroy();
613            headCollision.Destroy();
614            Timer.SingleShot(4.0, Victory);
615        };
616
617        // Kutsutaan kun pelaajat saapuu kentän päähän.
618        activateBoss = delegate
619        {
620            // Nostetaan bossi ylös maasta.
621            boss.MoveTo(position + new Vector(0, boss.Height * 0.4), 500);
622            boss.Animation.Start(1);
623            boss.Animation.StopOnLastFrame = true;
624            boss.Animation.Played += delegate
625            {
626                // Taistelu alkaa.
627                eyes.ForEach(e => e.IsVisible = true);
628
629                // Laitetaan lyöntianimaatio päälle.
630                boss.Animation = bossHitAnimation;
631                boss.Animation.Start();
632            };
633        };
634    }
635
636    void CreatePrisoner(Vector position, double width, double height)
637    {
638        GameObject prisoner = new GameObject(width * 1.2, height * 2);
639        prisoner.Position = position;
640        prisoner.Y -= height / 2.0;
641        prisoner.Image = prisonerImage;
642        Add(prisoner, 1);
643    }
644
645    void CreateSpike(Vector position, double width, double height, Image img)
646    {
647        PhysicsObject spike = PhysicsObject.CreateStaticObject(width, height);
648        spike.Image = img;
649        spike.Position = position;
650        //spike.Tag = "burn";
651        Add(spike);
652    }
653
654    void CreateGate(Vector position, double width, double height)
655    {
656        PhysicsObject gate = PhysicsObject.CreateStaticObject(width, height);
657        gate.Image = gateImage;
658        gate.Color = Color.HotPink;
659        gate.Position = position;
660        gate.Y -= height / 2.0;
661        gate.Tag = "gate";
662        Add(gate);
663    }
664
665    void CreateLevel(Vector position, double width, double height)
666    {
667        PhysicsObject lever = PhysicsObject.CreateStaticObject(width * 0.5, height);
668        lever.Image = leverLeftImage;
669        lever.Color = Color.Green;
670        lever.Position = position;
671        lever.Y -= height / 2.0;
672        lever.IgnoresCollisionResponse = true;
673        Add(lever);
674
675        AddCollisionHandler(lever, "player", delegate(PhysicsObject p, PhysicsObject l)
676        {
677            if (lever.Image == leverLeftImage)
678            {
679                lever.Image = leverRightImage;
680                GetObjectsWithTag("gate").ForEach(g => g.Destroy());
681            }
682        });
683    }
684
685    void CreateSwingTrap(Vector position, double width, double height)
686    {
687        const double swingArc = 30; // Heiluu 30 astetta edestakaisin.
688        const double swingSpeed = 1.5;
689        const double ropeLength = 400;
690        var center = position + new Vector(0, ropeLength);
691
692        // Ajastukset heilutteluun.
693        double deltaTime = 1 / 60.0;
694        double time = 0.0;
695
696        PhysicsObject swing = PhysicsObject.CreateStaticObject(width, height);
697        swing.Image = swingTrapImage;
698        swing.Position = position;
699        Add(swing);
700
701        GameObject rope = new GameObject(ropeLength, 10);
702        rope.Color = new Color(10, 30, 10);
703        Add(rope);
704
705        var updateTimer = new Timer { Interval = deltaTime };
706        updateTimer.Timeout += delegate
707        {
708            time += deltaTime;
709
710            // Heilurin kulma on sinimuotoinen funktio ajan suhteen.
711            var angle = Angle.FromDegrees(-90.0 + Math.Sin(time * swingSpeed) * swingArc);
712            swing.Position = center + angle.GetVector() * ropeLength;
713            swing.Angle = angle;
714
715            // Päivitetään narun sijainti ja kulma.
716            rope.Angle = angle;
717            rope.Position = center + angle.GetVector() * ropeLength * 0.5;
718        };
719        updateTimer.Start();
720    }
721
722    void CreatePitchfork(Vector position, double width, double height)
723    {
724        double size = 30;
725        double ratio = pitchforkImage.Width / pitchforkImage.Height;
726
727        Improvement fork = new PitchForkImprovement(size * ratio, size);
728        fork.Image = pitchforkImage;
729        fork.Animations = new List<Animation> { pitchforkWalk, pitchforkAttack };
730        fork.Position = position;
731        fork.Tag = "improvement";
732        Add(fork);
733
734    }
735
736    void CreateTreeBranch(Vector position, double width, double height)
737    {
738        PhysicsObject branch = PhysicsObject.CreateStaticObject(width, height);
739        branch.Position = position;
740        branch.Image = treeBranchImage;
741        Add(branch, -1);
742    }
743
744    void CreateTreeTrunk(Vector position, double width, double height)
745    {
746        GameObject trunk = new GameObject(width * 3, height);
747        trunk.Position = position;
748        trunk.Image = treeTrunkImage;
749        Add(trunk, -1);
750    }
751
752    void CreateTreeRoot(Vector position, double width, double height)
753    {
754        GameObject roots = new GameObject(width * 9, height * 4);
755        roots.Position = position;
756        roots.Y -= height;
757        roots.Image = treeBottomImage;
758        Add(roots, -1);
759    }
760
761    void CreateFlame(Vector position, double width, double height, bool suuri)
762    {
763        PhysicsObject flame = new PhysicsObject(width, height * 2);
764        //flame.Image = flameImage;
765        flame.Color = Color.Red;
766        double hieman = height * 0.3;
767        flame.Position = position - new Vector(0, hieman);
768        flame.CollisionIgnoreGroup = 3;
769        flame.Tag = "burn";
770        flame.Animation = new Animation(blaze) { FPS = RandomGen.NextInt(20, 26) };
771        flame.Animation.Step(RandomGen.NextInt(0, 12));
772        flame.Animation.Resume();
773        flame.CanRotate = false;
774        Add(flame, 1);
775
776        Smoke savu = new Smoke();
777        if (suuri)
778        {
779            flame.IgnoresCollisionResponse = true;
780
781            savu.ParticleImage = smokeImage1;
782            savu.OuterParticleImage = smokeImage2;
783            savu.MaxLifetime = 1.0;
784            savu.MaxScale = 200;
785            savu.MinScale = 10;
786            savu.Position = flame.Position;
787            Wind = new Vector(-10, 0);
788            Add(savu);
789            flame.MakeStatic();
790        }
791
792        AddCollisionHandler(flame, "milkparticle", delegate(PhysicsObject c, PhysicsObject particle)
793        {
794            particle.Destroy();
795            flame.Destroy();
796            savu.Destroy();
797
798        });
799    }
800
801    void CreateBlockObject(Vector position, double width, double height)
802    {
803        // Säädin vähän tätä jotta laatikko näkyy hyvin. Pitää ehkä tehdä laatikolle ihan oma metodi.
804        PhysicsObject block = PhysicsObject.CreateStaticObject(width, height);
805        block.IsVisible = false;
806        //block.Image = blockImages[levelNumber];
807        block.Position = position;
808        block.Y -= height / 2.0;
809        Add(block, 1);
810
811        GameObject visibleBlock = new GameObject(width, height * 1.5);
812        visibleBlock.Position = position;
813        visibleBlock.Image = blockImages[levelNumber];
814        visibleBlock.Y -= height / 2.0;
815        Add(visibleBlock, -1);
816    }
817
818    void CreateMilk(Vector position, double width, double height)
819    {
820        double size = 30;
821        double ratio = milkImage.Height / milkImage.Width;
822
823        Improvement milk = new MilkImprovement(size, size * ratio);
824        milk.Image = milkImage;
825        milk.Animations = new List<Animation> { milkWalk, milkThrow };
826        milk.Position = position;
827        //milk.Tag = "milk";
828        milk.Tag = "improvement";
829        milk.sound = splash;
830        Add(milk);
831
832        //PhysicsObject milk = new PhysicsObject(size, size * ratio);
833        //milk.Image = milkImage;
834        //milk.Position = position;
835        //milk.Tag = "milk";
836        //Add(milk);
837    }
838
839    void CreateWorm(Vector position, double width, double height)
840    {
841        PlatformCharacter worm = new PlatformCharacter(width, height * 0.6);
842        worm.Position = position;
843        worm.Animation = new Animation(wormAnimation);
844        worm.Animation.FPS = RandomGen.NextInt(18, 24);
845        worm.Animation.Step(RandomGen.NextInt(0, 16));
846        worm.Animation.Resume();
847        worm.Tag = "worm";
848        worm.CollisionIgnoreGroup = 3;
849        Add(worm, 1);
850
851        PlatformWandererBrain brain = new PlatformWandererBrain();
852        brain.Speed = 60;
853        brain.FallsOffPlatforms = false;
854        brain.TriesToJump = true;
855        worm.Brain = brain;
856
857        AddCollisionHandler(worm, "pitchfork", delegate(PhysicsObject w, PhysicsObject p) { w.Destroy(); });
858    }
859
860    void CreateCrawly(Vector position, double width, double height)
861    {
862        PlatformCharacter crawly = new PlatformCharacter(width * 2, height * 0.6);
863        crawly.Position = position;
864        crawly.Color = Color.Gray;
865        crawly.Animation = new Animation(crawl);
866        crawly.Animation.FPS = RandomGen.NextInt(18, 24);
867        crawly.Animation.Step(RandomGen.NextInt(0, 16));
868        crawly.Animation.Resume();
869        crawly.Tag = "burn";
870        crawly.CollisionIgnoreGroup = 3;
871        Add(crawly, 1);
872
873        GameObject flame = new GameObject(width * 1.4, height * 2);
874        flame.Animation = new Animation(blaze) { FPS = RandomGen.NextInt(20, 26) };
875        flame.Animation.Step(RandomGen.NextInt(0, 12));
876        flame.Animation.Resume();
877        Add(flame);
878
879        // Pakko liikutella näin koska lapsioliona liekki näkyisi ryömijän päällä.
880        Timer flameMover = new Timer { Interval = 0.05 };
881        flameMover.Timeout += delegate
882        {
883            double hieman = height * 0.75;
884            flame.Position = crawly.Position + new Vector(0, hieman);
885        };
886        flameMover.Start();
887
888        PlatformWandererBrain brain = new PlatformWandererBrain();
889        brain.Speed = 20;
890        brain.FallsOffPlatforms = true;
891
892        crawly.Brain = brain;
893
894        // Sammuu törmätessään maitoon.
895        AddCollisionHandler(crawly, "milkparticle", delegate(PhysicsObject c, PhysicsObject particle)
896        {
897            particle.Destroy();
898            crawly.Brain = null;
899            crawly.Animation = new Animation(crawly.Animation.CurrentFrame);
900            crawly.Tag = "";
901            flame.Destroy();
902            RemoveCollisionHandlers(crawly);
903        });
904    }
905
906    void CreateShroom(Vector position, double width, double height)
907    {
908        PlatformCharacter shroom = new PlatformCharacter(width, height * 2);
909        shroom.Position = position + new Vector(0, shroom.Height / 2);
910        shroom.Tag = "burn";
911        shroom.Tag += "shroom";
912        //shroom.AnimWalk = new Animation();
913        shroom.CollisionIgnoreGroup = 3;
914        Add(shroom, 1);
915        //bool immune = false;
916
917        PlatformWandererBrain brain = new PlatformWandererBrain();
918        brain.Speed = 20;
919        brain.FallsOffPlatforms = false;
920        shroom.Brain = brain;
921
922        FollowerBrain attackBrain = new FollowerBrain("player");
923        attackBrain.DistanceFar = Window.Width / 2.5;
924        attackBrain.DistanceClose = Window.Width / 2;
925        attackBrain.StopWhenTargetClose = false;
926        attackBrain.Speed = brain.Speed * 6;
927        attackBrain.FarBrain = brain;
928        shroom.Brain = attackBrain;
929
930        int matoja = RandomGen.NextInt(1, 3);
931        int rahkeet = 10;
932
933        //// Taiotaan matoja
934        var castTimer = new Timer { Interval = 6.0 };
935        castTimer.Timeout += delegate
936        {
937            //shroom.PlayAnimation();
938
939            Timer.SingleShot(RandomGen.NextDouble(3, 5), delegate { shroom.Brain = attackBrain; });
940
941            Timer.SingleShot(1.5,
942                delegate
943                {
944                    for (int i = 0; i < matoja; i++)
945                    {
946                        CreateWorm(shroom.Position + RandomGen.NextVector(-200, 0, 200, 0), TILE_SIZE, TILE_SIZE);
947                        shroom.Brain = brain;
948                    }
949                });
950
951
952        };
953
954        attackBrain.TargetClose += delegate()
955        {
956            if (!castTimer.Enabled)
957            {
958                castTimer.Start();
959            }
960        };
961
962        AddCollisionHandler(shroom, "pitchfork", delegate(PhysicsObject s, PhysicsObject f)
963        {
964            matoja += RandomGen.NextInt(1, 5);
965            rahkeet--;
966            if (rahkeet < 1)
967            {
968                shroom.Destroy();
969                castTimer.Stop();
970                //Timer.SingleShot(6, NextLevel);
971            }
972        });
973    }
974
975    void CreateFireMage(Vector position, double width, double height)
976    {
977        PlatformCharacter mage = new PlatformCharacter(width * 3, height * 4);
978        mage.Position = position;
979        mage.Y += mage.Height / 2.0;
980        mage.Tag = "burn";
981        mage.Tag += "fireMage";
982        mage.AnimWalk = new Animation(firemageAnimation);
983        mage.CollisionIgnoreGroup = 3;
984        Add(mage, 1);
985        bool immune = false;
986
987        // Pään päällä oleva liekki (taitaa olla vähän huonossa kohtaa tällä hetkellä)
988        PhysicsObject flame = new PhysicsObject(width * 1.4, height * 2);
989        flame.Y += mage.Height * 0.65;
990        flame.X += mage.FacingDirection.GetVector().X + 30;
991        flame.Animation = new Animation(blaze);
992        flame.IgnoresPhysicsLogics = true;
993        flame.Animation.Start();
994        mage.Add(flame);
995
996        PlatformWandererBrain brain = new PlatformWandererBrain();
997        brain.Speed = 20;
998        brain.FallsOffPlatforms = false;
999        //mage.Brain = brain;
1000
1001        //PhysicsObject trigger = PhysicsObject.CreateStaticObject(10, Level.Height); //A truly cool and efficient way to make the boogeyman react only to our closeness
1002        //trigger.Position = mage.Position - new Vector(Window.Width / 2, 0);
1003        ////trigger.Color = Color.Red;
1004        //trigger.IsVisible = false;
1005        //trigger.IgnoresCollisionResponse = true;
1006        //Add(trigger);
1007
1008        FollowerBrain attackBrain = new FollowerBrain("player");
1009        attackBrain.DistanceFar = Window.Width / 2.5;
1010        attackBrain.DistanceClose = Window.Width / 2;
1011        attackBrain.StopWhenTargetClose = false;
1012        attackBrain.Speed = brain.Speed * 6;
1013        attackBrain.FarBrain = brain;
1014        mage.Brain = attackBrain;
1015
1016        // Taiotaan tulta välillä.
1017        var castTimer = new Timer { Interval = 10.0 };
1018        castTimer.Timeout += delegate
1019        {
1020            // TODO: Kävelyanimaatio pysähtyy jostain syystä tämän animaation jälkeen.
1021            mage.PlayAnimation(firemageCastAnimation);
1022
1023            Timer.SingleShot(RandomGen.NextDouble(5, 8), delegate { mage.Brain = attackBrain; });
1024
1025            Timer.SingleShot(1.5,
1026                delegate
1027                {
1028                    for (int i = 0; i < 6; i++)
1029                    {
1030                        CreateFlame(new Vector(attackBrain.CurrentTarget.X + RandomGen.NextDouble(-300, 300), mage.Y + mage.Height * 1.5), 30, 60, false);
1031                        mage.Brain = brain;
1032                    }
1033                });
1034
1035        };
1036
1037        attackBrain.DistanceToTarget.AddTrigger(Window.Width / 2, TriggerDirection.Down, delegate()
1038        {
1039            castTimer.Start();
1040            attackBrain.DistanceToTarget.RemoveTriggers(Window.Width / 2);
1041        });
1042
1043        //castTimer.Start();
1044
1045        AddCollisionHandler(mage, "milkparticle", delegate(PhysicsObject fireMage, PhysicsObject milk)
1046        {
1047            if (milk.Y > fireMage.Y + fireMage.Height * 0.15 && !immune)
1048            {
1049                flame.Size *= 0.95;
1050                immune = true;
1051                if (flame.Height < height)
1052                {
1053                    castTimer.Stop();
1054                    CreatePitchfork(mage.Position, TILE_SIZE, TILE_SIZE);
1055                    mage.Destroy();
1056                    Timer.SingleShot(6, NextLevel);
1057                }
1058                Timer.SingleShot(0.5, delegate { immune = false; });
1059
1060            }
1061        });
1062
1063        //AddCollisionHandler(trigger, "player", delegate(PhysicsObject a, PhysicsObject b) { castTimer.Start(); });
1064    }
1065
1066    void CreateHouse(Vector position, double width, double height)
1067    {
1068        // Näkyvä talo
1069        GameObject house = new GameObject(width * 10, height * 8);
1070        house.Image = houseImages[0];
1071        house.Position = position - new Vector(0, height * 2.5);
1072        Add(house, -2);
1073
1074        //Seisottava tasanne
1075        PhysicsObject platform = PhysicsObject.CreateStaticObject(house.Width - (TILE_SIZE * 3.25), 1);     //Tätä kohtaa on nyt vähän hakemalla haettu.
1076        platform.IsVisible = false;
1077        platform.Position = new Vector(house.X + (TILE_SIZE * 0.5), house.Top);
1078        Add(platform);
1079    }
1080
1081    void CreateBurnedHouse(Vector position, double width, double height)
1082    {
1083        GameObject house = new GameObject(width * 10, height * 8);
1084        house.Image = houseImages[1];
1085        house.Position = position - new Vector(0, height * 2.5);
1086        Add(house, -2);
1087
1088        PhysicsObject platform = PhysicsObject.CreateStaticObject(house.Width * 0.25, 1);
1089        platform.IsVisible = false;
1090        platform.Position = new Vector(house.X + platform.Width * 0.5, house.Top);
1091        Add(platform);
1092    }
1093
1094    private void CreateCart(Vector position, double width, double height)
1095    {
1096        double size = 0.7;
1097        PhysicsObject cart = new PhysicsObject(400 * size, 80 * size);
1098        cart.Position = position;
1099        cart.Image = cartImage;
1100        cart.CollisionIgnoreGroup = 2;
1101        Add(cart);
1102        PhysicsObject cartWheel = new PhysicsObject(160 * size, 160 * size, Shape.Circle);
1103        cartWheel.Image = cartWheelImage;
1104        cartWheel.Position = cart.Position + new Vector(-110, -30) * size;
1105        cartWheel.CollisionIgnoreGroup = 2;
1106        Add(cartWheel);
1107        AxleJoint joint = new AxleJoint(cart, cartWheel);
1108        Add(joint);
1109    }
1110
1111    private void CreateDummy(Vector position, double width, double height, Color color)
1112    {
1113        PhysicsObject dummy = PhysicsObject.CreateStaticObject(width, height);
1114        dummy.Position = position;
1115        dummy.Color = color;
1116        Add(dummy);
1117    }
1118
1119    void CreatePlayer(Vector position, double width, double height)
1120    {
1121        HillBilly player = new HillBilly(width, height * 2, names[players.Count()]);
1122        player.Shape = Shape.Rectangle;
1123        player.Position = position + new Vector(0, height * 0.5);
1124        player.Color = Color.White;
1125        player.AnimWalk = new Animation(normalWalk);
1126        player.AnimIdle = new Animation(playerIdle);
1127        player.AnimJump = new Animation(playerJump);
1128        player.AnimFall = new Animation(playerFall);
1129        player.Animations = new List<Animation>();
1130        player.Animations.Add(normalWalk);
1131        player.Animations.Add(playerIdle);
1132        player.AnimFall.StopOnLastFrame = true;
1133        players.Add(player);
1134        startingPlayers.Add(player);
1135        player.Tag = "player";
1136        Add(player);
1137
1138        AddCollisionHandler(player, "burn", delegate(PhysicsObject p, PhysicsObject t)
1139        {
1140            player.Life.Value--;
1141        });
1142
1143        AddCollisionHandler(player, "lava", delegate(PhysicsObject p, PhysicsObject t)
1144        {
1145            // TODO: Ota alempi rivi pois kommentista.
1146            //player.Life.Value = player.Life.MinValue;
1147        });
1148
1149        AddCollisionHandler(player, "worm", delegate(PhysicsObject p, PhysicsObject worm)
1150        {
1151            if (player.Y > worm.Y && Math.Abs(player.X - worm.X) < worm.Width / 2.0)
1152            {
1153                worm.Destroy();
1154            }
1155            else
1156            {
1157                player.Life.Value--;
1158            }
1159        });
1160
1161
1162        player.Life.LowerLimit += delegate
1163        {
1164            if (players.Count < 2)
1165            {
1166                Loss();
1167            }
1168            else
1169            {
1170                players.Remove(player);
1171                GetRidOfImprovement(player);
1172                player.Destroy();
1173            }
1174        };
1175
1176        AddCollisionHandler(player, "improvement", CollectImprovement);
1177    }
1178
1179    void CreateGroundTop(Vector position, double width, double height)
1180    {
1181        // Puolet pienempi näkymätön palikka alla johon törmää.
1182        PhysicsObject ground = PhysicsObject.CreateStaticObject(width, height / 2.0);
1183        ground.IsVisible = false;
1184        ground.Position = position - new Vector(0.0, TILE_SIZE / 4.0);
1185        Add(ground);
1186
1187        // Maanpinnan näkyvä osa.
1188        GameObject visibleGround = new GameObject(width, height);
1189        visibleGround.Image = groundTopImages[levelNumber];
1190        visibleGround.Position = position;
1191        visibleGround.TextureWrapSize = new Vector(width / TILE_SIZE, height / TILE_SIZE);
1192        Add(visibleGround, -1);
1193
1194        int probability = RandomGen.NextInt(100);
1195        bool wheat = probability < 20;
1196
1197        if (wheat && levelNumber < 2)
1198        {
1199            GameObject wheatBlock = new GameObject(width * 1.5, height * 2);
1200            wheatBlock.Image = foregroundDecorations[levelNumber];
1201            wheatBlock.X = visibleGround.X;
1202            wheatBlock.Bottom = visibleGround.Bottom;
1203            wheatBlock.TextureWrapSize = new Vector(width / TILE_SIZE, height / TILE_SIZE);
1204            Add(wheatBlock, 2);
1205        }
1206    }
1207
1208    void CreateGround(Vector position, double width, double height)
1209    {
1210        PhysicsObject ground = PhysicsObject.CreateStaticObject(width, height);
1211        ground.Image = groundImages[levelNumber];
1212        ground.Position = position;
1213        ground.TextureWrapSize = new Vector(width / TILE_SIZE, height / TILE_SIZE);
1214        Add(ground, -1);
1215    }
1216    #endregion
1217
1218    void Victory()
1219    {
1220        ClearAll();
1221        MessageDisplay.Add("Voitit muutes belin.");
1222    }
1223
1224    void SetControls()
1225    {
1226        Keyboard.Listen(Key.A, ButtonState.Down, delegate { startingPlayers[0].Walk(-PLAYER_SPEED); }, "Player 1 moves left");
1227        Keyboard.Listen(Key.D, ButtonState.Down, delegate { startingPlayers[0].Walk(PLAYER_SPEED); }, "Player 1 moves right");
1228        Keyboard.Listen(Key.W, ButtonState.Down, delegate { startingPlayers[0].Jump(PLAYER_SPEED * 2); }, "Player 1 jumps");    //Just PLAYER_SPEED felt alright as well
1229        Keyboard.Listen(Key.E, ButtonState.Pressed, delegate { startingPlayers[0].UseImprovement(); }, "Player 1 uses their tools");
1230        Keyboard.Listen(Key.Tab, ButtonState.Pressed, GetRidOfImprovement, "Player 1 throws their tools away", startingPlayers[0]);
1231
1232        Keyboard.Listen(Key.Left, ButtonState.Down, delegate { startingPlayers[1].Walk(-PLAYER_SPEED); }, "Player 2 moves left");
1233        Keyboard.Listen(Key.Right, ButtonState.Down, delegate { startingPlayers[1].Walk(PLAYER_SPEED); }, "Player 2 moves right");
1234        Keyboard.Listen(Key.Up, ButtonState.Down, delegate { startingPlayers[1].Jump(PLAYER_SPEED * 2); }, "Player 2 jumps");
1235        Keyboard.Listen(Key.RightShift, ButtonState.Pressed, delegate { startingPlayers[1].UseImprovement(); }, "Player 2 uses their tools");
1236        Keyboard.Listen(Key.Enter, ButtonState.Pressed, GetRidOfImprovement, "Player 1 throws their tools away", startingPlayers[1]);
1237
1238        Keyboard.Listen(Key.F12, ButtonState.Pressed, NextLevel, null);
1239        Keyboard.Listen(Key.R, ButtonState.Pressed, StartGame, null);
1240
1241        Keyboard.Listen(Key.F1, ButtonState.Pressed, ShowControlHelp, "Show help");
1242        Keyboard.Listen(Key.Escape, ButtonState.Pressed, ConfirmExit, "Exit game");
1243    }
1244
1245    void GetRidOfImprovement(HillBilly player)
1246    {
1247        if (player.Improvement != null)
1248        {
1249            Improvement parannus = player.Improvement;
1250            parannus.Position = player.Position + player.FacingDirection.GetVector() * 100;
1251            parannus.IsVisible = true;
1252            parannus.IgnoresCollisionResponse = false;
1253            parannus.Tag = "improvement";
1254            player.Improvement.Rid();
1255        }
1256    }
1257
1258    public void CreateMilkParticles(HillBilly billy, int size, int xBase, int yBase, Vector position, String tag)
1259    {
1260        for (int i = 0; i < 10; i++)
1261        {
1262            const double maxLife = 1.0;
1263            PhysicsObject milkParticle = new PhysicsObject(size, size, Shape.Circle);
1264            milkParticle.Color = new Color(255, 255, 255, 128);
1265            milkParticle.Position = billy.Position + position;
1266            milkParticle.IgnoresCollisionResponse = true;
1267            milkParticle.Tag = tag;
1268            milkParticle.LifetimeLeft = TimeSpan.FromSeconds(maxLife);
1269            Add(milkParticle);
1270
1271            // Väri muuttuu läpinäkyväksi.
1272            var fadeTimer = new Timer { Interval = 0.07 };
1273            fadeTimer.Timeout += delegate
1274            {
1275                byte c = 255;
1276                milkParticle.Color = new Color(c, c, c, (byte)(128 * milkParticle.LifetimeLeft.TotalSeconds / maxLife));
1277            };
1278            fadeTimer.Start();
1279            milkParticle.Destroyed += fadeTimer.Stop;
1280
1281            // Random lentonopeus.
1282            var rx = RandomGen.NextDouble(-50, 50);
1283            var ry = RandomGen.NextDouble(-50, 50);
1284            milkParticle.Hit(new Vector(billy.FacingDirection.GetVector().X * (xBase + rx), yBase + ry));
1285        }
1286    }
1287
1288    void Loss()
1289    {
1290        //TODO: Sumthin' flashy for our fallen friends.
1291        Exit();
1292    }
1293
1294    void CollectImprovement(PhysicsObject player, PhysicsObject milk)
1295    {
1296        HillBilly billy = player as HillBilly;
1297        if (billy == null || billy.Improvement != null)
1298            return;
1299
1300        Improvement milkI = milk as Improvement;
1301        billy.GainImprovement(milkI);
1302
1303        milk.IsVisible = false;
1304        milk.IgnoresCollisionResponse = true;
1305        milk.Tag = "none";
1306
1307        //Remove(milk);
1308        //billy.AnimWalk = new Animation(milkWalk);
1309        //billy.AnimIdle = new Animation(milkWalk.CurrentFrame);
1310    }
1311
1312    public void ForkThings(HillBilly Owner)
1313    {
1314        PhysicsObject evilClone = new PhysicsObject(Owner.Width, Owner.Height * 0.7);
1315        evilClone.Position = Owner.Position + Owner.FacingDirection.GetVector() * 40 + new Vector(0, -(Owner.Height * 0.3));
1316        evilClone.Color = Color.Red;
1317        evilClone.IsVisible = false;
1318        evilClone.Tag = "pitchfork";
1319        evilClone.IgnoresCollisionResponse = true;
1320        evilClone.IgnoresPhysicsLogics = true;
1321        evilClone.LifetimeLeft = TimeSpan.FromSeconds(Owner.Animation.FPS * Owner.Animation.FrameCount);
1322        Add(evilClone);
1323
1324        Owner.PlayAnimation(Owner.Improvement.Animations[1], evilClone.Destroy);
1325    }
1326
1327    #region Camera
1328    void UpdateCamera()
1329    {
1330        double minY = players.Min(p => p.Y);
1331        double maxY = players.Max(p => p.Y);
1332        double minX = players.Min(p => p.X) + cameraOffset;
1333
1334        Vector minPosition = new Vector(Math.Max(minX, cameraTargetX), minY);
1335        Vector maxPosition = new Vector(minX, maxY);
1336
1337        if (levelNumber < 2)
1338        {
1339            cameraTarget = (minPosition + maxPosition) * 0.5;
1340            cameraTarget.X = Math.Max(cameraTargetX, minX); //Lellllll.
1341
1342            //cameraTarget.Y = Math.Max(cameraTarget.X, Level.Bottom + Window.Height/2.0);
1343
1344            cameraTargetX = Math.Max(cameraTargetX, minX);
1345
1346            cameraTarget.X = Math.Min(cameraTargetX, rightCamLimit);
1347            cameraTarget.Y = Math.Max(cameraTarget.Y, bottomCamLimit);
1348        }
1349        else if (levelNumber == 2)
1350        {
1351            cameraTarget.Y = ((minPosition + maxPosition) * 0.5).Y;
1352            cameraTarget.Y = Math.Max(cameraTarget.Y, bottomCamLimit);
1353
1354            // Pakotetaan kameraa eteenpäin. Jos kaikki pelaajat on näytön oikealla puolella, niin liikutetaan nopeammin.
1355            double cameraSpeed = players.All(p => Camera.WorldToScreen(p.Position).X > 0) ? 4.0 : 1.0;
1356            cameraTarget.X += cameraSpeed;
1357
1358            cameraTarget.X = Math.Min(cameraTarget.X, rightCamLimit);
1359
1360            if (cameraTarget.X == rightCamLimit && activateBoss != null)
1361            {
1362                activateBoss();
1363                activateBoss = null;
1364            }
1365        }
1366
1367        // Pelaajien sijainnin rajaus ikkunaan.
1368        double windowMax = Camera.ScreenToWorld(new Vector(Window.Width / 2.0, 0)).X;
1369        double windowMin = Camera.ScreenToWorld(new Vector(-Window.Width / 2.0, 0)).X;
1370        foreach (var player in players)
1371        {
1372            player.Left = Math.Max(player.Left, windowMin);
1373            player.Right = Math.Min(player.Right, windowMax);
1374        }
1375    }
1376
1377
1378    protected override void Update(Time time)
1379    {
1380        Camera.Position += (cameraTarget - Camera.Position) * time.SinceLastUpdate.TotalSeconds * cameraSpeed;
1381        //Camera.X += (cameraTargetX - Camera.X) * time.SinceLastUpdate.TotalSeconds * cameraSpeed;
1382
1383
1384        base.Update(time);
1385    }
1386
1387    /// <summary>
1388    /// Yritän leikkiä kameralla. Vielä varmaan hetken pidempään.
1389    /// </summary>
1390    /// <param name="gameTime"></param>
1391    /*
1392    protected override void Update(Microsoft.Xna.Framework.GameTime gameTime)
1393    {
1394        foreach(HillBilly player in players)
1395        {
1396            playerPositionsX.Add(player.Position.X);
1397            playerPositionsY.Add(player.Position.Y);
1398        }
1399
1400        double maxX = playerPositionsX.Max();
1401        double maxY = playerPositionsY.Max();
1402        double minX = playerPositionsX.Min();
1403        double minY = playerPositionsY.Min();
1404
1405        Vector minPosition = new Vector(minX, minY);
1406        Vector maxPosition = new Vector(maxX, maxY);
1407
1408        Camera.Position = (minPosition + maxPosition) * 0.5;
1409
1410        playerPositionsX.Clear();
1411        playerPositionsY.Clear();
1412
1413        base.Update(gameTime);
1414    }
1415     */
1416    #endregion
1417
1418
1419}
Note: See TracBrowser for help on using the repository browser.