bossrush.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /* This file is part of Invaders.
  2. *
  3. * Copyright (C) 2020 LCM.
  4. * You may use, distribute and modify Invaders under the terms of the
  5. * GPLv3 license, available at <https://www.gnu.org/licenses/\>.
  6. */
  7. #include "definitions.hpp"
  8. #include "rocket.hpp"
  9. #include "enemy.hpp"
  10. #include "player.hpp"
  11. #include "boss.hpp"
  12. #include "powerup.hpp"
  13. #include "functions.hpp"
  14. #include "wall.hpp"
  15. using std::cout;
  16. using std::endl;
  17. using std::min;
  18. using std::max;
  19. int main(int argc,char** argv)
  20. {
  21. if(argc>1){
  22. if(strcmp(argv[1],"--uber-debug")!=0 && strcmp(argv[1],"--info")!=0){
  23. cout<<"Usage: "<<argv[0]<<" [--info]"<<endl;
  24. return 1;
  25. }
  26. if(strcmp(argv[1],"--info")==0){
  27. cout<<endl<<"Curses Invaders " VERSION " - Bossrush"<<endl;
  28. cout<<endl<<"Game developed by Giacomo Parolini (jp) and Enrico Guiraud (blue) in years 2010-2013."<<endl;
  29. cout<<"Source code is available under request to jp@lcm.mi.infn.it (it's quite ugly, I warn you ;-) )"<<endl;
  30. cout<<"Report any bug to the same mail address."<<endl<<endl;
  31. return 1;
  32. }
  33. }
  34. typedef std::list<bullet> b_list;
  35. typedef std::vector<wall> w_vec;
  36. typedef std::list<rocket> r_list;
  37. srand(time(NULL));
  38. //OBJECTS INIZIALIZATION
  39. player player1; //player is automatically created in [C/2][R]
  40. boss bosses[5]; //vector of bosses
  41. b_list bullets; //list of player's bullets
  42. b_list bombs; //list of enemies' bombs
  43. b_list powerups; //list of powerups
  44. r_list rockets; //list of rockets
  45. boss boss1;
  46. std::list<enemy> enemies;
  47. int refresh_time=100; //how long the program waits before refreshing the screen
  48. int chflag=0; //cheat flag: 0=normal, 1=cheats allowed.
  49. int num=0;
  50. int commands[CMD_NUM];
  51. read_commands(commands); //0:left,1:right,2:up,3:down,4:pause,5:shoot1,6:shoot2,7:mute,8:quit
  52. WINDOW *Score,*BossHP;
  53. //PARAMETERS/UTILITIES
  54. double shootrate; //probability of an enemy shooting a bomb
  55. double poweruprate; //probability of a powerup being dropped
  56. int walls_num; //number of walls
  57. int command; //keyboard input
  58. int score=0; //score: gain +100 when an enemy is destroyed and +50 when a bomb is destroyed
  59. int level=1; //difficulty level
  60. create_std_bosses();
  61. std::string bossname1=getenv("HOME");
  62. bossname1=bossname1+RECORD_DIR+BOSS_FILE1+".dat";
  63. boss newboss1(1,1,100,9,6,BOSS_FILE1);
  64. newboss1.loadpicture(bossname1.c_str());
  65. std::string bossname2=getenv("HOME");
  66. bossname2=bossname2+RECORD_DIR+BOSS_FILE2+".dat";
  67. boss newboss2(1,1,200,11,5,BOSS_FILE2);
  68. newboss2.loadpicture(bossname2.c_str());
  69. std::string bossname3=getenv("HOME");
  70. bossname3=bossname3+RECORD_DIR+BOSS_FILE3+".dat";
  71. boss newboss3(1,1,300,9,6,BOSS_FILE3);
  72. newboss3.loadpicture(bossname3.c_str());
  73. std::string bossname4=getenv("HOME");
  74. bossname4=bossname4+RECORD_DIR+BOSS_FILE4+".dat";
  75. boss newboss4(1,1,400,11,6,BOSS_FILE4);
  76. newboss4.loadpicture(bossname4.c_str());
  77. std::string bossname5=getenv("HOME");
  78. bossname5=bossname5+RECORD_DIR+BOSS_FILE5+".dat";
  79. boss newboss5(1,1,500,17,5,BOSS_FILE5);
  80. newboss5.loadpicture(bossname5.c_str());
  81. bosses[0]=newboss1;
  82. bosses[1]=newboss2;
  83. bosses[2]=newboss3;
  84. bosses[3]=newboss4;
  85. bosses[4]=newboss5;
  86. boss1=bosses[0];
  87. boss1.alive=true;
  88. player1.weaponclass=0;
  89. //NCURSES STUFF
  90. initscr();
  91. curs_set(0);
  92. noecho();
  93. cbreak();
  94. keypad(stdscr,TRUE);
  95. start_color();
  96. init_pair(0,COLOR_WHITE,COLOR_BLACK);
  97. init_pair(1,COLOR_GREEN,COLOR_BLACK); //PLAYER
  98. init_pair(2,COLOR_RED,COLOR_BLACK); //ENEMY
  99. init_pair(3,COLOR_YELLOW,COLOR_BLACK); //BULLETS-POWERUPS
  100. init_pair(4,COLOR_MAGENTA,COLOR_BLACK); //WALLS
  101. init_pair(5,COLOR_CYAN,COLOR_BLACK); //BOSS
  102. init_pair(6,COLOR_BLUE,COLOR_BLACK); //BOMBS
  103. init_pair(7,COLOR_RED,COLOR_RED);
  104. init_pair(8,COLOR_GREEN,COLOR_GREEN);
  105. init_pair(9,COLOR_BLACK,COLOR_GREEN);
  106. Score=newwin(3,10,R/3,C+3);
  107. BossHP=newwin(3,15,R/3-3,C+3);
  108. level = choose_level_bossrush(commands);
  109. setup_level_bossrush(level, shootrate, poweruprate, walls_num, refresh_time);
  110. w_vec walls(walls_num);
  111. int i=0;
  112. for(w_vec::iterator it=walls.begin(); it!=walls.end(); ++it, ++i) //creating walls (in a quite symmetric pattern)
  113. 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);
  114. player1.set_commands(commands);
  115. if(level==1)
  116. player1.weaponclass=2;
  117. else if(level<4)
  118. player1.weaponclass=1;
  119. erase();
  120. if(argc>1)
  121. if(strcmp(argv[1],"--uber-debug")==0){ player1.weaponclass=5; player1.weaponclassrkt=5; player1.rocketlauncher=true; player1.length=MAX_LENGTH; }
  122. /////////ENTERING MAIN LOOP
  123. while(1)
  124. {
  125. napms(refresh_time); //ncurses sleep function (ms)
  126. timeout(0);
  127. command = getch();
  128. if(command!=ERR) //READING INPUT
  129. command = tolower(command);
  130. if(command == commands[8]){ //q = exit game
  131. endwin();
  132. cout<<lightgreen<<"Game exited correctly."<<none<<endl;
  133. return 1;
  134. }
  135. if(command == commands[4])
  136. pause_game(chflag); //p = pause game
  137. if(chflag==1) //cheats
  138. get_cheat(command,player1,enemies,shootrate);
  139. if(command == commands[0] || command == KEY_LEFT || command == commands[1] || command == KEY_RIGHT || ((command == commands[2]|| command == KEY_UP || command == commands[3] || command == KEY_DOWN) && chflag==1)){ //a or d = move player (if cheats are triggered, also w and s)
  140. for(int i=player1.x;i<player1.x+player1.length;i++) mvaddch(player1.y,i,' ');
  141. player1.next_pos(command);
  142. }
  143. if(command==commands[5] || command==commands[6]) { //spacebar = shoot!
  144. player1.shoot(bullets);
  145. if(player1.rocketlauncher) player1.shootrkt(rockets);
  146. }
  147. for(int i=0;i<boss1.width;i++) mvaddch(boss1.y,boss1.x+i,' ');
  148. for(int j=0;j<boss1.height;j++){
  149. mvaddch(boss1.y+j,boss1.x,' ');
  150. mvaddch(boss1.y+j,boss1.x+boss1.width-1,' ');
  151. }
  152. boss1.next_pos();
  153. if((double)rand()/RAND_MAX<shootrate*25.)
  154. boss1.shoot(bombs);
  155. if(!bullets.empty()) //evaluate new bullets' positions
  156. for(b_list::iterator it=bullets.begin(); it!=bullets.end(); ++it){
  157. mvaddch(it->y,it->x,' ');
  158. it->next_pos();
  159. }
  160. bullets.unique(); //remove duplicates of bullets (i.e. player can't shoot enemies)
  161. if(!rockets.empty()) //evaluate new bullets' positions
  162. for(r_list::iterator it=rockets.begin(); it!=rockets.end(); ++it){
  163. mvaddch(it->y,it->x,' ');
  164. it->next_pos();
  165. }
  166. rockets.unique();
  167. if(!bombs.empty()) //evaluate new bombs' positions
  168. for(b_list::iterator it=bombs.begin(); it!=bombs.end(); ++it){
  169. mvaddch(it->y,it->x,' ');
  170. it->next_pos();
  171. }
  172. bombs.unique(); //remove duplicates of bombs
  173. if(!powerups.empty()) //new powerups' positions
  174. for(b_list::iterator it=powerups.begin(); it!=powerups.end(); ++it){
  175. mvaddch(it->y,it->x,' ');
  176. it->next_pos();
  177. }
  178. powerups.unique(); //FIXME: THIS ONLY WORKS ON CONSECUTIVE ELEMENTS OF THE LIST!! we should at least sort powerups before calling unique()
  179. interactions(player1,bullets,bombs,enemies,walls,powerups,rockets,boss1,score,poweruprate);
  180. if(boss1.health<=0)
  181. if(num<4){
  182. score+=250*level*(num+1);
  183. for(int i=max(0,boss1.y-1);i<min(R-1,boss1.y+boss1.height+1);i++)
  184. for(int j=0;j<C;j++)
  185. mvaddch(i,j,' ');
  186. num++;
  187. mvwprintw(BossHP,0,1," ");
  188. if((double)rand()/RAND_MAX<0.25*num){
  189. if((double)rand()/RAND_MAX<1./POWERUP_RATIO){
  190. if((double)rand()/RAND_MAX<1./ROCKET_RATIO){
  191. powerup newpowerup(boss1.x,boss1.y+1,512);
  192. powerups.push_back(newpowerup);
  193. }
  194. else{
  195. powerup newpowerup(boss1.x,boss1.y+1,128);
  196. powerups.push_back(newpowerup);
  197. }
  198. }
  199. else{
  200. powerup newpowerup(boss1.x,boss1.y+1);
  201. powerups.push_back(newpowerup);
  202. }
  203. }
  204. if(num==4 && player1.weaponclass<3) player1.weaponclass++;
  205. boss1=bosses[num];
  206. boss1.alive=true;
  207. }
  208. ///////ENDGAME CHECKS
  209. if((boss1.health<1 && num==4) || gameover(player1,bombs))
  210. {
  211. WINDOW *replay;
  212. if (boss1.health<1 && num==4)
  213. {
  214. Victory_bossrush(boss1.name,score,level,chflag);
  215. replay=newwin(3,25,26,20);
  216. } else
  217. {
  218. Defeat(score);
  219. replay=newwin(3,25,17,20);
  220. }
  221. box(replay,ACS_VLINE,ACS_HLINE);
  222. switch(char choice = playagain(replay)) // playagain() returns 'y'/'n'/'q'
  223. {
  224. case 'y':
  225. case 'n':
  226. delwin(replay);
  227. timeout(500);
  228. score=0;
  229. erase();
  230. refresh();
  231. if(choice=='n')
  232. level = choose_level_bossrush(commands);
  233. setup_level_bossrush(level, shootrate, poweruprate, walls_num, refresh_time);
  234. reset(player1, enemies, boss1, bullets, bombs, walls, walls_num, powerups, rockets, chflag); // reset box, player, enemy and deletes all bullets and bombs
  235. resetbosses(bosses,boss1,player1,level);
  236. num=0;
  237. erase();
  238. refresh();
  239. continue; // Go to the beginning of the main loop
  240. case 'q':
  241. endwin();
  242. cout<<lightgreen<<"Game exited correctly."<<none<<endl;
  243. return 0;
  244. }
  245. }
  246. draw(player1,bullets,bombs,enemies,walls,powerups,rockets,boss1);
  247. write_score(Score,score);
  248. if(boss1.alive){
  249. write_bosshp(BossHP,boss1.health,boss1.healthmax,boss1.name);
  250. wnoutrefresh(BossHP);
  251. }
  252. wnoutrefresh(Score);
  253. refresh();
  254. }
  255. ////////END OF MAIN LOOP
  256. endwin();
  257. return 0;
  258. }