Subversion Repositories shark

Rev

Blame | Last modification | View Log | RSS feed

/*
 * Invaders 2004
 * Copyright (C) 2004 Nicola Rialti, Alessandro Vannuccini, Matteo Corsini

 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.

 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE@.  See the GNU
 * General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
 * USA.
 */


#include <kernel/kern.h>
#include <drivers/glib.h>
#include <drivers/keyb.h>
#include <semaphore.h>
#include <stdlib.h>
#include <math.h>

#define YMENU          10            
#define XMIN           50
#define XMAX           600
#define YMIN           100
#define YMAX           450
#define VEL            3              // velocità dei nemici
#define VEL_NAVICELLA  6              // velocità della navicella
#define D              10             // raggio dell'astronave invasore
#define ESC            27             // ASCII code of ESCAPE key
#define MAX_ENEMIES    15             // numero massimo di nemici
#define MAX_MISSILE    3              // numero massimo di missili
#define INITIAL_LIFE   3              // numero di vite iniziali

#define    HEIGHT_NAV               10    // altezza della navicella
#define    COLOR_NAV                4     // colore della navicella
#define    LENGTH_NAV               20    // lunghezza della navicella

#define    LENGTH_MISSILE           7     // lunghezza del missile

#define    ENEMY_CREATOR_PERIOD     400000
#define    ENEMY_CREATOR_WCET       100
#define    ENEMY_CREATOR_MET        100

#define    NAVICELLA_PERIOD         10000
#define    NAVICELLA_WCET           500
#define    NAVICELLA_MET            500

#define    ENEMY_PERIOD             40000  // 25 fps
//#define    ENEMY_PERIOD             16666  // 60 fps
#define    ENEMY_WCET               1000
#define    ENEMY_MET                800

#define    MISSILE_PERIOD           40000
#define    MISSILE_WCET             500


int num_enemies;                 // numero dei nemici che varia a seconda dello schema
int speed;                       // velocità dei nemici che varia a seconda dello schema

double  tick = 1.0;             /* system tick = 1 ms           */
sem_t   mutex;
PID pid;

/* Struttura con i dati dei nemici */
struct enemy_table {
  int status;         // 0 -> risorsa libera, 1 -> risorsa occupata
  int killed;         // 1 -> il nemico è stato ucciso          
  PID pid;
  WORD x,y;          
  int color;
} enemy_table[MAX_ENEMIES];

struct table {
  int count_enemies;
  int count_missile;
  int score;
  int level;
  int killed;         // 1 -> l'astronave è stata colpita
  int life;      
  WORD x_center;
  /* semafori di mutua per scrivere nelle strutture condivise   */
  /* un semaforo per il contatore dei missili, uno per i nemici */
  /* uno per la posizione dei nemici                            */
  sem_t mx_missile;             // Semaforo per la struttura condivisa
  sem_t mx_navicella;           // semaforo per la posizione della navicella
  sem_t mx_enemies[MAX_ENEMIES];// Semaforo per le strutture dei nemici
} navicella_table;

void init_navicella_table(struct table *m)
{  
  int i;
  sem_init(&m->mx_missile,0,1);
  for (i=0;i<MAX_ENEMIES;i++) {
    sem_init(&m->mx_enemies[i],0,1);
  }
  m->count_enemies = m->count_missile = m->score = m->level = m->killed = 0;
  m->life = INITIAL_LIFE;
}

void draw_fly(int x, int y, int c)
{
  int b;
  if (!c)
    b=0;
  else
    b=15;
  sem_wait(&mutex);
  grx_disc(x, y, D, c);
  grx_disc(x, y, D/3, b);
  grx_disc(x+D*4/5, y, D/10, b);
  grx_disc(x-D*4/5, y, D/10, b);
  grx_disc(x,y+D*4/5,D/10,b);
  grx_disc(x,y-D*4/5,D/10,b);

  sem_post(&mutex);
}
void draw_navicella(int x,int c)
{
  int l=LENGTH_NAV;
  int h=HEIGHT_NAV;
  sem_wait(&mutex);
  grx_line(x-LENGTH_NAV/2,YMAX,x+LENGTH_NAV/2,YMAX,c);    // base
  grx_line(x-l/2,YMAX,x-l/2,YMAX-h/2,c);                  // parte dx
  grx_line(x-l/2,YMAX-h/2,x-l*7/20,YMAX-h,c);
  grx_line(x-l/5,YMAX-h/2,x-l*7/20,YMAX-h,c);

  grx_line(x+l/2,YMAX,x+l/2,YMAX-h/2,c);                  // parte sx
  grx_line(x+l/2,YMAX-h/2,x+l*7/20,YMAX-h,c);
  grx_line(x+l/5,YMAX-h/2,x+l*7/20,YMAX-h,c);

 
  grx_line(x-l/6,YMAX-h/2,x,YMAX-h*5/4,c);
  grx_line(x+l/6,YMAX-h/2,x,YMAX-h*5/4,c);

  sem_post(&mutex);
}
void draw_missile(int x,int y,int c)
{
  sem_wait(&mutex);
  grx_line(x,y+LENGTH_MISSILE/2,x,y-LENGTH_MISSILE/2,c);
  sem_post(&mutex);
}
void draw_lifes(int life)
{
  char s[15];
  sprintf(s,"Navicelle: %d",life);
  sem_wait(&mutex);
  grx_text("          ",XMIN+300,YMENU+10, 0,  0);
  grx_text(s,XMIN+300,YMENU+10, 12, 0);
  sem_post(&mutex);
}

