invaders_fork.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #include "bullet.hpp"
  2. #include "enemy.hpp"
  3. #include "player.hpp"
  4. #include "box.hpp"
  5. #include "boss.hpp"
  6. #include "powerup.hpp"
  7. #include "definitions.hpp"
  8. #include "functions.hpp"
  9. #include "wall.hpp"
  10. using std::cout;
  11. using std::endl;
  12. using std::min;
  13. int main()
  14. {
  15. typedef std::list<bullet> b_list;
  16. typedef std::list<enemy> e_list;
  17. typedef std::vector<wall> w_vec;
  18. srand(time(NULL));
  19. //OBJECTS INIZIALIZATION
  20. Box box1;
  21. player player1; //player is automatically created in [C/2][R]
  22. e_list enemies; //vector of enemies
  23. b_list bullets; //list of player's bullets
  24. b_list bombs; //list of enemies' bombs
  25. b_list powerups; //list of powerups
  26. int refresh_time; //how long the program waits before refreshing the screen
  27. int chflag=0; //cheat flag: 0=normal, 1=cheats allowed, 2=special mode activated, 3=both special mode and cheats.
  28. boss boss1;
  29. WINDOW *Score,*BossHP;
  30. //PARAMETERS/UTILITIES
  31. double shootrate; //probability of an enemy shooting a bomb
  32. int command; //keyboard input
  33. int score=0; //score: gain +100 when an enemy is destroyed and +50 when a bomb is destroyed
  34. char level='1';
  35. bool sound=true; //difficulty level
  36. //NCURSES STUFF
  37. initscr();
  38. curs_set(0);
  39. noecho();
  40. cbreak();
  41. keypad(stdscr,TRUE);
  42. start_color();
  43. init_pair(0,COLOR_WHITE,COLOR_BLACK);
  44. init_pair(1,COLOR_GREEN,COLOR_BLACK); //PLAYER
  45. init_pair(2,COLOR_RED,COLOR_BLACK); //ENEMY
  46. init_pair(3,COLOR_YELLOW,COLOR_BLACK); //BULLETS-POWERUPS
  47. init_pair(4,COLOR_MAGENTA,COLOR_BLACK); //WALLS
  48. init_pair(5,COLOR_CYAN,COLOR_BLACK); //BOSS
  49. init_pair(6,COLOR_BLUE,COLOR_BLACK); //BOMBS
  50. init_pair(7,COLOR_RED,COLOR_RED);
  51. init_pair(8,COLOR_GREEN,COLOR_GREEN);
  52. //////////PROGRAM START: creation of game objects and set of parameters
  53. WALLS_NUM=2;
  54. ENEMY_NUM=choose_level(shootrate, refresh_time, boss1, level); //choose difficulty level and set game parameters and boss
  55. erase();
  56. if(atoi(&level)==1) WALLS_NUM=3;
  57. w_vec walls(WALLS_NUM);
  58. Score=newwin(3,10,R/3,C+3);
  59. BossHP=newwin(3,15,R/3-3,C+3);
  60. load_enemies(enemies,ENEMY_NUM);
  61. int i=0;
  62. for(w_vec::iterator it=walls.begin(); it!=walls.end(); ++it, ++i) //creating walls (in a quite symmetric pattern)
  63. it->create((i+1)*(C/(3*WALLS_NUM+1))+i*(2*C/(3*WALLS_NUM+1)),2*R/3,(int)min(6,2*C/(3*WALLS_NUM+1)),2,3);
  64. box1.refresh(bullets, bombs, enemies, player1, score, boss1, walls, powerups); //matrix is loaded for the first time
  65. /////////ENTERING MAIN LOOP
  66. int childPID0=fork();
  67. if(childPID0==0 && sound){
  68. music();
  69. return 0;
  70. }
  71. while(1)
  72. {
  73. napms(refresh_time); //ncurses sleep function (ms)
  74. timeout(0);
  75. command = getch();
  76. if(command!=ERR) //READING INPUT
  77. command = tolower(command);
  78. if(command == 'q'){ //q = exit game
  79. endwin();
  80. kill_music(childPID0);
  81. cout<<lightgreen<<"Game exited correctly."<<none<<endl;
  82. return 1;
  83. }
  84. if(command == 'p')
  85. pause_game(chflag); //p = pause game
  86. if(chflag==1 || chflag==3){ //cheats
  87. if(command == '+' && player1.weaponclass<5) player1.weaponclass++; //increase weaponclass
  88. if(command == '\\' && player1.weaponclass>1) player1.weaponclass--; //decrease weaponclass
  89. if(command == '-' && player1.length>2){ //decrease size
  90. mvaddch(player1.y,player1.x+player1.length-1,' ');
  91. player1.length--;
  92. }
  93. if(command == '\'' && player1.length<20) player1.length++; //increase size
  94. if(command == 'n') //nuke enemies
  95. for(e_list::iterator it=enemies.begin();it!=enemies.end();it++){
  96. it->alive=false;
  97. mvaddch(it->y,it->x,' ');
  98. }
  99. }
  100. if(chflag!=2 && chflag!=3)
  101. get_KonamiCode(command,chflag,boss1,enemies,bullets,bombs,powerups,box1);
  102. if(command == 'a' || command == KEY_LEFT || command == 'd' || command == KEY_RIGHT ||
  103. ((command == 'w'|| command == KEY_UP || command == 's' || command == KEY_DOWN) &&
  104. (chflag==1 || chflag==3))){ //a or d = move player (if cheats are triggered, also w and s)
  105. for(int i=player1.x;i<player1.x+player1.length;i++) mvaddch(player1.y,i,' ');
  106. player1.next_pos(command);
  107. }
  108. if(command==' '){ //spacebar = shoot!
  109. if(sound){
  110. int childPID=fork();
  111. if(childPID==0){
  112. system("beep -f 1000 -l 30 -n -f 850 -l 30");
  113. return 0;
  114. }
  115. }
  116. player1.shoot(bullets);
  117. }
  118. if(command=='m'){ //mute/unmute
  119. if(sound) kill_music(childPID0);
  120. else{
  121. childPID0=fork();
  122. if(childPID0==0){
  123. music();
  124. return 0;
  125. }
  126. }
  127. sound=!sound;
  128. }
  129. if(enemyalive(enemies)) //if there's at least one enemy alive:
  130. {
  131. int n_enemies=0;
  132. e_list::const_iterator e_end = enemies.end();
  133. for(e_list::iterator it=enemies.begin(); it!=e_end; ++it)
  134. if(it->alive) n_enemies++; //counts alive enemies
  135. for(e_list::iterator it=enemies.begin(); it!=e_end; ++it)
  136. {
  137. mvaddch(it->y,it->x,' ');
  138. it->next_pos(); //evaluate new positions
  139. if(it->alive && (double)rand()/RAND_MAX<(shootrate*ENEMY_NUM/n_enemies)){ //try a bomb-dropping
  140. if(sound){
  141. int childPID=fork();
  142. if(childPID==0){
  143. system("beep -f 1500 -l 30 -n -f 1000 -l 30");
  144. return 0;
  145. }
  146. }
  147. it->shoot(bombs);
  148. }
  149. }
  150. }
  151. else boss1.alive = true; //if no enemy is alive, boss spawns
  152. if(boss1.alive) //if boss is alive, moves and shoots
  153. {
  154. for(int i=0;i<boss1.width;i++) mvaddch(boss1.y,boss1.x+i,' ');
  155. for(int j=0;j<boss1.height;j++){
  156. mvaddch(boss1.y+j,boss1.x,' ');
  157. mvaddch(boss1.y+j,boss1.x+boss1.width-1,' ');
  158. }
  159. boss1.next_pos();
  160. if((double)rand()/RAND_MAX<shootrate*25.){ //boss's shootrate is 25 times the one of normal enemies
  161. if(sound){
  162. int childPID=fork();
  163. if(childPID==0){
  164. system("beep -f 1500 -l 30 -n -f 1000 -l 30");
  165. return 0;
  166. }
  167. }
  168. boss1.shoot(bombs);
  169. }
  170. }
  171. if(!bullets.empty()) //evaluate new bullets' positions
  172. for(b_list::iterator it=bullets.begin(); it!=bullets.end(); ++it){
  173. mvaddch(it->y,it->x,' ');
  174. it->next_pos();
  175. }
  176. bullets.unique(); //remove duplicates of bullets (i.e. player can't shoot enemies)
  177. if(!bombs.empty()) //evaluate new bombs' positions
  178. for(b_list::iterator it=bombs.begin(); it!=bombs.end(); ++it){
  179. mvaddch(it->y,it->x,' ');
  180. it->next_pos();
  181. }
  182. bombs.unique(); //remove duplicates of bombs
  183. if(!powerups.empty()) //new powerups' positions
  184. for(b_list::iterator it=powerups.begin(); it!=powerups.end(); ++it){
  185. mvaddch(it->y,it->x,' ');
  186. it->next_pos();
  187. }
  188. powerups.unique(); //FIXME: THIS ONLY WORKS ON CONSECUTIVE ELEMENTS OF THE LIST!! we should at least sort powerups before calling unique()
  189. box1.refresh(bullets, bombs, enemies, player1, score, boss1, walls, powerups);
  190. ///////ENDGAME CHECKS
  191. if(boss1.health<1) //YOU WON!!
  192. {
  193. if(sound){
  194. kill_music(childPID0);
  195. int childPID=fork();
  196. if(childPID==0){
  197. system("beep -f 1000 -l 150 -n -f 800 -l 150 -n -f 1000 -l 150 -n -f 1500 -l 600");
  198. return 0;
  199. }
  200. }
  201. Victory(boss1.name,score,level,chflag);
  202. WINDOW *replay;
  203. replay=newwin(3,25,26,20);
  204. box(replay,ACS_VLINE,ACS_HLINE);
  205. if(playagain(replay)) //playagain() returns true if player wants to play again, false otherwise
  206. {
  207. delwin(replay);
  208. timeout(500);
  209. score=0;
  210. erase();
  211. refresh();
  212. choose_level(shootrate, refresh_time, boss1, level);
  213. reset(box1, player1, enemies, boss1, bullets, bombs, walls, powerups, level,chflag); // reset box, player, enemy and deletes all bullets and bombs
  214. erase();
  215. refresh();
  216. continue;
  217. }
  218. else {
  219. endwin();
  220. cout<<lightgreen<<"Game exited correctly."<<none<<endl;
  221. return 0;
  222. }
  223. }
  224. if(gameover(box1,player1))
  225. {
  226. if(sound){
  227. kill_music(childPID0);
  228. int childPID=fork();
  229. if(childPID==0){
  230. system("beep -f 700 -l 150 -n -f 585 -l 150 -n -f 550 -l 150 -n -f 520 -l 600");
  231. return 0;
  232. }
  233. }
  234. Defeat(score);
  235. WINDOW* replay;
  236. replay=newwin(3,25,17,20);
  237. box(replay,ACS_VLINE,ACS_HLINE);
  238. if(playagain(replay)) //playagain() returns true if player wants to play again, false otherwise
  239. {
  240. delwin(replay);
  241. timeout(500);
  242. score=0;
  243. erase();
  244. refresh();
  245. choose_level(shootrate, refresh_time, boss1, level);
  246. reset(box1, player1, enemies, boss1, bullets, bombs, walls, powerups, level,chflag); // reset box, player, enemy and delete all bullets and bombs
  247. erase();
  248. refresh();
  249. continue;
  250. }
  251. else {
  252. endwin();
  253. cout<<lightgreen<<"Game exited correctly."<<none<<endl;
  254. return 0;
  255. }
  256. }
  257. write_score(Score,score);
  258. if(boss1.alive){
  259. write_bosshp(BossHP,boss1.health,boss1.healthmax,boss1.name);
  260. wrefresh(BossHP);
  261. }
  262. wrefresh(Score);
  263. refresh();
  264. }
  265. ////////END OF MAIN LOOP
  266. endwin();
  267. return -1; //program never really reaches here, but compiler is happy
  268. }