void scores_write (void *ptr) { scores_init (); scores_load (); scores_generate_html (); while (running) { if (score_new) { fprintf (stdout, "New score received\n"); scores_print (); score_new = 0; } } }
/** * Funzione di rendering e gestione delle iterazioni tra gli oggetti della scena */ void control_task() { int i; /* System V: inizializzazione */ // Queue id per i messaggi int qid; // Chiave del progetto per individuare la coda dei messaggi key_t msgkey; // Genero la chiave ipc msgkey = ftok(FTOK_PATH, FTOK_PROJ_ID); // Apro (o creo) la coda if((qid = msgget(msgkey, 0666 | IPC_CREAT)) == -1) { perror("Impossibile creare la coda"); exit(1); } /* Inoltre creo una queue per ogni alieno, per trasmettere le comunicazioni * relative alle collisioni */ int qid_coll[ALIEN_NUM]; key_t msgkey_coll[ALIEN_NUM]; // Struttura per memorizzare lo stato delle collisioni ed inviarlo coem messaggio all'alieno collision_msg_t coll_m; coll_m.mtype = 1; /* Genero le chiavi e creo le code */ for(i = 0; i < ALIEN_NUM; i++) { msgkey_coll[i] = ftok(FTOK_PATH, FTOK_PROJ_ID_COLL_BASE + i); // Apro (o creo) la coda if((qid_coll[i] = msgget(msgkey_coll[i], 0666 | IPC_CREAT)) == -1) { perror("Impossibile creare la coda"); exit(1); } } int last_alien_hit = -1;// Id dell'ultimo alieno colpito int obj_n = 1; // Numero di oggetti nella scena int scores = 0; // Punteggio char buffer[512]; // Buffer per stampare le stats unsigned long iterations = 0; // Numero di iterazioni int aliens = ALIEN_NUM; // Buffer di ricezione object_data_t recv_data; // Informazioni degli oggetti; la navicella e' in posizione 0. // L'elemento corrente e' puntato dal puntatore current object_data_t objects[OBJECTS_MAX]; // Oggetto corrente e suo id; spaceship = -1; object_data_t *current; int current_id; // Variabile che indica se il loop deve essere eseguito int playing = 1; // Variabile temporanea per lo stato delle collisioni dell'oggetto corrente int col; // Inizializzo le ncurses initscr(); // Inizializzo i colori delle ncurses #ifdef COLORS start_color(); init_pair(1, COLOR_WHITE, COLOR_BLACK); attron(COLOR_PAIR(1)); #endif // Non visualizzo i tasti premuti noecho(); // Inizializzo il generatore random srand((int)time(0)); // Nascondo il cursore curs_set(0); // Inizializzo la navicella objects[0].type = OT_SPACESHIP; // Inizializzo gli oggetti come non utilizzati for(i = 0; i < OBJECTS_MAX; i++) objects[i].x = -1; // Finche' il gioco non finisce, eseguo do { // Ricevo i dati di un oggetto dalla coda messaggi msgrcv(qid, &recv_data, sizeof(recv_data) - sizeof(recv_data.mtype), 1, 0); // Se non e' la navicella, ricerco nella lista l'oggetto ricevuto current = NULL; if(recv_data.type != OT_SPACESHIP) { for(i = 1; i < OBJECTS_MAX; i++) { if(recv_data.pid == objects[i].pid) { current = &objects[i]; current_id = i; i = OBJECTS_MAX; } } // Non l'ho trovato, cerco uno spazio libero if(current == NULL) { for(i = 1; i < OBJECTS_MAX; i++) if(objects[i].x == -1) { obj_n++; current = &objects[i]; i = OBJECTS_MAX; } } } // Altrimenti la navicella sta' in posizione 0 else { current = &objects[0]; current_id = 0; } // Collision detect int collision_count = 0; // Se l'oggetto corrente ha una posizione inizializzata, faccio // il check delle collisioni if(current->x != -1) { for(i = 0; i < OBJECTS_MAX; i++) { // Un oggetto non collide con se stesso if(current_id == i) continue; // Nella posizione i non c'e' nessun oggetto if(objects[i].x == -1) continue; // Se una bomba colpisce un alieno, me ne frego if(((objects[i].type == OT_BOMB) && (current->type == OT_ALIEN)) || ((objects[i].type == OT_ALIEN) && (current->type == OT_BOMB))) continue; // Se due missili si colpiscono, me ne frego if(((objects[i].type == OT_MISSILE) && (current->type == OT_MISSILE))) continue; // Controllo lo stato delle collisioni tra l'oggetto corrente // e quello in posizione i col = control_check_collision(&objects[i], current); // Se c'e' stata una collisione if(col != 0) { // Imposto il flag collision_count = 1; // Se abilitato, stampo una stringa di debug #ifdef DEBUG char cinfo[1024]; sprintf(cinfo, "Collision: type %d and type %d, x %d and x %d, y %d and y %d", (int) objects[i].type, (int) current->type, objects[i].x, current->x, objects[i].y, current->y); mvaddstr(1, 1, cinfo); #endif // A seconda del tipo di oggetto corrente, faccio un azione diversa // per ogni tipo di collisione switch(current->type) { // Se un missile colpisce un alieno, toglie una vita // o lo ammazza, ed incrementa il punteggio case OT_MISSILE: if(objects[i].type == OT_ALIEN) { if((last_alien_hit == objects[i].pid) && (iterations >= MIN_HIT_DIFF)) { coll_m.coll = 'z'; last_alien_hit = -1; } else { coll_m.coll = 'c'; last_alien_hit = objects[i].pid; } iterations = 0; msgsnd(qid_coll[objects[i].id], &coll_m, sizeof(coll_m) - sizeof(coll_m.mtype), 0); scores += objects[i].size * 10; } // Se una bomba ed un missile collidono, killo la bomba else if(objects[i].type == OT_BOMB) kill(current->pid, SIGQUIT); // E killo il missile in ogni caso kill(current->pid, SIGQUIT); break; // Collisione alieno case OT_ALIEN: // Se due alieni collidono rimbalzano if(objects[i].type == OT_ALIEN) { coll_m.coll = 'r'; // Se collidono e stanno andando entrambi // nella stessa dir, cambio direzione solo ad uno if(objects[i].dir == current->dir) { if(current->x < objects[i].x) msgsnd(qid_coll[current->id], &coll_m, sizeof(coll_m) - sizeof(coll_m.mtype), 0); else msgsnd(qid_coll[objects[i].id], &coll_m, sizeof(coll_m) - sizeof(coll_m.mtype), 0); } else { msgsnd(qid_coll[objects[i].id], &coll_m, sizeof(coll_m) - sizeof(coll_m.mtype), 0); msgsnd(qid_coll[current->id], &coll_m, sizeof(coll_m) - sizeof(coll_m.mtype), 0); } } // Se collide con un missile, invio il messaggio // all'alieno e killo il missile else if(objects[i].type == OT_MISSILE) { if(last_alien_hit == current->pid && iterations >= MIN_HIT_DIFF) { coll_m.coll = 'z'; last_alien_hit = -1; } else { coll_m.coll = 'c'; last_alien_hit = current->pid; } iterations = 0; msgsnd(qid_coll[current->id], &coll_m, sizeof(coll_m) - sizeof(coll_m.mtype), 0); scores += current->size * 10; kill(objects[i].pid, SIGQUIT); } // Se un alieno collide con la navicella, fine gioco else if(objects[i].type == OT_SPACESHIP) { playing = 0; usleep(SLEEP_OVER); } break; // Collisione bomba case OT_BOMB: // Se la bomba collide con la navicella, game over if(objects[i].type == OT_SPACESHIP) { playing = 0; usleep(SLEEP_OVER); } // Se una bomba ed un missile collidono, le killo else if(objects[i].type == OT_MISSILE) { kill(objects[i].pid, SIGQUIT); kill(current->pid, SIGQUIT); } break; // Collisione navicella case OT_SPACESHIP: // Se la navicella collide con un missile o con una bomba, fine gioco if((objects[i].type == OT_BOMB) || (objects[i].type == OT_ALIEN)) { playing = 0; usleep(SLEEP_OVER); } break; } // Aggiorno lo schermo refresh(); } } } // Qualsiasi oggetto sia, cancello prima di tutto la sua vecchia // porzione di schermo, ed inserisco nell'array degli oggetti i // dati appena ricevuti if(current->x != -1) clear_quad(current->x, current->y, current->size); *current = recv_data; // A seconda del tipo di oggetto, eseguo un operazione differente switch(recv_data.type) { // Astronave aliena case OT_ALIEN: // Se la vita di un alieno e' negativa, vuol dire che deve morire; // deve comunque inviare la struttura inizializzando come tipo // OT_DELETE if(current->life == -1) { aliens--; continue; } // A seconda del livello, disegno l'alieno in modo diverso switch(current->size) { case ALIEN_DATA1_SIZE: render_string_array(current->x, current->y, ALIEN_DATA1, ALIEN_DATA1_SIZE); break; case ALIEN_DATA2_SIZE: render_string_array(current->x, current->y, ALIEN_DATA2, ALIEN_DATA2_SIZE); break; case ALIEN_DATA3_SIZE: render_string_array(current->x, current->y, ALIEN_DATA3, ALIEN_DATA3_SIZE); break; } // Il nemico e' sceso troppo in basso, game over if(current->y > (SCREEN_HEIGHT - ALIEN_DATA2_SIZE)) { playing = 0; usleep(SLEEP_OVER); } break; // Navicella case OT_SPACESHIP: render_string_array(current->x, current->y, SPACE_SHIP_DATA, SPACE_SHIP_SIZE); break; // Bomba aliena case OT_BOMB: mvaddch(current->y, current->x, BOMB_DATA); break; // Missile dell'astronave case OT_MISSILE: mvaddch(current->y, current->x, MISSILE_DATA); break; // Un oggetto sta' morendo e vuole esser cancellato dall'array case OT_DELETE: // Invalido la sua entry nell'array current->x = -1; // Decremento il numero di oggetti della scena obj_n--; // Attendo che muoia (per non aver zombie) waitpid(current->pid); break; }; // Cancello la riga del punteggio mvaddstr(0, 0, "\t\t\t\t\t\t\t\t\t\t"); // Visualizzo il punteggio attuale sprintf(buffer, "Scores: %d", scores); mvaddstr(0, 1, buffer); // Visualizzo il numero di oggetti della scena sprintf(buffer, "Active Processes: %d", obj_n); mvaddstr(0, 20, buffer); // Visualizzo il numero di oggetti della scena //sprintf(buffer, "Last hit: %d", last_alien_hit); //mvaddstr(0, 50, buffer); // Visualizzo il numero di alieni sprintf(buffer, "Aliens: %d", aliens); mvaddstr(0, 50, buffer); // Rendo invisibile il cursore e faccio il refresh curs_set(0); refresh(); // Aggiorno il numero di iterazioni iterations++; } while(playing && aliens > 0); // Fermo le ncurses #ifdef COLORS attroff(COLOR_PAIR(1)); #endif endwin(); // Se ci son processi rimasti, invio un segnale di kill per terminarli for (i = 0; i < OBJECTS_MAX; i++) { if(objects[i].x != -1) { // Se e' un alieno, utilizzo la coda dei messaggi per le collisioni // per dire di uccidersi if(objects[i].type == OT_ALIEN) { coll_m.coll = 'd'; msgsnd(qid_coll[objects[i].id], &coll_m, sizeof(coll_m) - sizeof(coll_m.mtype), 0); } else { kill(objects[i].pid, SIGQUIT); } // Attendo che il processo esca waitpid(objects[i].pid); obj_n--; objects[i].x = -1; } } // Elimino tutte le code dei messaggi create in precedenza msgctl(qid, IPC_RMID, NULL); for(i = 0; i < ALIEN_NUM; i++) msgctl(qid_coll[i], IPC_RMID, NULL); // Aggiungo il punteggio alla lista degli highscore e visualizzo // un messaggio di fine gioco system("clear"); int pos = scores_add(scores); if(aliens == 0) printf("Hai vinto!\n"); else printf("Hai perso!\n"); if(pos == 0) printf("Nuovo punteggio high score! %d\n", scores); else printf("Il tuo punteggio e' %d\n", scores); // Visualizzo la lista dei punteggi alti int scorl[SCORES_N_MAX]; scores_load(scorl); for(i = 0; i < SCORES_N_MAX; i++) printf("\t%d\t%d\n", i+1, scorl[i]); }