void draw_score(int score)
{
  char s[10];
  sprintf(s,"Score: %d",score);
  sem_wait(&mutex);
  grx_text("           ",XMIN+300,YMENU+20, 0, 0);
  grx_text(s,XMIN+300,YMENU+20, 12, 0);
  sem_post(&mutex);
}

void end_fun(KEY_EVT* k)
{
  sys_end();
}
TASK missile(void *arg)
{
  int index;
  int     x, y;
  int     oy;
  int     dy;
  int     col;
  int     outy;
           
  index = (int)arg;

  sem_wait(&navicella_table.mx_navicella);
  x = navicella_table.x_center;                   // centro del missile
  sem_post(&navicella_table.mx_navicella);
  y = oy = YMAX-HEIGHT_NAV-LENGTH_MISSILE;        
  dy = LENGTH_MISSILE/2;
  col = 2;                                        // colore missile
  while (1) {
    y-=dy;
    outy = (y <= YMIN);    
    /* se il missile è uscito dallo schermo */
    /* libero la risorsa                    */
    if (outy) {
      sem_wait(&navicella_table.mx_missile);
      navicella_table.count_missile--;
      sem_post(&navicella_table.mx_missile);
      draw_missile(x,oy,0);
      break;
    }
    draw_missile(x, oy, 0);
    draw_missile(x, y, col);
    int i;
   
    /* Confronto la posizione di ogni nemico */
    /* con la posizione del missile          */
    /* per verificare se è stato colpito     */
    for (i=0;i<MAX_ENEMIES;i++)
      {
        sem_wait(&navicella_table.mx_enemies[i]);
        if (enemy_table[i].status && !enemy_table[i].killed && +
          x >= enemy_table[i].x-D && x <= enemy_table[i].x+D && +
          y >= enemy_table[i].y-D && y <= enemy_table[i].y+D) {
          enemy_table[i].killed=1;                   // segnalo all'invasore che deve morire
          sem_post(&navicella_table.mx_enemies[i]);
          draw_missile(x, y, 0);
          return NULL;
        }
        else
          sem_post(&navicella_table.mx_enemies[i]);
      }
    oy = y;
    task_endcycle();
  }
  return NULL;
}

void shot()
{
  SOFT_TASK_MODEL m;
  sem_wait(&navicella_table.mx_missile);
  if (navicella_table.count_missile<MAX_MISSILE) {  
    navicella_table.count_missile++;
    int count=navicella_table.count_missile;
    sem_post(&navicella_table.mx_missile);
    soft_task_default_model(m);
    soft_task_def_level(m,0);
    soft_task_def_periodic(m);
    soft_task_def_arg(m,(void*)count-1);
    soft_task_def_period(m,MISSILE_PERIOD);
    soft_task_def_wcet(m, MISSILE_WCET);
    soft_task_def_met(m, NAVICELLA_MET);
    soft_task_def_usemath(m);
    pid = task_create("soft_missile", missile, &m, NULL);
    task_activate(pid);
  }
  else
    sem_post(&navicella_table.mx_missile);
}

void hard_shot()
{
  HARD_TASK_MODEL m;
  sem_wait(&navicella_table.mx_missile);
  if (navicella_table.count_missile<MAX_MISSILE) {  
    navicella_table.count_missile++;
    int count=navicella_table.count_missile;
    sem_post(&navicella_table.mx_missile);
    hard_task_default_model(m);
    hard_task_def_periodic(m);
    hard_task_def_arg(m,(void*)count-1);
    hard_task_def_wcet(m, MISSILE_WCET);
    hard_task_def_mit(m, NAVICELLA_PERIOD);
    hard_task_def_usemath(m);
    pid = task_create("hard_missile", missile, &m, NULL);
    task_activate(pid);
  }
  else
    sem_post(&navicella_table.mx_missile);
}

