Après tous ces chapitres sur la POO, nous allons prendre un peu de bon temps pour mettre toutes les notions apprises en pratique. Je vous propose de nouveau de créer un jeu. Il ne s'agira pas d'un jeu de plateau mais d'un jeu de bataille navale. Mais attention ! Pas le bon vieux jeu où on visait au hasard les cases B7 puis E4 en espérant toucher ou couler un porte-avion ! Non. Je pensais plutôt à une sorte de jeu de rôle au tour par tour. Vous disposerez d'un navire (une frégate, un galion…) et devrez affronter un navire adverse, le couler ou l'arraisonner. Le but étant de gagner de l'or, de perfectionner votre navire, d'augmenter votre équipage…
L'objectif est bien sûr de mettre en œuvre la conception orientée objet dont je vous parle et reparle depuis plusieurs chapitres. Comme à chaque fois, je commencerai par vous décrire le projet, ses objectifs, ses contraintes… puis je vous fournirai quelques conseils ou pistes avant de vous livrer une solution possible. Prêt ? Alors à l'abordage !
Ce TP est long à réaliser. S'il exige que vous maîtrisiez la POO, il n'exige pas que vous soyez devenus un maître en la matière. Toutefois, il vous faudra sûrement quelques jours pour en venir à bout. Bon courage.
Règles du jeu
Le déroulement
Comme indiqué en introduction, il s'agira d'un jeu de rôle au tour par tour. Votre navire enchaînera les combats. Entre deux combats, trois actions seront possibles :
- Retourner au port pour effectuer des réparations, recruter des matelots, améliorer votre navire ou sauvegarder.
- Rester en mer pour de nouveaux combats.
- Partir au large pour affronter des adversaires plus puissants.
À chaque combat, le jeu proposera plusieurs choix au joueur :
- Bombarder : le navire attaquera son adversaire à coups de canon.
- Aborder : le navire attaquera son adversaire en lançant un abordage.
- Défendre : l'équipage du navire se préparera à subir un abordage et renforcera temporairement sa défense.
- Manœuvrer : le navire tentera d'esquiver les boulets de canon de l'adversaire.
- Fuir : le joueur met fin à l'assaut et fuit.
Les navires
Il existera différents types de navires : les navires de guerre, les navires de commerce, les navires pirates et les navires corsaires. Ceux-ci pourront être classés en deux catégories :
- Navires légaux : cette catégorie comprendra les navires de guerre, les navires de commerce et les navires corsaires. Ils auront la capacité de bombarder les navires adverses afin de les couler.
- Navires illégaux : cette catégorie comprendra les navires pirates et les navires corsaires. Ils auront la capacité de se lancer à l'abordage des navires adverses afin de les capturer.
Vous aurez remarqué que les corsaires feront partie des deux catégories ce qui devrait vous rappeler l'héritage multiple. Chaque type de navire aura bien sûr ses spécificités :
- Navires de guerre : ils disposeront d'une force de frappe supérieure aux autres navires.
- Navires de commerce : les plus faibles, ils auront la capacité de vendre des marchandises dans les ports, leur permettant de gagner davantage d'or.
- Navires pirates : navires rapides, ils gagneront davantage d'or à l'issue d'un combat.
- Navires corsaires : sans capacité particulière supplémentaire.
Les statistiques
Tout navire disposera des statistiques suivantes, ainsi que des bonus associés :
- Coque : mesure l'état de la coque. Une fois à 0, le navire coule et est perdu.
- Équipage : mesure le nombre d'hommes sur le navire. Une fois à 0, un navire ne peut plus être dirigé et est donc perdu.
- Puissance : mesure la puissance de feu des canons des navires légaux.
- Attaque : mesure la force d'attaque de l'équipage des navires illégaux.
- Cuirasse : mesure la résistance du navire aux boulets de canon.
- Défense : mesure la résistance de l'équipage aux abordages.
- Vitesse : mesure la vitesse du navire, ce qui lui permet plus facilement d'esquiver.
À noter que les deux premières statistiques nécessiteront une valeur maximale et une valeur courante. Les navires de commerce disposeront d'un stock de marchandises échangeable contre de l'or au port.
Cahier des charges
Gameplay
Venons-en désormais aux détails techniques. Encore une fois, le jeu se déroulera en mode console (oui je sais, vous avez hâte de pouvoir faire des fenêtres avec des boutons et tout, mais encore un tout petit peu de patience ). Pour égayer tout cela, il serait bon que vous fassiez appel au package NT_Console
en apportant un peu de couleur à notre vieille console ainsi que quelques bip. Le jeu devra pouvoir se jouer au clavier à l'aide des touches ←, ↑, →, ↓, Entrée ou Escape. Pensez à faire appel à la fonction get_key
pour cela. Pour vous donner un ordre d'idée de ce que j'ai obtenu, voici quelques captures d'écran. À vrai dire, j'aurais voulus insérer quelques ASCII arts mais ça ne rendait pas très bien.
Comme vous pouvez le voir sur les captures, le joueur devra avoir accès aux statistiques de son navire à tout moment et, lors des combats, à celles de son adversaire. Il est évident que les choix proposés au joueur devront être clairs (plus de «tapez sur une touche pour voir ce qui va se passer») et que le jeu devra retourner un message à la suite de chaque action, afin par exemple de savoir si le tir de canon a échoué ou non, combien de points ont été perdus, pourquoi votre navire a perdu (coque déchiquetée ou équipage massacré ?)… Bref, cette fois, j'exige que votre programme soit présentable.
Je vais également vous imposer de proposer la sauvegarde-chargement de vos parties. Puisque vous pourrez améliorer vos navires pour vous confronter à des adversaires toujours plus puissants, il serait dommage de ne pas proposer la possibilité de sauvegarder votre jeu.
Les calculs
Pour le calcul des dégâts liés à vos coups de cannons ou de sabre, je vous laisse libre (mon programme n'est d'ailleurs pas toujours très équilibré en la matière). Voici toutefois les formules que j'ai utilisées pour ma part :
$D_{bombardement} = {{(P_{att} + P^{bonus}_{att})^2}\over {P_{att} + P^{bonus}_{att} + P_{def} + P^{bonus}_{def}}}$
$D_{abordage} = {{(A_{att} + A^{bonus}_{att})^2}\over {A_{att} + A^{bonus}_{att} + A_{def} + A^{bonus}_{def}}} \times {{E^{actuel}_{att}} \over {E^{max}_{att}}}$
Ici, $D$ correspond aux dégâts occasionnés, $P$ à la puissance, $A$ à l'attaque, $E$ à l'équipage, $att$ à l'attaquant et $def$ au défenseur. Pour savoir si un navire esquivera ou non vos tirs, j'ai tiré un nombre entre 0 et 100 et regardé s'il était ou non supérieur à :
${{(V_{att} + V^{bonus}_{att})}\over {V_{att} + V^{bonus}_{att} + V_{def} + V^{bonus}_{def}}} \times 120$
Où $V$ est bien entendu la vitesse du navire, 120 étant un coefficient permettant de compliquer encore davantage l'esquive des boulets. Ces formules valent ce qu'elles valent, elles ne sont pas paroles d'évangile : si vous disposez de formules plus pertinentes, n'hésitez pas à les utiliser.
POO
Enfin, pour ceux qui ne l'auraient pas encore compris, je vais vous imposer l'emploi de «tactiques orientées objet» :
- utiliser des types
TAGGED
pour vos navires; - utiliser au moins une
INTERFACE
et un typeABSTRACT
; - disposer de méthodes polymorphes (je n'ai pas dit que toutes devaient l'être);
- utiliser des méthodes
PRIVATE
; - créer au moins un couple de packages père-fils.
Attention, je ne vous impose pas que tout votre code soit conçu façon objet : tout n'a pas besoin d'être encapsulé, toutes les méthodes n'ont pas besoin d'être polymorphes… J'exige simplement que ces cinq points (au moins) soient intégrés à votre projet. Rien ne vous empêche d'employer la généricité ou des types contrôlés si le cœur vous en dit, bien entendu.
Voici le diagramme de classe que j'ai utilisé (encore une fois, rien ne vous oblige à employer le même). Libre à vous de faire hériter les méthodes de bombardement et d'abordage de vos interfaces ou de votre classe mère.
Une solution possible
L'organisation
Comme à chaque TP, je compte bien vous fournir une solution. Mais cette solution est bien entendu perfectible. Elle est également complexe et nécessitera quelques explications. Tout d'abord, évoquons l'organisation de mes packages :
- Game : la procédure principale. Elle ne contient que très peu de chose, l'essentiel se trouvant dans les packages.
- P_Point : propose le type T_Point et les méthodes associées. Ce type permet pour chaque statistique (par exemple la vitesse), de disposer d'une valeur maximale, d'une valeur courante et d'une valeur bonus.
- P_Navire : gère les classes, méthodes et interfaces liées aux différents types navires. Ce package aurait du être scindé en plusieurs sous-package pour respecter les règles d'encapsulation. Mais pour que le code gagne en lisibilité et surtout en compacité, j'ai préféré tout réunir en un seul package. Cela vous permettra d'analyser plus facilement le code, les méthodes…
- P_Navire.list : le package fils. Celui-ci est fait pour proposer différents navires (frégates, galions, corvette…) au joueur et à l'ordinateur.
- P_Variables : gère les variables globales du projet (coût d'une amélioration, temps d'affichage des messages… ) ainsi que les fonctionnalités aléatoires.
- P_Data : gère l'enregistrement et la sauvegarde des navires dans des fichiers texte.
- P_Screen : gère tous les affichages : affichage de texte accentué, affichage des messages de combat (tir manqué, abordage réussi, fuite…), affichage des différents menus (menu de combat, menu du marché, menus pour choisir entre une nouvelle partie et une ancienne, menu pour choisir le type de bateau sur lequel vous souhaitez naviguer…)
- P_Modes : package le plus important, c'est lui qui gère tout ce que vous faites au clavier, que ce soit durant les phases de combat, lors de l'affichage du menu du marché… Bref, c'est le cœur du jeu puisqu'il gère les différents modes de jeu. Attention, les menus sont affichés grâce à P_Screen, mais seulement affichés, leur utilisation se fait grâce à P_Modes.
Le code
Game.adb
Venons-en au code à proprement parler. Voici à quoi se limite la procédure principale :
1 2 3 4 5 6 7 8 9 10 11 12 13 | WITH Nt_Console ; USE Nt_Console ; WITH P_Navire ; USE P_Navire ; WITH P_Modes ; USE P_Modes ; PROCEDURE Game IS BEGIN set_cursor(visible => false) ; DECLARE Joueur : T_Navire'Class := first_mode ; BEGIN market_mode(joueur) ; END ; END Game ; |
game.adb
On déclare un objet joueur de la classe T_Navire
que l'on initialise en lançant First_mode()
. Celui-ci proposera de choisir entre créer une nouvelle partie et en charger une ancienne. Dans chacun des cas, un Navire est renvoyé.
Ensuite, on lance le mode marché (Market_mode()
) lequel se chargera de lancer les autres modes si besoin est.
P_Point
Ce package présente peu d'intérêt et de difficultés :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | PACKAGE P_Point IS TYPE T_Point IS TAGGED RECORD Max, Current, Bonus : Integer ; END RECORD ; Function "-" (left : T_Point ; right : integer) return integer ; FUNCTION Total (P : T_Point) RETURN Integer ; FUNCTION Ecart(P : T_Point) RETURN Integer ; PROCEDURE Raz(P : OUT T_Point) ; PROCEDURE Init(P : IN OUT T_Point) ; PROCEDURE Init(P : IN OUT T_Point ; N : Natural) ; end P_Point ; |
P_Point.ads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | PACKAGE BODY P_Point IS FUNCTION "-" (Left : T_Point ; Right : Integer) RETURN Integer IS BEGIN RETURN Integer'Max(0,Left.Current - Right) ; END "-" ; FUNCTION Total(P : T_Point) RETURN Integer IS BEGIN RETURN P.Current + P.Bonus ; END Total ; FUNCTION Ecart(P : T_Point) RETURN Integer IS BEGIN RETURN P.Max - P.Current ; END Ecart ; PROCEDURE Raz(P : OUT T_Point) IS BEGIN P.Bonus := 0 ; END Raz ; PROCEDURE Init(P : IN OUT T_Point) IS BEGIN P.Current := P.Max ; P.Bonus := 0 ; END Init ; PROCEDURE Init(P : IN OUT T_Point ; N : Natural) IS BEGIN P.Max := N ; P.Current := P.Max ; P.Bonus := 0 ; END Init ; end P_Point ; |
P_Point.adb
P_Navire
L'un des principaux packages du jeu. Il définit mon type T_Navire
comme ABSTRACT
, mes interface T_Legal
et T_Illegal
. Trois méthodes abstraites sont proposées : Bombarde(), Aborde() et Init(). Des trois, seule Init() est réellement polymorphe. Les deux autres emploient chacune une méthode privée afin de limiter le code. J'aurais pu choisir de modifier le code de bombardement pour les navires de guerre, mais j'ai préféré modifier les statistiques pour accroître les points de Puissance initiaux afin de fournir un avantage initial aux navires de guerre qui peut toutefois être comblé pour les autres navires. Autrement dit, le bonus se fait grâce à Init() mais pas grâce à Bombarde(). Il en est de même pour Aborde(). Cela évite également que le code devienne gigantesque, ce qui ne vous faciliterait pas non plus son analyse.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | WITH P_Point ; USE P_Point ; WITH Ada.Strings.Unbounded ; USE Ada.Strings.Unbounded ; PACKAGE P_Navire IS ------------------------------- --TYPES ET METHODES ABSTRAITS-- ------------------------------- TYPE T_Navire IS ABSTRACT TAGGED RECORD Nom : Unbounded_string := Null_unbounded_string ; Coque : T_Point ; Equipage : T_Point ; Puissance : T_Point ; Attaque : T_Point ; Cuirasse : T_Point ; Defense : T_Point ; Vitesse : T_Point ; Playable : Boolean := False ; Gold : Natural := 0 ; END RECORD ; TYPE T_Stat_Name IS (Coque, Equipage, Puissance, Attaque, Cuirasse, Defense, Vitesse, Gold); TYPE T_Stat IS ARRAY(T_Stat_Name RANGE coque..Gold) OF Natural ; PROCEDURE Bombarde(Att : IN T_Navire ; Def : in out T_Navire'Class) IS ABSTRACT ; PROCEDURE Aborde (Att : IN T_Navire ; Def : IN OUT T_Navire'Class) IS ABSTRACT ; FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Navire IS ABSTRACT ; TYPE T_Legal IS INTERFACE ; TYPE T_Illegal IS INTERFACE ; ------------------- --TYPES CONCRETS -- ------------------- TYPE T_Warship IS NEW T_Navire AND T_Legal WITH NULL RECORD ; TYPE T_Tradeship IS NEW T_Navire AND T_Legal WITH RECORD Stock : Integer ; END RECORD ; TYPE T_Corsair IS NEW T_Navire AND T_Legal AND T_Illegal WITH NULL RECORD ; TYPE T_Pirate IS NEW T_Navire AND T_Illegal WITH NULL RECORD ; ---------------------- --METHODES CONCRETES-- ---------------------- OVERRIDING PROCEDURE Bombarde(Att : IN T_Warship ; Def : in out T_Navire'Class) ; OVERRIDING PROCEDURE Bombarde(Att : IN T_Tradeship ; Def : in out T_Navire'Class) ; OVERRIDING PROCEDURE Bombarde(Att : IN T_Corsair ; Def : in out T_Navire'Class) ; OVERRIDING PROCEDURE Bombarde(Att : IN T_Pirate ; Def : IN OUT T_Navire'Class) IS NULL ; OVERRIDING PROCEDURE Aborde(Att : IN T_Warship ; Def : in out T_Navire'Class) is null ; OVERRIDING PROCEDURE Aborde(Att : IN T_Tradeship ; Def : in out T_Navire'Class) is null ; OVERRIDING PROCEDURE Aborde(Att : IN T_Corsair ; Def : in out T_Navire'Class) ; OVERRIDING PROCEDURE Aborde(Att : IN T_Pirate ; Def : in out T_Navire'Class) ; OVERRIDING FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Warship ; OVERRIDING FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Tradeship ; OVERRIDING FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Corsair ; OVERRIDING FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Pirate ; PROCEDURE Defend(Bateau : IN OUT T_Navire'Class) ; PROCEDURE Manoeuvre(Bateau : IN OUT T_Navire'Class) ; FUNCTION Est_Mort(Bateau : T_Navire'Class) return boolean ; PROCEDURE Raz_Bonus(Bateau : OUT T_Navire'Class) ; PROCEDURE Reparer (Navire : in out T_Navire'Class) ; PROCEDURE Recruter (Navire : in out T_Navire'Class) ; PROCEDURE Vendre (Navire : IN OUT T_Tradeship) ; PROCEDURE Ameliorer_Coque (Navire : IN OUT T_Navire'Class) ; PROCEDURE Ameliorer_Equipage (Navire : IN OUT T_Navire'Class) ; PROCEDURE Ameliorer_Puissance(Navire : IN OUT T_Navire'Class) ; PROCEDURE Ameliorer_Attaque (Navire : IN OUT T_Navire'Class) ; PROCEDURE Ameliorer_Cuirasse (Navire : IN OUT T_Navire'Class) ; PROCEDURE Ameliorer_Defense (Navire : IN OUT T_Navire'Class) ; PROCEDURE Ameliorer_Vitesse (Navire : IN OUT T_Navire'Class) ; PROCEDURE Bat(Vainqueur : IN OUT T_Navire'Class ; Perdant : IN T_Navire'Class) ; PROCEDURE Perd(Navire : IN T_Navire'Class) ; PRIVATE PROCEDURE Private_Bombarde(Att : IN T_Navire'Class ; Def : IN OUT T_Navire'Class) ; PROCEDURE Private_Aborde (Att : IN T_Navire'Class ; Def : IN OUT T_Navire'Class) ; FUNCTION Esquive(Def : IN T_Navire'Class ; Att : IN T_Navire'Class) RETURN Boolean ; END P_Navire ; |
P_Navire.ads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | WITH P_Variables ; USE P_Variables ; WITH Ada.Text_Io ; USE Ada.Text_Io ; WITH P_Screen ; USE P_Screen ; WITH Nt_Console ; USE NT_Console ; PACKAGE BODY P_Navire IS ------------------------------------------- --CAPACITE D'ESQUIVE AU COURS D'UN ASSAUT-- ------------------------------------------- FUNCTION Esquive(Def : IN T_Navire'Class ; Att : IN T_Navire'Class) RETURN Boolean IS BEGIN RETURN Random > (Att.Vitesse.total*120 /(Att.Vitesse.total + Def.Vitesse.Total)); END Esquive ; ------------------------- --CAPACITE DE BOMBARDER-- ------------------------- PROCEDURE Private_Bombarde(Att : IN T_Navire'class ; Def : in out T_Navire'Class) IS --FORMULE GENERALE degats : integer := 0 ; BEGIN IF Def.Esquive(Att) THEN IF att.Playable THEN Put_Esquive_Message(Light_Red) ; else Put_Esquive_Message(Green) ; end if ; ELSE Degats := Integer( float(Att.Puissance.total**2) / float(Att.Puissance.Total + Def.Cuirasse.Total)) ; Def.Coque.Current := Def.Coque - Degats ; IF Att.Playable THEN Put_Bombard_Message(Degats,Green) ; ELSE Put_Bombard_Message(Degats,Light_Red) ; END IF ; END IF ; END Private_Bombarde ; OVERRIDING PROCEDURE Bombarde(Att : IN T_Warship ; Def : in out T_Navire'Class) IS --POUR BATEAUX DE GUERRE BEGIN Private_Bombarde(Att,Def) ; END Bombarde ; OVERRIDING PROCEDURE Bombarde(Att : IN T_Tradeship ; Def : in out T_Navire'Class) IS --POUR BATEAUX COMMERCIAUX BEGIN Private_Bombarde(Att,Def) ; END Bombarde ; OVERRIDING PROCEDURE Bombarde(Att : IN T_Corsair ; Def : in out T_Navire'Class) IS --POUR CORSAIRES BEGIN Private_Bombarde(Att,Def) ; END Bombarde ; ------------------------- --CAPACITE D'ABORDER-- ------------------------- PROCEDURE Private_aborde(Att : IN T_Navire'class ; Def : in out T_Navire'Class) IS --FORMULE GENERALE degats : integer := 0 ; BEGIN IF Def.Esquive(Att) THEN IF att.Playable THEN Put_Esquive_Message(Light_Red) ; ELSE Put_Esquive_Message(Green) ; END IF ; ELSE Degats := Integer( Float(Att.Attaque.Total)**2 / Float(Att.Attaque.Total + Def.Defense.Total) * Float(Att.Equipage.Current)/Float(Att.Equipage.Max)) ; Def.Equipage.Current := Def.Equipage - Degats ; IF Att.Playable THEN Put_Abordage_Message(Degats,Green) ; ELSE Put_Abordage_Message(Degats,Light_Red) ; END IF ; END IF ; END Private_aborde ; OVERRIDING PROCEDURE aborde(Att : IN T_Corsair ; Def : in out T_Navire'Class) IS --POUR CORSAIRES BEGIN Private_aborde(Att,Def) ; END aborde ; OVERRIDING PROCEDURE aborde(Att : IN T_Pirate ; Def : in out T_Navire'Class) IS --POUR PIRATES BEGIN Private_aborde(Att,Def) ; END aborde ; ------------------ --INITIALISATION-- ------------------ FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_warship IS Navire : T_Warship ; BEGIN Navire.Nom := Nom ; Navire.Coque.init(Stat(Coque)) ; Navire.Equipage.init (Stat(Equipage)) ; Navire.Puissance.init(Stat(Puissance)*120/100) ; Navire.Attaque.init (Stat(Attaque)) ; Navire.Cuirasse.init (Stat(Cuirasse)) ; Navire.Defense.init (Stat(Defense)) ; Navire.Vitesse.init (Stat(Vitesse)*70/100) ; Navire.Playable := False ; Navire.Gold := Stat(Gold) ; RETURN Navire ; END Init ; FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Tradeship IS Navire : T_Tradeship ; BEGIN Navire.Nom := Nom ; Navire.Coque.init(Stat(Coque)) ; Navire.Equipage.init (Stat(Equipage)) ; Navire.Puissance.init(Stat(Puissance)*70/100) ; Navire.Attaque.init (Stat(Attaque)) ; Navire.Cuirasse.init (Stat(Cuirasse)*110/100) ; Navire.Defense.init (Stat(Defense)*110/100) ; Navire.Vitesse.init (Stat(Vitesse)*90/100) ; Navire.Playable := False ; Navire.Gold := Stat(Gold) ; Navire.stock := 15 ; RETURN Navire ; END Init ; FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Corsair IS Navire : T_Corsair ; BEGIN Navire.Nom := Nom ; Navire.Coque.init(Stat(Coque)) ; Navire.Equipage.init (Stat(Equipage)) ; Navire.Puissance.init(Stat(Puissance)) ; Navire.Attaque.init (Stat(Attaque)) ; Navire.Cuirasse.init (Stat(Cuirasse)) ; Navire.Defense.init (Stat(Defense)) ; Navire.Vitesse.init (Stat(Vitesse)) ; Navire.Playable := False ; Navire.Gold := Stat(Gold) ; RETURN Navire ; END Init ; FUNCTION Init (Nom : unbounded_string ; Stat : T_Stat) RETURN T_Pirate IS Navire : T_Pirate ; BEGIN Navire.Nom := Nom ; Navire.Coque.init(Stat(Coque)) ; Navire.Equipage.init (Stat(Equipage)) ; Navire.Puissance.init(Stat(Puissance)) ; Navire.Attaque.init (Stat(Attaque)*120/100) ; Navire.Cuirasse.init (Stat(Cuirasse)*70/100) ; Navire.Defense.init (Stat(Defense)) ; Navire.Vitesse.init (Stat(Vitesse)*130/100) ; Navire.Playable := False ; Navire.Gold := Stat(Gold) ; RETURN Navire ; END Init ; ------------------------ --CAPACITÉ DE DEFENSE -- ------------------------ PROCEDURE Defend(Bateau : IN OUT T_Navire'Class) IS BEGIN Bateau.Defense.Bonus := Bateau.Defense.Current * 25 /100 ; IF Bateau.Playable THEN Put_Defense_Message(Green) ; ELSE Put_Defense_Message(Light_Red) ; END IF ; END Defend ; ------------------------- --CAPACITÉ DE MANOEUVRE-- ------------------------- PROCEDURE Manoeuvre(Bateau : IN OUT T_Navire'Class) IS BEGIN Bateau.Vitesse.Bonus := Bateau.Vitesse.Current * 25 /100 ; IF Bateau.Playable THEN Put_Manoeuvre_Message(Green) ; ELSE Put_Manoeuvre_Message(Light_Red) ; END IF ; END Manoeuvre ; ------------------------------------------------ --FONCTION POUR SAVOIR SI UN BATEAU EST COULE -- ------------------------------------------------ FUNCTION Est_Mort(Bateau : T_Navire'Class) RETURN Boolean IS BEGIN RETURN Bateau.Coque.current = 0 OR Bateau.Equipage.current = 0 ; END Est_Mort ; ----------------------------------- --REMISE À ZÉRO POUR DBT DE TOUR -- ----------------------------------- PROCEDURE Raz_Bonus(Bateau : OUT T_Navire'Class) IS BEGIN Bateau.Coque.raz ; Bateau.Equipage.raz ; Bateau.Puissance.raz ; Bateau.Attaque.raz ; Bateau.Cuirasse.raz ; Bateau.Defense.raz ; Bateau.Vitesse.raz ; END Raz_Bonus ; ---------------------------- --MÉTHODES POUR LE MARCHÉ -- ---------------------------- PROCEDURE Reparer (Navire : IN OUT T_Navire'Class) IS Cout : constant Natural := (Navire.Coque.Max - Navire.Coque.Current) * Repair_Cost ; BEGIN IF Cout <= Navire.Gold THEN Navire.Coque.Init ; Navire.Gold := Navire.Gold - Cout ; ELSE Navire.Coque.Current := Navire.Coque.Current + (Navire.Gold / Repair_Cost) ; Navire.Gold := Navire.Gold mod Repair_Cost ; END IF ; Bleep ; END Reparer ; PROCEDURE Recruter (Navire : IN OUT T_Navire'Class) IS Cout : constant Natural := (Navire.Equipage.max - Navire.Equipage.current) * Recrute_cost ; BEGIN IF Cout <= Navire.Gold THEN Navire.Equipage.Init ; Navire.Gold := Navire.Gold - Cout ; ELSE Navire.Equipage.Current := Navire.Equipage.Current + (Navire.Gold / Recrute_Cost) ; Navire.Gold := Navire.Gold mod Recrute_Cost ; END IF ; Bleep ; END Recruter ; PROCEDURE Vendre (Navire : IN OUT T_Tradeship) IS BEGIN Navire.Gold := Navire.Gold + Navire.Stock * Goods_Cost ; Navire.Stock := 0 ; Bleep ; END Vendre ; PROCEDURE Ameliorer_Coque (Navire : IN OUT T_Navire'Class) IS BEGIN IF Coque_Cost <= Navire.Gold THEN Navire.Gold := Navire.Gold - Coque_Cost ; Navire.Coque.Max := Navire.Coque.Max + 2 ; Navire.Coque.Current := Navire.Coque.Current + 2 ; Coque_Cost := Coque_cost * 2 ; END IF ; Bleep ; END Ameliorer_Coque ; PROCEDURE Ameliorer_Equipage (Navire : IN OUT T_Navire'Class) IS BEGIN IF Equipage_Cost <= Navire.Gold THEN Navire.Gold := Navire.Gold - Equipage_Cost ; Navire.Equipage.Max := Navire.Equipage.Max + 2 ; Navire.Equipage.Current := Navire.Equipage.Current + 2 ; Equipage_Cost := Equipage_cost * 2 ; END IF ; Bleep ; END Ameliorer_Equipage ; PROCEDURE Ameliorer_Puissance(Navire : IN OUT T_Navire'Class) IS BEGIN IF Puissance_Cost <= Navire.Gold THEN Navire.Gold := Navire.Gold - Puissance_Cost ; Navire.Puissance.Max := Navire.Puissance.Max + 1 ; Navire.Puissance.Current := Navire.Puissance.Current + 1 ; Puissance_Cost := Puissance_cost * 2 ; END IF ; Bleep ; END Ameliorer_Puissance ; PROCEDURE Ameliorer_Attaque (Navire : IN OUT T_Navire'Class) IS cout : constant natural := Attaque_Cost * Navire.Equipage.max ; BEGIN IF cout <= Navire.Gold THEN Navire.Gold := Navire.Gold - cout ; Navire.Attaque.Max := Navire.Attaque.Max + 1 ; Navire.Attaque.Current := Navire.Attaque.Current + 1 ; Attaque_Cost := Attaque_cost + 1 ; END IF ; Bleep ; END Ameliorer_Attaque ; PROCEDURE Ameliorer_Cuirasse (Navire : IN OUT T_Navire'Class) IS BEGIN IF Cuirasse_Cost <= Navire.Gold THEN Navire.Gold := Navire.Gold - Cuirasse_Cost ; Navire.Cuirasse.Max := Navire.Cuirasse.Max + 1 ; Navire.Cuirasse.Current := Navire.Cuirasse.Current + 1 ; Cuirasse_Cost := Cuirasse_cost * 2 ; END IF ; Bleep ; END Ameliorer_Cuirasse ; PROCEDURE Ameliorer_Defense (Navire : IN OUT T_Navire'Class) IS cout : constant natural := Defense_Cost * Navire.Equipage.max ; BEGIN IF cout <= Navire.Gold THEN Navire.Gold := Navire.Gold - cout ; Navire.Defense.Max := Navire.Defense.Max + 1 ; Navire.Defense.Current := Navire.Defense.Current + 1 ; Defense_Cost := Defense_cost + 1 ; END IF ; Bleep ; END Ameliorer_Defense ; PROCEDURE Ameliorer_Vitesse (Navire : IN OUT T_Navire'Class) IS BEGIN IF Vitesse_Cost <= Navire.Gold THEN Navire.Gold := Navire.Gold - Vitesse_Cost ; Navire.Vitesse.Max := Navire.Vitesse.Max + 1 ; Navire.Vitesse.Current := Navire.Vitesse.Current + 1 ; Vitesse_Cost := Vitesse_cost * 2 ; END IF ; Bleep ; END Ameliorer_Vitesse ; ------------------------- --GAIN DE FIN DE COMBAT-- ------------------------- PROCEDURE Bat(Vainqueur : IN OUT T_Navire'Class ; Perdant : IN T_Navire'Class) IS Gain_or, Gain_Stock : Natural := 0 ; BEGIN goto_xy(2,10) ; set_foreground(green) ; Put("VOUS AVEZ VAINCU VOTRE ADVERSAIRE !") ; IF Vainqueur IN T_Pirate'Class THEN Gain_Or := Perdant.Gold / 4 ; ELSE Gain_Or := Perdant.Gold / 5 ; END IF ; Vainqueur.Gold := Vainqueur.Gold + Gain_Or ; goto_xy(0,11) ; set_foreground(green) ; Put("Vous remportez " & integer'image(Gain_or) & " or") ; IF Vainqueur IN T_Tradeship'Class THEN Gain_stock := (Niveau-1) * 3 + 1 ; T_Tradeship(Vainqueur).Stock := T_Tradeship(Vainqueur).Stock + Gain_Stock ; Put(" et " & integer'image(Gain_Stock) & " stocks") ; END IF ; put(" !") ; Set_Foreground(Black) ; delay Message_time * 2.0 ; END Bat ; PROCEDURE Perd(Navire : IN T_Navire'Class) IS BEGIN goto_xy(2,10) ; set_foreground(light_red) ; Put("VOUS AVEZ PERDU CONTRE VOTRE ADVERSAIRE !") ; goto_xy(0,11) ; IF Navire.Coque.Current = 0 THEN Put("La coque de votre navire est d" & Character'Val(130) & "truite.") ; ELSIF Navire.Equipage.Current = 0 then Put("Votre " & Character'Val(130) & "quipage est massacr" & Character'Val(130) & ".") ; END IF ; Set_Foreground(Black) ; delay Message_time * 2.0 ; END Perd ; END P_Navire ; |
P_Navire.adb
P_Navire.list
Peu d'intérêt, c'est ici que sont écrits les statistiques des différents navires (frégate, trois-mâts, galion et corvette). Vous pouvez en ajouter autant que bon vous semble. Le seul inconvénient, c'est qu'il faudra recompiler le code source (les données sont hard-coded).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | package P_Navire.List is TYPE T_Navire_Id IS RECORD Nom : Unbounded_String ; Stat : T_Stat ; END RECORD ; type T_Liste_Navire is array(positive range <>) of T_Navire_Id ; ------------- -- NAVIRES -- ------------- --EXEMPLE STATS Coque Equpg Puiss Att Cuir Defse Vits Gold Stat_Fregate : T_Stat := (15, 10, 14, 8, 8, 6, 8, 200) ; Stat_Gallion : T_Stat := (20, 14, 10, 10, 12, 8, 4, 500) ; Stat_Corvette : T_Stat := (12, 7, 8, 8, 10, 4, 16, 150) ; Stat_Trois_Mats : T_Stat := (16, 8, 12, 7, 10, 8, 10, 300) ; Liste_Navire : T_Liste_Navire :=( (To_Unbounded_String("Frégate"), Stat_Fregate), (To_Unbounded_String("Gallion"), Stat_Gallion), (To_Unbounded_String("Corvette"), Stat_Corvette), (To_Unbounded_String("Trois-Mâts"), Stat_Trois_Mats) ); ------------------------------ -- GÉNÉRATION D'ADVERSAIRES -- ------------------------------ PROCEDURE Mettre_Niveau(Navire : IN OUT T_Navire'Class ; Niveau : Positive) ; FUNCTION Generer_Ennemi(Niveau : Natural := 1) RETURN T_Navire'Class ; End P_Navire.List ; |
p_navire-list.ads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | WITH P_Variables ; USE P_Variables ; package body P_Navire.List is PROCEDURE Mettre_Niveau(Navire : IN OUT T_Navire'Class ; Niveau : Positive) IS coef : float ; BEGIN Coef := 1.5**(Niveau-1) ; Navire.Coque.Init(Integer(Float(Navire.Coque.Max) * Coef)) ; Navire.Equipage.Init(Integer(Float(Navire.Equipage.Max) * Coef)) ; Navire.Puissance.Init(Integer(Float(Navire.Puissance.Max) * Coef)) ; Navire.Attaque.Init(Integer(Float(Navire.Attaque.Max) * Coef)) ; Navire.Cuirasse.Init(Integer(Float(Navire.Cuirasse.Max) * Coef)) ; Navire.Defense.Init(Integer(Float(Navire.Defense.Max) * Coef)) ; Navire.Vitesse.Init(Integer(Float(Navire.Vitesse.Max) * Coef)) ; Coef := 2.0**(Niveau-1) ; Navire.Gold := integer(float(Navire.Gold) * coef) ; END Mettre_Niveau ; FUNCTION Generer_Ennemi(Niveau : Natural := 1) RETURN T_Navire'Class IS Navire : ACCESS T_Navire'Class ; N : Natural ; BEGIN N:= Random mod Liste_Navire'Length + 1 ; CASE Random mod 4 IS WHEN 0 => Navire := new T_Warship'(init(Liste_Navire(N).nom, Liste_Navire(N).stat)) ; WHEN 1 => Navire := new T_Tradeship'(init(Liste_Navire(N).nom, Liste_Navire(N).stat)) ; WHEN 2 => Navire := new T_Pirate'(init(Liste_Navire(N).nom, Liste_Navire(N).stat)) ; WHEN others => Navire := new T_Corsair'(init(Liste_Navire(N).nom, Liste_Navire(N).stat)) ; END CASE ; Mettre_Niveau(Navire.All,Niveau) ; RETURN Navire.all ; END Generer_Ennemi ; End P_Navire.List ; |
p_navire-list.adb
P_Variables
Là encore peu d'intérêt, hormis si vous souhaitez modifier le temps d'affichage des message, le coût de base d'une amélioration ou des réparations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | WITH Ada.Strings.Unbounded ; USE Ada.Strings.Unbounded ; WITH Ada.Numerics.Discrete_Random ; PACKAGE P_Variables IS subtype T_Pourcentage is integer range 0..100 ; PACKAGE P_Random IS NEW Ada.Numerics.Discrete_Random(T_Pourcentage) ; Germe : P_Random.Generator ; PROCEDURE Reset ; FUNCTION Random RETURN T_Pourcentage ; Message_Time : CONSTANT Duration := 2.0 ; Repair_Cost : CONSTANT Natural := 5 ; Recrute_Cost : CONSTANT Natural := 5 ; Goods_cost : CONSTANT Natural := 5 ; Coque_Cost : Natural := 25 ; Equipage_Cost : Natural := 25 ; Puissance_Cost : Natural := 25 ; Attaque_Cost : Natural := 2 ; Cuirasse_Cost : Natural := 25 ; Defense_Cost : Natural := 2 ; Vitesse_Cost : Natural := 25 ; Niveau : Natural := 1 ; Save_File_Name : unbounded_string := Null_unbounded_string ; PRIVATE PROCEDURE Reset(G : P_Random.Generator) RENAMES P_Random.Reset ; FUNCTION Random(G : P_Random.Generator) RETURN T_Pourcentage RENAMES P_Random.Random ; end P_Variables ; |
P_Variables.ads
1 2 3 4 5 6 7 8 9 10 11 12 13 | PACKAGE body P_Variables IS PROCEDURE Reset IS BEGIN Reset(Germe) ; END Reset ; FUNCTION Random RETURN T_Pourcentage IS BEGIN RETURN Random(Germe) ; END Random ; end P_Variables ; |
P_Variables.adb
P_Data
Comme dit précédemment, ce package sert à l'enregistrement et au chargement de parties enregistrées dans des fichiers texte. Bref, c'est du déjà-vu pour vous :
1 2 3 4 5 6 7 | WITH P_Navire ; USE P_Navire ; PACKAGE P_Data IS FUNCTION Load_Navire(File_Name : String) RETURN T_Navire'Class ; PROCEDURE Save_Navire(Navire : in T_Navire'class) ; end P_Data ; |
P_Data.ads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | WITH Ada.Text_IO ; USE Ada.Text_IO ; WITH Ada.Strings.Unbounded ; USE Ada.Strings.Unbounded ; WITH P_Variables ; USE P_Variables ; WITH P_Point ; USE P_Point ; PACKAGE BODY P_Data IS FUNCTION Load_Navire(File_Name : String) RETURN T_Navire'Class IS FUNCTION Value(F : File_type) RETURN Integer IS BEGIN RETURN Integer'Value(Get_Line(F)) ; END Value ; Navire : ACCESS T_Navire'Class ; F : File_Type ; BEGIN Open(F, In_File,"./data/" & File_Name & ".txt") ; CASE Value(F) IS WHEN 1 => Navire := NEW T_Warship ; WHEN 2 => Navire := NEW T_Tradeship ; WHEN 3 => Navire := NEW T_Pirate ; WHEN others => Navire := NEW T_Corsair ; END CASE ; Navire.nom := to_unbounded_string(get_line(F)) ; Navire.Coque := (Value(F),Value(F),0) ; Navire.Equipage := (Value(F),Value(F),0) ; Navire.Puissance := (Value(F),Value(F),0) ; Navire.Attaque := (Value(F),Value(F),0) ; Navire.Cuirasse := (Value(F),Value(F),0) ; Navire.Defense := (Value(F),Value(F),0) ; Navire.Vitesse := (Value(F),Value(F),0) ; Navire.Gold := Value(F) ; IF Navire.All IN T_Tradeship'Class THEN T_Tradeship(Navire.All).Stock := Value(F) ; END IF ; Coque_Cost := value(F) ; Equipage_Cost := value(F) ; Puissance_Cost := value(F) ; Attaque_Cost := value(F) ; Cuirasse_Cost := value(F) ; Defense_Cost := value(F) ; Vitesse_Cost := value(F) ; Close(F) ; RETURN Navire.All ; END Load_Navire ; PROCEDURE Save_Navire(Navire : in T_Navire'class) IS F : File_Type ; PROCEDURE Save_Stat(F : File_Type ; P : T_Point) IS BEGIN Put_Line(F,Integer'Image(P.Max)) ; Put_Line(F,Integer'Image(P.Current)) ; END Save_Stat ; BEGIN Create(F,Out_File,"./data/" & to_string(Save_File_Name) & ".txt") ; IF Navire IN T_Warship'Class THEN Put_Line(F,"1") ; ELSIF Navire IN T_Tradeship'Class THEN Put_Line(F,"2") ; ELSIF Navire IN T_Pirate'Class THEN Put_Line(F,"3") ; ELSIF Navire IN T_Corsair'Class THEN Put_Line(F,"4") ; END IF ; Put_Line (F, To_String(Navire.Nom)) ; Save_Stat(F, Navire.Coque) ; Save_Stat(F, Navire.Equipage) ; Save_Stat(F, Navire.Puissance) ; Save_Stat(F, Navire.Attaque) ; Save_Stat(F, Navire.Cuirasse) ; Save_Stat(F, Navire.Defense) ; Save_Stat(F, Navire.Vitesse) ; Put_Line (F, Integer'Image(Navire.Gold)) ; IF Navire IN T_Tradeship'Class THEN Put_Line(F, Integer'Image(T_Tradeship(Navire).Stock)) ; END IF ; Put_Line (F, Integer'Image(Coque_Cost)) ; Put_Line (F, Integer'Image(Equipage_Cost)) ; Put_Line (F, Integer'Image(Puissance_Cost)) ; Put_Line (F, Integer'Image(Attaque_Cost)) ; Put_Line (F, Integer'Image(Cuirasse_Cost)) ; Put_Line (F, Integer'Image(Defense_Cost)) ; Put_Line (F, Integer'Image(Vitesse_Cost)) ; Close(F) ; END Save_Navire ; END P_Data ; |
P_Data.adb
P_Screen
Package important : c'est là que se font tous les affichages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | WITH Nt_Console ; USE Nt_Console ; WITH P_Navire ; USE P_Navire ; WITH P_Point ; USE P_Point ; PACKAGE P_Screen IS TYPE T_Position IS (Gauche, Droite) ; PROCEDURE Put(N : Integer ; Color : Color_Type := Black ; X,Y : Integer := -1) ; PROCEDURE Print(Text : String ; Color : Color_Type := Black ; X,Y : Integer := -1) ; PROCEDURE Put_Title ; PROCEDURE Put_First_Menu(Indice : Natural := 1) ; PROCEDURE Put_Fight_Menu(Navire : T_Navire'Class ; Indice : Natural := 1) ; PROCEDURE Put_NextFight_Menu(Indice : Natural := 1) ; PROCEDURE Put_Status(Navire : T_Navire'class ; Pos : T_Position := Gauche) ; PROCEDURE Put_Point(Point : T_Point) ; PROCEDURE Put_Esquive_Message(Color : Color_Type := Green) ; PROCEDURE Put_Bombard_Message(Degats : Integer ; Color : Color_Type := Green) ; PROCEDURE Put_Abordage_Message(Degats : Integer ; Color : Color_Type := Green) ; PROCEDURE Put_Defense_Message(Color : Color_Type := Green) ; PROCEDURE Put_Manoeuvre_Message(color : color_type := green) ; PROCEDURE Put_Fuite_Message ; PROCEDURE Put_Gold(Navire : T_Navire'class ; X : X_Pos := 40 ; Y : Y_Pos := 16) ; PROCEDURE Put_Market_Menu1(Navire : T_Navire'Class ; Indice : Natural := 1) ; PROCEDURE Put_Market_Menu2(Indice : Natural := 1) ; PROCEDURE Put_Select_Menu1(Indice : Natural := 1) ; PROCEDURE Put_Select_Menu2(Indice : Natural := 1) ; end P_Screen ; |
P_Screen.ads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | WITH Ada.Text_IO ; USE Ada.Text_IO ; WITH P_Variables ; USE P_Variables ; with P_Navire.list ; use P_Navire.list ; WITH Ada.Strings.Unbounded ; USE Ada.Strings.Unbounded ; WITH Ada.Integer_Text_IO ; PACKAGE BODY P_Screen IS ----------------------------------------------------------- --AFFICHER UN ENTIER AVEC UNE COULEUR ET UN LIEU SPÉCIFIÉ-- ----------------------------------------------------------- PROCEDURE Put(N : Integer ; Color : Color_Type := black ; X,Y : Integer := -1) IS BEGIN IF X >= 0 AND Y >= 0 THEN Goto_Xy(X,Y) ; END IF ; Set_Foreground(Color) ; Set_BackGround(White) ; Ada.Integer_Text_IO.put(n,0) ; Set_Foreground(Black) ; end put ; ---------------------------------------------------------- --AFFICHER UN TEXTE AVEC UNE COULEUR ET UN LIEU SPÉCIFIÉ-- ---------------------------------------------------------- PROCEDURE Print(Text : String ; Color : Color_Type := Black ; X,Y : Integer := -1) IS BEGIN IF X >= 0 AND Y >= 0 THEN Goto_Xy(X,Y) ; END IF ; Set_Foreground(Color) ; Set_BackGround(White) ; FOR I IN Text'RANGE LOOP CASE Text(I) IS WHEN 'é' => Put(Character'Val(130)) ; WHEN 'â' => Put(Character'Val(131)) ; WHEN 'è' => Put(Character'Val(138)) ; WHEN OTHERS => Put(Text(I)) ; END CASE ; END LOOP ; Set_Foreground(Black) ; END Print ; ---------------------- --AFFICHAGE DU TITRE-- ---------------------- PROCEDURE Put_Title IS BEGIN goto_xy(0,0) ; set_background(white) ; Set_Foreground(light_red) ; Put_Line(" BATAILLE NAVALE") ; new_line ; Set_Foreground(black) ; END Put_Title; ----------------------------- --AFFICHAGE DU PREMIER MENU-- ----------------------------- PROCEDURE Put_First_Menu(Indice : Natural := 1) IS X : constant Natural := 9 ; Y : CONSTANT Natural := 4 ; color : color_type := blue ; BEGIN Print("Que souhaitez-vous faire ?",color,0,Y-1) ; FOR I IN 1..2 LOOP IF Indice=I THEN Color := Light_Red ; ELSE Color := Blue ; END IF ; CASE I IS WHEN 1 => Print("NOUVELLE PARTIE",Color,X,Y) ; WHEN 2 => Print("CHARGER UNE ANCIENNE PARTIE",Color,X+20,Y); END CASE ; END LOOP ; Goto_Xy(X+20*(Indice-1) + 10,Y+1) ; Set_Foreground(Light_Red) ; Put(Character'Val(30)) ; Set_Foreground(Black) ; END Put_First_Menu ; -------------------- --MENU DE BATAILLE-- -------------------- PROCEDURE Put_Fight_Menu(Navire : T_Navire'Class ; Indice : Natural:=1) IS X : constant Natural := 9 ; Y : constant Natural := 13 ; blank_line : constant string(1..80) := (others => ' ') ; BEGIN Goto_Xy(0,Y) ; put(blank_line) ; Goto_Xy(X,Y) ; IF Indice = 1 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; IF Navire IN T_Illegal'Class THEN Put("ABORDER ") ; END IF ; Goto_Xy(X+12,Y) ; IF Indice = 2 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; IF Navire IN T_Legal'Class THEN Put("BOMBARDER ") ; END IF ; Goto_Xy(X+24,Y) ; IF Indice = 3 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Put("DEFENDRE ") ; IF Indice = 4 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Put("MANOEUVRER ") ; IF Indice = 5 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Put("FUIR") ; Goto_Xy(0,Y+1) ; put(blank_line) ; Goto_Xy(X+4+12*(Indice-1),Y+1) ; Set_Foreground(Light_Red) ; put(character'val(30)) ; Set_Foreground(Black) ; END Put_Fight_Menu ; ------------------------- --MENU D'APRÈS BATAILLE-- ------------------------- PROCEDURE Put_NextFight_Menu(Indice : Natural := 1) IS X : constant Natural := 9 ; Y : CONSTANT Natural := 12 ; color : color_type := blue ; blank_line : constant string(1..80) := (others => ' ') ; BEGIN FOR I IN -2..+2 LOOP Goto_Xy(0,Y+I) ; Put(Blank_Line) ; END LOOP ; Print("Que souhaitez-vous faire désormais ?",color,0,Y) ; FOR I IN 1..3 LOOP IF Indice=I THEN Color := Light_Red ; ELSE Color := Blue ; END IF ; CASE I IS WHEN 1 => Print("DEBARQUER",Color,X,Y+1) ; WHEN 2 => Print("FAIRE VOILE",Color,X+20,Y+1); WHEN 3 => Print("PRENDRE LE LARGE",Color,X+40,Y+1) ; END CASE ; END LOOP ; Goto_Xy(X+20*(Indice-1) + 3,Y+2) ; Set_Foreground(Light_Red) ; Put(Character'Val(30)) ; set_foreground(black) ; END Put_Nextfight_Menu ; ----------------------------------- --AFFICHAGE DU STATUS D'UN BATEAU-- ----------------------------------- PROCEDURE Put_Status(Navire : T_Navire'class ; Pos : T_Position := Gauche) is X : Natural ; y : constant natural := 15 ; BEGIN IF Pos = Gauche THEN X:= 0 ; ELSE X:= 39 ; END IF ; set_background(white) ; print(" " & to_string(Navire.nom), black, x, y) ; Set_Foreground(Light_Red) ; Goto_Xy(X,Y+1) ; Put(" " & Character'Val(2) & " ") ; put_point(Navire.coque) ; Set_Foreground(Green) ; Goto_Xy(X,Y+2) ; Put(" " & Character'Val(3) & " ") ; Put_Point(Navire.Equipage) ; Goto_Xy(X,Y+3) ; Put("Psce:") ; Put_Point(Navire.Puissance) ; Goto_Xy(X,Y+4) ; Put("Attq:") ; Put_Point(Navire.Attaque) ; Goto_Xy(X,Y+5) ; Put("Cuir:") ; Put_Point(Navire.Cuirasse) ; Goto_Xy(X,Y+6) ; Put("Dfns:") ; Put_Point(Navire.Defense) ; Goto_Xy(X,Y+7) ; Put("Vits:") ; Put_Point(Navire.Vitesse) ; END Put_Status ; ------------------------- --AFFICHAGE DU TYPE X/Y-- ------------------------- PROCEDURE Put_Point(Point : T_Point) IS BEGIN IF Point.Current <= Point.Max / 4 THEN Put(Point.Current,Light_Red) ; ELSE Put(Point.Current) ; END IF ; Put('/') ; Put(Point.Max) ; IF Point.Bonus > 0 THEN Put('+') ; Put(Point.Bonus) ; END IF ; END Put_Point ; --------------------------------- --AFFICHAGE DES MESSAGES DU JEU-- --------------------------------- PROCEDURE Put_Esquive_Message(color : color_type := green) IS BEGIN goto_xy(0,11) ; IF Color = Green THEN set_foreground(green) ; Put("Vous avez esquiv"& character'val(130) &" l'attaque adverse !") ; Set_Foreground(Black) ; ELSE Set_Foreground(light_Red) ; Put("L'adversaire a esquiv"& character'val(130) &" votre attaque !") ; Set_Foreground(Black) ; END IF ; delay message_time ; END Put_Esquive_Message ; PROCEDURE Put_Bombard_Message(Degats : Integer ; Color : Color_Type := Green) IS BEGIN Goto_Xy(0,11) ; set_foreground(black) ; IF Color = Green THEN Put("Votre bombardement a caus"& Character'Val(130) & " ") ; Put(degats,green) ; put(" points de d"& Character'Val(130) &"g"& Character'Val(131) &"ts") ; ELSE Put("Le bombardement ennemi a caus"& Character'Val(130) & " ") ; Put(degats,light_red) ; put(" points de d"& Character'Val(130) &"g"& Character'Val(131) &"ts") ; END IF ; DELAY message_time ; END Put_Bombard_Message ; PROCEDURE Put_Abordage_Message(Degats : Integer ; Color : Color_Type := Green) IS BEGIN Goto_Xy(0,11) ; set_foreground(black) ; IF Color = Green THEN Put("Votre abordage a tu"& Character'Val(130) & " ") ; Put(degats,green) ; put(" marins ennemis") ; ELSE Put("L'abordage ennemi a tu"& Character'Val(130) & " ") ; Put(degats,light_red) ; put(" de vos marins") ; END IF ; DELAY message_time ; END Put_Abordage_Message ; PROCEDURE Put_Defense_Message(color : color_type := green) IS BEGIN goto_xy(0,11) ; IF Color = Green THEN set_foreground(green) ; Put("Vos hommes se pr"& character'val(130) &"parent "& character'val(133) &" l'abordage !") ; Set_Foreground(Black) ; ELSE Set_Foreground(light_Red) ; Put("L'ennemi se pr"& character'val(130) &"pare "& character'val(133) &" l'abordage !") ; Set_Foreground(Black) ; END IF ; delay Message_time ; END Put_Defense_Message ; PROCEDURE Put_Manoeuvre_Message(color : color_type := green) IS BEGIN goto_xy(0,11) ; IF Color = Green THEN set_foreground(green) ; Put("Votre navire se place sous le vent !") ; Set_Foreground(Black) ; ELSE Set_Foreground(light_Red) ; Put("Le navire ennemi se place sous le vent !") ; Set_Foreground(Black) ; END IF ; delay Message_time ; END Put_Manoeuvre_Message ; PROCEDURE Put_Fuite_Message IS BEGIN goto_xy(0,11) ; Set_Foreground(light_Red) ; Put("Vous fuyez devant l'adversit" & character'val(130) & " !") ; Set_Foreground(Black) ; delay Message_time ; END Put_Fuite_Message ; -------------------------------- --AFFICHAGE DES MENUS DU MARCHÉ-- -------------------------------- PROCEDURE Put_Gold(Navire : T_Navire'class ; X : X_Pos := 40 ; Y : Y_Pos := 16) IS blank_line : constant string(1..80 - X) := (others => ' ') ; BEGIN Goto_Xy(X,Y) ; Put(Blank_Line) ; Goto_Xy(X,Y) ; set_foreground(black) ; Put("Or : ") ; IF Navire.Gold = 0 THEN Set_Foreground(Light_Red) ; END IF ; Put(Integer'Image(Navire.Gold)) ; Set_Foreground(Black) ; END Put_Gold ; PROCEDURE Put_Market_Menu1(Navire : T_Navire'Class ; Indice : Natural := 1) IS X : constant Natural := 9 ; Y : constant Natural := 13 ; blank_line : constant string(1..80) := (others => ' ') ; BEGIN Goto_Xy(0,Y-1) ; Put(Blank_Line) ; Goto_Xy(0,Y) ; put(blank_line) ; IF Indice = 1 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Goto_Xy(X,Y-1) ; Put("PRENDRE") ; Goto_xy(X,Y) ; Put("LA MER") ; IF Indice = 2 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Goto_Xy(X+12,Y-1) ; Put("REPARER") ; Goto_xy(x+12,Y) ; Put("(" & integer'image((Navire.coque.max - Navire.coque.current) * Repair_cost) &")") ; IF Indice = 3 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Goto_Xy(X+24,Y-1) ; Put("RECRUTER") ; Goto_xy(x+24,Y) ; Put("(" & integer'image((Navire.Equipage.max - Navire.Equipage.current) * Recrute_cost) &")") ; IF Indice = 4 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Goto_Xy(X+36,Y-1) ; Put("ACHETER ") ; IF Indice = 5 THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; IF Navire IN T_Tradeship'Class THEN Goto_Xy(X+48,Y-1) ; Put(" VENDRE") ; Goto_xy(X+50,Y) ; Put("(" & integer'image(T_Tradeship(Navire).stock * Goods_cost) &")") ; END IF ; Goto_Xy(0,Y+1) ; put(blank_line) ; Goto_Xy(X+4+12*(Indice-1),Y+1) ; Set_Foreground(Light_Red) ; put(character'val(30)) ; Set_Foreground(Black) ; END Put_Market_Menu1 ; PROCEDURE Put_Market_Menu2(Indice : Natural := 1) IS X : constant Natural := 35 ; Y : constant Natural := 12 ; blank_line : constant string(1..80) := (others => ' ') ; BEGIN FOR I IN 1..7 LOOP IF Indice = I THEN Set_Foreground(Light_Red) ; ELSE Set_Foreground(Blue) ; END IF ; Goto_Xy(0,Y-I) ; Put(Blank_Line) ; Goto_Xy(X,Y-I) ; CASE I IS WHEN 1 => Put("Gouvernail (" & integer'image(Vitesse_cost) & ") + 1 Vitesse") ; WHEN 2 => Put("Boucliers (" & integer'image(Defense_cost) & "/marin) + 1 Defense") ; WHEN 3 => Put("Blindage (" & integer'image(Cuirasse_cost) & ") + 1 Cuirasse") ; WHEN 4 => Put("Sabres (" & integer'image(Attaque_cost) & "/marin) + 1 Attaque") ; WHEN 5 => Put("Cannons (" & integer'image(Puissance_cost) & ") + 1 Puissance") ; WHEN 6 => Put("Couchettes (" & integer'image(Equipage_cost) & ") + 2 Equipage"); WHEN 7 => Put("Planches (" & integer'image(Coque_cost) & ") + 2 Coque") ; END CASE ; END LOOP ; Goto_Xy(X-2,Y-Indice) ; Set_Foreground(Light_Red) ; put(character'val(26)) ; Set_Foreground(Black) ; END Put_Market_Menu2 ; PROCEDURE Put_Select_Menu1(Indice : Natural := 1) IS BEGIN FOR I IN 1..4 LOOP IF Indice = I THEN set_foreground(Light_Red) ; Goto_Xy(0,I+3) ; put(character'val(26)) ; ELSE set_foreground(Blue) ; END IF ; goto_xy(2,I+3) ; CASE I IS WHEN 1 => put("Navire de guerre") ; WHEN 2 => put("Navire marchand") ; WHEN 3 => put("Pirate") ; WHEN 4 => Put("Corsaire") ; END CASE ; END LOOP ; set_foreground(black) ; END Put_Select_Menu1 ; PROCEDURE Put_Select_Menu2(Indice : Natural := 1) IS color : color_type ; BEGIN FOR I IN Liste_Navire'range LOOP IF Indice = I THEN color := Light_Red ; print("" & character'val(26),color,20,I+3) ; ELSE Color := Blue ; print(" ",color,20,I+3) ; END IF ; print(to_string(Liste_navire(i).nom),color,22,i+3) ; END LOOP ; set_foreground(black) ; END Put_Select_Menu2 ; end P_Screen ; |
P_Screen.adb
P_Modes
Et enfin, le cœur du jeu : P_Mode. C'est dans ce dernier package que sont gérés les touches du clavier et la réaction à adopter.
1 2 3 4 5 6 7 8 9 10 11 12 | WITH P_Navire ; USE P_Navire ; PACKAGE P_Modes IS FUNCTION First_Mode RETURN T_Navire'Class ; PROCEDURE Fight_Mode (Joueur : IN OUT T_Navire'Class) ; FUNCTION NextFight_Mode RETURN natural ; PROCEDURE Market_Mode(Joueur : IN OUT T_Navire'Class) ; PROCEDURE Buy_Mode(Joueur : IN OUT T_Navire'Class) ; FUNCTION Select_Mode RETURN T_Navire'class ; END P_Modes ; |
P_Modes.ads
Le nombre de procédures et fonctions est restreint : First_Mode()
gère le tout premier menu pour choisir entre une nouvelle ou une ancienne partie ; en cas de nouvelle partie, il lancera Select_Mode()
qui permet au joueur de choisir son navire et sa classe (marchand, pirate…) ; puis il accède au menu du marché, Market_Mode()
qui est le principal menu (c'est de là que se font les sauvegardes en appuyant sur Echap, les achats avec Buy_Mode()
, les ventes, les réparations ou le départ en mer avec Fight_Mode()
) ; enfin, NextFight_Mode()
gère un menu proposant au joueur de rentrer au port ou de continuer son aventure à la fin de chaque combat.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | WITH Ada.Text_IO ; USE Ada.Text_IO ; WITH Ada.Strings.Unbounded ; USE Ada.Strings.Unbounded ; WITH Nt_Console ; USE Nt_Console ; WITH P_Screen ; USE P_Screen ; WITH P_Variables ; USE P_Variables ; WITH P_Navire.List ; USE P_Navire.List ; WITH P_Data ; USE P_Data ; PACKAGE BODY P_Modes IS FUNCTION First_Mode RETURN T_Navire'Class IS Position : Natural := 1 ; touche : character ; BEGIN Main_Loop : LOOP Clear_Screen(White) ; Put_Title ; Put_First_Menu(Position) ; Touche := Get_Key ; IF Character'Pos(Touche) = 75 AND Position = 2 --TOUCHE GAUCHE THEN Position := 1 ; ELSIF Character'Pos(Touche) = 77 AND Position = 1 --TOUCHE DROITE THEN Position := 2 ; END IF ; IF Character'Pos(Touche) = 13 THEN Print("Entrez le nom du fichier :",Blue,0,6) ; Save_File_Name := To_Unbounded_String(Get_Line) ; IF Position = 1 THEN RETURN Select_Mode ; ELSIF Position = 2 THEN RETURN Load_Navire(To_string(save_file_name)) ; END IF ; END IF ; END LOOP Main_loop ; END First_Mode ; PROCEDURE Fight_Mode(Joueur : IN OUT T_Navire'Class) IS Touche : Character ; Position : Natural := 4 ; N : T_Pourcentage ; Ordi : T_Navire'Class := generer_ennemi(Niveau) ; BEGIN Main_loop : LOOP Raz_bonus(Joueur) ; Clear_Screen(White) ; Put_Title ; Put_Status(Joueur,Gauche) ; Put_Status(Ordi,Droite) ; IF Joueur.Est_Mort THEN Joueur.Perd ; EXIT ; END IF ; ------------------------ -- TOUR JOUEUR HUMAIN -- ------------------------ LOOP Put_Fight_Menu(Joueur,Position) ; Touche := Get_Key ; --touche gauche IF Character'Pos(Touche) = 75 THEN IF Position = 1 OR (Position = 2 AND Joueur NOT IN T_Illegal'Class) THEN NULL ; ELSIF Position = 3 AND Joueur NOT IN T_Legal'Class THEN Position := Position - 2 ; ELSE Position := Position - 1 ; END IF ; END IF ; --touche droite IF Character'Pos(Touche) = 77 and position < 5 THEN IF Position = 1 AND Joueur NOT IN T_Legal'Class THEN Position := Position + 2 ; ELSE Position := Position + 1 ; END IF ; END IF ; --touche entrée IF Character'Pos(Touche) = 13 THEN CASE Position IS WHEN 1 => Joueur.Aborde(Ordi) ; WHEN 2 => joueur.bombarde(ordi) ; WHEN 3 => joueur.defend ; WHEN 4 => joueur.manoeuvre ; WHEN OTHERS => put_fuite_message ; exit Main_loop ; END CASE ; EXIT ; END IF ; END LOOP ; --------------------- -- TOUR ORDINATEUR -- --------------------- Raz_bonus(Ordi) ; Clear_Screen(White) ; Put_Title ; Put_Status(Joueur,Gauche) ; Put_Status(Ordi,Droite) ; IF Ordi.Est_Mort THEN Joueur.Bat(Ordi) ; EXIT ; END IF ; N := Random ; IF N >= 90 THEN Ordi.Manoeuvre ; ELSIF N>=80 THEN Ordi.Defend ; ELSIF Ordi IN T_Legal'Class AND Ordi IN T_Illegal'Class THEN IF N mod 2 = 0 THEN Ordi.Bombarde(Joueur) ; ELSE Ordi.Aborde(Joueur) ; END IF ; ELSIF Ordi IN T_Legal'Class THEN Ordi.Bombarde(Joueur) ; else ordi.aborde(joueur) ; END IF ; END LOOP Main_loop ; END Fight_Mode ; FUNCTION NextFight_Mode RETURN natural IS Position : Natural := 1 ; touche : character ; BEGIN LOOP Put_NextFight_Menu(position) ; Touche := Get_Key ; --TOUCHE GAUCHE IF Character'Pos(Touche) = 75 AND Position > 1 THEN Position := Position - 1 ; END IF ; --TOUCHE DROITE IF Character'Pos(Touche) = 77 AND Position < 3 THEN Position := Position + 1 ; END IF ; IF Character'Pos(Touche) = 13 OR Character'Pos(Touche) = 72 THEN CASE Position IS WHEN 1 => Niveau := 1 ; WHEN 3 => Niveau := Niveau + 1 ; WHEN OTHERS => null ; END CASE ; RETURN Position ; END IF ; END LOOP ; END NextFight_Mode ; PROCEDURE Market_Mode(Joueur : IN OUT T_Navire'Class) IS Position : Natural := 1 ; Touche : character ; BEGIN Main_Loop : LOOP Raz_bonus(Joueur) ; Clear_Screen(White) ; Put_Title ; Put_Status(Joueur,Gauche) ; Put_Gold(joueur) ; LOOP Put_Market_Menu1(Joueur,Position) ; Touche := Get_Key ; --touche gauche IF Character'Pos(Touche) = 75 and position > 1 THEN Position := Position - 1 ; END IF ; --touche droite IF Character'Pos(Touche) = 77 and ((Joueur in T_Tradeship'class and position = 4) or position < 4) THEN Position := Position + 1 ; END IF ; --touche echap IF Character'Pos(Touche) = 27 THEN Save_Navire(Joueur) ; Print("Fichier sauvegardé sous " & To_String(Save_File_Name) & ".txt",Red,0,24) ; bleep ; EXIT Main_Loop ; END IF; --touche entrée IF Character'Pos(Touche) = 13 or Character'Pos(Touche) = 72 THEN CASE Position IS WHEN 1 => Fight_loop : loop Fight_Mode(Joueur) ; IF Joueur.Est_Mort THEN touche := get_key ; EXIT Main_Loop ; ELSE EXIT Fight_loop WHEN NextFight_Mode = 1 ; END IF ; END LOOP Fight_Loop ; WHEN 2 => Joueur.reparer ; WHEN 3 => Joueur.recruter ; WHEN 4 => Buy_Mode(joueur) ; WHEN OTHERS => T_Tradeship(Joueur).vendre ; END CASE ; EXIT ; END IF ; END LOOP ; END LOOP Main_loop ; END Market_Mode ; PROCEDURE Buy_Mode(Joueur : IN OUT T_Navire'Class) IS Position : Natural := 1 ; Touche : character ; BEGIN while position > 0 LOOP Put_Market_Menu2(Position) ; Touche := Get_Key ; --touche haut IF Character'Pos(Touche) = 72 and position < 7 THEN Position := Position + 1 ; END IF ; --touche bas IF Character'Pos(Touche) = 80 and position > 0 THEN Position := Position - 1 ; END IF ; --touche gauche ou droite IF Character'Pos(Touche) = 75 or Character'Pos(Touche) = 77 THEN Position := 0 ; END IF ; --touche entrée IF Character'Pos(Touche) = 13 THEN CASE Position IS WHEN 1 => Joueur.Ameliorer_vitesse ; WHEN 2 => Joueur.Ameliorer_defense ; WHEN 3 => Joueur.Ameliorer_cuirasse ; WHEN 4 => Joueur.Ameliorer_attaque ; WHEN 5 => Joueur.Ameliorer_puissance ; WHEN 6 => Joueur.Ameliorer_equipage ; when 7 => Joueur.Ameliorer_coque ; WHEN OTHERS => null ; END CASE ; Put_Gold(joueur) ; Put_Status(Joueur,Gauche) ; END IF ; END LOOP ; END Buy_Mode ; FUNCTION Select_Mode RETURN T_Navire'Class IS Navire : ACCESS T_Navire'Class ; Pos1,Pos2 : Natural := 1 ; touche : character ; BEGIN Main_Loop : LOOP Menu1 : LOOP Clear_Screen(White) ; Put_Title ; Put_Select_Menu1(Pos1) ; Touche := Get_Key ; --touche haut IF Character'Pos(Touche) = 72 and pos1 > 1 THEN pos1 := pos1 - 1 ; END IF ; --touche bas IF Character'Pos(Touche) = 80 and pos1 < 4 THEN pos1 := pos1 + 1 ; END IF ; --touche entrée ou droite IF Character'Pos(Touche) = 13 or Character'Pos(Touche) = 77 THEN bleep ; EXIT Menu1 ; END IF; END LOOP Menu1 ; Menu2 : LOOP Put_Select_Menu2(Pos2) ; Touche := Get_Key ; --touche haut IF Character'Pos(Touche) = 72 and pos2 > 1 THEN pos2 := pos2 - 1 ; END IF ; --touche bas IF Character'Pos(Touche) = 80 and pos2 < Liste_Navire'length THEN pos2 := pos2 + 1 ; END IF ; --touche entrée ou droite IF Character'Pos(Touche) = 13 or Character'Pos(Touche) = 77 THEN bleep ; EXIT Main_Loop ; END IF; IF Character'Pos(Touche) = 75 THEN EXIT Menu2 ; END IF; END LOOP Menu2 ; END LOOP Main_loop ; CASE Pos1 IS WHEN 1 => Navire := NEW T_Warship'(Init(Liste_Navire(Pos2).nom, Liste_Navire(Pos2).stat)) ; WHEN 2 => Navire := NEW T_Tradeship'(Init(Liste_Navire(Pos2).nom, Liste_Navire(Pos2).stat)) ; WHEN 3 => Navire := NEW T_Pirate'(Init(Liste_Navire(Pos2).nom, Liste_Navire(Pos2).stat)) ; WHEN others => Navire := NEW T_Corsair'(Init(Liste_Navire(Pos2).nom, Liste_Navire(Pos2).stat)) ; END CASE ; Navire.Playable := True ; Navire.Gold := 100 ; return Navire.all ; END Select_Mode ; END P_Modes ; |
P_Modes.adb
Pistes d'amélioration :
- Ajouter un écran affichant les meilleurs scores obtenus, les navires les plus puissants, les plus riches, les plus peuplés…
- Ajouter une nationalité à votre navire (français, anglais, portugais, hollandais, espagnol, pirate…) ajoutant de nouveaux bonus/malus ou proposant des navires spécifiques.
- Vous pouvez également approfondir le système de jeu en proposant de personnaliser les armes (grappins, filets, sabres, lances, petits ou gros cannons…) ou les manœuvres, ou encore de changer pour un navire plus performant.
- Pourquoi ne pas proposer un jeu en deux temps : des phases de bataille navale (ce que vous venez de créer) et des phases d'exploration où le joueur devrait déplacer son navire sur une carte.