Frank Duignan
/
Nucleo_microrealms
Microrealms: An adventure game on the mbed platform
Diff: realm.cpp
- Revision:
- 0:4da21a20e2c1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/realm.cpp Thu Dec 04 14:17:50 2014 +0000 @@ -0,0 +1,593 @@ +/* +Copyright (C) 2014 Frank Duignan + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "mbed.h" +#include "realm.h" +#include "serial.h" +// Find types: h(ealth),s(trength),m(agic),g(old),w(eapon) +const char FindTypes[]={'h','s','m','g','w'}; + + +// The following arrays define the bad guys and +// their battle properies - ordering matters! +// Baddie types : O(gre),T(roll),D(ragon),H(ag) +const char Baddies[]={'O','T','D','H'}; +// The following is 4 sets of 4 damage types +const byte WeaponDamage[]={10,10,5,25,10,10,5,25,10,15,5,15,5,5,2,10}; +#define ICE_SPELL_COST 10 +#define FIRE_SPELL_COST 20 +#define LIGHTNING_SPELL_COST 30 +const byte FreezeSpellDamage[]={10,20,5,0}; +const byte FireSpellDamage[]={20,10,5,0}; +const byte LightningSpellDamage[]={15,10,25,0}; +const byte BadGuyDamage[]={10,10,15,5}; +int GameStarted = 0; +tPlayer thePlayer; +tRealm theRealm; +void delay(int len); + +void delay(int len) +{ + wait(len/1000); +} +void runGame(void) +{ + char ch; + + printString("MicroRealms on mbed."); + showHelp(); + while(GameStarted == 0) + { + + showGameMessage("Press S to start a new game"); + ch = getUserInput(); + + if ( (ch == 'S') || (ch == 's') ) + GameStarted = 1; + } + + initRealm(&theRealm); + initPlayer(&thePlayer,&theRealm); + showPlayer(&thePlayer); + showRealm(&theRealm,&thePlayer); + showGameMessage("Press H for help"); + + while (1) + { + ch = getUserInput(); + ch = ch | 32; // enforce lower case + switch (ch) { + case 'h' : { + showHelp(); + break; + } + case 'n' : { + showGameMessage("North"); + step('n',&thePlayer,&theRealm); + break; + } + case 's' : { + showGameMessage("South"); + step('s',&thePlayer,&theRealm); + break; + + } + case 'e' : { + showGameMessage("East"); + step('e',&thePlayer,&theRealm); + break; + } + case 'w' : { + showGameMessage("West"); + step('w',&thePlayer,&theRealm); + break; + } + case '#' : { + if (thePlayer.wealth) + { + showRealm(&theRealm,&thePlayer); + thePlayer.wealth--; + } + else + showGameMessage("No gold!"); + break; + } + case 'p' : { + showPlayer(&thePlayer); + break; + } + } // end switch + } // end while +} +void step(char Direction,tPlayer *Player,tRealm *Realm) +{ + int new_x, new_y; + new_x = Player->x; + new_y = Player->y; + byte AreaContents; + switch (Direction) { + case 'n' : + { + if (new_y > 0) + new_y--; + break; + } + case 's' : + { + if (new_y < MAP_HEIGHT-1) + new_y++; + break; + } + case 'e' : + { + if (new_x < MAP_WIDTH-1) + new_x++; + break; + } + case 'w' : + { + if (new_x > 0) + new_x--; + break; + } + } + AreaContents = Realm->map[new_y][new_x]; + if ( AreaContents == '*') + { + showGameMessage("A rock blocks your path."); + return; + } + Player->x = new_x; + Player->y = new_y; + int Consumed = 0; + switch (AreaContents) + { + + // const char Baddies[]={'O','T','B','H'}; + case 'O' :{ + showGameMessage("A smelly green Ogre appears before you"); + Consumed = doChallenge(Player,0); + break; + } + case 'T' :{ + showGameMessage("An evil troll challenges you"); + Consumed = doChallenge(Player,1); + break; + } + case 'D' :{ + showGameMessage("A smouldering Dragon blocks your way !"); + Consumed = doChallenge(Player,2); + break; + } + case 'H' :{ + showGameMessage("A withered hag cackles at you wickedly"); + Consumed = doChallenge(Player,3); + break; + } + case 'h' :{ + showGameMessage("You find an elixer of health"); + setHealth(Player,Player->health+10); + Consumed = 1; + break; + + } + case 's' :{ + showGameMessage("You find a potion of strength"); + Consumed = 1; + setStrength(Player,Player->strength+1); + break; + } + case 'g' :{ + showGameMessage("You find a shiny golden nugget"); + Player->wealth++; + Consumed = 1; + break; + } + case 'm' :{ + showGameMessage("You find a magic charm"); + Player->magic++; + Consumed = 1; + break; + } + case 'w' :{ + Consumed = addWeapon(Player,random(MAX_WEAPONS-1)+1); + showPlayer(Player); + break; + } + case 'X' : { + // Player landed on the exit + printString("A door! You exit into a new realm"); + setHealth(Player,100); // maximize health + initRealm(&theRealm); + showRealm(&theRealm,Player); + } + } + if (Consumed) + Realm->map[new_y][new_x] = '.'; // remove any item that was found +} +int doChallenge(tPlayer *Player,int BadGuyIndex) +{ + char ch; + char Damage; + const byte *dmg; + int BadGuyHealth = 100; + printString("Press F to fight"); + ch = getUserInput() | 32; // get user input and force lower case + if (ch == 'f') + { + printString("Choose action"); + while ( (Player->health > 0) && (BadGuyHealth > 0) ) + { + // Player takes turn first + if (Player->magic > ICE_SPELL_COST) + printString("(I)CE spell"); + if (Player->magic > FIRE_SPELL_COST) + printString("(F)ire spell"); + if (Player->magic > LIGHTNING_SPELL_COST) + printString("(L)ightning spell"); + if (Player->Weapon1) + { + eputs("(1)Use "); + printString(getWeaponName(Player->Weapon1)); + } + if (Player->Weapon2) + { + eputs("(2)Use "); + printString(getWeaponName(Player->Weapon2)); + } + printString("(P)unch"); + ch = getUserInput(); + switch (ch) + { + case 'i': + case 'I': + { + printString("FREEZE!"); + Player->magic -= ICE_SPELL_COST; + BadGuyHealth -= FreezeSpellDamage[BadGuyIndex]+random(10); + zap(); + break; + } + case 'f': + case 'F': + { + printString("BURN!"); + Player->magic -= FIRE_SPELL_COST; + BadGuyHealth -= FireSpellDamage[BadGuyIndex]+random(10); + zap(); + break; + } + case 'l': + case 'L': + { + printString("ZAP!"); + Player->magic -= LIGHTNING_SPELL_COST; + BadGuyHealth -= LightningSpellDamage[BadGuyIndex]+random(10); + zap(); + break; + } + case '1': + { + dmg = WeaponDamage+(Player->Weapon1<<2)+BadGuyIndex; + printString("Take that!"); + BadGuyHealth -= *dmg + random(Player->strength); + setStrength(Player,Player->strength-1); + break; + } + case '2': + { + dmg = WeaponDamage+(Player->Weapon2<<2)+BadGuyIndex; + printString("Take that!"); + BadGuyHealth -= *dmg + random(Player->strength); + setStrength(Player,Player->strength-1); + break; + } + case 'p': + case 'P': + { + printString("Thump!"); + BadGuyHealth -= 1+random(Player->strength); + setStrength(Player,Player->strength-1); + break; + } + default: { + printString("You fumble. Uh oh"); + } + } + // Bad guy then gets a go + + if (BadGuyHealth < 0) + BadGuyHealth = 0; + Damage = BadGuyDamage[BadGuyIndex]+random(5); + setHealth(Player,Player->health - Damage); + eputs("Health: you "); printHex(Player->health); + eputs(", them " );printHex(BadGuyHealth); + eputs("\r\n"); + } + if (Player->health == 0) + { // You died + printString("You are dead. Press Reset to restart"); + while(1); + } + else + { // You won! + Player->wealth = 50 + random(50); + showGameMessage("You win! Their gold is yours"); + return 1; + } + + } + else + { + showGameMessage("Our 'hero' chickens out"); + return 0; + } +} +int addWeapon(tPlayer *Player, int Weapon) +{ + char c; + eputs("You stumble upon "); + switch (Weapon) + { + case 1: + { + printString("a mighty axe"); + break; + } + case 2: + { + printString("a sword with mystical runes"); + break; + } + case 3: + { + printString("a bloody flail"); + break; + } + default: + printHex(Weapon); + } + if ( (Player->Weapon1) && (Player->Weapon2) ) + { + // The player has two weapons already. + showPlayer(Player); + printString("You already have two weapons"); + printString("(1) drop Weapon1, (2) for Weapon2, (0) skip"); + c = getUserInput(); + switch(c) + { + case '0':{ + return 0; // don't pick up + } + case '1':{ + Player->Weapon1 = Weapon; + break; + } + case '2':{ + Player->Weapon2 = Weapon; + break; + } + } + } + else + { + if (!Player->Weapon1) + { + Player->Weapon1 = Weapon; + } + else if (!Player->Weapon2) + { + Player->Weapon2 = Weapon; + } + } + return 1; +} +const char *getWeaponName(int index) +{ + switch (index) + { + case 0:return "Empty"; break; + case 1:return "Axe";break; + case 2:return "Sword"; break; + case 3:return "Flail"; break; + } +} + +void setHealth(tPlayer *Player,int health) +{ + if (health > 100) + health = 100; + if (health < 0) + health = 0; + Player->health = health; + +} +void setStrength(tPlayer *Player, byte strength) +{ + if (strength > 100) + strength = 100; + if (strength < 0) + strength = 0; + Player->strength = strength; +} +void initPlayer(tPlayer *Player,tRealm *theRealm) +{ + // get the player name + int index=0; + byte x,y; + char ch=0; + // Initialize the player's attributes + eputs("Enter the player's name: "); + while ( (index < MAX_NAME_LEN) && (ch != '\n') && (ch != '\r')) + { + ch = getUserInput(); + if ( ch > '0' ) // strip conrol characters + { + + Player->name[index++]=ch; + eputc(ch); + } + } + Player->name[index]=0; // terminate the name + setHealth(Player,100); + Player->strength=50+random(50); + Player->magic=50+random(50); + Player->wealth=10+random(10); + Player->Weapon1 = 0; + Player->Weapon2 = 0; + // Initialize the player's location + // Make sure the player does not land + // on an occupied space to begin with + do { + x=random(MAP_WIDTH); + y=random(MAP_HEIGHT); + + } while(theRealm->map[y][x] != '.'); + Player->x=x; + Player->y=y; +} +void showPlayer(tPlayer *thePlayer) +{ + eputs("\r\nName: "); + printString(thePlayer->name); + eputs("health: "); + printHex(thePlayer->health); + eputs("\r\nstrength: "); + printHex(thePlayer->strength); + eputs("\r\nmagic: "); + printHex(thePlayer->magic); + eputs("\r\nwealth: "); + printHex(thePlayer->wealth); + eputs("\r\nLocation : "); + printHex(thePlayer->x); + eputs(" , "); + printHex(thePlayer->y); + eputs("\r\nWeapon1 : "); + printString(getWeaponName(thePlayer->Weapon1)); + eputs("Weapon2 : "); + printString(getWeaponName(thePlayer->Weapon2)); +} +void initRealm(tRealm *Realm) +{ + int x,y; + int Rnd; + // clear the map to begin with + for (y=0;y < MAP_HEIGHT; y++) + { + for (x=0; x < MAP_WIDTH; x++) + { + Rnd = random(100); + + if (Rnd >= 98) // put in some baddies + Realm->map[y][x]= Baddies[random(sizeof(Baddies))]; + else if (Rnd >= 95) // put in some good stuff + Realm->map[y][x]= FindTypes[random(sizeof(FindTypes))]; + else if (Rnd >= 90) // put in some rocks + Realm->map[y][x]='*'; + else // put in empty space + Realm->map[y][x] = '.'; + } + } + + // finally put the exit to the next level in + x = random(MAP_WIDTH); + y = random(MAP_HEIGHT); + Realm->map[y][x]='X'; +} +void showRealm(tRealm *Realm,tPlayer *thePlayer) +{ + int x,y; + printString("The Realm:"); + for (y=0;y<MAP_HEIGHT;y++) + { + for (x=0;x<MAP_WIDTH;x++) + { + + if ( (x==thePlayer->x) && (y==thePlayer->y)) + eputc('@'); + else + eputc(Realm->map[y][x]); + } + eputs("\r\n"); + } + printString("\r\nLegend"); + printString("(T)roll, (O)gre, (D)ragon, (H)ag, e(X)it"); + printString("(w)eapon, (g)old), (m)agic, (s)trength"); + printString("@=You"); +} +void showHelp() +{ + + printString("Help"); + printString("N,S,E,W : go North, South, East, West"); + printString("# : show map (cost: 1 gold piece)"); + printString("(H)elp"); + printString("(P)layer details"); + +} + +void showGameMessage(char *Msg) +{ + printString(Msg); + printString("Ready"); +} +char getUserInput() +{ + char ch = 0; + + while (ch == 0) + { + ch = egetc(); + prbs(); // cycle the prbs generator while waiting for user input + } + return ch; +} +unsigned prbs() +{ + // This is an unverified 31 bit PRBS generator + // It should be maximum length but this has not been verified + static unsigned long shift_register=0xa5a5a5a5; + unsigned long new_bit=0; + static int busy=0; // need to prevent re-entrancy here + if (!busy) + { + busy=1; + new_bit= ((shift_register & (1<<27))>>27) ^ ((shift_register & (1<<30))>>30); + new_bit= ~new_bit; + new_bit = new_bit & 1; + shift_register=shift_register << 1; + shift_register=shift_register | (new_bit); + busy=0; + } + return shift_register & 0x7ffffff; // return 31 LSB's +} +unsigned random(unsigned range) +{ + // Implementing my own version of modulus + // as it is a lot smaller than the library version + // To prevent very long subtract loops, the + // size of the value returned from prbs has been + // restricted to 8 bits. + int Rvalue = (prbs()&0xff); + while (Rvalue >= range) + Rvalue -= range; + return Rvalue; +} +void zap() +{ + +} \ No newline at end of file