void move_right()
{
  int x,ox;
  sem_wait(&navicella_table.mx_missile);
  x=ox=navicella_table.x_center;
  sem_post(&navicella_table.mx_missile);
  if (ox<XMAX) {
    sem_wait(&navicella_table.mx_missile);
    x+=VEL_NAVICELLA;
    navicella_table.x_center=x;
    sem_post(&navicella_table.mx_missile);

    draw_navicella(ox,0);
    draw_navicella(x,COLOR_NAV);
  }
}
void move_left()
{
  int x,ox;
  sem_wait(&navicella_table.mx_missile);
  x=ox=navicella_table.x_center;
  sem_post(&navicella_table.mx_missile);
  if (ox>XMIN) {
    sem_wait(&navicella_table.mx_missile);
    x-=VEL_NAVICELLA;
    navicella_table.x_center=x;
    sem_post(&navicella_table.mx_missile);
    draw_navicella(ox,0);
    draw_navicella(x,COLOR_NAV);
  }
}

TASK navicella()
{
  navicella_table.x_center=XMAX/2;
  draw_navicella(XMAX/2,4);  
  KEY_EVT a;
  keyb_set_map(itaMap);
  a.flag = 0;
  a.scan = KEY_ENT;
  a.ascii = 13;
  keyb_hook(a,shot);
  a.scan = KEY_Z;
  a.ascii = 'z';
  keyb_hook(a,move_left);
  a.scan = KEY_X;    
  a.ascii = 'x';
  keyb_hook(a,move_right);
  while(1) {
    sem_wait(&navicella_table.mx_missile);
    if(navicella_table.killed) {               // controllo se sono stato colpito
      if (navicella_table.life==0)             // e se ho terminato le vite
        sys_end();                                    
      else {
        navicella_table.life--;                // decremento il contatore delle astronavi
        navicella_table.killed=0;              // reimposto il flag killed a 0
        draw_lifes(navicella_table.life);
      }
    }
    sem_post(&navicella_table.mx_missile);
    task_endcycle();
  }
  return NULL;
}

TASK enemy_missile(void *arg)
{
  int index;
  int     x, y;
  int     oy;
  int     dy;
  int     col;
  int     outy;
           
  index = (int)arg;

  sem_wait(&navicella_table.mx_enemies[index]);
  x = enemy_table[index].x;                       // posizione dell'invasore X
  y = oy = enemy_table[index].y;                  // posizione dell'invasore Y
  sem_post(&navicella_table.mx_enemies[index]);      
  dy = LENGTH_MISSILE;
  col = 4;                                        // colore missile
  while (1) {
    y+=dy;
    outy = (y >= YMAX-HEIGHT_NAV);    
    if (outy) {
      draw_missile(x,oy,0);
      break;
    }
    draw_missile(x, oy, 0);
    draw_missile(x, y, col);
   
    /* Confronto la posizione della navicella  */
    /* con la posizione del missile            */
    /* per verificare se è stata colpita       */

    if (y>=YMAX-HEIGHT_NAV-LENGTH_MISSILE) {
      sem_wait(&navicella_table.mx_missile);
      //int colpita = (x >= navicella_table.x_center-LENGTH_NAV/2) && (x <= navicella_table.x_center+LENGTH_NAV/2);
      if (x >= navicella_table.x_center-LENGTH_NAV/2 && x <= navicella_table.x_center+LENGTH_NAV/2) {
        navicella_table.killed=1;                   // segnalo alla navicella che è stata colpita
        sem_post(&navicella_table.mx_missile);   
      }
      else
        sem_post(&navicella_table.mx_missile);
    }
    oy = y;
    task_endcycle();
  }
  return NULL;
}

void hard_enemy_shot(int index)
{
  HARD_TASK_MODEL m;

  hard_task_default_model(m);
  hard_task_def_periodic(m);
  hard_task_def_arg(m,(void*)index);
  hard_task_def_wcet(m, MISSILE_WCET);
  hard_task_def_mit(m, NAVICELLA_PERIOD*1000);
  hard_task_def_usemath(m);
  pid = task_create("hard_enemy_missile", enemy_missile, &m, NULL);
  task_activate(pid);
}

