Frank Duignan / Mbed 2 deprecated Nucleo_microrealms

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers realm.cpp Source File

realm.cpp

00001 /*
00002 Copyright (C) 2014  Frank Duignan
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00017 */
00018 #include "mbed.h"
00019 #include "realm.h"
00020 #include "serial.h"
00021 // Find types: h(ealth),s(trength),m(agic),g(old),w(eapon)
00022 const char FindTypes[]={'h','s','m','g','w'};
00023 
00024 
00025 // The following arrays define the bad guys and 
00026 // their battle properies - ordering matters!
00027 // Baddie types : O(gre),T(roll),D(ragon),H(ag)
00028 const char Baddies[]={'O','T','D','H'};
00029 // The following is 4 sets of 4 damage types
00030 const byte WeaponDamage[]={10,10,5,25,10,10,5,25,10,15,5,15,5,5,2,10};
00031 #define ICE_SPELL_COST 10
00032 #define FIRE_SPELL_COST 20
00033 #define LIGHTNING_SPELL_COST 30
00034 const byte FreezeSpellDamage[]={10,20,5,0};
00035 const byte FireSpellDamage[]={20,10,5,0};
00036 const byte LightningSpellDamage[]={15,10,25,0};
00037 const byte BadGuyDamage[]={10,10,15,5};
00038 int GameStarted = 0;
00039 tPlayer thePlayer;
00040 tRealm theRealm;
00041 void delay(int len);
00042 
00043 void delay(int len)
00044 {
00045     wait(len/1000);
00046 }
00047 void runGame(void)
00048 {
00049     char ch;
00050     
00051     printString("MicroRealms on mbed.");  
00052     showHelp();     
00053     while(GameStarted == 0)
00054     {
00055         
00056         showGameMessage("Press S to start a new game");
00057         ch = getUserInput();            
00058         
00059         if ( (ch == 'S') || (ch == 's') )
00060             GameStarted = 1;
00061     }
00062     
00063     initRealm(&theRealm);   
00064     initPlayer(&thePlayer,&theRealm);
00065     showPlayer(&thePlayer);
00066     showRealm(&theRealm,&thePlayer);
00067     showGameMessage("Press H for help");
00068     
00069     while (1)
00070     {
00071         ch = getUserInput();
00072         ch = ch | 32; // enforce lower case
00073         switch (ch) {
00074             case 'h' : {
00075                 showHelp();
00076                 break;
00077             }
00078             case 'n' : {
00079                 showGameMessage("North");
00080                 step('n',&thePlayer,&theRealm);
00081                 break;
00082             }
00083             case 's' : {
00084                 showGameMessage("South");
00085                 step('s',&thePlayer,&theRealm);
00086                 break;
00087 
00088             }
00089             case 'e' : {
00090                 showGameMessage("East");
00091                 step('e',&thePlayer,&theRealm);
00092                 break;
00093             }
00094             case 'w' : {
00095                 showGameMessage("West");
00096                 step('w',&thePlayer,&theRealm);
00097                 break;
00098             }
00099             case '#' : {        
00100                 if (thePlayer.wealth)       
00101                 {
00102                     showRealm(&theRealm,&thePlayer);
00103                     thePlayer.wealth--;
00104                 }
00105                 else
00106                     showGameMessage("No gold!");
00107                 break;
00108             }
00109             case 'p' : {                
00110                 showPlayer(&thePlayer);
00111                 break;
00112             }
00113         } // end switch
00114     } // end while
00115 }
00116 void step(char Direction,tPlayer *Player,tRealm *Realm)
00117 {
00118     int new_x, new_y;
00119     new_x = Player->x;
00120     new_y = Player->y;
00121     byte AreaContents;
00122     switch (Direction) {
00123         case 'n' :
00124         {
00125             if (new_y > 0)
00126                 new_y--;
00127             break;
00128         }
00129         case 's' :
00130         {
00131             if (new_y < MAP_HEIGHT-1)
00132                 new_y++;
00133             break;
00134         }
00135         case 'e' :
00136         {
00137             if (new_x <  MAP_WIDTH-1)
00138                 new_x++;
00139             break;
00140         }
00141         case 'w' :
00142         {
00143             if (new_x > 0)
00144                 new_x--;
00145             break;
00146         }       
00147     }
00148     AreaContents = Realm->map[new_y][new_x];
00149     if ( AreaContents == '*')
00150     {
00151         showGameMessage("A rock blocks your path.");
00152         return;
00153     }
00154     Player->x = new_x;
00155     Player->y = new_y;
00156     int Consumed = 0;
00157     switch (AreaContents)
00158     {
00159         
00160         // const char Baddies[]={'O','T','B','H'};
00161         case 'O' :{
00162             showGameMessage("A smelly green Ogre appears before you");
00163             Consumed = doChallenge(Player,0);
00164             break;
00165         }
00166         case 'T' :{
00167             showGameMessage("An evil troll challenges you");
00168             Consumed = doChallenge(Player,1);
00169             break;
00170         }
00171         case 'D' :{
00172             showGameMessage("A smouldering Dragon blocks your way !");
00173             Consumed = doChallenge(Player,2);
00174             break;
00175         }
00176         case 'H' :{
00177             showGameMessage("A withered hag cackles at you wickedly");
00178             Consumed = doChallenge(Player,3);
00179             break;
00180         }
00181         case 'h' :{
00182             showGameMessage("You find an elixer of health");
00183             setHealth(Player,Player->health+10);
00184             Consumed = 1;       
00185             break;
00186             
00187         }
00188         case 's' :{
00189             showGameMessage("You find a potion of strength");
00190             Consumed = 1;
00191             setStrength(Player,Player->strength+1);
00192             break;
00193         }
00194         case 'g' :{
00195             showGameMessage("You find a shiny golden nugget");
00196             Player->wealth++;           
00197             Consumed = 1;
00198             break;
00199         }
00200         case 'm' :{
00201             showGameMessage("You find a magic charm");
00202             Player->magic++;                        
00203             Consumed = 1;
00204             break;
00205         }
00206         case 'w' :{
00207             Consumed = addWeapon(Player,random(MAX_WEAPONS-1)+1);
00208             showPlayer(Player);
00209             break;          
00210         }
00211         case 'X' : {
00212             // Player landed on the exit
00213             printString("A door! You exit into a new realm");
00214             setHealth(Player,100); // maximize health
00215             initRealm(&theRealm);
00216             showRealm(&theRealm,Player);
00217         }
00218     }
00219     if (Consumed)
00220         Realm->map[new_y][new_x] = '.'; // remove any item that was found
00221 }
00222 int doChallenge(tPlayer *Player,int BadGuyIndex)
00223 {
00224     char ch;
00225     char Damage;
00226     const byte *dmg;
00227     int BadGuyHealth = 100;
00228     printString("Press F to fight");
00229     ch = getUserInput() | 32; // get user input and force lower case
00230     if (ch == 'f')
00231     {
00232         printString("Choose action");
00233         while ( (Player->health > 0) && (BadGuyHealth > 0) )
00234         {
00235             // Player takes turn first
00236             if (Player->magic > ICE_SPELL_COST)
00237                 printString("(I)CE spell");
00238             if (Player->magic > FIRE_SPELL_COST)
00239                 printString("(F)ire spell");
00240             if (Player->magic > LIGHTNING_SPELL_COST)
00241                 printString("(L)ightning spell");
00242             if (Player->Weapon1)
00243             {
00244                 eputs("(1)Use ");
00245                 printString(getWeaponName(Player->Weapon1));
00246             }   
00247             if (Player->Weapon2)
00248             {
00249                 eputs("(2)Use ");
00250                 printString(getWeaponName(Player->Weapon2));
00251             }
00252             printString("(P)unch");
00253             ch = getUserInput();
00254             switch (ch)
00255             {
00256                 case 'i':
00257                 case 'I':
00258                 {
00259                     printString("FREEZE!");
00260                     Player->magic -= ICE_SPELL_COST;
00261                     BadGuyHealth -= FreezeSpellDamage[BadGuyIndex]+random(10);
00262                     zap();
00263                     break;
00264                 }
00265                 case 'f':
00266                 case 'F':
00267                 {
00268                     printString("BURN!");
00269                     Player->magic -= FIRE_SPELL_COST;
00270                     BadGuyHealth -= FireSpellDamage[BadGuyIndex]+random(10);
00271                     zap();
00272                     break;
00273                 }
00274                 case 'l':
00275                 case 'L':
00276                 {
00277                     printString("ZAP!");
00278                     Player->magic -= LIGHTNING_SPELL_COST;
00279                     BadGuyHealth -= LightningSpellDamage[BadGuyIndex]+random(10);
00280                     zap();
00281                     break;
00282                 }
00283                 case '1':
00284                 {
00285                     dmg = WeaponDamage+(Player->Weapon1<<2)+BadGuyIndex;
00286                     printString("Take that!");
00287                     BadGuyHealth -= *dmg + random(Player->strength);
00288                     setStrength(Player,Player->strength-1);
00289                     break;
00290                 }
00291                 case '2':
00292                 {
00293                     dmg = WeaponDamage+(Player->Weapon2<<2)+BadGuyIndex;
00294                     printString("Take that!");
00295                     BadGuyHealth -= *dmg + random(Player->strength);
00296                     setStrength(Player,Player->strength-1);
00297                     break;
00298                 }
00299                 case 'p':
00300                 case 'P':
00301                 {
00302                     printString("Thump!");
00303                     BadGuyHealth -= 1+random(Player->strength);
00304                     setStrength(Player,Player->strength-1);
00305                     break;
00306                 }
00307                 default: {
00308                     printString("You fumble. Uh oh");
00309                 }
00310             }
00311             // Bad guy then gets a go 
00312             
00313             if (BadGuyHealth < 0)
00314                 BadGuyHealth = 0;
00315             Damage = BadGuyDamage[BadGuyIndex]+random(5);
00316             setHealth(Player,Player->health - Damage);
00317             eputs("Health: you "); printHex(Player->health);
00318             eputs(", them " );printHex(BadGuyHealth);
00319             eputs("\r\n");
00320         }
00321         if (Player->health == 0)
00322         { // You died
00323             printString("You are dead. Press Reset to restart");
00324             while(1);
00325         }
00326         else
00327         { // You won!
00328             Player->wealth = 50 + random(50);           
00329             showGameMessage("You win! Their gold is yours");            
00330             return 1;
00331         }
00332         
00333     }
00334     else
00335     {
00336         showGameMessage("Our 'hero' chickens out");
00337         return 0;
00338     }
00339 }
00340 int addWeapon(tPlayer *Player, int Weapon)
00341 {
00342     char c;
00343     eputs("You stumble upon ");
00344     switch (Weapon)
00345     {
00346         case 1:
00347         {   
00348             printString("a mighty axe");
00349             break;
00350         }
00351         case 2:
00352         {   
00353             printString("a sword with mystical runes");
00354             break;
00355         }
00356         case 3:
00357         {   
00358             printString("a bloody flail");
00359             break;
00360         }       
00361         default:
00362             printHex(Weapon);
00363     }
00364     if ( (Player->Weapon1) && (Player->Weapon2) )
00365     {
00366         // The player has two weapons already.
00367         showPlayer(Player);
00368         printString("You already have two weapons");        
00369         printString("(1) drop Weapon1, (2) for Weapon2, (0) skip");
00370         c = getUserInput();
00371         switch(c)
00372         {            
00373             case '0':{
00374                 return 0; // don't pick up
00375             }
00376             case '1':{
00377                 Player->Weapon1 = Weapon;
00378                 break;
00379             }
00380             case '2':{
00381                 Player->Weapon2 = Weapon;
00382                 break;
00383             }
00384         }
00385     }
00386     else
00387     {
00388         if (!Player->Weapon1)
00389         {
00390             Player->Weapon1 = Weapon;   
00391         }
00392         else if (!Player->Weapon2)
00393         {
00394             Player->Weapon2 = Weapon;
00395         }
00396     }   
00397     return 1;
00398 }
00399 const char *getWeaponName(int index)
00400 {
00401     switch (index)
00402     {
00403         case 0:return "Empty"; break;
00404         case 1:return "Axe";break;
00405         case 2:return "Sword"; break;
00406         case 3:return "Flail"; break;
00407     }
00408 }
00409 
00410 void setHealth(tPlayer *Player,int health)
00411 {
00412     if (health > 100)
00413         health = 100;
00414     if (health < 0)
00415         health = 0;
00416     Player->health = health;
00417     
00418 }   
00419 void setStrength(tPlayer *Player, byte strength)
00420 {
00421     if (strength > 100)
00422         strength = 100;
00423     if (strength < 0)
00424         strength = 0;
00425     Player->strength = strength;
00426 }
00427 void initPlayer(tPlayer *Player,tRealm *theRealm)
00428 {
00429     // get the player name
00430     int index=0;
00431     byte x,y;
00432     char ch=0;
00433     // Initialize the player's attributes
00434     eputs("Enter the player's name: ");
00435     while ( (index < MAX_NAME_LEN) && (ch != '\n') && (ch != '\r'))
00436     {
00437         ch = getUserInput();
00438         if ( ch > '0' ) // strip conrol characters
00439         {
00440             
00441             Player->name[index++]=ch;
00442             eputc(ch);
00443         }
00444     }
00445     Player->name[index]=0; // terminate the name
00446     setHealth(Player,100);
00447     Player->strength=50+random(50);
00448     Player->magic=50+random(50);    
00449     Player->wealth=10+random(10);
00450     Player->Weapon1 = 0;
00451     Player->Weapon2 = 0;
00452     // Initialize the player's location
00453     // Make sure the player does not land
00454     // on an occupied space to begin with
00455     do {
00456         x=random(MAP_WIDTH);
00457         y=random(MAP_HEIGHT);
00458         
00459     } while(theRealm->map[y][x] != '.');
00460     Player->x=x;
00461     Player->y=y;
00462 }
00463 void showPlayer(tPlayer *thePlayer)
00464 {
00465     eputs("\r\nName: ");
00466     printString(thePlayer->name);
00467     eputs("health: ");
00468     printHex(thePlayer->health);
00469     eputs("\r\nstrength: ");
00470     printHex(thePlayer->strength);
00471     eputs("\r\nmagic: ");
00472     printHex(thePlayer->magic);
00473     eputs("\r\nwealth: ");
00474     printHex(thePlayer->wealth);    
00475     eputs("\r\nLocation : ");
00476     printHex(thePlayer->x);
00477     eputs(" , ");
00478     printHex(thePlayer->y); 
00479     eputs("\r\nWeapon1 : ");
00480     printString(getWeaponName(thePlayer->Weapon1));
00481     eputs("Weapon2 : ");
00482     printString(getWeaponName(thePlayer->Weapon2));
00483 }
00484 void initRealm(tRealm *Realm)
00485 {
00486     int x,y;
00487     int Rnd;
00488     // clear the map to begin with
00489     for (y=0;y < MAP_HEIGHT; y++)
00490     {
00491         for (x=0; x < MAP_WIDTH; x++)
00492         {
00493             Rnd = random(100);
00494             
00495             if (Rnd >= 98) // put in some baddies
00496                 Realm->map[y][x]=   Baddies[random(sizeof(Baddies))];
00497             else if (Rnd >= 95) // put in some good stuff
00498                 Realm->map[y][x]=   FindTypes[random(sizeof(FindTypes))];
00499             else if (Rnd >= 90) // put in some rocks
00500                 Realm->map[y][x]='*'; 
00501             else // put in empty space
00502                 Realm->map[y][x] = '.'; 
00503         }
00504     }
00505     
00506     // finally put the exit to the next level in
00507     x = random(MAP_WIDTH);
00508     y = random(MAP_HEIGHT);
00509     Realm->map[y][x]='X';
00510 }
00511 void showRealm(tRealm *Realm,tPlayer *thePlayer)
00512 {
00513     int x,y;
00514     printString("The Realm:");  
00515     for (y=0;y<MAP_HEIGHT;y++)
00516     {
00517         for (x=0;x<MAP_WIDTH;x++)
00518         {
00519             
00520             if ( (x==thePlayer->x) && (y==thePlayer->y))
00521                 eputc('@');
00522             else
00523                 eputc(Realm->map[y][x]);
00524         }
00525         eputs("\r\n");
00526     }
00527     printString("\r\nLegend");
00528     printString("(T)roll, (O)gre, (D)ragon, (H)ag, e(X)it");
00529     printString("(w)eapon, (g)old), (m)agic, (s)trength");
00530     printString("@=You");
00531 }
00532 void showHelp()
00533 {
00534 
00535     printString("Help");
00536     printString("N,S,E,W : go North, South, East, West");
00537     printString("# : show map (cost: 1 gold piece)");
00538     printString("(H)elp");
00539     printString("(P)layer details");
00540     
00541 }
00542 
00543 void showGameMessage(char *Msg)
00544 {
00545     printString(Msg);
00546     printString("Ready");   
00547 }
00548 char getUserInput()
00549 {
00550     char ch = 0;
00551     
00552     while (ch == 0)
00553     {
00554         ch = egetc();
00555         prbs(); // cycle the prbs generator while waiting for user input
00556     }
00557     return ch;
00558 }
00559 unsigned prbs()
00560 {
00561     // This is an unverified 31 bit PRBS generator
00562     // It should be maximum length but this has not been verified 
00563     static unsigned long shift_register=0xa5a5a5a5;
00564     unsigned long new_bit=0;
00565     static int busy=0; // need to prevent re-entrancy here
00566     if (!busy)
00567     {
00568         busy=1;
00569         new_bit= ((shift_register & (1<<27))>>27) ^ ((shift_register & (1<<30))>>30);
00570         new_bit= ~new_bit;
00571         new_bit = new_bit & 1;
00572         shift_register=shift_register << 1;
00573         shift_register=shift_register | (new_bit);
00574         busy=0;
00575     }
00576     return shift_register & 0x7ffffff; // return 31 LSB's 
00577 }
00578 unsigned random(unsigned range)
00579 {
00580     // Implementing my own version of modulus
00581     // as it is a lot smaller than the library version
00582     // To prevent very long subtract loops, the
00583     // size of the value returned from prbs has been
00584     // restricted to 8 bits.
00585     int Rvalue = (prbs()&0xff);
00586     while (Rvalue >= range)
00587         Rvalue -= range; 
00588     return Rvalue;
00589 }
00590 void zap()
00591 {
00592     
00593 }