/* This file is part of Invaders. * * Copyright (C) 2020 LCM. * You may use, distribute and modify Invaders under the terms of the * GPLv3 license, available at . */ #include "functions.hpp" #include "definitions.hpp" using std::cout; using std::cin; using std::endl; using std::min; extern std::mutex m_bullets; //========RECORD'S METHODS=========== void record::print() { printw("%s\t%i\n",nick.c_str(),score); } void record::printwin(WINDOW* win) { wprintw(win,"%s.......%i",nick.c_str(),score); } void record::print(std::ofstream& recordfile) { if(!recordfile.is_open()) { printw("error: record file is not open "); return; } recordfile << std::setw(6) << std::left << nick << " " << score << endl; } //=======INDIPENDENT FUNCTIONS========= void print_title() //CAPITAL LETTERS TITLE! { attron(COLOR_PAIR(5)); mvprintw(0,0," __ _ _ _ _ _ _ _ _ _ __"); mvprintw(1,0,"__// |_ |_| |_| | |_ | |\\ | | | |_| |\\ |_ |_| |_ \\\\__"); mvprintw(2,0," \\\\__ _| | | | |_ |_ | | \\| \\/ | | |/ |_ |\\ _| __//"); attron(COLOR_PAIR(0)); } void print_catchphrase(std::string phrase){ static int head=60; static int tail=60; phrase.resize(59,' '); attron(COLOR_PAIR(4)); if(head<1){ head=60; } if(head0?phrase.size()-(60-head):60); } head--; } std::string choose_phrase(){ std::string phr; int r=(int)(23*(double)rand()/RAND_MAX); switch(r){ case 0: phr="Now with cheats!"; break; case 1: phr="20 percent cooler than your 3D-graphics games!"; break; case 2: phr="NCurses rulez!"; break; case 3: phr="References to people and events are purely random."; break; case 4: phr=">>> Crush <<< Kill >>> Destroy <<< SWAG >>>"; break; case 5: phr="Also try Apocalypse 2.0!"; break; case 6: phr=")]=>---- # ASCII IS ART!!! # ----<=[("; break; case 7: phr="Still a better program than Isgro's ones..."; break; case 8: phr="<< Oh, sul serio, minchia raga, ne'? >>"; break; case 9: phr="Cool game, bro, but needs more ponies."; break; case 10: phr="Hit R!!!"; break; case 11: phr="Konami Code is still fashion."; break; case 12: phr="Almost completely debugged!"; break; case 13: phr="(((( Kill them with WUBZ! ))))"; break; case 14: phr="choose_phrase() is best function."; break; case 15: phr="zsh: segmentation fault (core dumped) invaders"; break; case 16: phr="Aliens! Aliens everywhere!"; break; case 17: phr="Breaks the fourth wall! Breaks the fourth wall!"; break; case 18: phr="Them customizable controls!!!"; break; case 19: phr=">~~~~~~~~~~~~~~~~~~~~~< You shall be assimilated into Linux."; break; case 20: phr="Did you try inv_bossrush?"; break; case 21: phr="Keep calm and FUCKIN' KILL ALIENS."; break; case 22: phr="Read the fucking `man` page!!!"; break; } return phr; } void print_info(){ WINDOW *info; info=newwin(20,80,0,0); box(info,ACS_VLINE,ACS_HLINE); mvwprintw(info,0,1,"Welcome to Space Invaders!"); wattron(info,COLOR_PAIR(1)); mvwprintw(info,2,1,"About the Game:"); wattron(info,COLOR_PAIR(6)); mvwprintw(info,3,1,"This is a Terminal-playable game where you control a moving cannon base"); mvwprintw(info,4,1,"("); wattron(info,COLOR_PAIR(1)); wprintw(info,"========"); wattron(info,COLOR_PAIR(6)); wprintw(info,") with the aim to destroy all the enemy Space Invaders"); mvwprintw(info,5,1,"("); wattron(info,COLOR_PAIR(2)); wprintw(info,"#"); wattron(info,COLOR_PAIR(6)); wprintw(info,") assaulting the Earth. After killing all the Space Invaders, you shall face"); mvwprintw(info,6,1,"the Big Alien Boss, the most powerful of all the alien enemies."); mvwprintw(info,7,1,"During the game, mind the Powerups ("); wattron(info,COLOR_PAIR(3)); wprintw(info,"+"); wattron(info,COLOR_PAIR(6)); wprintw(info,","); wattron(info,COLOR_PAIR(1)); wprintw(info,"-"); wattron(info,COLOR_PAIR(6)); wprintw(info,","); wattron(info,COLOR_PAIR(4)); wprintw(info,"X"); wattron(info,COLOR_PAIR(6)); wprintw(info,") that will increase"); mvwprintw(info,8,1,"your shooting power if you manage to get them."); wattron(info,COLOR_PAIR(1)); mvwprintw(info,10,1,"Default Controls: "); wattron(info,COLOR_PAIR(5)); mvwprintw(info,11,1,"<- "); wattron(info,COLOR_PAIR(6)); wprintw(info," A or Left Arrow"); wattron(info,COLOR_PAIR(5)); mvwprintw(info,12,1,"-> "); wattron(info,COLOR_PAIR(6)); wprintw(info," D or Right Arrow"); wattron(info,COLOR_PAIR(5)); mvwprintw(info,13,1,"shoot "); wattron(info,COLOR_PAIR(6)); wprintw(info," spacebar"); wattron(info,COLOR_PAIR(3)); mvwprintw(info,15,10,"Game developed by Giacomo Parolini & Enrico Guiraud (v.4.4)"); wattron(info,COLOR_PAIR(6)); mvwprintw(info,17,14,"Click any key to return to the Start Menu"); wattron(info,COLOR_PAIR(0)); wrefresh(info); timeout(-1); if(getch()!=ERR){ delwin(info); erase(); refresh(); } } int choose_level(int* commands) { std::string phrase; phrase=choose_phrase(); char input; do{ print_title(); print_catchphrase(phrase); attron(COLOR_PAIR(1)); mvprintw(5,0,"Choose difficulty level:"); attron(COLOR_PAIR(1)); mvprintw(6,0,"1- Easy"); attron(COLOR_PAIR(3)); mvprintw(7,0,"2- Medium"); attron(COLOR_PAIR(2)); mvprintw(8,0,"3- Hard"); attron(COLOR_PAIR(4)); mvprintw(9,0,"4- Impossible"); attron(COLOR_PAIR(5)); mvprintw(10,0,"i- Info"); attron(COLOR_PAIR(6)); mvprintw(11,0,"h- Highscores"); attron(COLOR_PAIR(1)); mvprintw(12,0,"c- Commands"); attron(COLOR_PAIR(2)); mvprintw(13,0,"q- Quit"); refresh(); timeout(80); input=tolower(getch()); if(!(input=='1' || input=='2' || input=='3' || input=='4' || input=='i' || input=='h' || input=='r' || input =='q') && input!=ERR){ attron(COLOR_PAIR(2)); mvprintw(14,0,"Bad input. Please choose a number within 1 and 4."); attron(COLOR_PAIR(0)); } if(input=='i') print_info(); if(input=='h') print_scores(); if(input=='r') phrase=choose_phrase(); if(input=='c') change_commands(commands); if(input=='q'){ endwin(); cout<0) line--; break; case 'X': delwin(change); erase(); refresh(); return; case '\n': wattron(change,COLOR_PAIR(2)); mvwprintw(change,line+5,1,"%s: %s",name[line].c_str(),chcommands[line].c_str()); wrefresh(change); timeout(-1); cmd=wgetch(change); commands[line]=tolower(cmd); wmove(change,line+5,0); wclrtoeol(change); box(change,ACS_VLINE,ACS_HLINE); wattron(change,COLOR_PAIR(1)); break; } wrefresh(change); }while(cmd!='X'); delwin(change); erase(); refresh(); return; } void load_enemies(e_list& enemies,int enemy_num) { enemies.clear(); for(int i=0; iC-1) { c=0; r++; if(r>R-2) break; } enemy newenemy(c++,r); if(newenemy.y%2!=0) newenemy.direction=1; enemies.push_back(newenemy); } } char playagain(WINDOW* replay) { char answer; do { wattron(replay,COLOR_PAIR(2)); mvwprintw(replay,1,3,"Play again? [y/n/q] "); answer=tolower(wgetch(replay)); }while(answer!='y' && answer!='n' && answer!='q'); return answer; } bool gameover(player& _player,b_list& bombs) //Checks if a bomb/enemy/boss hit the player. { for(b_list::iterator it=bombs.begin(); it!=bombs.end(); ++it) if((it->x>=_player.x && it->x<_player.x+_player.length) && (it->y==_player.y) && !_player.godmode) return true; return false; } void reset(player& _player, e_list &enemies, boss& boss1, b_list& bullets, b_list& bombs, w_vec& walls, int walls_num, b_list& powerups, r_list& rockets, int& chflag) { _player.x=C/2; //resetting initial position and stats of player1 _player.y=R-1; _player.weaponclass=0; _player.length=8; _player.rocketlauncher=FALSE; int c=0, r=0; e_list::const_iterator e_end = enemies.end(); for(e_list::iterator it = enemies.begin(); it!=e_end; ++it) //resetting all the enemies { if(c==C) { c=0; r++; } it->alive = true; it->x=c++; it->y=r; if(it->y%2==0) it->direction=0; else it->direction=1; } boss1.alive = false; bullets.clear(); //destroying all bullets/bombs/etc bombs.clear(); powerups.clear(); rockets.clear(); chflag=0; walls.resize(walls_num); for(int i=0;ialive==true) { isalive = true; break; } return isalive; } bool operator<(record record1, record record2) { if(record1.score.5) wattron(BossHP,COLOR_PAIR(1)); else if((double)hp/hpmax>.25) wattron(BossHP,COLOR_PAIR(3)); else wattron(BossHP,COLOR_PAIR(2)); wmove(BossHP,2,0); wdeleteln(BossHP); mvwprintw(BossHP,2,0,"%i / %i HP",hp,hpmax); //writes boss's hp / hpmax (color depends on hp/hpmax ratio) } void Victory(std::string name,int score,int level,int chflag){ score+=1500*level; WINDOW *victory; victory=newwin(19,32,7,17); box(victory,ACS_VLINE,ACS_HLINE); wattron(victory,COLOR_PAIR(1)); mvwprintw(victory,2,4,"YOU DEFEATED %s!",name.c_str()); wattron(victory,COLOR_PAIR(3)); mvwprintw(victory,4,5,"+ %i pts!",level*1500); wattron(victory,COLOR_PAIR(1)); mvwprintw(victory,4,5,"YOU WON!"); wattron(victory,COLOR_PAIR(3)); mvwprintw(victory,4,5,"Your score is: %i",score); wrefresh(victory); if(chflag==0) refreshrecords(score,victory); else{ wattron(victory,COLOR_PAIR(4)); mvwprintw(victory,7,3,"I think you used cheats..."); } wrefresh(victory); delwin(victory); } void Defeat(int score){ WINDOW *defeat; defeat=newwin(10,32,7,17); box(defeat,ACS_VLINE,ACS_HLINE); wattron(defeat,COLOR_PAIR(2)); mvwprintw(defeat,3,10,"GAME OVER!"); wattron(defeat,COLOR_PAIR(3)); mvwprintw(defeat,6,4,"Your score was: %i pts!",score); wrefresh(defeat); delwin(defeat); } void get_SpecialMode(int c,int& chflag,boss& boss1,e_list& enemies,b_list& bullets,b_list& bombs,r_list& rockets){ if(get_KonamiCode(c)){ activate_combo(boss1,enemies,bullets,bombs,rockets); if(chflag==0) chflag=2; if(chflag==1) chflag=3; } } bool get_KonamiCode(int c){ //UP,UP,DOWN,DOWN,LEFT,RIGHT,LEFT,RIGHT,B,A static int combo=0; switch(combo){ case 0: case 1: if(c==KEY_UP) combo++; else if(c!=ERR) combo=0; break; case 2: case 3: if(c==KEY_DOWN) combo++; else if(c!=ERR) combo=0; break; case 4: case 6: if(c==KEY_LEFT) combo++; else if(c!=ERR) combo=0; break; case 5: case 7: if(c==KEY_RIGHT) combo++; else if(c!=ERR) combo=0; break; case 8: if(c=='b') combo++; else if(c!=ERR) combo=0; break; case 9: if(c=='a'){ return true; } else if(c!=ERR) combo=0; break; } return false; } void get_cheat(char command,player& player1,e_list& enemies,double& shootrate){ switch(command){ case '+': if(player1.weaponclass<5) player1.weaponclass++; //increase weaponclass break; case '\\': if(player1.weaponclass>1) player1.weaponclass--; //decrease weaponclass break; case '-': if(player1.length>2){ //decrease size mvaddch(player1.y,player1.x+player1.length-1,' '); player1.length--; } break; case '*': if(player1.lengthalive=false; mvaddch(it->y,it->x,' '); } break; case 'r': //activate rocketlauncher and increase weaponclassrkt if(!(player1.rocketlauncher)) player1.rocketlauncher=TRUE; else if(player1.weaponclassrkt0) player1.weaponclassrkt--; else player1.rocketlauncher=FALSE; break; case 'u': //trigger uber mode player1.rocketlauncher=TRUE; player1.weaponclass=MAX_WEAPONCLASS; player1.weaponclassrkt=MAX_WEAPONCLASSRKT; player1.length=MAX_LENGTH; break; case 'g': //trigger/untrigger godmode player1.godmode=!player1.godmode; break; case 'f': //freeze: enemies won't shoot. shootrate=0; break; } } void activate_combo(boss& boss1,e_list& enemies,b_list& bullets,b_list& bombs,r_list& rockets){ //if the player performs the Konami Code, the normal boss is replaced with BIG_ALIENBOSS boss bossextra(1,1,500,17,5,BOSS_FILE5); boss1 = bossextra; std::string bossname=getenv("HOME"); bossname=bossname+RECORD_DIR+BOSS_FILE5+".dat"; boss1.loadpicture(bossname.c_str()); for(int i=0;i<7;){ attron(COLOR_PAIR(i++)); mvprintw(15,15,"SPECIAL MODE ACTIVATED!!!"); refresh(); napms(150); } attron(COLOR_PAIR(0)); napms(1500); for(e_list::iterator i=enemies.begin();i!=enemies.end();i++) i->alive=false; bullets.clear(); bombs.clear(); rockets.clear(); erase(); } //=============BOX'S REPLACEMENT FUNCTIONS============================ void draw(player& player1,b_list& bullets,b_list& bombs,e_list& enemies,w_vec& walls,b_list& powerups,r_list& rockets,boss& boss1){ struct point { point() { x=y=0; } point(int X, int Y) { x=X; y=Y; } int x,y; }; static std::vector bullets_p, enemies_p, bombs_p, powerups_p, rockets_p, walls_p, player_p, boss_p; //REDRAW BULLETS for(auto bullet_p: bullets_p) mvaddch(bullet_p.y,bullet_p.x,' '); bullets_p.clear(); attron(COLOR_PAIR(3)); for(auto bullet: bullets) { mvaddch(bullet.y,bullet.x,BULLET_SPRITE); bullets_p.push_back(point(bullet.x,bullet.y)); } //REDRAW BOMBS for(auto bomb_p: bombs_p) mvaddch(bomb_p.y,bomb_p.x,' '); bombs_p.clear(); attron(COLOR_PAIR(6)); for(auto bomb: bombs) { //if(bomb.y.5*boss1.healthmax) attron(COLOR_PAIR(5)); else if(boss1.health>.25*boss1.healthmax) attron(COLOR_PAIR(3)); else attron(COLOR_PAIR(2)); mvaddch(i,j,boss1.picture[i-boss1.y][j-boss1.x]); boss_p.push_back(point(j,i)); } //REDRAW PLAYER for(auto play_point: player_p) mvaddch(play_point.y,play_point.x,' '); player_p.clear(); if(player1.godmode) attron(COLOR_PAIR(5)); else attron(COLOR_PAIR(1)); for(int i=player1.x;i0) { mvaddch(j+walls[i].y,k+walls[i].x,WALL_SPRITE); walls_p.push_back(point(k+walls[i].x,j+walls[i].y)); } } } void drop_powerup(int x,int y,b_list& powerups) { if((double)rand()/RAND_MAX<1./POWERUP_RATIO){ //1 powerup out of POWERUP_RATIO is either a "-" (with ID 128 instead of 64) or a "X" if((double)rand()/RAND_MAX<1./ROCKET_RATIO){ //1 powerup out of ROCKET_RATIO*POWERUP_RATIO is a "X" (ID 512) powerup newpowerup(x,y,512); powerups.push_back(newpowerup); } else{ powerup newpowerup(x,y,128); powerups.push_back(newpowerup); } } else{ powerup newpowerup(x,y); //otherwise, it is a "+" powerups.push_back(newpowerup); } } void interactions(player& player1,b_list& bullets,b_list& bombs,e_list& enemies,w_vec& walls,b_list& powerups,r_list& rockets,boss& boss1,int& score, double poweruprate){ bool should_continue; b_list::iterator it1=bullets.begin(); while(it1!=bullets.end()) { should_continue = false; if(it1->y<=0) { //bullet reached the ceiling it1 = bullets.erase(it1); continue; } b_list::iterator it2 = bombs.begin(); while(it2!=bombs.end()) { if(it1->x==it2->x && (it1->y==it2->y || it1->y==it2->y+1)){ //bullet+bomb it1=bullets.erase(it1); should_continue = true; it2=bombs.erase(it2); score+=50; break; } else ++it2; } if(should_continue) continue; for(e_list::iterator it3=enemies.begin(); it3!=enemies.end(); ++it3) if(it1->x==it3->x && it1->y==it3->y && it3->alive){ //bullet+enemy it1=bullets.erase(it1); should_continue = true; it3->alive=false; if((double)rand()/RAND_MAXx,it3->y+1,powerups); score+=100; break; } if(should_continue) continue; if((it1->x>=boss1.x+boss1.width/2-2 && it1->x<=boss1.x+boss1.width/2+2) && boss1.alive){ //bullet+boss boss1.health--; if(it1->y==boss1.y) it1=bullets.erase(it1); //bullet gets destroyed only when has reached boss's top else { ++it1; continue; } //(to make the boss lose life more quickly) } ++it1; } r_list::iterator itr=rockets.begin(); while(itr != rockets.end()) { should_continue = false; if(itr->y<=0) //rocket reached the ceiling { itr=rockets.erase(itr); continue; } b_list::iterator it2=bombs.begin(); //bomb+rocket while(it2!=bombs.end()) { if((itr->x==it2->x && itr->y==it2->y) || (itr->v>0 && (itr->x==it2->x-1 && itr->y==it2->y+1)) || (itr->v<0 && (itr->x==it2->x+1 && itr->y==it2->y+1))){ //rocket+bomb itr=rockets.erase(itr); should_continue = true; it2=bombs.erase(it2); score+=50; break; } else ++it2; } if(should_continue) continue; e_list::iterator it3 = enemies.begin(); while(it3!=enemies.end()) { if(itr->x==it3->x && itr->y==it3->y){ //rocket+enemy itr=rockets.erase(itr); it3=enemies.erase(it3); should_continue = true; break; } else ++it3; } if(should_continue) continue; if((itr->x>=boss1.x+boss1.width/2-2 && itr->x<=boss1.x+boss1.width/2+2) && boss1.alive) //rocket+boss { boss1.health--; if(itr->y==boss1.y) { itr=rockets.erase(itr); continue; } } ++itr; } b_list::iterator itb=bombs.begin(); while(itb!=bombs.end()){ if(itb->y>=R) //bomb reached the floor { itb=bombs.erase(itb); continue; } if(itb->x>=player1.x && itb->xy>player1.y) //bomb+player { itb=bombs.erase(itb); continue; } ++itb; } b_list::iterator itp=powerups.begin(); while( itp!=powerups.end()){ if(itp->y==player1.y && itp->x>=player1.x && itp->xid){ case 64: if(player1.weaponclass2){ mvaddch(player1.y,player1.x+player1.length-1,' '); player1.length--; } break; case 512: if(!(player1.rocketlauncher)) player1.rocketlauncher=TRUE; else if(player1.weaponclassrkty>=R) //powerup reached the floor { itp=powerups.erase(itp); continue; } ++itp; } for(size_t i=0;i0) { b_list::iterator it1=bullets.begin(); while(it1!=bullets.end()) { if(it1->x==walls[i].x+j && it1->y==walls[i].y+k){ it1=bullets.erase(it1); walls[i].health[k][j]--; } else ++it1; } b_list::iterator it2=bombs.begin(); while(it2!=bombs.end()) { if(it2->x==walls[i].x+j && it2->y==walls[i].y+k){ it2=bombs.erase(it2); walls[i].health[k][j]--; } else ++it2; } r_list::iterator it3=rockets.begin(); while(it3!=rockets.end()) { if(it3->x==walls[i].x+j && it3->y==walls[i].y+k){ it3=rockets.erase(it3); walls[i].health[k][j]--; } else ++it3; } b_list::iterator it4=powerups.begin(); while(it4!=powerups.end()) { if(it4->x==walls[i].x+j && it4->y==walls[i].y+k){ it4=powerups.erase(it4); } else ++it4; } } } } //********** SAVE FUNCTIONS ***************************** void refreshrecords(int newscore,WINDOW* win) { r_vec records; std::string nick; record newrecord; std::string local_recpath; std::string local_dir=getenv("HOME"); //get environment variable $HOME local_dir+=RECORD_DIR; //we set local_dir and local_recpath: ~/.local/share/invaders/records.dat local_recpath=local_dir; local_recpath+=RECORD_FILE; wattron(win,COLOR_PAIR(5)); mvwprintw(win,6,5,"Please insert your nick"); mvwprintw(win,7,2,"(up to 5 characters): "); wattron(win,COLOR_PAIR(1)); echo(); char getnick[6]; wscanw(win,"%s",getnick); nick=getnick; nick.resize(5,'.'); noecho(); std::ifstream recordin(local_recpath.c_str()); //first, check if local_recpath exists; if not, create it. if(recordin) //note that local_recpath is actually a symlink to global_recpath { recordin >> newrecord.nick; recordin >> newrecord.score; while(!recordin.eof()) { records.push_back(newrecord); recordin >> newrecord.nick; recordin >> newrecord.score; } recordin.close(); newrecord.score=newscore; newrecord.nick=nick; records.push_back(newrecord); sort(records.rbegin(), records.rend()); wattron(win,COLOR_PAIR(6)); mvwprintw(win,9,11,"TOP FIVE"); wattron(win,COLOR_PAIR(0)); int count=0; for(r_vec::iterator it=records.begin(); (it!=records.begin()+5 && it!=records.end()); ++it,++count) { wmove(win,10+count,9); it->printwin(win); } count=0; for(r_vec::iterator it=records.begin(); it!=records.end(); ++it) { count++; if(*it==newrecord) { mvwprintw(win,16,3,"You're number %i out of %i",count,records.size()); break; } } std::ofstream recordout(local_recpath.c_str()); for(r_vec::iterator it=records.begin(); it!=records.end(); ++it) it->print(recordout); recordout.close(); } else //records.dat not found { //if local_recpath does not exist, then we must create the local_dir. recordin.close(); recordin.clear(); create_folder(0); //now we check if global_recpath exists. std::string global_recpath=GLOBAL_DIR; //global_recpath is GLOBAL_DIR/records.dat global_recpath+=RECORD_FILE; //we try to open GLOBAL_DIR/records.dat std::ifstream globalin(global_recpath.c_str()); if(!globalin){ globalin.close(); globalin.clear(); create_folder(1); //try to create global_dir (will fail if already std::ofstream globalout(global_recpath.c_str()); //exists) and save the global_recpath. globalout.close(); globalout.clear(); chmod(global_recpath.c_str(),S_IRWXG | S_IRWXU | S_IRWXO); } else{ //just save to GLOBAL_DIR/records.dat globalin >> newrecord.nick; globalin >> newrecord.score; while(!globalin.eof()) { records.push_back(newrecord); globalin >> newrecord.nick; globalin >> newrecord.score; } globalin.close(); } //finally, create the symlink to global_recpath symlink(global_recpath.c_str(),local_recpath.c_str()); newrecord.score=newscore; newrecord.nick=nick; records.push_back(newrecord); sort(records.rbegin(), records.rend()); //and save there the records. std::ofstream recordout(local_recpath.c_str()); for(r_vec::iterator it=records.begin(); it!=records.end(); ++it) it->print(recordout); recordout.close(); } } void print_scores(){ r_vec records; std::string recordpath; std::string record_dir=getenv("HOME"); record_dir+=RECORD_DIR; recordpath=record_dir; recordpath+=RECORD_FILE; std::ifstream recordin(recordpath.c_str()); record newrecord; int i=1; if(recordin){ WINDOW *recs; recs=newwin(25,30,0,0); box(recs,ACS_VLINE,ACS_HLINE); wattron(recs,COLOR_PAIR(5)); mvwprintw(recs,1,1,"======= HIGHSCORES ======="); wattron(recs,COLOR_PAIR(0)); recordin >> newrecord.nick; recordin >> newrecord.score; while(!recordin.eof() && i<21) { records.push_back(newrecord); recordin >> newrecord.nick; recordin >> newrecord.score; i++; } recordin.close(); i=1; for(r_vec::iterator it=records.begin(); it!=records.end(); ++it){ if(i<10) mvwprintw(recs,i+2,1,"0%i- ",i); else mvwprintw(recs,i+2,1,"%i- ",i); it->printwin(recs); i++; } wrefresh(recs); timeout(-1); if(getch()!=ERR){ delwin(recs); erase(); refresh(); } } else{ WINDOW *recs; std::string host=getenv("USER"); recs=newwin(5,3+host.length()+record_dir.length(),5,5); box(recs,ACS_VLINE,ACS_HLINE); wattron(recs,COLOR_PAIR(5)); mvwprintw(recs,1,1,"Save file:"); mvwprintw(recs,2,1,"%s",record_dir.c_str()); mvwprintw(recs,3,1,"%s not found.",RECORD_FILE); //mvwprintw(recs,4,1,"not found."); wrefresh(recs); timeout(-1); if(getch()!=ERR){ delwin(recs); erase(); refresh(); } } } /*//=========== THREADS FUNCTIONS ============================== void *pmusic(void *arg){ while(1){ system("beep 330 -l 150 -n -f 1 -l 40 -n -f 494 -l 159 -n -f 1 -l 40 -n -f 660 -l 150 -n -f 1 -l 40 -n -f 590 -l 150 -n -f 660 -l 150 -n -f 494 -l 100 -n -f 494 -l 100 -n -f 523 -l 150 -n -f 1 -l 40 -n -f 440 -l 150 -n -f 1 -l 40 -n -f 494 -l 150 -n -f 1 -l 40 -n -f 392 -l 100 -n -f 392 -l 100 -n -f 440 -l 150 -n -f 370 -l 150 -n -f 1 -l 40 -n -f 392 -l 150 -n -f 1 -l 40 -n -f 330 -l 100 -n -f 330 -l 100 -n -f 370 -l 150 -n -f 1 -l 40 -n -f 294 -l 150 -n -f 1 -l 40 -n -f 330 -l 150 -n -f 247 -l 100 -n -f 247 -l 100 -n -f 261 -l 150 -n -f 1 -l 40 -n -f 311 -l 150 -n -f 1 -l 40 -n -f 330 -l 150 -n -f 1 -l 40 -n -f 247 -l 100 -n -f 247 -l 100 -n -f 262 -l 150 -n -f 1 -l 40 -n -f 370 -l 150 -n -f 1 -l 40 -n -f 330 -l 150 -n -f 1 -l 40 -n -f 494 -l 159 -n -f 1 -l 40 -n -f 660 -l 150 -n -f 1 -l 40 -n -f 590 -l 150 -n -f 660 -l 150 -n -f 494 -l 100 -n -f 494 -l 100 -n -f 523 -l 150 -n -f 1 -l 40 -n -f 440 -l 150 -n -f 1 -l 40 -n -f 494 -l 150 -n -f 1 -l 40 -n -f 392 -l 100 -n -f 392 -l 100 -n -f 440 -l 150 -n -f 370 -l 150 -n -f 1 -l 40 -n -f 392 -l 150 -n -f 1 -l 40 -n -f 330 -l 100 -n -f 330 -l 100 -n -f 370 -l 150 -n -f 1 -l 40 -n -f 294 -l 150 -n -f 1 -l 40 -n -f 330 -l 150 -n -f 247 -l 100 -n -f 247 -l 100 -n -f 261 -l 150 -n -f 1 -l 40 -n -f 311 -l 150 -n -f 1 -l 40 -n -f 330 -l 150 -n -f 1 -l 40 -n -f 247 -l 100 -n -f 247 -l 100 -n -f 262 -l 150 -n -f 1 -l 40 -n -f 370 -l 150 -n -f 1 -l 40 -n -f 330 -l 150 -n -f 1 -l 40 2> /dev/null"); napms(2000); } } void *pshoot_sound(void *arg){ system("beep -f 1000 -l 30 -n -f 850 -l 30 2> /dev/null"); } void *penshoot_sound(void *arg){ system("beep -f 1500 -l 30 -n -f 1000 -l 30 2> /dev/null"); } void *pwin_theme(void *arg){ system("beep -f 1000 -l 150 -n -f 800 -l 150 -n -f 1000 -l 150 -n -f 1500 -l 600 2> /dev/null"); } void *plose_theme(void *arg){ system("beep -f 700 -l 150 -n -f 585 -l 150 -n -f 550 -l 150 -n -f 520 -l 600 2> /dev/null"); } void pkill_music(pthread_t thread){ pthread_cancel(thread); system("beep -f 1 2> /dev/null"); }*/ //=========BOSSRUSH FUNCTIONS======================= int choose_level_bossrush(int* commands) { std::string phrase; phrase=choose_phrase(); char input; do{ print_title(); print_catchphrase(phrase); attron(COLOR_PAIR(1)); mvprintw(5,0,"Choose difficulty level:"); attron(COLOR_PAIR(1)); mvprintw(6,0,"1- Easy"); attron(COLOR_PAIR(3)); mvprintw(7,0,"2- Medium"); attron(COLOR_PAIR(2)); mvprintw(8,0,"3- Hard"); attron(COLOR_PAIR(4)); mvprintw(9,0,"4- Impossible"); attron(COLOR_PAIR(5)); mvprintw(10,0,"i- Info"); attron(COLOR_PAIR(6)); mvprintw(11,0,"h- Highscores"); attron(COLOR_PAIR(1)); mvprintw(12,0,"c- Commands"); attron(COLOR_PAIR(2)); mvprintw(13,0,"q- Quit"); refresh(); timeout(80); input=tolower(getch()); if(!(input=='1' || input=='2' || input=='3' || input=='4' || input=='i' || input=='h' || input=='r' || input=='q') && input!=ERR){ attron(COLOR_PAIR(2)); mvprintw(14,0,"Bad input. Please choose a number within 1 and 4."); attron(COLOR_PAIR(0)); } if(input=='i') print_info(); else if(input=='h') print_scores_bossrush(); else if(input=='r') phrase=choose_phrase(); else if(input=='c') change_commands(commands); else if(input=='q'){ endwin(); cout<health=bosses->healthmax; bosses++; bosses->health=bosses->healthmax; bosses++; bosses->health=bosses->healthmax; bosses++; bosses->health=bosses->healthmax; bosses++; bosses->health=bosses->healthmax; boss1=*Bosses; boss1.alive=true; player1.weaponclass=1; } void Victory_bossrush(std::string name,int score,int level,int chflag){ score+=1500*level; WINDOW *victory; victory=newwin(19,32,7,17); box(victory,ACS_VLINE,ACS_HLINE); wattron(victory,COLOR_PAIR(1)); mvwprintw(victory,2,5,"YOU DEFEATED %s!",name.c_str()); wattron(victory,COLOR_PAIR(3)); mvwprintw(victory,4,5,"+ %i pts!",level*1500); wattron(victory,COLOR_PAIR(1)); mvwprintw(victory,4,5,"YOU WON!"); wattron(victory,COLOR_PAIR(3)); mvwprintw(victory,4,5,"Your score is: %i",score); wrefresh(victory); if(chflag==0) refreshrecords_bossrush(score,victory); else{ wattron(victory,COLOR_PAIR(4)); mvwprintw(victory,7,3,"I think you used cheats..."); } wrefresh(victory); delwin(victory); } void refreshrecords_bossrush(int newscore,WINDOW* win) { r_vec records; std::string nick; record newrecord; std::string local_recpath; std::string local_dir=getenv("HOME"); //get environment variable $HOME local_dir+=RECORD_DIR; //we set local_dir and local_recpath: ~/.local/share/invaders/records_bossrush.dat local_recpath=local_dir; local_recpath+=RECORD_FILE_BOSSRUSH; wattron(win,COLOR_PAIR(5)); mvwprintw(win,6,5,"Please insert your nick"); mvwprintw(win,7,2,"(up to 5 characters): "); wattron(win,COLOR_PAIR(1)); echo(); char getnick[6]; wscanw(win,"%s",getnick); nick=getnick; nick.resize(5,'.'); noecho(); std::ifstream recordin(local_recpath.c_str()); if(recordin) { recordin >> newrecord.nick; recordin >> newrecord.score; while(!recordin.eof()) { records.push_back(newrecord); recordin >> newrecord.nick; recordin >> newrecord.score; } recordin.close(); newrecord.score=newscore; newrecord.nick=nick; records.push_back(newrecord); sort(records.rbegin(), records.rend()); wattron(win,COLOR_PAIR(6)); mvwprintw(win,9,11,"TOP FIVE"); wattron(win,COLOR_PAIR(0)); int count=0; for(r_vec::iterator it=records.begin(); (it!=records.begin()+5 && it!=records.end()); ++it,++count) { wmove(win,10+count,9); it->printwin(win); } count=0; for(r_vec::iterator it=records.begin(); it!=records.end(); ++it) { count++; if(*it==newrecord) { mvwprintw(win,16,3,"You're number %i out of %i",count,records.size()); break; } } std::ofstream recordout(local_recpath.c_str()); for(r_vec::iterator it=records.begin(); it!=records.end(); ++it) it->print(recordout); recordout.close(); } else //records_bossrush.dat not found { recordin.close(); recordin.clear(); create_folder(0); //this will fail if local_dir already exists (possible if player played bossrush before). //now we check if global_recpath exists. std::string global_recpath=GLOBAL_DIR; //global_recpath is GLOBAL_DIR/records_bossrush.dat global_recpath+=RECORD_FILE_BOSSRUSH; //we try to open GLOBAL_DIR/records.dat std::ifstream globalin(global_recpath.c_str()); if(!globalin){ globalin.close(); globalin.clear(); create_folder(1); //try to create global_dir (will fail if already std::ofstream globalout(global_recpath.c_str()); //exists) and save the global_recpath. globalout.close(); globalout.clear(); chmod(global_recpath.c_str(),S_IRWXG | S_IRWXU | S_IRWXO); } else{ //just save to GLOBAL_DIR/records_bossrush.dat globalin >> newrecord.nick; globalin >> newrecord.score; while(!globalin.eof()) { records.push_back(newrecord); globalin >> newrecord.nick; globalin >> newrecord.score; } globalin.close(); } //finally, create the symlink to global_recpath symlink(global_recpath.c_str(),local_recpath.c_str()); newrecord.score=newscore; newrecord.nick=nick; records.push_back(newrecord); sort(records.rbegin(), records.rend()); //and save there the records. std::ofstream recordout(local_recpath.c_str()); for(r_vec::iterator it=records.begin(); it!=records.end(); ++it) it->print(recordout); recordout.close(); } } void print_scores_bossrush(){ r_vec records; std::string recordpath; std::string record_dir=getenv("HOME"); record_dir+=RECORD_DIR; recordpath=record_dir; recordpath+=RECORD_FILE_BOSSRUSH; std::ifstream recordin(recordpath.c_str()); record newrecord; int i=1; if(recordin){ WINDOW *recs; recs=newwin(25,30,0,0); box(recs,ACS_VLINE,ACS_HLINE); wattron(recs,COLOR_PAIR(5)); mvwprintw(recs,1,1,"======= HIGHSCORES ======="); wattron(recs,COLOR_PAIR(0)); recordin >> newrecord.nick; recordin >> newrecord.score; while(!recordin.eof() && i<21) { records.push_back(newrecord); recordin >> newrecord.nick; recordin >> newrecord.score; i++; } recordin.close(); i=1; for(r_vec::iterator it=records.begin(); it!=records.end(); ++it){ if(i<10) mvwprintw(recs,i+2,1,"0%i- ",i); else mvwprintw(recs,i+2,1,"%i- ",i); it->printwin(recs); i++; } wrefresh(recs); timeout(-1); if(getch()!=ERR){ delwin(recs); erase(); refresh(); } } else{ WINDOW *recs; std::string host=getenv("USER"); recs=newwin(6,25+host.length(),5,5); box(recs,ACS_VLINE,ACS_HLINE); wattron(recs,COLOR_PAIR(5)); mvwprintw(recs,1,1,"Save file:"); mvwprintw(recs,2,1,"%s",record_dir.c_str()); mvwprintw(recs,3,1,"%s",RECORD_FILE_BOSSRUSH); mvwprintw(recs,4,1,"not found."); wrefresh(recs); timeout(-1); if(getch()!=ERR){ delwin(recs); erase(); refresh(); } } } void create_readme(){ std::string recordpath; std::string record_dir=getenv("HOME"); record_dir+=RECORD_DIR; recordpath=record_dir; recordpath+="README.txt"; std::ifstream checkread(recordpath.c_str()); if(!checkread){ checkread.close(); checkread.clear(); std::ofstream readme(recordpath.c_str()); readme<<"#==Space Invaders=="< for graphic terminal management."< and for graphics."< and may not work correctly on some terminals. Versions 3.0 and following also contain executable \"bossrush\"."<.dat and open it with any text editor (like Gedit, Vim or Notepad)."<\" or \"./checkboss \". Syntax of setboss.sh is \"./setboss.sh \"; the script will substitute the boss of the -th game level (1=easy, 2=medium, 3=hard, 4=impossible, 5=special boss) with your custom boss. Notice that setboss.sh needs you to pass the argument WITHOUT the \".dat\"."< /dev/null; exit -1\" SIGINT SIGTERM"<$INPUT_FILE.tmp"<$INPUT_FILE"<$INPUT_FILE.tmp"<$INPUT_FILE"<