void soft_enemy_shot(int index)
{
  SOFT_TASK_MODEL m;

  soft_task_default_model(m);
  soft_task_def_periodic(m);
  soft_task_def_period(m, MISSILE_PERIOD);
  soft_task_def_arg(m,(void*)index);
  soft_task_def_wcet(m, MISSILE_WCET);
  soft_task_def_met(m, 800);
  soft_task_def_usemath(m);
  pid = task_create("soft_enemy_missile", enemy_missile, &m, NULL);
  task_activate(pid);
}

TASK    enemy(void *arg)
{
  int index;
  int     x, y;
  int     ox, oy;
  int     dx,dy;
  int     col;
  int     outx, outy;
  int direzione = 1;
           
  index = (int)arg;

  x = ox = XMIN;
  y = oy = YMIN+D*2;
  dy = D*2;                           // passo di discesa verticale
  col = 1 + index;                    // colore nemico
  enemy_table[index].color=col;  
 
  /* il nemico controlla se è stato colpito da un missile */
  while (1) {
    sem_wait(&navicella_table.mx_enemies[index]);   // proteggo la risorsa del nemico[i]
    if (enemy_table[index].killed==1){              // se è settato il FLAG killed=>devo morire
      enemy_table[index].status=0;                  // libero la risorsa
      sem_post(&navicella_table.mx_enemies[index]); // libero il semaforo
      draw_fly(ox, oy, 0);                            
      sem_wait(&navicella_table.mx_missile);
      navicella_table.count_enemies--;           // decremento il contatore dei nemici
      navicella_table.count_missile--;           // decremento il contatore dei missili
      navicella_table.score++;                   // conta il numero di nemici uccisi
      draw_score(navicella_table.score);         // scrivo il nuovo punteggio
      sem_post(&navicella_table.mx_missile);
      break;
    }
    else
      sem_post(&navicella_table.mx_enemies[index]);
    dx = (float)(VEL * (direzione));                // passo di spostamento orizzontale
    x += dx;                                        
    outx = (x >= XMAX) || (x <= XMIN);    
    outy = (y >= YMAX-HEIGHT_NAV);        

    int sparo = rand()%500;

    /* SPARO?? */
    if (sparo==0) {
      //count_missile++;                             // un solo missile per volta, si combatte in 2
      soft_enemy_shot(index);
    }

    /* Controllo se sono arrivato al bordo dello schermo */    
    if (outx) {
        x = x - dx;     y = y + 2 * D;
        direzione=-direzione;                      // in tal caso cambio direzione
        dx = (float)(VEL * (direzione));
        x += dx;
        y += dy;
    }
    if (outy) {
      sys_end();
    }
    draw_fly(ox, oy, 0);
    draw_fly(x, y, col);
    ox = x; oy = y;
    // scrivo nella struttura condivisa
    sem_wait(&navicella_table.mx_enemies[index]);
    enemy_table[index].x = x;
    enemy_table[index].y = y;
    sem_post(&navicella_table.mx_enemies[index]);
    task_endcycle();
  }
  return NULL;
}

TASK enemy_creator(void *arg)
{
  int index=0;
  int i;
  SOFT_TASK_MODEL m;
  while(1) {
    if (navicella_table.count_enemies<MAX_ENEMIES) {
      sem_post(&navicella_table.mx_navicella);        // semaforo di mutua esclusione per la risorsa generale
      index=navicella_table.count_enemies;            // l'indice parte da 0 fino a MAX_ENEMIES-1
      navicella_table.count_enemies++;                // il contatore va da 1 a MAX_ENEMIES
      sem_post(&navicella_table.mx_navicella);      
      /* cerco una posizione libera       */
      /* nell'array di nemici enemy_table */
      for (i=0;i<MAX_ENEMIES;i++) {                  
        sem_wait(&navicella_table.mx_enemies[i]);    // semaforo di mutua per la risorsa dei nemici[i]
        if (!enemy_table[i].status) {
          index=i;                                   // se la risorsa [i] è libera esco dal ciclo
          break;                                     // senza liberare il semaforo
        }
        sem_post(&navicella_table.mx_enemies[i]);    // se la risorsa è occupata libero il semaforo e passo a i+1
      }
      /* ALMENO UNA RISORSA DEVE ESSERE LIBERA      */
      /* quindi dopo il for questa la eseguo sempre */
      enemy_table[index].status=1;                   // occupo la risora e inizializzo tutte le variabili
      enemy_table[index].killed=0;                  
      enemy_table[index].x=XMIN;
      enemy_table[index].y=YMIN;
      sem_post(&navicella_table.mx_enemies[index]);  // libero il semaforo di mutua per la risorsa[i]
      soft_task_default_model(m);
      soft_task_def_level(m,0);
      soft_task_def_periodic(m);
      soft_task_def_arg(m,(void*)index);
      soft_task_def_period(m,ENEMY_PERIOD);
      soft_task_def_wcet(m, ENEMY_WCET);
      soft_task_def_met(m, NAVICELLA_MET);
      soft_task_def_usemath(m);
      pid = task_create("soft_enemy", enemy, &m, NULL);
      task_activate(pid);
    }
    task_endcycle();
  }
  return NULL;
}

