invaders.cpp 11 KB

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