9002aa6d0d17facf39818408e607e2717bbf3da8
[sdk] / installer / coursework / Chapter 6 - Classes, Methods and Instances / Lab6 / lab6.ec
1 import "ecere"
2 #include <stdio.h>
3
4 class Spell
5 {
6 public:
7    int difficulty;
8    int damage;
9    int manaCost;
10
11    virtual void Backfire(Creature self, Creature opponent)
12    {
13       self.health -= damage/4;
14    }
15
16    virtual void Success(Creature self, Creature opponent)
17    {
18       if(damage > opponent.health) damage = opponent.health;
19       PrintLn(self._class.name, " did ", damage, " damage to ", opponent._class.name, ".");
20       opponent.health -= damage;
21    }
22 }
23
24 class FireBall : Spell { difficulty = 20, damage = 8; manaCost = 5; };
25 class Lightning : Spell  { difficulty = 10, damage = 4; manaCost = 3; };
26 class Healing : Spell
27 {
28    difficulty = 20;
29    manaCost = 5;
30    void Success(Creature self, Creature opponent)
31    {
32       self.health += self.maxHealth / 5;
33       if(self.health > self.maxHealth) self.health = self.maxHealth;
34    }
35
36    void Backfire(Creature self, Creature opponent)
37    {
38       self.health -= damage/4;
39    }
40 };
41
42 class Creature
43 {
44 public:
45    int xp;
46    int health, maxHealth;
47    int mana, maxMana;
48    int dexterity;
49    int magic;
50    int strength;
51    int gold;
52    Array<Spell> spells;
53    Array<Equipment> equipment;
54
55    void CastSpell(Spell spell, Creature opponent)
56    {
57       if(mana >= spell.manaCost)
58       {
59          int r = GetRandom(0, spell.difficulty);
60          mana -= spell.manaCost;
61          if(magic >= r)
62          {
63             PrintLn(_class.name, " cast ", spell._class.name, " successfully.");
64             spell.Success(this, opponent);
65          }
66          else if(r > magic * 2)
67          {
68             PrintLn(_class.name, "'s ", spell._class.name, " backfired.");
69             spell.Backfire(this, opponent);
70          }
71          else
72             PrintLn(_class.name, " unsucessfully cast ", spell._class.name, ".");
73       }
74    }
75
76    void Attack(Creature opponent)
77    {
78       Weapon weapon = (Weapon)(equipment ? equipment[EquipmentSlot::rightHand] : null);
79       int d, r, o;
80       if(!weapon) weapon = bareHand;
81       o = GetRandom(0, opponent.dexterity);
82       d = GetRandom(0, dexterity - weapon.difficulty);
83       if(d > o)
84       {
85          int d = GetRandom(1, strength);
86          int where = GetRandom(0, 100);
87          int armor = 0;
88          int howBad = 0;
89          EquipmentSlot slot;
90          int damage;
91
92          if(where < 60)
93          {
94             slot = body;
95             howBad = 2;
96          }
97          else if(where < 80)
98          {
99             slot = head;
100             howBad = 3;
101          }
102          else if(where < 95)
103          {
104             slot = legs;
105             howBad = 1;
106          }
107          else
108          {
109             slot = feet;
110             howBad = 1;
111          }
112          if(opponent.equipment && opponent.equipment[slot])
113             armor = ((Armor)opponent.equipment[slot]).decDamage;
114          damage = Max(1, (d * weapon.damage - armor) * howBad / 10);
115          if(damage > opponent.health) damage = opponent.health;
116          opponent.health -= damage;
117          PrintLn(_class.name, " did ", damage, " damage to ", opponent._class.name, ".");
118       }
119       else
120          PrintLn(_class.name, " missed.");
121    }
122 }
123
124 Weapon bareHand { difficulty = 3, damage = 1 };
125
126 enum EquipmentSlot { leftHand, rightHand, head, feet, body, legs, ring, ring2, ring3, ring4 };
127
128 class Equipment
129 {
130 public:
131    /*int modMagic;
132    int modHealth;
133    int modDexterity;*/
134    int value;
135    EquipmentSlot slot;
136    bool twoHands;
137
138    virtual void Show();
139 }
140
141 class Armor : Equipment
142 {
143 public:
144    int decDamage;
145
146    void Show()
147    {
148       Print("Damage -", decDamage);
149    }
150 }
151
152 class Weapon : Equipment
153 {
154 public:
155    int difficulty;
156    int damage;
157
158    void Show()
159    {
160       Print("Difficulty: ", difficulty, ", Damage +", damage);
161    }
162 }
163
164 class LightShield : Armor { decDamage = 2; slot = leftHand; value = 20; };
165 class HeavyShield : Armor { decDamage = 5; slot = leftHand; value = 100; };
166 class Helmet      : Armor { decDamage = 5; slot = head; value = 60; };
167 class SteelBoots  : Armor { decDamage = 2; slot = feet; value = 40; };
168 class LightArmor  : Armor { decDamage = 4; slot = body; value = 40; };
169 class PlateArmor  : Armor { decDamage = 8; slot = body; value = 150; };
170 class PlateLeggings : Armor { decDamage = 3; slot = legs; value = 50; };
171
172 class Dagger      : Weapon { difficulty = 2, damage = 2, value  = 10, slot = rightHand; };
173 class LongSword   : Weapon { difficulty = 4, damage = 4, value  = 40, slot = rightHand; };
174 class BattleSword : Weapon { difficulty = 8, damage = 10, value = 100, slot = rightHand, twoHands = true; };
175
176 class Slug           : Creature { xp = 10;  maxHealth = 10;  dexterity = 7; strength = 5; gold = 1; }
177 class GiantRat       : Creature { xp = 30;  maxHealth = 20;  dexterity = 9; strength = 8; gold = 3; }
178 class GiantSpider    : Creature { xp = 50;  maxHealth = 30;  dexterity = 20; strength = 10; gold = 4; }
179 class Bat            : Creature { xp = 70;  maxHealth = 10;  dexterity = 40; strength = 5; gold = 6; }
180 class Goblin         : Creature
181 {
182    xp = 120; maxHealth = 50;  dexterity = 50; strength = 25; gold = 10;
183 }
184 class Ghoul          : Creature { xp = 250; maxHealth = 70;  dexterity = 20; strength = 30; gold = 30; }
185 class DarkKnight     : Creature
186 {
187    xp = 500; maxHealth = 100; dexterity = 50; strength = 50; gold = 50; magic = 30; maxMana = 50;
188    spells = { [ FireBall { } ] };
189    equipment = { [ HeavyShield { }, LongSword { }, Helmet { }, SteelBoots { }, PlateArmor { }, PlateLeggings { }, null, null, null, null ] };
190 };
191
192 Array<Class> badGuys { [ class(Slug), class(GiantRat), class(GiantSpider), class(Goblin), class(Bat), class(DarkKnight), class(Ghoul) ] };
193
194 class EvilSorcerer   : Creature
195 {
196    xp = 1000; maxHealth = 1000; dexterity = 75; strength = 50; gold = 20000; magic = 50; maxMana = 500;
197    equipment = { [ HeavyShield { }, LongSword { }, Helmet { }, SteelBoots { }, PlateArmor { }, PlateLeggings { }, null, null, null, null ] };
198    spells = { [ FireBall { }, Lightning { }, Healing { } ] };
199 }
200
201 Array<Equipment> shopInventory
202 {
203    [
204       Dagger { },
205       LongSword { },
206       BattleSword { },
207
208       LightShield { },
209       HeavyShield { },
210       Helmet { },
211       SteelBoots { },
212       LightArmor { },
213       PlateArmor { },
214       PlateLeggings { }
215    ]
216 };
217
218 enum GameState { realm, shop, fight, training, sorcerer, end };
219
220 class Player : Creature
221 {
222 public:
223    int manaPotions;
224    int healthPotions;
225    int training;
226    spells = { [ FireBall { }, Lightning { }, Healing { } ] };
227    equipment = { [ null, null, null, null, null, null, null, null, null, null ] };
228 }
229
230 Player player { xp = 0, maxHealth = 40, health = 40, mana = 20, maxMana = 20, magic = 10, strength = 10, dexterity = 10, gold = 50, training = 2 };
231 Creature opponent;
232
233 class RPGApp : Application
234 {
235    GameState state;
236    char command[1024];
237
238    void PrintStatus()
239    {
240       PrintLn("");
241       switch(state)
242       {
243          case sorcerer:
244          case fight:
245             PrintLn("You are fighting a ", opponent._class.name);
246             PrintLn(opponent._class.name, "'s Health: ", opponent.health, "/",opponent.maxHealth);
247             PrintLn("Your Health: ", player.health, "/", player.maxHealth, ", Mana: ", player.mana, "/",player.maxMana);
248             PrintLn("[A]ttack");
249             PrintLn("[R]un");
250             if(player.healthPotions)
251                PrintLn("[H]ealth potion");
252             if(player.manaPotions)
253                PrintLn("[M]ana potion");
254             if(player.spells.count)
255             {
256                int n = 1;
257                PrintLn("Cast a spell:");
258                for(s : player.spells)
259                   PrintLn("   ", n++, ". ", s._class.name);
260             }
261             break;
262          case shop:
263          {
264             int n = 1;
265             PrintLn("Welcome to the village shop! What could we interest you in?");
266             PrintLn("   [H]ealth potions (10)  [M]ana potions (15)  Go [B]ack to the realm");
267             PrintLn("   You have ", player.gold, " gold coins");
268             for(i : shopInventory)
269             {
270                Print("   ", n++, ". ", i._class.name, ": ");
271                i.Show();
272                PrintLn(" (", i.value, ")");
273             }
274             break;
275          }
276          case realm:
277             PrintLn("You are wandering in the realm. What would you like to do?");
278             PrintLn("[F]ight bad guys   Visit the [S]hop   [R]est     St[a]ts");
279             if(player.xp >= 1000)
280                PrintLn("Are you ready to rescue the [P]rincess?");
281             if(player.training)
282                PrintLn("Do you want to [T]rain? You have ", player.training, " training points.");
283             break;
284          case training:
285             PrintLn("You have ", player.training, " training points. What would you like to improve?");
286             PrintLn("[H]ealth");
287             PrintLn("[M]ana");
288             PrintLn("[S]trength");
289             PrintLn("[D]exterity");
290             PrintLn("Ma[g]ic");
291             PrintLn("   Go [B]ack to the realm");
292             break;
293       }
294    }
295
296    void GetCommand()
297    {
298       gets(command);
299       strlwr(command);
300    }
301    bool AreYouSure()
302    {
303       char input[1024];
304       gets(input);
305       strlwr(command);
306       return input[0] == 'y';
307    }
308
309    void OpponentAttacks()
310    {
311       if(opponent.health > 0 && player.health > 0)
312       {
313          if(opponent.spells && opponent.spells.count && opponent.mana > opponent.maxMana / 5)
314          {
315             if(GetRandom(0,1) == 1)
316             {
317                int s = GetRandom(0, opponent.spells.count-1);
318                if(opponent.mana >= opponent.spells[s].manaCost)
319                   opponent.CastSpell(opponent.spells[s], player);
320                else
321                   opponent.Attack(player);
322             }
323             else
324                opponent.Attack(player);
325          }
326          else
327             opponent.Attack(player);
328       }
329       if(player.health <= 0)
330       {
331          PrintLn("You died :(");
332          state = end;
333       }
334       else if(opponent.health <= 0)
335       {
336          int trainingPointsBefore = player.xp / 50;
337          PrintLn("Congratulations! You won the fight. You gained ", opponent.xp/10, " xp points and ", opponent.gold, " gold.");
338          player.gold += opponent.gold;
339          player.xp += opponent.xp / 10;
340          player.training += player.xp / 50 - trainingPointsBefore;
341          delete opponent;
342          if(state == sorcerer)
343             PrintLn("You saved the princess!! The end.");
344          state = realm;
345       }
346    }
347
348    void FindOpponent()
349    {
350       while(true)
351       {
352          int c = GetRandom(0, badGuys.count-1);
353          opponent = eInstance_New(badGuys[c]);
354          if(opponent.xp < 40 || opponent.xp <= player.xp)
355             break;
356          delete opponent;
357       }
358       opponent.health = opponent.maxHealth;
359       opponent.mana = opponent.maxMana;
360       state = fight;
361    }
362
363    void ProcessCommand()
364    {
365       if(command[0] == 'q')
366       {
367          PrintLn("Are you sure you want to quit?");
368          if(AreYouSure())
369             state = end;
370       }
371       switch(state)
372       {
373          case shop:
374             switch(command[0])
375             {
376                case 'b': state = realm; break;
377                case 'm': case 'h':
378                {
379                   int price = (command[0] == 'm') ? 15 : 10;
380                   if(player.gold < price)
381                      PrintLn("You do not have enough gold!");
382                   else
383                   {
384                      (command[0] == 'm') ? player.manaPotions++ : player.healthPotions++;
385                      player.gold -= price;
386                   }
387                   break;
388                }
389                default:
390                {
391                   int item = atoi(command);
392                   if(item && item <= shopInventory.count)
393                   {
394                      Equipment eq = shopInventory[item-1];
395                      EquipmentSlot slot = eq.slot;
396                      int tradeIn;
397                      Equipment tradeIn1 = null, tradeIn2 = null;
398                      if(slot == ring)
399                         while(player.equipment[slot] && slot < ring4)
400                            slot++;
401
402                      if(slot == rightHand && eq.twoHands)
403                      {
404                         if(player.equipment[EquipmentSlot::leftHand])
405                            tradeIn1 = player.equipment[EquipmentSlot::leftHand];
406                         if(player.equipment[EquipmentSlot::rightHand])
407                            tradeIn2 = player.equipment[EquipmentSlot::rightHand];
408                      }
409                      else if((slot == leftHand || slot == rightHand) && player.equipment[EquipmentSlot::rightHand] && player.equipment[EquipmentSlot::rightHand].twoHands)
410                      {
411                         if(player.equipment[EquipmentSlot::rightHand])
412                            tradeIn1 = player.equipment[EquipmentSlot::rightHand];
413                      }
414                      else if(player.equipment[slot])
415                         tradeIn1 = player.equipment[slot];
416
417                      tradeIn = ((tradeIn1 ? tradeIn1.value : 0) + (tradeIn2 ? tradeIn2.value : 0)) / 2;
418                      if(player.gold + tradeIn < eq.value)
419                         PrintLn("You do not have enough gold!");
420                      else
421                      {
422                         if(player.equipment[slot])
423                            PrintLn("You will need to trade in your ", player.equipment[slot]._class.name, ", for ", tradeIn, ".");
424
425                         PrintLn("Are you sure you want to buy this ", eq._class.name, " for ", eq.value, "?");
426                         if(AreYouSure())
427                         {
428                            if(tradeIn1) shopInventory.Add(tradeIn1);
429                            if(tradeIn2) shopInventory.Add(tradeIn2);
430                            player.equipment[slot] = eq;
431                            player.gold += tradeIn - eq.value;
432
433                            shopInventory.Remove(shopInventory.Find(eq));
434
435                            //shopInventory.TakeOut(eq);
436                         }
437                      }
438                   }
439                }
440             }
441             break;
442          case fight:
443          case sorcerer:
444          {
445             bool fightBack = false;
446             switch(command[0])
447             {
448                case 0:
449                case 'a':
450                   player.Attack(opponent);
451                   fightBack = true;
452                   break;
453                case 'm':
454                   if(player.manaPotions)
455                   {
456                      player.manaPotions--;
457                      player.mana += player.maxMana / 5;
458                      if(player.mana > player.maxMana) player.mana = player.maxMana;
459                   }
460                   break;
461                case 'h':
462                   if(player.healthPotions)
463                   {
464                      player.healthPotions--;
465                      player.health += player.maxHealth / 5;
466                      if(player.health > player.maxHealth) player.health = player.maxHealth;
467                   }
468                   break;
469                case 'r':
470                   OpponentAttacks();
471                   if(player.health > 0)
472                      state = realm;
473                   break;
474                default:
475                {
476                   int item = atoi(command);
477                   if(item && item <= player.spells.count)
478                   {
479                      if(player.mana >= player.spells[item-1].manaCost)
480                      {
481                         player.CastSpell(player.spells[item-1], opponent);
482                         fightBack = true;
483                      }
484                      else
485                         PrintLn("Not enough mana to cast that spell.");
486                   }
487                }
488             }
489             if(fightBack)
490                OpponentAttacks();
491             break;
492          }
493          case realm:
494             switch(command[0])
495             {
496                case 'a':
497                {
498                   EquipmentSlot c;
499                   PrintLn("\nYour statistics:");
500                   PrintLn("XP: ", player.xp);
501                   PrintLn("Health: ", player.health, "/", player.maxHealth);
502                   PrintLn("Mana:   ", player.mana, "/", player.maxMana);
503                   PrintLn("Strength: ", player.strength, ", Dexterity: ", player.dexterity, ", Magic: ", player.magic);
504                   PrintLn("Gold: ", player.gold);
505                   PrintLn("Equipment:");
506                   for(c = leftHand; c <= ring4; c++)
507                   {
508                      Equipment eq = player.equipment[c];
509                      if(eq)
510                      {
511                         Print(c, ": ", eq._class.name, ": ");
512                         eq.Show();
513                         PrintLn("");
514                      }
515                   }
516                   if(player.manaPotions)
517                      PrintLn(player.manaPotions, " mana potions");
518                   if(player.healthPotions)
519                      PrintLn(player.healthPotions, " health potions");
520                   if(player.training)
521                      PrintLn(player.training, " training points");
522                   break;
523                }
524                case 's': state = shop; break;
525                case 'b': state = realm; break;
526                case 'f': FindOpponent(); break;
527                case 't': state = training; break;
528                case 'p':
529                   if(player.xp > 1000)
530                   {
531                      opponent = EvilSorcerer { };
532                      state = sorcerer;
533                   }
534                   break;
535                case 0:
536                case 'r':
537                   if(GetRandom(0, 3) == 0)
538                   {
539                      PrintLn("Your rest was interrupted!");
540                      FindOpponent();
541                      OpponentAttacks();
542                   }
543                   else
544                   {
545                      player.health += player.maxHealth / 5;
546                      if(player.health > player.maxHealth) player.health = player.maxHealth;
547                      player.mana += player.maxMana / 5;
548                      if(player.mana > player.maxMana) player.mana = player.maxMana;
549                   }
550                   break;
551             }
552             break;
553          case training:
554          {
555             bool valid = true;
556             switch(command[0])
557             {
558                case 'h': player.health += player.maxHealth / 5; player.maxHealth += player.maxHealth / 5; break;
559                case 'm': player.mana += player.maxMana / 5; player.maxMana += player.maxMana / 5; break;
560                case 's': player.strength += player.strength / 5; break;
561                case 'd': player.dexterity += player.dexterity / 5; break;
562                case 'g': player.magic += player.magic / 5; break;
563                case 'b': state = realm;
564                default: valid = false;
565             }
566             if(valid)
567             {
568                player.training--;
569                if(!player.training)
570                   state = realm;
571             }
572             break;
573          }
574       }
575    }
576
577    void Main()
578    {
579       RandomSeed((uint)(((uint64)(GetTime() * 1000)) & MAXDWORD));
580       PrintLn("Welcome to this great minimalist RPG!");
581       PrintLn("You will need to save the princess from an Evil Sorcerer.");
582       PrintLn("But first you should wander the realm to fight the sorcerer's minions, ");
583       PrintLn("gaining experience and equipment in the process. You will need to reach");
584       PrintLn("at least 1000 experience points to search for the sorcerer's hideout.");
585       PrintLn("At any time you can [Q]uit.");
586       while(state != end)
587       {
588          PrintStatus();
589          GetCommand();
590          ProcessCommand();
591       }
592       system("pause");
593    }
594 }