PID crea_navicella()
{
  SOFT_TASK_MODEL m_s;
  PID pid;
  soft_task_default_model(m_s);
  soft_task_def_level(m_s,0);
  soft_task_def_period(m_s,NAVICELLA_PERIOD);
  soft_task_def_wcet(m_s, NAVICELLA_WCET);
  soft_task_def_met(m_s, NAVICELLA_MET);
  soft_task_def_usemath(m_s);
  pid = task_create("navicella", navicella, &m_s, NULL);
  return pid;
}

PID hard_crea_navicella()
{
  HARD_TASK_MODEL m_s;
  PID pid;
  hard_task_default_model(m_s);
  hard_task_def_level(m_s,0);
  hard_task_def_wcet(m_s, NAVICELLA_WCET);
  hard_task_def_mit(m_s, NAVICELLA_PERIOD);
  hard_task_def_usemath(m_s);
  pid = task_create("navicella", navicella, &m_s, NULL);
  return pid;
}

PID crea_enemy_creator()
{
  SOFT_TASK_MODEL m_s;
  PID pid;

  soft_task_default_model(m_s);
  soft_task_def_level(m_s,0);
  soft_task_def_periodic(m_s);
  soft_task_def_period(m_s,ENEMY_CREATOR_PERIOD);
  soft_task_def_wcet(m_s, ENEMY_CREATOR_WCET);
  soft_task_def_met(m_s,ENEMY_CREATOR_MET);
  soft_task_def_usemath(m_s);
  pid = task_create("enemy_creator", enemy_creator, &m_s, NULL);
  return pid;
}
/*
PID crea_enemy_creator()
{
  HARD_TASK_MODEL m_s;
  PID pid;

  hard_task_default_model(m_s);
  hard_task_def_level(m_s,0);
  hard_task_def_periodic(m_s);
  hard_task_def_mit(m_s,ENEMY_CREATOR_PERIOD);
  hard_task_def_wcet(m_s, ENEMY_CREATOR_WCET);
  hard_task_def_usemath(m_s);
  pid = task_create("hard_enemy_creator", enemy_creator, &m_s, NULL);
  return pid;
}
*/


/****************************************************************/

/* This function is called when the system exits */
void byebye(void *arg)
{
  grx_close();
  cprintf("Numero di nemici totali: %d\n",navicella_table.count_enemies);
  cprintf("LIVELLO: %d\n",navicella_table.level);
  cprintf("Numero di nemici uccisi: %d\n",navicella_table.score);
}

/****************************** MAIN ******************************/

void main(int argc, char **argv)
{
  TIME seme;          /* used to init the random seed */

  init_navicella_table(&navicella_table);

  /* Set the closing function */
  sys_atrunlevel(byebye, NULL, RUNLEVEL_BEFORE_EXIT);

  /* graphic card Initialization */
  if (grx_init() < 1) {
    sys_abort(1);
  }

  if (grx_open(640, 480, 8) < 0) {
    cprintf("GRX Err\n");
    sys_abort(1);
  }

  /* The scenario */
  char s[10];
  sprintf(s,"Astronavi: %d",navicella_table.life);
  grx_rect(XMIN-D-1, YMIN-D-1, XMAX+D+1, YMAX+D+1, 14);
  grx_text("SpaceInvaders...maddechè"               , XMIN, YMENU+10, 13,0);
  grx_text("ENTER shot, 'z' Left, 'x' Right"        , XMIN, YMENU+20, 12, 0);
  grx_text("ESC   exit to DOS"                      , XMIN, YMENU+30, 12, 0);
  grx_text(s                                , XMIN+300, YMENU+10, 12, 0);
  grx_text("Score: 0",XMIN+300,YMENU+20,12,0);

  /* randomize!!!! */
  seme = sys_gettime(NULL);
  srand(seme);


  KEY_EVT k;
  keyb_set_map(itaMap);

  k.flag=0;
  k.scan=KEY_ESC;
  k.ascii=ESC;
  keyb_hook(k,end_fun);

  pid=hard_crea_navicella();
  task_activate(pid);

  pid=crea_enemy_creator();
  task_activate(pid);
}
/*--------------------------------------------------------------*/