Übungszettel 4 ============== In dieser und den nächsten Übungen werden wir uns mit der (Weiter-)Entwicklung eines Spiels beschäftigen. Bisher umfasst das Spiel die folgenden Module: * GameTypes.hs * GameLogic.hs * GameDraw.hs * GameConfig.hs * GameMain.hs Sie können es mit `stack exec Game` ausprobieren. Wie Sie sehen werden, sind uns bei der Implementation dieses Spiels leider einige Fehler unterlaufen. Außerdem fehlen noch einige wichtige Features, aber zum Glück kennen sich unsere Tutanden gut genug aus, um uns zu helfen! Issue 1 --------- Sie haben in der Vorlesung bereits *Record syntax* kennengelernt. Im Modul `GameLogic.hs` unter "Initialization" findet sich die unschöne Funktion `newWorld`. Geben Sie dieser Funktion eine anschauliche Form, indem Sie Teilausdrücke refaktorisieren (in sinnvollen Funktionen oder `where`-/`let`-Klauseln) und verwenden Sie *Record syntax* um eine default World anzulegen! Bedenken Sie, dass sie zur Zuweisung einzelner *Record fields* genau deren Namen verwenden müssen (nicht die daraus erstellten Lenses). Issue 2 --------- In der Datei `GameDraw.hs` wird bestimmt, wie eine `World` angezeigt wird. 1. Ergänzen Sie den Code, so dass ein toter Boss als rotes `'T'`, ein toter Hero als grünes `'T'` dargestellt wird. 2. Ergänzen Sie das Spiel um einen visuellen Hinweis, der anzeigt, ob das Spiel pausiert ist. Issue 3 --------- Obwohl die Spielerbewegung einwandfrei funktioniert, schlägt der entsprechende QuickCheck-Test fehl! Korrigieren Sie den QuickCheck-Test. Issue 4 --------- 1. Implementieren Sie eine neue `Action`, die die Blickrichtung des Helden ändert, ohne dass ein World-Update stattfindet. Erweitern Sie hierfür entsprechend den `Action`-Typ in `GameTypes.hs`, modifizieren Sie `performAction` in `GameLogic.hs` und schreiben Sie eine Funktion `changeDirection :: Direction -> World -> World`. Erweitern Sie außerdem `getAction` in `GameConfig.hs`, so dass gilt: * `'h'` führt zu Blick nach `West` * `'j'` führt zu Blick nach `North` * `'k'` führt zu Blick nach `South` * `'l'` führt zu Blick nach `East`. 2. Eine Kollegin hat begonnen ein neues Feature zu implementieren: Eine neue `Action` soll dem Spieler/der Spielerin das Stellen von Fallen vor dem Helden ermöglichen. Bewegt sich ein Monster auf eine solche Falle, soll diese zuschnappen und Schaden zufügen. Die Kollegin hat bereits einen `Action`-Wert (`SetTrap`) und einen `Entity`- Wert (`Trap`) in `GameTypes.hs` angelegt und `getAction` in `GameConfig.hs` angepasst. Im GameLogic-Modul hat sie die zu modifizierenden Stellen mit einem `-- TODO`-Kommentar markiert. Bringen Sie ihre Arbeit zuende. Bonus: Issue 5 --------- An einigen Stellen im Code fügen Entities Schaden zu. Hard coded finden sich folgende Schadenswerte: * Angreifender `Hero` fügt Boss 45 Schaden zu * Explodierende `Bomb` fügt Held 30 bzw. entfernter 15 Schaden zu * Läuft der Held in ein `Fire` fügt es ihm 15 Schaden zu * Läuft der Boss in eine `Trap` fügt diese ihm x Schaden zu Implementieren Sie ein sinnvolles Schadensystem, in dem Sie den Typ `Stats` um ein Feld `_damage :: Integer` erweitern. Ein großes Feuer soll mehr Schaden zufügen als ein kleines. Passen Sie die `GameLogic` entsprechend an. Hinweis: Trap hat bisher keine Stats. Wie Sie hier verfahren, ist Ihnen überlassen. Appendix: -------- Die wichtigsten Lens operators (**unbedingt anschauen**): https://github.com/ekmett/lens/wiki/Operators Auch das hier ist definitv einen Blick Wert: http://intolerable.me/lens-operators-intro/ Und hier noch ein Link zu Setter: https://hackage.haskell.org/package/lens-4.15.2/docs/Control-Lens-Setter.html